Run the self-hosted runner
Run kanman's code work on your own infrastructure with a Docker image that connects outbound only, without opening ports or sharing database credentials.
By default, kanman runs each story in an isolated machine in Frankfurt, Germany. If your code must not leave your network, run the coding work on your own infrastructure with the self-hosted runner.
How it works
The runner is the same executor host kanman uses in its cloud, packaged as the Docker image kanman/executor-host:
- It pulls work. It opens an outbound HTTPS connection to kanman, registers, asks for the next queued run of your workspace and reports back. No inbound ports, no VPN, no firewall exceptions for kanman.
- It authenticates with a workspace API token (
km_...). It never receives database credentials. Each run it picks up gets its own run token, which stops working when the run ends. - For each run it clones the repository, creates the run branch, starts the coding agent with the run’s brief and the kanman MCP, and reports progress, the diff summary, the commits and a transcript of the agent’s work.
- The repository checkout stays on your machine.
What the model provider receives is described in What model providers see. The coding agent calls the provider from the runner, with the key you give the runner or, for teams that use their own key, with that key.
Coming in a later release
Acceptance checks on your runner. Today the acceptance spec runs (red before the work, green in a fresh environment and on a clean checkout) only run in kanman cloud, so in a workspace that sends its runs to self-hosted runners these checks cannot run: kanman retries them and then asks you in Decisions. Teams on Trial without an acceptance manifest, CI and the reviewer are not affected.
Requirements
- A Linux host or VM with Docker. The runner needs CPU and memory like a CI job for your repository.
- Outbound HTTPS to kanman, to your git host, and to your model provider.
- A model provider key for the executors the runner offers:
ANTHROPIC_API_KEYfor Claude Code,OPENAI_API_KEYfor Codex. Not needed for teams that use their own key in kanman; their key comes with the run.
Step 1: Create a token
- Open Settings > API and click Create token.
- Name it after the runner, for example
runner-fra-1. - Choose an expiry (30 days, 90 days or 1 year) that matches your rotation policy. The runner needs no particular permission; any active token of the workspace works.
- Copy the token. It is shown once.
Step 2: Start the runner
Settings > Runners shows the command to copy. With a name and both executors it looks like this:
docker run -d --name kanman-runner \
--restart unless-stopped \
-e KANMAN_API_KEY=km_your_runner_token \
-e ANTHROPIC_API_KEY=your_anthropic_key \
-e RUNNER_NAME=runner-fra-1 \
-e RUNNER_EXECUTORS=claude-code,codex \
-e OPENAI_API_KEY=your_openai_key \
kanman/executor-host
| Variable | Required | Meaning |
|---|---|---|
KANMAN_API_KEY |
Yes | The workspace API token from step 1 |
ANTHROPIC_API_KEY, OPENAI_API_KEY |
For pass-through teams | Provider key for Claude Code or Codex |
RUNNER_NAME |
No | Name shown in Settings > Runners. Default: the host name of the container |
RUNNER_EXECUTORS |
No | Comma-separated executors this runner offers: claude-code, codex. Default claude-code |
RUNNER_CONCURRENCY |
No | How many runs this runner works on at the same time. Default 1 |
LOG_LEVEL |
No | debug, info, warn or error. Default info |
Pin the image to a version tag in production and update deliberately.
Step 3: Check the status
Open Settings > Runners. The runner appears with its name, executors, version, the time it was last seen and its status. The list refreshes every 30 seconds:
| Status | Meaning |
|---|---|
| Online | Connected and accepting runs. The runner reports every 30 seconds. |
| Finishing work | The runner was asked to stop. It finishes the runs it has and takes no new ones. |
| Offline | Not connected, or no report for two minutes. Runs wait in the queue until a runner is online. |
Step 4: Send work to your runners
The choice applies to the whole workspace. Open Settings > AI providers, expand Advanced and turn off Kanman Cloud. From then on, queued runs of all teams go to your runners and are picked up in order. Settings > Runners confirms where runs execute. Concurrency still follows each team’s policy and its plan.
Scale and update
- More capacity: start more runners with different names, or raise
RUNNER_CONCURRENCYon a larger host. - Update: stop the container with enough time to finish its runs, for example
docker stop --time 1800 kanman-runner. On stop the runner shows Finishing work, completes its runs and goes offline. Then start the new version. - Rotate the token: create a new token, restart the runner with it, then revoke the old one. A revoked or expired token takes the runner offline.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| The runner does not start | KANMAN_API_KEY is missing or does not start with km_. Check the container logs with docker logs kanman-runner. |
| The runner stays offline | The token is wrong, expired or revoked, or outbound HTTPS to kanman is blocked. Check the container logs. |
| Runs stay queued | No runner is online, or no online runner offers the team’s executor. Check RUNNER_EXECUTORS. |
| Runs fail right after they start | The runner has no provider key for the executor, or the runner host cannot reach your git host or model provider. |
Last updated: January 1, 0001
Open kanman