Keep your source content on brand
Goal: flag forbidden, competitor, and off-preferred terms in your source content and rewrite what fails, so what goes to translation (or production) is already on-brand. This is source governance, before any translation. The profile format lives in Voice profile; setting one up takes ten minutes.
The video below shows the whole path on one repository, in one language, with no server, no model and no second language:
- A person reviews and confirms a drafted context graph: the recipe, a voice profile and terms.
kapi checkruns as a gate over operator documentation, interface strings and a marketing page.- Three failures are corrected in the source. The fourth becomes a term decision the graph keeps, so the next check enforces it.
The interface has changed since this was recorded. The workflow it demonstrates still applies, but some screens and labels differ from the current release. The recording runs kapi check --strict, which is plain kapi check in the current release, and grades findings as major or minor. The current kapi check marks each finding FAILS or REPORTS.
- Desktop
- Agent (Claude)
- CLI
With a voice profile bound in the project (Project Settings), the checks enforce it over everything the project tracks:
- Run the checks. Run on everything on the project's Map runs them, and its findings count opens what they found. Word-rule and voice findings appear alongside hygiene and length, each named by rule, located to a block, with the suggested wording.
- Fix at the block. Open the flagged file, correct the wording, re-run; the score climbs as findings clear.
- Fix the rule as well as the draft. A recurring off-brand term belongs in the project's terms: add it under Context → Terms so every later check enforces it.
Ask for the sweep:
Check
blog/against our voice profile and fix anything off-brand.
The assistant has the voice from the rules kapi writes into CLAUDE.md and AGENTS.md, so its rewrites follow the voice as well as the rules, and it asks kapi context <path> for the full voice when a file needs more. It runs check_file, rewrites each flagged block, and lands the edits with apply_edits (structure intact, no second model). When a term recurs, it can note it with context_note, which records a suggestion; keep it with kapi context review. It re-checks until the gate is green.
Check against a profile (yours, or a built-in starter pack) plus any inline constraints:
kapi check blog-post.md --profile-file brand/voice.yaml
kapi check blog-post.md --pack marketing-blog
kapi check product-brief.md --forbid "synergy" --forbid "disrupt" --max-words 500
Exit 0 is a pass, 3 means at least one finding fails; --json emits the kapi.check/v2 Report with one finding per block (Checks documents the schema). Then fix and re-check:
kapi inspect blog-post.md --jsonl > blocks.jsonl
# write an operation per flagged block, with its ref and rev, to edits.json
# (keep the <x id="…"/> tags)
kapi apply edits.json --dry-run # preview
kapi apply edits.json # write through the faithful round-trip
kapi check blog-post.md --profile-file brand/voice.yaml
An edit to a block that changed since you read it, or that would corrupt an inline code, is refused, and nothing in the change set is written; see Edit content. For deterministic substitution of the terms a voice file carries, with no assistant, kapi voice rewrite --profile-file brand/voice.yaml reads stdin or --input-text and reports each change. To also add the missing rule while fixing the draft, ship both in one change set:
{"ops": [
{"op": "replace_text", "at": {"doc": "blog-post.md", "block": "p"}, "if_match": "r:b74d19a2c3e4f506",
"edits": [{"find": "leverage", "text": "use"}]},
{"op": "term", "action": "upsert", "term": "leverage", "locale": "en", "status": "forbidden", "replacement": "use"}
]}
The term operation lands in the project's terms after the content, so the next check enforces it (requires a kapi project). A use of the term then fails; add "advisory":true to have it report instead, or "competitor":true for a competitor's name. Run this change set yourself. An assistant's term operation is refused, and the change set with it, so an assistant sends its content edits alone and records the rule as a suggestion for you to keep.
In a project
Bind the profile once (defaults.voice.profile, naming the profile in the project's voice store) and every surface picks it up: the findings on the desktop Map, the assistant's loop, bare kapi check, and the ship gate's voice gate. When you translate, kapi also adds the bound voice to the translation prompt, so target-language output starts on-brand.
Next
- Set up your brand guide in 10 minutes: from starter pack to bound profile.
- Content governance for AI: voice + terms + checks as one guardrail set.
- Check content like tests: the gate mechanics and exit codes.