CLI reference
Work your tasks from the terminal: see what you are on, find what you can claim, pull a task's brief, and record what you learned while building. Built so a coding agent can use it as easily as you can — every command takes --json.
npx -y kichma@1 loginThe examples below are written as kichma …, which is what you type with the CLI installed (npm i -g kichma@1). Running it through npx instead? Prefix each one with npx -y kichma@1 — the grammar is identical either way.
This page is generated from the same command table the terminal's kichma --help prints, and every example on it is run through the real argument parser in CI. If something here is wrong, --help is wrong in the same way.
What a command can change
The CLI holds a credential for you, and it is deliberately not allowed to rewrite the plan with it. Three of the commands below look like writes and are not — they park a proposal for a human to accept. Each command is tagged:
- reads
- Returns what the graph says. Changes nothing.
- local
- Writes to this machine — a credential file, a git branch — and to your own claim.
- proposes
- Parks a pending proposal. A human accepts or discards it; nothing reaches the graph until they do.
- offline
- Needs no account and no network. Verification must not depend on us being reachable.
Scope
Scope follows your checkout: inside a connected repo commands narrow to its project, outside one they span your org.
- --project <id>
Target one project by id, ignoring which repo you are in.
- --all-projects
Span the whole org, ignoring the current repo. Refused by
scan, which checks one checkout against one project.- --json
Machine-readable output. Carries exactly the same facts as the plain form — the terminal rendering has no colour and adds nothing.
Commands
login
localconnect this device
kichma login [--url]Starts a device-code flow: the terminal prints a short code and a URL, you approve it in a browser you are already signed in to, and the credential lands in ~/.kichma. No password is typed into a terminal and no token is pasted between windows.
The credential belongs to you, not to the machine — anything done with it is attributed to your account, including work an agent does on your behalf. Approve one per machine, and revoke one you no longer trust from Settings → Devices or with kichma logout.
login connects to https://kichma.ai unless --url or KICHMA_URL names another instance.
- --url <url>
Connect to a self-hosted or staging instance instead of the hosted one.
Has no project to scope, so the scope flags do not apply.
npx -y kichma@1 loginThe first thing to run, on a machine with nothing installed.
kichma login --url https://kichma.internalPoint at a self-hosted instance.
logout
localrevoke this device
kichma logoutRevokes this device's credential server-side and deletes the local file. The revocation is immediate: a credential removed here stops working on the next request, rather than lingering until it expires.
Takes no flags. Revoking a device you are not sitting at is done from Settings → Devices.
Has no project to scope, so the scope flags do not apply.
tasks --mine
readswhat you're on (default)
kichma tasks --mineThe tasks claimed by you, with each one's status, the branch and repo it was claimed on, and its pull request if one is open. Bare kichma tasks means this — it is the commoner question.
Health flags ride along: a task whose branch has gone quiet, or whose PR has been open longer than its size suggests, says so here rather than waiting for someone to look at a dashboard.
kichma tasksThe morning check, from inside a connected repo.
tasks --available
readswhat you can claim, ranked
kichma tasks --available [--all]Unclaimed tasks, ranked rather than listed: critical-path work first, then tasks whose completion unblocks the most other work. The ranking is computed from the plan's dependency graph, so it moves as the plan moves.
Blocked work is summarised rather than shown — a count, plus the single biggest blocker — because a list of things you cannot start is noise. --all widens the list past your own discipline when you want to see everything.
- --all
Include tasks outside your discipline. Without it the list is filtered to work you're set up to do.
kichma tasks --available --allEverything claimable, discipline filter off.
context
readsthe project: what, who for, architecture, what's in flight
kichma contextEverything an agent needs before its first task in a repo: the thesis, who the product is for, the market and product requirements with their status, the architecture decisions already taken, the constraints and non-goals, and what is in flight right now.
Generated live from the graph at read time, which is the point — there is nothing to keep in sync and no snapshot to go stale. Run it once per session rather than committing its output; a checked-in copy is exactly the drift this product exists to kill.
Takes no positional arguments. To read a project you are not standing in, pass --project <id>.
kichma contextAn agent's first command in an unfamiliar repo.
kichma context --jsonThe same facts, shaped for a harness to parse.
brief <KEY>
readswhat to build, and why
kichma brief <KEY>One task's full brief: what to build, its definition of done, the requirement it implements and that requirement's own parent — the Why-trace, all the way up to the idea that justified the work.
It also carries what has already been settled: decisions recorded against the task, the components it touches, and the dependencies that must land first. An agent that reads this is not guessing at acceptance criteria, which is the whole argument for briefing an agent properly instead of prompting it harder.
kichma brief T-42Everything about T-42, including why it exists.
pickup <KEY>
localclaim it, switch to its branch, print the brief
kichma pickup <KEY> [--repo, --force, --no-switch]Three things in one step: the task is claimed in your name, a task/<KEY>-<slug> branch is cut and checked out, and the brief is printed. The branch name carries the display key because a key is immutable and never reused — a branch from six months ago still resolves to the same task, and never to a different one.
The claim is what makes work visible to everyone else, so claiming and starting are deliberately the same action. If the checkout is dirty or you manage branches yourself, --no-switch does the claim and the brief and leaves git alone.
- --repo <owner/name>
Name the repo explicitly when the checkout can't be detected, or when the project spans more than one.
- --force
Claim a task someone else holds. The previous claim is released and recorded, never silently overwritten.
- --no-switch
Claim it and print the brief without touching the local checkout — for a dirty tree, or a worktree you want to cut yourself.
kichma pickup T-42Claim it and start work.
kichma pickup T-42 --no-switchClaim it without touching the working tree.
decide "<what>"
proposesrecord a decision you made while building
kichma decide "<what>" [--why, --instead, --task, --since]Building answers questions the documents did not — which library, which trade-off, what you gave up. This writes that back to the design document it belongs in, against the task you were on.
It changes nothing. The decision is parked as a proposal against the project's Architecture Decisions, and someone with access accepts or discards it. That asymmetry is deliberate: a terminal can record what it learned and still cannot rewrite the plan.
--since covers the decision that was made months ago and never written down. The commit is verified against a repo connected to the project and its authored date is recorded, so the entry reads "in effect since 2026-06-12 … first recorded today" instead of pretending the decision is new. There is deliberately no flag for typing a date: an unverifiable date would be recorded as fact and sealed into an audit export, which is worse than no date at all.
- --why "<reason>"
The context and the consequences, as you actually think of them.
- --instead "<rejected>"
What you turned down, and why. The half of a decision that is always lost first.
- --task <KEY>
The task it was decided under. Read from your
task/T-…branch when omitted.- --since <commit>
A commit that already put this decision into effect. Verified server-side; its authored date becomes part of the record.
kichma decide "Rust + cpal for the audio engine" \ --why "CoreAudio, WASAPI and ALSA all have mature Rust bindings" \ --instead "C++ with JUCE (licence), Zig (immature audio ecosystem)"A decision taken during the task you are on.
kichma decide "TypeScript across the whole stack" \ --why "One language for the CLI, the app and the scan runner" \ --since a1b2c3dA decision the first commit already made, dated from that commit.
defer "<what>"
proposespropose moving scope to a later milestone
kichma defer "<what>" [--to, --constraint, --because, --move, --task, --stdin]A deferral moves the plan, never the promise. The requirement keeps asking for the deferred thing, so it stays visibly outstanding; only the tasks move. Pointing this at an R- or MR- key is refused by name rather than quietly accepted, because deferring a requirement would de-promise it with nothing saying so.
--constraint is required, and it is the whole mechanism. A deferral without one is a cancellation nobody labelled as such — the constraint is what a later agent reads mid-task to know what today's shortcut must not foreclose.
Flags cover the simple case: whole tasks moving to a later milestone. Narrowing a task — keeping part of it in this milestone and carrying the rest forward as a new task — carries structure flags cannot express honestly, so it goes through --stdin as a JSON payload. The agent composes it, because only the agent can see which tasks a slice actually threads through.
Like decide, it changes nothing until a human accepts it. Every part of a deferral lands together or not at all: a partially applied deferral would narrow less than was asked for while reporting success.
- --to <milestone>
The milestone it moves to, by name. Created on accept if it does not exist yet.
- --constraint "<what not to foreclose>"
Required. What the work happening now must not make impossible later.
- --because "<why>"
Why it is being deferred — the body of the recorded entry.
- --move <KEY,KEY>
Tasks that move wholesale, keeping all of their scope. Comma-separated.
- --task <KEY>
The task it was recorded under. Read from your branch when omitted.
- --stdin
Read the whole deferral as JSON on stdin — the only way to narrow a task and carry its remainder forward.
kichma defer "Windows support" --to v2 --move T-16,T-17 \ --constraint "keep the audio backend behind a trait — no CoreAudio calls in shared code" \ --because "no Windows test hardware until Q3"Two whole tasks move to a later milestone.
kichma defer --stdin < deferral.jsonNarrow one task and carry its remainder forward as a new one.
propose "<task>"
proposespropose a task found while building
kichma propose "<task>" [--implements, --acceptance, --size, --milestone, --why, --task]The work you find while doing other work. Rather than a TODO comment nobody reads or a mental note that evaporates, it becomes a proposed task traced to a requirement, waiting for triage.
--implements, --acceptance and --size are all required, and the CLI asks for all three missing ones at once rather than one round trip at a time. The first is the seam law: a task that implements nothing is build-with-no-why, which is the exact drift the graph exists to surface. The other two are what make the proposal triageable instead of a wish.
Parked as a proposal like the other two write commands. Nothing appears in the plan until someone accepts it.
- --implements <R-n>
Required. The requirement it serves — the seam law admits no orphans.
- --acceptance "<done>"
Required. What done means, concretely enough to check.
- --size <S|M|L>
Required. Feeds the duration-weighted forecast, so a guess here moves the Gantt.
- --milestone <name>
A milestone by name. Defaults to the milestone of the task you're on.
- --why "<reason>"
Why the work is needed. Read by whoever triages the proposal.
- --task <KEY>
The task you found it under. Read from your branch when omitted.
kichma propose "WASAPI audio backend" \ --implements R-8 --size L \ --acceptance "audio plays on Windows 10 and 11 with latency under 20ms"A task discovered mid-build, traced to the requirement it serves.
scan
proposescheck imported tasks against this checkout, queue verdicts for review
kichma scan [--rescan-all]After importing a tracker's tickets, most of them claim a status nobody has checked against the code. This reads the checkout you are standing in and queues a verdict per imported task: the code confirms the claim, contradicts it, or settles nothing either way.
"Settles nothing" is a real verdict here, not a failure. A scan that cannot tell says so and writes nothing, because a confident wrong status in a source-of-truth product costs more than an unknown one.
Every verdict carries references — files, symbols, commits — rather than snippets, so a reviewer can check the reasoning instead of trusting it. Verdicts are queued for review like any other proposal; a scan cannot set a status by itself.
One checkout against one project, so --all-projects is refused by name. In CI, KICHMA_SCAN_TOKEN authenticates the run with nobody signed in.
- --rescan-all
Re-examine tasks that already have a verdict queued, instead of skipping them.
Takes --project, but refuses --all-projects by name.
kichma scanFrom the repo root, after a brownfield import.
audit verify <file>
offlinecheck an audit export's proof, offline
kichma audit verify <file> [--keys, --held, --url]Checks an audit export's hash chain and signatures without an account and without reaching Kichma: the thing an external auditor runs. The signing keys' public halves are published at /.well-known/kichma-audit-keys.json, which is why verification does not need us to be online or cooperative.
--held is the one that catches the interesting failure. A single export can only prove it is internally consistent; comparing it against an older one you kept proves history was extended rather than rewritten — a chain that got shorter, or that no longer reaches the head you already saw, is reported as exactly that.
Every failure is reported as one sentence an auditor can act on, naming which seal broke and how, rather than a boolean.
- --keys <file>
Verify against a local copy of the public keys instead of fetching them.
- --held <file>
An older export you kept. Proves the new one extends it rather than replacing it.
- --url <url>
Fetch the public keys from a named instance.
Has no project to scope, so the scope flags do not apply.
kichma audit verify kichma-audit-acme.jsonVerify an export end to end.
kichma audit verify new.json --held last-quarter.jsonProve the record was appended to, not rewritten.