Review & approve
Goal: take translations past what a machine can decide. kapi up produces: it brings every block to translated and holds the rest back for review. A person approves it; an assistant can pre-review first, leaving a score and its reasons for the person to read. Each review lands in the project's store, bound to the revision of the exact translation it approves and of the source it approves it for, so editing either side drops the approval. The model is the kapi loop; the store is the project store.
Settle the source first
The loop has a gate before the target work: kapi up settles your source and holds there until it clears its bar, so a source that is unchecked, off-brand or empty is not translated into every language and then redone when you fix it. A block whose source has not settled is held: kapi produces no translations for it, spends no AI on it, and reports it.
kapi up settles the source, holds any block below defaults.translate_after, and translates only the blocks that cleared it; the held ones wait for you to settle them.
The local source-settle loop, end to end:
- Run.
kapi upsettles each source block (terminology, voice, source checks), stamps it written, and holds any block whose checks fail (or, withtranslate_after: established, any block a person has not approved). Ready blocks translate; held blocks do not. A run that could translate nothing is reported as held on source. - See what's held.
kapi statusshows source readiness alongside coverage;kapi check --shipenforces the same source bar and lists the blocks that fail it. - Settle. Fix the flagged terms, voice findings, or source text, through the round-trip (
kapi apply) or your editor, so the next check clears them. Approving a source block is adecideoperation on the source, for the strictestablishedlevel. - Re-run.
kapi upre-settles only the blocks whose source changed and translates the newly-cleared ones. Repeat until nothing is held.
The level is defaults.translate_after in the recipe:
defaults:
translate_after: written # the default: source must clear its automated
# terminology, voice and source checks before translating
written is the default and requires the automated source checks to pass. established also requires a person to approve the source, for example for voice-critical or regulated content. none disables the hold and allows translation regardless of source state:
defaults:
translate_after: none # opt out: translate every block, settled or not
Review the translations
Approving translations is the person's half of the loop. Work the queue in Kapi Desktop, through your assistant, or on the command line.
- Desktop
- Agent (Claude)
- CLI
The Review surface is a queue you work through, keyboard-first:
- Enter from a gate cell. Click a ship-gate cell on the project view (or open Review from the sidebar); the queue narrows to that collection and locale, ordered findings-first so the risky blocks come up first.


- Inspect. Each block shows source and target side by side, with its check findings, provenance, and memory match below.
- Decide.
aapproves,rrejects (with a note; the block drops back to draft for the nextuppass to redo),spaceskips,j/kmove, andeputs the cursor in the translation. Edit the target text first when it needs a touch-up: links, bold and placeholders stay in place as chips you type around, and a plural shows one field per form. Save, then approve; the record binds to the edited text. When someone changed the file after you opened the block, the save or the approval stops and shows the text as it is now, and you choose whether to apply yours over it. The Changes card lists who changed the block, where and when. - Batch the clean ones. Approve clean approves every block in the current filter that has no findings, so you read only the exceptions. Each block is checked again as it is approved; one whose translation changed since the queue was listed, or that has gained a finding, stops the batch so you read it first.
- Let the AI read first. AI pre-review… scores the pending blocks with your model before you look; each block then carries an AI review score, so you spend your attention where it disagrees. Fix with AI drafts a correction through the same save path as a manual edit.
Approvals raise approved coverage immediately; the gate cell you entered from goes green when its threshold clears.
The queue with every language in one list, one block held on each of its five context layers in turn, an approval taken with the keyboard, and the batch that clears the blocks no check flagged.
Review in conversation when you are away from the desktop:
What's awaiting review in French? Show me the ones with findings first.
The assistant reads kapi status --review --json, presents each block with its findings, and drafts your verdicts as decide operations for you to apply with kapi apply: a decision is a person's, so the assistant records a pre-review and you approve. You say "approve", "reject: the tone is off", or "fix the term and approve"; for the last one the target is edited through the round-trip first, and the approval names the revision of the new wording.
The worklist, the read and the approval are one command each:
kapi status --review # blocks awaiting a person: file, key, locale
kapi inspect src/locales/en/app.json --jsonl # each block's editions, with the revision a decision names
kapi apply <<<'{"ops":[{"op":"decide","at":{"doc":"src/locales/en/app.json","block":"save.label","edition":"fr"},"if_match":"r:74dbfac2ed1c9d6e","outcome":"establish"}]}'
One queue holds every language. A translated block not yet approved is one row;
a source block your translate_after level holds is another, marked source in
the locale column and "isSource": true in the JSON. --lang narrows the
listing, and the source language is one of the choices:
kapi status --review --lang fr # one language
kapi status --review --lang fr,de # several, comma-separated or repeated
kapi status --review --lang en # the source-language blocks
A decision names the source document (the row's relative path), the block (its key) and the edition, and carries as if_match the revision kapi inspect lists for that edition, so it binds to the wording you read. A translation that changed since you read it refuses the decision as stale, with its current text. outcome is establish or reject; a decision with no edition approves the source wording, which Kapi Desktop's Review page also does. Run from an assistant's shell, a decision is refused unless KAPI_ACTOR=person says a person is at the keyboard. The decision is recorded in the project store and is durable at once, so every checkout of the project reads it and there is no second step. Read it back, with the evidence behind it, from kapi context log.
To share the record with the rest of the team, run kapi context sync. See Sharing context.
Piping works at scale: kapi inspect --jsonl through your own filter into kapi apply, one decide operation per edition you accept. A memory operation is different: it banks a source→target pair for future recycle leverage and does not promote a block to reviewed.
This recipe's worklist lives in your checkout and its decisions in the project's own store: one reviewer, one working copy at a time. When several reviewers (or a reviewer alongside an agent) need one shared queue, with assignments, live presence and per-block history, that is what connecting the project to a Bowrain server adds. See the Bowrain documentation.
Next
- Ship gates & CI: the
establishedthresholds this state satisfies. - The kapi loop: produce / promote / release, kept separate.
- The project store: the context store that holds the decision record, and the working data kapi rebuilds.