Add an acceptance manifest to your repo
Teach kanman how to start your app in a fresh environment and run acceptance specs, so every story ends with real proof.
The acceptance manifest is a small JSON file in your repository. It tells kanman how to start your application in a fresh environment and how to run the acceptance spec of one story. With it, the outcome gate can prove each change: the spec must fail before the work starts and pass on a clean checkout before the pull request becomes mergeable.
Without a manifest, only the Trial preset lets kanman work, and every evidence pack says that no outcome proof exists.
This guide takes about 30 minutes for a typical web application. The full key reference is on .kanman/acceptance.json and .kanman/verify.json.
To get a head start, let kanman open a pull request with a starter manifest for your stack: in the dry run of the team setup, or later in the team’s Settings > Repositories and tracker with Check acceptance manifests. Then adjust it with the steps below.
What you add
.kanman/
acceptance.json how to provision the app and run one story's spec
verify.json your local verify command (lint, typecheck, tests)
acceptance/
README.md optional: explains the folder to your team
<KEY>/ one folder per story, written by kanman
You write the two JSON files once. kanman writes the specs under .kanman/acceptance/<KEY>/ from each story’s Demonstrate block.
Step 1: Make the app start with one command
kanman needs a way to start your app from scratch, in an environment with nothing else running. Two options:
| Option | Use when |
|---|---|
docker_compose |
You can describe the app (and its database, if any) in a Compose file. This is the most common choice. |
apply |
The environment comes from a script or infrastructure tool, for example a preview deployment. |
If you choose Docker Compose, add a dedicated file, for example docker-compose.acceptance.yml, with a health check so kanman knows when the app is ready:
services:
app:
build: .
ports:
- "3000:3000"
environment:
PORT: "3000"
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:3000/health').then((r) => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"]
interval: 2s
timeout: 3s
retries: 30
Seed test data in the Compose file or on startup. Specs must run against the real app, never against mocks of it.
Step 2: Write .kanman/acceptance.json
This is the manifest of the public demo repository, which runs Playwright specs against a Fastify app:
{
"version": 1,
"provision": {
"type": "docker_compose",
"file": "docker-compose.acceptance.yml",
"up": "docker compose -f docker-compose.acceptance.yml up -d --build --wait",
"down": "docker compose -f docker-compose.acceptance.yml down -v"
},
"ready_url": "http://localhost:3000/api/invoices",
"ready_timeout_seconds": 120,
"setup": "npm ci && npx playwright install --with-deps chromium",
"run": {
"command": "npx playwright test",
"spec_arg": ".kanman/acceptance/{KEY}/",
"env": {
"BASE_URL": "http://localhost:3000"
}
},
"spec_dir": ".kanman/acceptance/{KEY}",
"artifacts": [
"test-results/**/trace.zip",
"test-results/**/*.png",
"test-results/**/*.webm",
"test-results/results.json",
"playwright-report/**"
]
}
What each part does:
provisionstarts and stops the environment.ready_urlis polled until it answers;ready_timeout_secondsis how long kanman waits.setupinstalls what the specs need.run.commandplusrun.spec_argruns one story’s specs.{KEY}becomes the story key, for exampleSBX-12.artifactsare the files kanman stores as proof: traces, screenshots, videos, reports. The plain pathtest-results/results.jsonis read as the JSON report, which gives the evidence pack its test counts.
Tip
Keep the trailing slash in spec_arg when you pass a folder. Playwright treats the argument as a pattern, so .kanman/acceptance/SBX-1 would also match SBX-12.
Step 3: Write .kanman/verify.json
The verify manifest is the command a developer runs before pushing. kanman runs it after the coding agent finishes, before review and the slower gates, and gives the agent one round to fix what it reports (see .kanman/verify.json). The step is optional, but it catches lint and type errors early:
{
"version": 1,
"cwd": ".",
"setup": "npm ci",
"command": "npm run lint && npm run typecheck && npm test",
"env": {
"CI": "true"
},
"ci_var_keys": []
}
If your tests need values from CI (for example a license key for a test tool), list only the names in ci_var_keys. The values stay in your CI settings; kanman reads them only for the verify command. Secrets that your CI cannot hand out, such as GitHub Actions secrets, go under secrets for runs instead.
Step 4: Try it locally
Run what kanman will run, with the example spec from the demo repository or one of your own:
docker compose -f docker-compose.acceptance.yml up -d --build --wait
npx playwright test .kanman/acceptance/EXAMPLE-1/
docker compose -f docker-compose.acceptance.yml down -v
If this works on a clean clone of your repository, it works for kanman.
Step 5: Protect the spec folder
The acceptance specs are the referee, so the implementation must never change them. kanman enforces this itself: executors can never write to .kanman/acceptance/**, and the diff guard stops a run if a commit touches the folder. We still recommend a second line in your git host:
# .github/CODEOWNERS (GitHub) or CODEOWNERS (GitLab)
/.kanman/ @your-org/tech-leads
Also make the commit status kanman/outcome-gate a required status check in your branch protection. Then a pull request can only be merged once the outcome gate has passed.
Step 6: Commit through a pull request
Add the files in a normal pull request and merge it. From the next story on, kanman:
- writes a spec from the Demonstrate block when the story moves toward Ready
- checks that the spec fails and does not mock its own target, then commits it to the branch
kanman/spec/<KEY> - after implementation, runs it against a fresh environment, then again on a clean checkout
- stores the artifacts and links them in the evidence pack
One setup for many repositories
A team with many similar repositories, for example dozens of Go services, does not need a manifest in each of them. Set a Default acceptance setup for the team in Team settings > Checks and delivery, in the fold with the default check files:
- Acceptance checks take the content of a
.kanman/acceptance.json, Local checks before review the content of a.kanman/verify.json. kanman checks both as you type and saves them only when they are valid. - Every repository of the team without its own file uses the default. A file in a repository always overrides it, so one special repository can keep its own setup.
{KEY}stands for the story key in the spec folder,spec_argand the run command, for examplego test ./.kanman/acceptance/{KEY}/....- Secrets named under
run.secretsfollow the same rules as in a repository: they reachsetupandrunonly when the team may use them (the secrets under What I may change in Team settings > Limits and budgets), and their values never appear in logs. - Team settings > Repositories and tracker shows each repository without its own file as Runs on the team’s default acceptance setup.
An example for Go services whose private modules come from your GitLab, with a read token granted to the team as the secret FM_GITLAB_READ_TOKEN. The Go toolchain and the git credential for the private modules come from the team environment (image golang:1.25, its setup step), so the commands stay plain and the runner needs only Docker:
{
"version": 1,
"provision": { "type": "apply", "command": "true" },
"setup": "go mod download",
"run": {
"command": "go test ./.kanman/acceptance/{KEY}/...",
"secrets": ["FM_GITLAB_READ_TOKEN"]
},
"framework": "other",
"artifacts": []
}
Private modules are downloaded in setup, not in provision: only setup and run receive secrets.
Frameworks other than Playwright
The manifest is framework-agnostic. Set framework to playwright, vitest, jest, pytest or other, and point run.command at your runner:
{
"version": 1,
"provision": { "type": "docker_compose", "file": "docker-compose.acceptance.yml" },
"ready_url": "http://localhost:8000/health",
"run": { "command": "pytest", "spec_arg": ".kanman/acceptance/{KEY}/" },
"framework": "pytest",
"artifacts": ["reports/**"]
}
Common problems
| Symptom | Fix |
|---|---|
| “Spec passes before implementation” | The behaviour already exists, or the Demonstrate block is too weak. Make the expected result specific to the new behaviour. |
| “Spec mocks its own target” | The spec intercepts the endpoint it should test. Remove the interception; specs must hit the real app. |
| The environment never becomes ready | ready_url does not answer within ready_timeout_seconds, or the port is not published. |
| Specs fail only in kanman | They depend on state from a previous run or on your local machine. Seed data on startup and use down -v to reset. |
Last updated: January 1, 0001
Open kanman