Set it up with your agent

Access is by request. The engine and its container images are private, and setting it up needs access to both. Interested? Request access: info@clankerlabs.com.

Paste this into the coding agent you already use, in the repository you want environments for:

Set up CLANKER.NET for this repository. Fetch https://clanker.net/setup.md and follow it step by
step. Ask me only for the decisions and approvals it marks. Never ask me to paste a secret into
this chat.

The rest of this page is what the agent follows. It is plain enough to read yourself, and each step is a command, so you can run any of them by hand.

Rules for the agent

  1. Never ask the user to paste a secret into the conversation, and never print one. Credentials go in a private file the user fills in (chmod 600), and replicator secrets import stores them. Say which names are missing, never what they hold.
  2. Nothing is created in a cloud until the user has approved the preview (step 8). Everything before it only writes files or reads.
  3. Ask once, all at once. Collect every decision in step 3 in a single message.
  4. Stop on a refusal. The engine refuses with a message that names the fix. Apply that fix, or ask the user. Do not work around it, and do not edit a generated file to make it pass.
  5. If step 2 is refused, stop. An authentication error or a “not found” there means the user does not have access yet. Tell them so, give the address in the note above, and do not look for a mirror, a fork or another copy of the engine.
  6. Commit nothing to the user’s default branch. Put the new files on a branch and say which.

1. Check the machine

node --version   # 22 or newer
git --version

Anything else the engine needs (an ssh client, for a server the user already runs) is reported by the verb that needs it.

2. Get the engine

Outside the user’s repository, with the user’s own git access (the clone is how access is checked):

git clone --depth 1 --branch v1 https://github.com/clankerlabs/CLANKERNET.git "$HOME/.replicator-engine"
(cd "$HOME/.replicator-engine" && npm ci)

Check that the checkout is at least as new as this page; if the count is 0, clone again with --branch main:

node "$HOME/.replicator-engine/packages/engine/bin/replicator.js" help | grep -c "setup github-app"

If the clone is refused, stop (rule 5).

From here on, replicator means node "$HOME/.replicator-engine/packages/engine/bin/replicator.js". The name replicator on the public package registry is a different program: always use this path.

3. Ask the user (one message)

Read the repository first, so the questions are short: how it starts (a dev server command and its port), whether it needs a database, and which other repositories belong to the same project. Then ask:

DecisionWhat to offer
Where the machine runsown-server: a server the user already has, on any cloud (its address, the ssh user, which must be root or have passwordless sudo). aws: a new server in their cloud account (region, hosted zone id). hetzner: a new server with web traffic through an outbound tunnel (an edge account id).
The domainThe DNS zone the names will live under, for example example.com. For own-server, the user creates one wildcard record. For the others the engine does.
An email addressFor the certificates the host obtains itself (own-server and aws).
Which repositoriesEach as owner/name. One becomes the default. A repository without a dev-container file is still included as a shared clone.
Who may use itGitHub logins, or a GitHub organisation.
A host idDefault dev-host. Lowercase letters, digits and dashes.

4. Write the host file

replicator init host --profile own-server --id <host id> --zone <zone> --address <address> --email <email> --gateway --private-images
replicator init host --profile aws --id <host id> --zone <zone> --region <region> --hosted-zone <zone id> --email <email> --gateway --private-images
replicator init host --profile hetzner --id <host id> --zone <zone> --account <edge account id> --gateway --private-images

Run the one that matches the choice in step 3. --gateway adds the sign-in service every public name needs; leave it out only for a host nobody will sign in to. --private-images makes the host pull the images with a registry read token; it is there because the images are private today. The verb checks the file against the schema before it writes hosts/<host id>.yml, never overwrites, and prints what is left. Do those things in the order it prints them; steps 5 and 6 below are the usual ones.

5. Store the credentials

The verb above prints the secrets this host needs, by name. Collect them without ever seeing a value.

For a server the user already runs, the engine logs in with a key pair of its own:

ssh-keygen -t ed25519 -N "" -f replicator-key
replicator secrets set hostSshPrivateKey --host <host id> < replicator-key
replicator secrets set hostSshPublicKey --host <host id> < replicator-key.pub

Action for the user: add replicator-key.pub to authorized_keys of the login user on the server (the agent cannot, unless the user says it already has access). Then delete both key files from the working folder.

Action for the user: the registry token (ghcrPullToken) is a GitHub token with the read:packages permission, created in the account that was given access. It goes in the private file below, not in the chat.

For anything else the verb listed (a cloud account’s credentials, an edge account token), create a private file and tell the user to fill it in with their editor. Do not read it back.

umask 077 && : > ./<host id>.env     # then NAME=value lines, filled in by the user
replicator secrets import --host <host id> --env-file ./<host id>.env --dry-run
replicator secrets import --host <host id> --env-file ./<host id>.env

--dry-run prints which names it would store and which are still missing. The command exits with 1 while a required one is missing. When it exits 0, ask the user to delete the file. Add the file name to .gitignore if the repository does not already ignore it.

6. Create the sign-in

People sign in with GitHub. One command creates the App the host uses for that, with a single approval in the user’s browser, and stores its credentials. A second mints the key each pod’s capability is signed with.

replicator setup github-app --host <host id> --org <organisation>   # omit --org for a personal account
replicator secrets rotate GATEWAY_BROKER_SECRET --host <host id> --yes

Approval for the user: open the link it prints in a browser on this machine and confirm. On a machine with no browser, --code <code> takes the code from the address GitHub sends the browser back to. Then ask the user to install the App on every repository in the fleet; the verb prints the link.

7. Write the repository files

In each repository that gets a container, on a branch:

replicator init devcontainer --name <repo name> --port web=<port>:public:/ [--postgres] [--image <image>]

--port is label=number[:public][:health path]. Use the port and health path found in step 3. Ask the user which image their own build produces if it is not obvious; the default is the engine’s base image.

In the repository of whoever owns the host (usually the one the agent is in):

replicator init fleet --host <host id> --repo <owner/name> --repo <owner/name> --users <login>,<login>

Use --org <organisation> instead of --users when access follows a GitHub organisation, and --workspace <owner/name> for a repository that should only be a shared clone.

Check the result, offline first because the dev-container files are read from GitHub at the ref the fleet names, and the branch is not pushed yet:

replicator validate clanker.yml --host <host id> --offline

Tell the user to merge the branches. Once they have, run it again without --offline.

8. Preview, then ask

replicator validate clanker.yml --host <host id>
replicator plan host <host id>

plan host changes nothing. Summarise it for the user in a few lines: what it would create, where, and which public names it would answer on. Approval for the user: do not continue without a clear yes.

9. Bring the host up

replicator host up --host <host id> --fleet clanker.yml

For own-server, this is the point to remind the user of the wildcard record from step 3 if it does not exist yet; host up says when it cannot find it.

10. The first pod and the check

replicator container provision --host <host id> --user <login> --repo clanker.yml
replicator host diagnostics --host <host id>

The first prints the pod’s card: its public name, its address and how to connect. Give it to the user. The second reads the proxy, the sign-in service and the host’s own log: report anything it flags.

The public names answer only behind the sign-in, and the sign-in page is the web app. A host serves it itself when its spec says gateway.app.serve: host (it needs a gateway image release that carries the app, and replicator host converge refuses with a message when it does not). Otherwise the app is published as a static site; the quickstart step 4 has it.

11. Hand over

Tell the user, in this order: the address of the app and of their pod, how to connect from a terminal and from a phone, which files were added and on which branches, which secret names are stored and where (the host’s own store, on this machine for a local state, which they should back up), and the commands to remove everything again (replicator container teardown, replicator host down).

When more than one person or machine will run the verbs, move the state to a bucket (host specs, “state”) and the workflow in the quickstart takes over from the commands above.