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 decision lands in the project's committed state store, 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, brand, source QA), 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 — never 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, brand 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"decision 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 + brand + source-QA 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 (brand-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 decision binds to the edited text. - Batch the clean ones. Approve clean approves every unit in the current filter that has no findings — you read the exceptions, not 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.
Entering the review queue from a pending ship-gate cell, working units with the keyboard verbs, editing a target before approving, rejecting one with a note, and batch-approving the clean remainder.
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 decision against the new hash.
The worklist and the decision are one command each:
kapi status --review # translated units not yet approved: file, id, locale
kapi apply <<<'{"kind":"review","file":"src/locales/fr/app.json","id":"save.label","locale":"fr","status":"reviewed"}'
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 decision lands in the state store (defaults.state, default .kapi-state.json) — commit it with your sources so the decision travels with the project:
git add .kapi-state.json
Piping works at scale: kapi status --review --json through your own filter into kapi apply. A kind:"tm" 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 decisions in the committed state store — one reviewer, one working copy at a time. When several reviewers (or a reviewer alongside an agent) need one shared queue — assignments, live presence, per-block history — that is what connecting the project to a Bowrain server adds. See the Bowrain documentation.
Next
- Ship gates & CI — the
reviewedthresholds these decisions satisfy. - The kapi loop — produce / promote / release, kept separate.
- The project store — why the state store is the one committed artifact.