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:

  • provision starts and stops the environment.
  • ready_url is polled until it answers; ready_timeout_seconds is how long kanman waits.
  • setup installs what the specs need.
  • run.command plus run.spec_arg runs one story’s specs. {KEY} becomes the story key, for example SBX-12.
  • artifacts are the files kanman stores as proof: traces, screenshots, videos, reports. The plain path test-results/results.json is 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:

  1. writes a spec from the Demonstrate block when the story moves toward Ready
  2. checks that the spec fails and does not mock its own target, then commits it to the branch kanman/spec/<KEY>
  3. after implementation, runs it against a fresh environment, then again on a clean checkout
  4. 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_arg and the run command, for example go test ./.kanman/acceptance/{KEY}/....
  • Secrets named under run.secrets follow the same rules as in a repository: they reach setup and run only 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.
Team settings, Checks and delivery: the default acceptance setup with acceptance checks for Go services in a container and local checks before review, both valid

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