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.
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. It is meant to run after implementation, before the slower gates. kanman does not run it yet (see .kanman/verify.json), so this step is optional for now:
{
"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 does not pass these variables to the executor yet.
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
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