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:

  • 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. 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:

  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

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