Context
A project's context is what its writing keeps to: the voice, the words to
use and to avoid, and wording already approved. Writers and agents read it
before they draft, and kapi check scores the result against the same context.
You work with four things:
| What it is | Where to read more | |
|---|---|---|
| a rule | something the project keeps to, such as "write Quickcast, not Quick cast". A check fails on it unless it is advisory. | Growing context |
| a suggestion | a rule somebody noticed and nobody has decided about yet. Checks report it and none fails on it. | Growing context |
| where it applies | the part of the project a rule or a voice holds for: one product, one channel, the whole project, or every project you work on | below |
| sharing | kapi context sync, which gives the rest of the team what you recorded and takes in what they did | Sharing context |
The same context serves writing in one language and in many. Language overrides adjust a voice for one language and leave the rest of it alone.
Ask what applies here
Before you write a file, ask what applies to it: run kapi context <path>,
open the file in Ask in Kapi Desktop, or let an assistant call
context_read over MCP. The answer is a short brief:
the voice to write in, one list of the words to use and to avoid there, and
what has been suggested but not yet decided. A person can read it, and an
assistant reads the same text.
kapi context docs/billing.md
# Writing docs/billing.md
Voice: Fernwell. Plain, second person, for studio owners who are not accountants. Short sentences.
Say this, not that:
- Fernwell Ledger, not "the Ledger": The product. Always the full name in prose.
- person, not "seat"
Suggested, not yet established:
- Quickcast, not "Quick cast", "Quick-cast", "QuickCast" (claude-code, seen in docs/billing.md)
Nothing else is recorded for this file. As you read the files around it, record with context_note (or `kapi context note`) what they do every time, including names your text does not use: each product, feature and plan name as written, the spelling variety, and a word chosen over a common alternative. Leave alone a word they write more than one way, with no note about it.
The word list gathers every rule that holds for the file: the project's own
terms, the rules you applied to every project, and the terms of a starter pack
the project uses as its voice. A rule held in two places is one line. The voice
shows only what the voice profile sets; kapi voice show --profile <name>
prints all of it.
A note in prose that a person kept, such as who the text addresses, is listed under Established notes in the answer for each file where it holds.
The answer is for the file's content. Ask with --comments before you write a
comment in a source file: a project can give its code comments guidance of
their own, and the answer then lists the limits that hold there.
kapi context cmd/main.go --comments
A rule held for one part of the project says nothing about the rest, so the answer for a file where it does not hold names the wording that stays as it is. A rename kept for the help pages leaves the API reference with the old name, and the answer for a file there says so:
Keep as it is in this file:
- "Workspace" is correct here; do not rename it to "Space". That rename holds only in changelog/ and help/.
kapi check holds the same line. "Space" in a file under legal/ is a finding
there, and it fails the check unless the rule is advisory.
With no file in hand (an ad-hoc draft, a starter pack), name a product from the recipe, a stored voice profile or a starter pack instead:
kapi context --profile marketing
--json gives the whole answer as data. --explain adds how kapi reached it:
which part of the project the file sits in, which recipe line chose the voice,
which project and which state of your context answered, whether the files on disk still match what kapi last read,
and any notes. Two answers read from the same state can be compared directly. A
stale answer means files changed since kapi last read them, and kapi up
reads them again.
Over MCP the context_read tool returns the same answer for
a path, and the same text is a resource: context://docs/billing.md, with
context://docs/billing.md?format=json for the document --json prints.
Search what the project says about a word
The other question takes a word or a phrase and asks everything the project keeps. In Kapi Desktop, search for the word in Ask; on the command line:
kapi context search "sign-in"
One question reaches the voice, the terms and the content memory together.
The answer lists the terms to use, the terms to avoid with their replacements,
and wording already approved, grouped by kind. Approved wording that contains a
term to avoid is flagged. Each term reports how often your content uses it, as
of the last kapi up, so a term added since then shows no uses until the next
run. The desktop explorer shows the same counts.
--locale narrows the terms to one language, and --json prints the same
document the MCP context_search tool returns.
| Question | Ask | Over MCP |
|---|---|---|
| what applies here? | kapi context <path> | call context_read, or read context://<path> |
| what do we know about this? | kapi context search <query> | call context_search |
An answer with nothing in it
A project with nothing recorded says so:
# Writing docs/billing.md
Nothing is recorded for this file yet. Write as the surrounding files do.
As you read the files around it, record with context_note (or `kapi context note`) what they do every time, including names your text does not use: each product, feature and plan name as written, the spelling variety, and a word chosen over a common alternative. Leave alone a word they write more than one way, with no note about it.
The last paragraph asks an assistant to note what it sees, and each note
arrives as a suggestion (Growing context). When the
checkout carries context files that kapi has not read yet, the answer starts
with a notice asking a person to run kapi store import.
The JSON carries the same fact as a coverage value, so a script or an
assistant can act on it. It counts what holds for the file: the voice, the
terms and the rules you kept. A search counts the terms it matched and the
approved wording it found.
coverage | What stood behind the answer |
|---|---|
covered | two or more of them |
thin | one of them, or suggestions alone |
empty | nothing |
Suggestions can raise an answer from empty to thin and never to covered.
coverage describes the answer, so a search for a word nobody here has written
about is empty however much the project holds elsewhere.
Rules and suggestions
A new project starts with no rules. They grow out of ordinary work: an
assistant notes the name the files always use, or the word you changed in its
draft, and each note arrives as a suggestion. A suggestion advises from the
moment it is recorded. Checks report it, no check fails on it, and it becomes a
rule when you keep it with kapi context review, or when your own work backs
it, such as a merged change that writes it.
Use the context before, during and after writing:
- Before: an agent reads the project's rules in the
AGENTS.mdorCLAUDE.mdof the folder it works in, which kapi writes from the context (below).kapi context <path>gives a person, or an agent that needs more than those files state, the full answer for one file. - During: an agent notes what it sees and what you change, as suggestions for you to decide about. A note applies only where the agent saw it, in that file's part of the project; applying it more widely is your decision in review, and evidence alone never widens it.
- After:
kapi checkscores the result block by block against the same rules, with an exit code, so they hold in the editing loop and again in CI with no assistant present.
Growing context covers noting, reviewing, and going back to an earlier state.
Rules files for agents
An agent loads the AGENTS.md or CLAUDE.md of the folder it works in before
it reads anything else, so kapi writes the project's rules there. The root's
files state the rules that hold everywhere and name the folders with rules of
their own; each of those folders gets files that state only what holds there:
its voice when it has one of its own, what to write and what not, the wording
that stays as it is, the notes a person kept that hold there, and the
kapi check line that verifies the result. For a
project that renamed Workspaces to Spaces in its help pages and changelog, the
legal terms get this:
<!-- kapi:rules (written by kapi from this project's context; edit outside this section) -->
## Writing rules for legal/
These rules hold for the files in legal/, beside the project's rules in the root AGENTS.md. Where the two differ, follow this file. kapi writes this section from the project's context, so edit outside it.
Voice: Legal. Exact and formal.
This voice takes the place of the project's voice for these files.
Keep as it is:
- "Workspace" is correct here; do not rename it to "Space". That rename holds only in changelog/ and help/.
Before you finish, run `kapi check <file>` on each file you changed and fix what it reports. `kapi context legal/<file>` gives the full answer for one file when you need more than this section.
<!-- /kapi:rules -->
kapi owns the marked section and nothing else: your own text in the file stays
as you wrote it, and a CLAUDE.md that imports @AGENTS.md gets no section of
its own. A file kapi created is removed once its folder has no rules of its
own; a file with your text in it only loses the section. Each list is capped,
most important rules first, with the command that lists the rest, and the
output is the same for the same context, so the files are safe to commit and
their diffs show what changed in the rules.
kapi init writes the files, and kapi rewrites them when the context changes:
after a decision in kapi context review or in Kapi Desktop, after
kapi context sync, and at the end of kapi up. kapi context sync --files-only
writes them on demand, and kapi init --no-rules-files leaves a project
without them.
Where a rule applies
Different parts of a project can need different guidance. A framework and its companion app may have distinct voices; a marketing page and an API reference may use different registers. The recipe says which part of the project each file belongs to, along two structural axes:
| Axis | Answers | In the recipe |
|---|---|---|
| product | which thing this belongs to | a key under profiles: |
| channel | which surface it ships on | a channel: on the collection, as product/channel |
Each key under profiles: is a product, and the channels it lists are the
surfaces that product ships on. A collection says where its files belong with
one channel:. A project with one voice for everything declares no products
at all, and the project defaults hold for every file.
profiles:
acme:
channels: [docs, app, landing]
voice:
profile: acme
collections:
- name: acme-docs
channel: acme/docs
base: web
content:
- path: "docs/**/*.md"
- name: acme-landing
channel: acme/landing
content:
- path: "site/pages/**/*.mdx"
This example defines one product with three channels. Add another key under
profiles: for a second product. Channel names belong to their product, so two
products can each have a docs channel with different guidance.
A collection's channel: is always written product/channel. A bare channel
name is a load error, even when exactly one product declares it, and the error
names the qualified form to paste. Products and channels are lowercase,
stable identifiers that are never translated, so guidance stays attached when
a term is reworded. The project file
reference covers the field
shapes in full.
Further axes
A project can name further dimensions its content varies along, under
defaults.coordinates. Every collection inherits them, and a collection that
differs on one axis overrides that axis alone with its own coordinates:.
defaults:
coordinates:
brand: acme
collections:
- name: acme-docs
channel: acme/docs
coordinates:
mode: how-to
content:
- path: "docs/**/*.md"
Two axes have a conventional spelling. brand is coarser than product: a
workspace has brands, a brand has products, a product ships channels. mode is
the kind of document, in the sense of the Diátaxis scheme: tutorial,
how-to, reference or explanation, which lets tutorials and architecture
notes take different guidance. Declare whatever axis your content needs.
An axis can be given a kind under axes:, and with a kind one value can sit
inside another. A geo axis takes places: countries, their counties, and the
cities and territories your recipe declares. A rule kept for Norway then holds
for content written for Oslo. Place content in markets and areas
walks through it.
Product and channel are never written under coordinates:. They come from a
collection's channel:, and a recipe that repeats them there is rejected at
load.
What holds for a product
The voice, the terms and the content memory are kept in your workspace, one set per project. The recipe says which voice and which terms hold for each product:
| Context | Holds | Chosen by |
|---|---|---|
| voice profile | tone, register, style measures and pattern rules | defaults.voice, or a product's voice: |
| terms | the approved word for each concept, per language, and every word to avoid | the project's own terms, or a product's termstore: |
| content memory | wording already produced and approved | the project's own content memory |
profiles:
acme-labs:
channels: [docs]
voice:
profile: acme-labs # this product's voice
termstore: labs-terms # this product's terms
Every wording rule ("write this, not that") is a term, with the same shape as
the term_rules: a check or a translation step takes: a term, its replacement
and whether a violation fails the check. A voice file may carry such rules
under terms:, as the starter packs do, and kapi store import moves them into
the project's terms. The voice profile
reference lists the fields.
A collection with no target language can say so with source_only: true, so a
run reads and checks it and writes nothing back; the project file
reference covers it.
When more than one voice could apply
The most specific guidance wins:
A file takes the most specific guidance the recipe gives it; a collection with no channel takes the project default.
- A product chooses a voice and terms. Its
voice:wins as written; failing that, a voice profile stored under the product's own name; failing that,defaults.voice. Terms come from the product'stermstore:, else from the project's own terms. - A channel adjusts that voice. A channel entry inside the voice profile replaces the tone, the style, or both, so a landing-page register is written once beside the voice it varies. A channel with no entry takes the base voice.
Terms hold on every channel. The words a product uses and avoids are the same on every surface it ships on, so a channel changes the register and leaves the terms alone.
kapi checks these declarations when it loads the recipe, and rejects unknown channels, unqualified channel references, invalid identifiers and a voice named two ways.
kapi context <path> --explain says which of these chose the voice for that
file.
Guidance with dates
A product's guidance can hold for a period, given as a date or an RFC3339
instant. valid_from is inclusive and valid_to exclusive, so a valid_to
date excludes that whole day.
profiles:
acme-relaunch:
channels: [landing]
voice:
profile: acme-relaunch
valid_from: 2026-09-01
valid_to: 2026-12-01
Outside its dates the product's guidance stops holding, and the files fall back to the next guidance up, as if the product were not declared. One run uses one instant throughout, so a long run cannot cross a boundary halfway. The first run, check or push that falls back says so:
governance: profile "acme-relaunch" expired 2026-12-01; governing with the project default
kapi context search labels each dated product active, upcoming or
expired, so a writer can see that guidance has an end date before it lapses.
A single term can carry the same dates. During a rename, a dated term can say recognise the old name until March, where an undated one says never use it.
One more axis: language
Adding target_languages to the recipe changes nothing about where guidance
holds. A translated block takes the guidance of its source: the voice of
acme/landing is the voice its Norwegian landing page is written in, and the
terms of acme/docs are the terms its German documentation uses.
A language adds an override inside the voice profile, next to the channel
overrides: a locales: entry carries the formality, the point of view, the
cultural notes and the examples for that language. Terms carry their
renderings per language. The guidance you write for the source governs every
language, and the kapi loop keeps the languages in step.
Sharing context
The context lives in your workspace on this machine, shared by every clone and
worktree of the project. To share it with the rest of the team, name a place in
kapi.yaml and run kapi context sync:
context:
backend: git
Sharing context covers the places you can name, backups, and reading context files into a project.
Related
- Growing context: noting a rule with the evidence behind it, reviewing suggestions, and going back to an earlier state.
- Sharing context:
kapi context sync, and carrying a project's context in one file. - Content governance for AI: the how-to; set up the context and gate on it.
- Keep terms consistent: building and enforcing the terms.
- The project store: where the context is kept on this machine.
- Project file reference: the
profiles:,channel:andcoordinates:fields in full. kapi contextandkapi context search: each command's flags and output.