Review & approve
Goal: take translations past what a machine can decide. kapi up produces: it brings every unit to translated and parks the rest. A person promotes: reviewed, then optionally signed-off. Each review lands in the project's committed unit-state record, bound to the content hash of the exact translation it blesses, so an approval can never silently outlive the text it approved. 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 an un-checked, off-brand, or empty source is never translated into every language only to be redone when you fix it. A block whose source has not settled is held (its translations are not produced) and the run says so plainly rather than spending AI on it.
kapi up settles the source, holds any block below defaults.source_gate, 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 its authoring status (authored → checked → approved), and holds any block below the gate. Ready blocks translate; held blocks do not. A run that could translate nothing surfaces as held on source rather than as a silent skip. - 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. An explicit source sign-off is akind:"review"entry on the source, for the strictapprovedgate. - Re-run.
kapi upre-settles only the blocks whose source changed and translates the newly-cleared ones. Repeat until nothing is held.
The gate level is defaults.source_gate in the recipe:
defaults:
source_gate: checked # the default: source must clear its automated
# terminology, voice and source checks before translating
checked is the default when unset: the same bar the server holds to, with no human bottleneck. approved additionally requires a human source sign-off (voice-critical or regulated content). none disables the gate entirely, the deliberate "draft freely, raw MT" opt-out for single-player work that wants translations regardless of source state:
defaults:
source_gate: none # opt out: translate every block, settled or not
Then the person's half of the loop (promoting the translations themselves) is the rest of this page.
- 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 units come up first.
- Inspect. Each unit shows source and target side by side, with its check findings, provenance, and memory match below.
- Decide.
aapproves,rrejects (with a note; the unit drops back to draft for the nextuppass to redo),ssigns off,spaceskips,j/kmove. Edit the target text first when it needs a touch-up: save, then approve; the record binds to the edited text. - Batch the clean ones. Approve clean approves every unit in the current filter that has no findings, so you read the exceptions rather than the bulk.
- Let the AI read first. AI pre-review… scores the pending units with your model before you look; each unit 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 reviewed coverage immediately; the gate cell you entered from goes green when its threshold clears.
The queue with every language in one list, one unit held on each of its five context layers in turn, an approval taken with the keyboard, and the batch that clears the units no check flagged.
Review conversationally; useful when you're the reviewer but not at the desktop:
What's awaiting review in French? Show me the ones with findings first.
The assistant reads kapi status --review --json, presents each unit with its findings, and records your verdicts with kapi apply (kind:"review"). You say "approve", "reject: the tone is off", or "fix the term and approve"; for the last one it edits the target through the round-trip first, then records the approval against the new hash.
The worklist and the approval are one command each:
kapi status --review # units awaiting a person: file, id, locale
kapi apply <<<'{"kind":"review","file":"src/locales/fr/app.json","id":"save.label","locale":"fr","status":"reviewed"}'
One queue holds every language. A translated unit not yet approved is one row;
a source unit your source_gate is waiting on 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 units
kapi apply records target-language decisions. Approve source wording in the
Review page of Kapi Desktop, which writes it to the same project store under
the source locale.
Address the unit exactly as the worklist lists it. status is "reviewed" by default; "signed-off" is the optional final rung for contractual or regulated content. The state record lands in the project store's working set; kapi commit writes it into the unit-state record under .kapi/state/, which you commit with your sources so it travels with the project:
kapi status # what is staged but not yet committed
kapi commit # → .kapi/state/*.jsonl
git add .kapi/state/
Piping works at scale: kapi status --review --json through your own filter into kapi apply. A kind:"memory" entry is different: it banks a source→target pair for future recycle leverage and does not promote a unit to reviewed.
This recipe's worklist lives in your checkout and its unit state in the committed record: 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
reviewedthresholds this state satisfies. - The kapi loop: produce / promote / release, kept separate.
- The project store: why the unit-state record is the committed half and
store.dbthe derived one.