Workflow gates for AI coding agents

Your agent says the tests passed.

Sometimes it is right, and you cannot tell which time from the transcript — because the transcript is written by the same thing you are checking. kanban-flow moves the proof into files on disk: the gates do not read the agent's summary, they read .works/.

$ npm install -g @phuthuycoding/kanban-flow

brainstorm planning implementation testing review done

Setup the agent can finish

Install, init, then one command teaches the agent the project: kf autoconfig prints what is done, what is missing, and the command that closes each gap. Hand the output to your agent — or let it run the command itself.

$ npm install -g @phuthuycoding/kanban-flow added 1 package $ kf init # or --defaults on a non-TTY ✓ .works/{brainstorm…done} · .kf/ seeded ✓ 11 skills and 7 agents → kf plugin (/kf:flow) · AGENTS.md created $ kf autoconfig # a briefing the agent finishes ## Setup checklist - [x] Project config (.kf/config.json) - [x] kf plugin (kf@kanban-flow, Claude Code) — installed, enabled (scope: user) - [x] Base review rules (.kf/review/rules/) - [x] Stack rule packs: node - [ ] Declared contexts — run: kf contexts - [ ] Phase hooks (.kf/hooks/) — optional ## Workflow guide — pipeline, gates on every transition, commands $ kf new user-login --context auth Created 'user-login' → .works/brainstorm/ Next: kf instruct spec-requirement --change user-login $

A gate is a file that exists, or does not

Every work item walks one pipeline, and only the CLI moves it between stages. Most stages owe an artifact, and a transition is refused when that artifact is missing, empty, still full of template placeholders, or carrying a real secret.

Refusals, not warnings

A testing report that does not say PASS does not reach review. A review report that does not say PASS does not archive, nor does one with no docs: key. While the item is in review, kf validate reports docs: updated without a change under the living docs in docs/specs/ as an error.

Three decisions stay human

Confirming the requirement, approving the execution contract (approval starts the item), and merging the pull request after a review PASS. The tool never takes those.

Approval bound to the bytes

Approval carries a SHA-256 fingerprint of the contract. Edit the plan and it is invalid until planning approves it again.

An override leaves a mark

--force works, and is written into .kfw.json where a reviewer will find it. Nothing is skipped quietly.

Evidence that expires

Most of the mechanics here exist elsewhere. One I have not found anywhere else: every entry into testing mints a fresh execution id, and a report is accepted only when its execution: field matches the current one.

Fix a failure, go round again, and yesterday's green report is inert. It is not deleted, argued with, or trusted less — it simply stops matching, so passing again costs exactly one honest test run.

# first pass$ kf stage x testing → execution run-1$ kf stage x review ✓ report says run-1 # review came back FAIL, code changed$ kf stage x implementation$ kf stage x testing → execution run-2$ kf stage x review ✗ refused report still says run-1

From approval to the merge gate, in your session

Once you approve the plan, which starts the item, the session you work in runs the rest. It dispatches a test-writer, a developer and a code-reviewer per task, running developers, up to the live developer cap, at once in one worktree on tasks whose files overlap no open task, and the plan's task table names a file allowlist for every task. Approval seals it.

kf next reads the ledger, the plan, the reports and the verify logs and prints what is due now: which seat to dispatch, which task to verify, which ledger line to write, which task is complete, and where a judgement is the session's to make. It changes no file and starts nothing; the session still dispatches every seat. kf record writes each ledger line, stamped, under the item lock, and kf next --resume picks a loop up after compaction. Behind it runs one state machine per task, folded from the ledger, with a liveness guard: every open task gets an action, a seat in flight or a wait, or else a stop saying kf next has no rule for it, never silence.

The live developer cap starts at min(2, ceiling), steps up by one after each clean parallel wave and halves (never below 1) on a contention-shaped verify failure; the ceiling is harness.developers.max (integer 1..16, default 6). worktree.domains (boolean, default true) switches the .test domain off: with it false, there are no .test DNS or proxy probes, kf status prints only http://127.0.0.1:<port>, hooks get no KFW_WORKTREE_DOMAIN; ports and routes are still allocated and JSON outputs still carry domain.

After each task commit, kf verify decides the mechanical part, not the developer's report: it checks the files the task changed against the allowlist (--commits for the pipelined loop) and runs the verify commands you pinned in config, plus harness.verify.related with the task's changed files appended, so a task runs only its related tests. Once a wave's tasks are complete, kf verify user-login --wave 1 runs the full suite on the wave's head; the next wave's developers wait until that wave verify passed; kf loop-stats measures where the loop's time went. Before review, kf verify --stage records its run at the item's HEAD, and kf stage review moves only on a passing record (or a waiver the human gives when no stage commands are pinned) — never on the report's word. The review gate reuses the last wave's record when it passed at HEAD, so --stage runs only when kf status does not show PASS at HEAD. The work stops when a review PASS waits for its merge, or earlier with a named reason. The commands kf drive, kf run, kf runs, kf harness were removed.

$ kf tasks authTASK-001 wave 1 done deps: - files: auth/TASK-002 wave 1 done deps: - files: e2e/ $ kf verify auth --task TASK-002 --base 9f8e7d6Every changed file is inside TASK-002's Files.All 1 task verify command(s) passed. $ kf verify auth --stageAll 2 stage verify command(s) passed.

The plan decides the scope

Every task's allowlist is part of the approved contract. Editing it after approval means approving again.

kf checks, the agent does not

A file outside the allowlist exits 2. Verify commands come only from .kf/config.json, never from an artifact.

Migrating is one command

kf doctor --fix removes the retired harness keys and the run state left in item metadata, and keeps harness.verify.

Start in one command

Needs Node 20 or newer. kf init seeds .kf/, installs the 11 skills and 7 agents (code-reviewer, scout, spec-reviewer, developer, test-writer, automation-writer and researcher) the skills dispatch — as the kf plugin in Claude Code (/plugin marketplace add, /plugin install kf@kanban-flow; then start with /kf:flow), as kf-<name> copies for other runtimes — and leaves your existing AGENTS.md alone. kf autoconfig then prints a briefing — context, a setup checklist with the command that fixes each missing item, the review rules — that the agent configures the project from.

npm install -g @phuthuycoding/kanban-flow

cd your-project
kf init                             # seeds .kf/, installs the skills
kf autoconfig                       # hand this briefing to your agent
kf new user-login --context auth    # opens Phase 1 in brainstorm
kf status --change user-login       # the checklist, and what is blocking
kf next user-login                  # after approval: what the task loop does now
kf record user-login dispatched TASK-001 developer --model sonnet  # one stamped ledger line
kf verify user-login --wave 1       # a complete wave's full suite; the next wave's developers wait for it
kf verify user-login --stage        # records the run at HEAD; kf stage review reads that record
kf doctor                           # is the project itself healthy?
kf config set --global reviewer Alice  # reviewer, agents, skills: global, workspace or project; the project wins