Šķîþ ţö ḿàîñ çöñţéñţ

Bowrain Þŕöĵéçţ Ḿöđéļ

À bowrain þŕöĵéçţ îš à .kapi þŕöĵéçţ ŵîţĥ à bowrain: ƃļöçķ öñ îţš ŕéçîþé. Ţĥéŕé îš öñé þŕöĵéçţ ḿöđéļ šĥàŕéđ ŵîţĥ ţĥé kapi ÇĻÎ: à šîñĝļé kapi.yaml ŕéçîþé ƒîļé àţ ţĥé þŕöĵéçţ ŕööţ àñđ à šîƃļîñĝ .kapi/ đîŕéçţöŕý.

Đîŕéçţöŕý Šţŕüçţüŕé

my-app/
├── kapi.yaml # the recipe (committed); fixed, conventional filename
├── .kapi/ # committed; the project's context
│ ├── manifest.yaml # bookkeeping: block counts, fingerprints
│ ├── filters.json # shared reader/writer configuration
│ ├── filters.local.json # personal overrides (gitignored)
│ ├── flows/ # optional file-per-flow definitions
│ │ └── pseudo.yaml
│ ├── terms.json # terms (bound by defaults.terms_source)
│ ├── voice.yaml # the voice profile (bound by defaults.voice)
│ ├── memory/ # content-memory bundles
│ │ └── memory.json # the primary (bound by defaults.memory_source)
│ ├── profiles/ # per-profile governance overrides
│ │ └── bowrain/
│ │ └── voice.yaml
│ ├── state/ # the unit-state record, one shard per document
│ │ └── src-locales-en-messages.jsonl
│ └── work/ # gitignored; everything derived
│ ├── store.db # the local index over everything committed
│ ├── vault/ # withheld redaction originals (local-only)
│ └── cache/ # free to delete, always
│ ├── sync-cache.json # the tree last declared to the server
│ ├── extractions/
│ └── collections/
└── src/
└── locales/
├── en/
│ └── messages.json
└── fr/
└── messages.json

Öŵñéŕšĥîþ žöñéš àţ ţĥé þŕöĵéçţ ŕööţ:

  • kapi.yaml: ĥàñđ-éđîţéđ, çöḿḿîţţéđ ţö ĝîţ. Ţĥé ŕéçîþé îš ţĥé šîñĝļé šöüŕçé öƒ ţŕüţĥ ƒöŕ þŕöĵéçţ çöñƒîĝüŕàţîöñ. Îţš ƒîẋéđ, çöñṽéñţîöñàļ ƒîļéñàḿé ḿéàñš éṽéŕý éđîţöŕ àñđ çöđé ĥöšţ (ĜîţĤüƃ, ĜîţĻàƃ) àþþļîéš ÝÀḾĻ šýñţàẋ ĥîĝĥļîĝĥţîñĝ ţö đš àñđ þŕéṽîéŵš ŵîţĥ ñö çöñƒîĝüŕàţîöñ. Öñé ţĥîñĝ ŵŕîţéš îţ ƃéšîđéš ýöü: àñ àẋîš àþþŕöṽéđ öñ ţĥé šéŕṽéŕ àŕŕîṽéš àš à kapi pull ţĥàţ éđîţš defaults.coordinates, ƒöŕ ŕéṽîéŵ îñ ĝîţ.
  • .kapi/: ţĥé çöḿḿîţţéđ çöñţéẋţ ĝŕàþĥ, ƒļàţ: terms.json, memory/ àñđ voice.yaml, ŵîţĥ þéŕ-þŕöƒîļé öṽéŕŕîđéš üñđéŕ profiles/<name>/, ŕéṽîéŵéđ ţĥŕöüĝĥ git diff ļîķé àñý öţĥéŕ šöüŕçé ƒîļé. .kapi/ îš çöḿḿîţţéđ îñ ƒüļļ; öñļý .kapi/work/ îš ĝîţîĝñöŕéđ.
  • .kapi/state/*.jsonl: ţĥé üñîţ-šţàţé ŕéçöŕđ, çöḿḿîţţéđ. kapi commit þüƃļîšĥéš šţàĝéđ üñîţ šţàţé îñţö îţ.
  • .kapi/work/store.db: kapi-öŵñéđ, ĝîţîĝñöŕéđ. Öñé ŠǪĻîţé ƒîļé ĥöļđîñĝ éṽéŕý šüƃšýšţéḿ'š ţàƃļéš: ƃļöçķ çàçĥé, ţéŕḿš šţöŕé, çöñţéñţ ḿéḿöŕý, ţĥé ŵöŕķîñĝ šéţ öƒ üñîţ šţàţé šţàĝéđ šîñçé ţĥé ļàšţ kapi commit, àñđ ţĥé þŕöĵéçţ'š çöñţéẋţ ĝŕàþĥ. Îţ îš àñ îñđéẋ öṽéŕ ţĥé çöḿḿîţţéđ šöüŕçéš àƃöṽé àñđ ŕéƃüîļđš ƒŕöḿ ţĥéḿ.
  • .kapi/work/cache/: ÇĻÎ-öŵñéđ, ĝîţîĝñöŕéđ. Éṽéŕýţĥîñĝ çĥéàþļý ŕéĝéñéŕàƃļé: ţĥé ţŕéé ļàšţ đéçļàŕéđ ţö ţĥé šéŕṽéŕ, éẋţŕàçţîöñ îñţéŕḿéđîàţéš, öṽéŕļàý ļàýéŕš. Šàƒé ţö đéļéţé àţ àñý ţîḿé.
  • .kapi/flows/*.yaml: öþţîöñàļ ƒîļé-þéŕ-ƒļöŵ đéƒîñîţîöñš, ĥàñđ-éđîţéđ, çöḿḿîţţéđ. Bowrain ŕéàđš ţĥéšé îñ àđđîţîöñ ţö îñļîñé flows: đéçļàŕéđ öñ ţĥé ŕéçîþé.

Ļöçàļ àñđ šéŕṽéŕ çöñṽéŕĝé îñ šĥàþé. Bowrain àñšŵéŕš ĝŕàþĥ ǫüéšţîöñš öṽéŕ öñé đàţàƃàšé šþàññîñĝ ŵöŕķšþàçéš, þŕöĵéçţš àñđ šţŕéàḿš; à þŕöĵéçţ àñšŵéŕš ţĥé šàḿé ǫüéŕý šĥàþéš öṽéŕ store.db ŵîţĥ ţĥöšé đîḿéñšîöñš ƒîẋéđ ţö öñé ṽàļüé, šö ŵĥîçĥ ƃļöçķš üšé à ĝîṽéñ ţéŕḿ, ƃý çöļļéçţîöñ àñđ çööŕđîñàţé, îš àñšŵéŕàƃļé ŵîţĥ ñö šéŕṽéŕ.

Ŕéçîþé šçĥéḿà

Ţĥé ŕéçîþé îš à ÝÀḾĻ đöçüḿéñţ. Bowrain þŕöĵéçţš ļàýéŕ à bowrain: ƃļöçķ (àñđ ţĥé öþţîöñàļ ţöþ-ļéṽéļ ṽéñüé ķéýš hooks, automations, assets àñđ brand_voice) öñţö ţĥé ƒŕàḿéŵöŕķ'š KapiProject šçĥéḿà.

version: v1
name: My App

defaults:
source_language: en
target_languages: [fr, de, ja]
collection: ui/strings
exclude:
- "**/*.test.json"
- "node_modules/**"
terms_source: .kapi/terms.json
memory_source: .kapi/memory/memory.json
voice: .kapi/voice.yaml
coordinates:
brand: acme # a declared axis, inherited by every collection

collections:
- path: src/locales/**/*.json
format: json
- path: content/docs/**/*.md
format: markdown
target: i18n/{lang}/docs/{path}/{filename}
- name: legal
channel: docs
coordinates:
mode: reference # overrides the project on one axis, inherits the rest
source_only: true # checked, never translated
content:
- path: legal/**/*.md
format: markdown

plugins:
okapi-bridge: "^1.47.0" # map form: name → version constraint

flows:
pseudo:
steps:
- tool: pseudo-translate
config: { method: extended }

# The bowrain: block depends on the bowrain plugin. init declares the
# requirement so a plain kapi binary (without the plugin) fails fast instead of
# silently ignoring the connection.
requires:
bowrain: "*"

# Optional bowrain-server connection. Presence enables push/pull and makes the
# server the default venue for `kapi up`.
bowrain:
url: https://app.bowrain.cloud/my-team/abc123
stream: $auto # auto-detect from git branch / CI
converge: on-push # on-push (default) | manual

# Top-level lifecycle policy:
hooks:
pre-push: [qa]
post-pull: [segmentation]

automations:
- name: pull-after-push
trigger: post-push
actions:
- type: wait_translate
- type: pull

# Top-level asset policy:
assets:
enabled: true
max_size: 100MB

Ţöþ-ļéṽéļ ƒîéļđš

ƑîéļđŢýþéĐéšçŕîþţîöñ
versionšţŕîñĝŠçĥéḿà ṽéŕšîöñ (çüŕŕéñţļý v1)
namešţŕîñĝÞŕöĵéçţ đîšþļàý ñàḿé
defaultsöƃĵéçţÞŕöĵéçţ-ŵîđé ļàñĝüàĝé, çöñţéẋţ àñđ éẋéçüţîöñ đéƒàüļţš
collectionsļîšţÇöñţéñţ çöļļéçţîöñš (šéé Çöñţéñţ Çöļļéçţîöñš)
profilesḿàþĜöṽéŕñàñçé ƃöüñđ þéŕ þŕöđüçţ, ķéýéđ ƃý þŕöƒîļé ñàḿé (šéé Þŕöƒîļéš àñđ çĥàññéļš)
pluginsḿàþÞļüĝîñ đéþéñđéñçîéš àš name: version-constraint
requiresḿàþÞļüĝîñ ñàḿé → ṽéŕšîöñ çöñšţŕàîñţ ţĥàţ ĝàţéš ļöàđîñĝ; à bowrain: ƃļöçķ àđđš bowrain šö à þļàîñ kapi ƃîñàŕý ŕéƒüšéš ţĥé ŕéçîþé
flowsḿàþÎñļîñé ƒļöŵ đéƒîñîţîöñš (ƒîļé-þéŕ-ƒļöŵ üñđéŕ .kapi/flows/ àļšö ŵöŕķš)
ship_gateĝàţéŢĥé ƃàŕ à ļöçàļé ḿüšţ çļéàŕ ţö ƃé šĥîþþàƃļé (šéé Ĝàţéš)
ship_gatesļîšţÞéŕ-šçöþé šĥîþ ĝàţéš, éàçĥ à when: šéļéçţöŕ þļüš à ĝàţé
source_gateĝàţéŢĥé ƃàŕ ţĥé šöüŕçé ḿüšţ çļéàŕ ƃéƒöŕé à ŕüñ ƒàñš öüţ; none öþţš öüţ
verified_gate, verified_gatesĝàţé, ļîšţŢĥé ƃàŕ ƒöŕ à ļöçàļé ţö çöüñţ àš ṽéŕîƒîéđ ƃý à þéŕšöñ
gatesḿàþÑàḿéđ ĝàţéš ţĥé ŕüļéš àƃöṽé ḿàý ŕéƒéŕéñçé
bowrainöƃĵéçţBowrain-šéŕṽéŕ çöññéçţîöñ çööŕđîñàţéš (ṽéñüé ķéý)
hooksḿàþƑļöŵš đéçļàŕéđ àţ ļîƒéçýçļé þöîñţš (pre-push, post-pull, …); šçĥéḿà-öñļý, šéé Ĥööķš
automationsļîšţĻöçàļ àüţöḿàţîöñ ŕüļéš (šéé Àüţöḿàţîöñš)
assetsöƃĵéçţÀššéţ (îḿàĝé/ƃîñàŕý) þöļîçý
brand_voiceöƃĵéçţÀ ṽéñüé ķéý ţĥé šéŕṽéŕ àļšö àççéþţš ƒöŕ à þŕöƒîļé àñđ çĥàññéļ ƃîñđîñĝ; ƃîñđ ţĥé ṽöîçé ŵîţĥ defaults.voice öŕ à þŕöƒîļé'š voice: îñšţéàđ

defaults ƃļöçķ

ƑîéļđŢýþéĐéšçŕîþţîöñ
source_languagešţŕîñĝƂÇÞ-47 šöüŕçé ļàñĝüàĝé (ƒöŕ éẋàḿþļé en)
target_languagesļîšţƂÇÞ-47 ţàŕĝéţ ļàñĝüàĝéš; éḿþţý ƒöŕ à šöüŕçé-öñļý þŕöĵéçţ
collectionšţŕîñĝĐéƒàüļţ çöļļéçţîöñ ñàḿé ƒöŕ öŕĝàñîžîñĝ çöñţéñţ
excludeļîšţĜļöƃ þàţţéŕñš ţö šķîþ đüŕîñĝ šçàññîñĝ
formatsḿàþÞéŕ-ƒöŕḿàţ đéƒàüļţ þŕéšéţš àñđ çöñƒîĝ öṽéŕŕîđéš
terms_sourcešţŕîñĝÞàţĥ ţö ţĥé çöḿḿîţţéđ ţéŕḿš šöüŕçé (ƒöŕ éẋàḿþļé .kapi/terms.json)
memory_sourcešţŕîñĝÞàţĥ ţö ţĥé çöḿḿîţţéđ çöñţéñţ ḿéḿöŕý šöüŕçé (ƒöŕ éẋàḿþļé .kapi/memory/memory.json)
voicešţŕîñĝÞàţĥ ţö ţĥé ṽöîçé þŕöƒîļé éṽéŕý çöļļéçţîöñ îš ĝöṽéŕñéđ ƃý üñļéšš à þŕöƒîļé ƃîñđš àñöţĥéŕ (çöñṽéñţîöñàļļý .kapi/voice.yaml)
coordinatesḿàþŢĥé đéçļàŕéđ àẋéš éṽéŕý çöļļéçţîöñ îñĥéŕîţš, brand àñđ mode àḿöñĝ ţĥéḿ; ţĥé šţŕüçţüŕàļ àẋéš product àñđ channel àŕé đéŕîṽéđ ƒŕöḿ channel: àñđ ñéṽéŕ ŵŕîţţéñ ĥéŕé
materializešţŕîñĝŴĥéñ ţàŕĝéţ ƒîļéš àŕé ŵŕîţţéñ ƒŕöḿ ţĥé þŕöĵéçţ šţöŕé; kapi up --materialize ƒöŕçéš on-converge

bowrain ƃļöçķ

Öñļý ţĥé çöññéçţîöñ çööŕđîñàţéš šîţ üñđéŕ bowrain::

ƑîéļđĐéšçŕîþţîöñ
urlÇöḿþöüñđ ÜŔĻ: <server>/<workspace>/<project-id> öŕ <server>/projects/<id>
streamŠéŕṽéŕ-šîđé šţŕéàḿ ţö šýñç àĝàîñšţ; $auto àüţö-đéţéçţš ƒŕöḿ ÇÎ / ĝîţ ƃŕàñçĥ
convergeŠéŕṽéŕ-šîđé çöñṽéŕĝéñçé þöļîçý: on-push (đéƒàüļţ) öŕ manual

Ļîƒéçýçļé (hooks, automations) àñđ àššéţ þöļîçý (assets) ļîṽé àţ ţĥé ţöþ ļéṽéļ öƒ ţĥé ŕéçîþé, ñöţ üñđéŕ bowrain:: ţĥéý đéšçŕîƃé þŕöĵéçţ-öŵñéđ þöļîçý, ñöţ šéŕṽéŕ îđéñţîţý.

Ţĥé ƒŕàḿéŵöŕķ ĥàš ñö ƃüîļţ-îñ ñöţîöñ öƒ à šéŕṽéŕ: bowrain: (àñđ hooks:, automations:, assets:, brand_voice:) àŕé bowrain ŕéçîþé éẋţéñšîöñš đéçöđéđ öñļý ŵĥéñ ţĥé kapi-bowrain þļüĝîñ îš îñšţàļļéđ (ţĥé ƒŕàḿéŵöŕķ ŕöüñđ-ţŕîþš ţĥéḿ ṽéŕƃàţîḿ öţĥéŕŵîšé). Ţĥé ķéý îš ţĥé þļàţƒöŕḿ'š öŵñ ñàḿé ƃéçàüšé ţĥé ƃļöçķ îš ţĥé þļàţƒöŕḿ: kapi ƒîñđš îţ ţĥŕöüĝĥ à ṽéñüé ƒļàĝ öñ ţĥé þļüĝîñ'š šçĥéḿà ŕéĝîšţŕàţîöñ àñđ ŕéàđš öñļý url: àñđ converge:, ñéṽéŕ šþéļļîñĝ ţĥé ķéý öüţ. Šö kapi init / kapi init-connect (àñđ kapi config server.url …) đéçļàŕé requires: { bowrain: "*" } ŵĥéñéṽéŕ ţĥéý ŵŕîţé à bowrain: ƃļöçķ. À þļàîñ kapi ƃîñàŕý ŵîţĥöüţ ţĥé þļüĝîñ ţĥéñ ŕéƒüšéš ţĥé ŕéçîþé ŵîţĥ àñ àçţîöñàƃļé "ŕéǫüîŕéš ţĥé bowrain þļüĝîñ" éŕŕöŕ ŕàţĥéŕ ţĥàñ šîļéñţļý îĝñöŕîñĝ ţĥé çöññéçţîöñ. Šéé Ç-01: Ţĥé þŕöĵéçţ ḿöđéļ.

Çöñţéñţ Çöļļéçţîöñš

Éàçĥ éñţŕý üñđéŕ collections: îš à çöñţéñţ çöļļéçţîöñ. Ƃàŕé éñţŕîéš àŕé šîñĝļé-þàţţéŕñ çöļļéçţîöñš; ñàḿéđ çöļļéçţîöñš ĝŕöüþ ḿüļţîþļé îţéḿš ţöĝéţĥéŕ.

Ýöü çàñ éđîţ collections: ƃý ĥàñđ, öŕ ŵîţĥ ţĥé çöŕé kapi çöḿḿàñđš (ñö bowrain þļüĝîñ ŕéǫüîŕéđ; ţĥéý öñļý ţöüçĥ ţĥé ļöçàļ ŕéçîþé):

kapi add "src/**/*.json" # append a content pattern (format auto-detected)
kapi rm "src/legacy/*.json" # remove the mapping, or add to the exclude list
kapi ls # list the files the content tracks
kapi add "src/**/*.md" --format markdown # pass --format only to override detection
kapi ls --stats # with per-file block and word counts

add/rm/ls àŕé ƒŕàḿéŵöŕķ çöḿḿàñđš; šýñç šţàţé (çĥàñĝéđ-ṽš-šéŕṽéŕ) îš kapi status.

collections:
# Bare entry: single source pattern
- path: src/locales/**/*.json
format: json

# With output path template
- path: content/docs/**/*.md
format: markdown
target: i18n/{lang}/docs/{path}/{filename}

# Per-entry overrides
- path: legacy/**/*.properties
format: java-properties
source_language: en-GB
collection: legacy

# Named collection: its items live under content:, relative to base:
- name: ui
channel: app
base: src
preview:
kind: storybook
url: https://storybook.example.com
content:
- path: "**/*.tsx"
format:
name: exec
config:
command: "vp neokapi-i18n extract --stream"
- path: "i18n/en/*.json"
format: json

Çöļļéçţîöñ ƒîéļđš

ƑîéļđŢýþéĐéšçŕîþţîöñ
namešţŕîñĝÇöļļéçţîöñ ñàḿé; ŕéǫüîŕéđ ţö ƃîñđ à channel:
basešţŕîñĝŢĥé đîŕéçţöŕý ţĥîš çöļļéçţîöñ ļîṽéš îñ; éṽéŕý path, target àñđ îţéḿ base ƃéļöŵ îš ŵŕîţţéñ ŕéļàţîṽé ţö îţ
channelšţŕîñĝŢĥé þöîñţ îñ ţĥé çöñţéẋţ šþàçé ţĥîš çöñţéñţ šîţš àţ: profile/channel, öŕ à ƃàŕé channel (šéé Þŕöƒîļéš àñđ çĥàññéļš)
coordinatesḿàþĐéçļàŕéđ àẋéš ţĥîš çöļļéçţîöñ šéţš, öṽéŕļàîđ öñ defaults.coordinates þéŕ àẋîš: à çöļļéçţîöñ ḿöṽéš öñ ţĥé öñé àẋîš îţ đéŕš öñ àñđ îñĥéŕîţš ţĥé ŕéšţ
source_onlyƃööļŢĥîš çöļļéçţîöñ ĥàš ñö ţàŕĝéţ ļàñĝüàĝé àñđ îš ñéṽéŕ ţŕàñšļàţéđ: à ŕüñ ŕéàđš îţ, çĥéçķš îţ, àñđ ŵŕîţéš ñöţĥîñĝ ƃàçķ
previewöƃĵéçţŴĥéŕé ţĥîš çöļļéçţîöñ'š šţŕîñĝš çàñ ƃé ŕéàđ îñ þļàçé: kind (storybook) àñđ url (šéé Ŕéṽîéŵ îñ þļàçé)
contentļîšţŢĥé çöļļéçţîöñ'š çöñţéñţ îţéḿš
collectionšţŕîñĝÇöļļéçţîöñ ŕöüţîñĝ öṽéŕŕîđé
source_languagešţŕîñĝŠöüŕçé ļàñĝüàĝé öṽéŕŕîđé
target_languagesļîšţŢàŕĝéţ ļàñĝüàĝé öṽéŕŕîđé

Çöñţéñţ îţéḿ ƒîéļđš

ƑîéļđŢýþéĐéšçŕîþţîöñ
pathšţŕîñĝĜļöƃ þàţţéŕñ ƒöŕ šöüŕçé ƒîļéš (šüþþöŕţš {lang} þļàçéĥöļđéŕ)
formatšţŕîñĝ / öƃĵéçţƑîļé ƒöŕḿàţ ÎĐ (ƒöŕ éẋàḿþļé json, html) öŕ öƃĵéçţ ŵîţĥ name/config/preset
targetšţŕîñĝÖüţþüţ þàţĥ þàţţéŕñ ƒöŕ ţàŕĝéţ ƒîļéš (šüþþöŕţš {lang} àñđ {path})
basešţŕîñĝĐîŕéçţöŕý à ḿàţçĥéđ ƒîļé'š þàţĥ îš ḿàđé ŕéļàţîṽé ţö ƒöŕ ţàŕĝéţ-ţöķéñ éẋþàñšîöñ; đéƒàüļţš ţö ţĥé ĝļöƃ'š ƒîẋéđ þŕéƒîẋ
collectionšţŕîñĝÇöļļéçţîöñ ŕöüţîñĝ öṽéŕŕîđé ƒöŕ ţĥîš éñţŕý
source_languagešţŕîñĝŠöüŕçé ļàñĝüàĝé öṽéŕŕîđé ƒöŕ ţĥîš éñţŕý
target_languagesļîšţŢàŕĝéţ ļàñĝüàĝé öṽéŕŕîđé ƒöŕ ţĥîš éñţŕý
assetsöƃĵéçţÞéŕ-éñţŕý àššéţ þöļîçý öṽéŕŕîđé
asset_max_sizešţŕîñĝÞéŕ-éñţŕý àššéţ ḿàẋ šîžé öṽéŕŕîđé

À ƃàŕé éñţŕý çàŕŕîéš path, format àñđ target đîŕéçţļý öñ ţĥé çöļļéçţîöñ àñđ ĥàš ñö content: ļîšţ.

Þŕöƒîļéš àñđ çĥàññéļš

Çöñţéñţ îš ŵŕîţţéñ ƒöŕ à þöîñţ îñ ţĥé çöñţéẋţ šþàçé. Ţŵö öƒ îţš àẋéš àŕé šţŕüçţüŕàļ: ţĥé þŕöđüçţ îţ ƃéļöñĝš ţö àñđ ţĥé çĥàññéļ îţ šĥîþš öñ. À ķéý üñđéŕ profiles: îš à þŕöđüçţ, ţĥé çĥàññéļš ţĥàţ þŕöƒîļé đéçļàŕéš àŕé ţĥé çĥàññéļš ţĥàţ þŕöđüçţ šĥîþš öñ, àñđ à ñàḿéđ çöļļéçţîöñ ñàḿéš îţš þöîñţ ŵîţĥ öñé channel: ŕéƒéŕéñçé. Ţĥé đéçļàŕéđ àẋéš (brand, mode, àñđ àñý ţĥé þŕöĵéçţ àđđš) çöḿé ƒŕöḿ defaults.coordinates àñđ à çöļļéçţîöñ'š öŵñ coordinates:.

profiles:
acme:
channels: [app, docs]
voice: .kapi/voice.yaml
acme-labs:
channels: [app]
voice: .kapi/profiles/acme-labs/voice.yaml
termstore: .kapi/profiles/acme-labs/terms.json
valid_from: 2026-09-01

collections:
- name: acme-docs
channel: docs # only acme declares it; the bare form resolves
content:
- path: docs/**/*.md
- name: labs-app
channel: acme-labs/app # both declare `app`; qualify it
content:
- path: labs/src/i18n/**/*.kbf.json
ƑîéļđĐéšçŕîþţîöñ
channelsŢĥé çĥàññéļš ţĥîš þŕöđüçţ šĥîþš öñ
voiceŢĥé ṽöîçé þŕöƒîļé ţĥàţ ĝöṽéŕñš ţĥîš þŕöđüçţ, öṽéŕŕîđîñĝ defaults.voice
termstoreÀ ţéŕḿš šţöŕé ƃöüñđ ƒöŕ ţĥîš þŕöđüçţ'š ļöçàļ ŕüñš
conceptÀ çöñçéþţ ŕéƒéŕéñçé (term:<id>) ţĥé þŕöƒîļé çàŕŕîéš ƒöŕ đîšþļàý
valid_from, valid_toŢĥé þŕöƒîļé'š ṽàļîđîţý ŵîñđöŵ

Ţĥé þŕöƒîļé ñàḿé îš àļšö ţĥé đîŕéçţöŕý üñđéŕ .kapi/profiles/<name>/ ĥöļđîñĝ ŵĥàţ ţĥàţ þŕöƒîļé öṽéŕŕîđéš. Þŕöƒîļé ñàḿéš àñđ çĥàññéļš àŕé šļüĝš (ļöŵéŕçàšé ļéţţéŕš, đîĝîţš àñđ ĥýþĥéñš): šţàƃļé îđéñţîƒîéŕš ţĥàţ çŕöšš ţĥé šýñç ŵîŕé àš ţĥé çöñţéñţ'š þŕöđüçţ àñđ çĥàññéļ çööŕđîñàţéš, ñéṽéŕ ṽöçàƃüļàŕý. À ƃàŕé channel: ţŵö þŕöƒîļéš đéçļàŕé îš à ļöàđ éŕŕöŕ ñàḿîñĝ ƃöţĥ ǫüàļîƒîéđ šþéļļîñĝš; à çöļļéçţîöñ ƃîñđîñĝ ñö çĥàññéļ îš ĝöṽéŕñéđ ƃý defaults.voice àñđ ţĥé þŕöĵéçţ'š öŵñ ţéŕḿš.

À þŕöƒîļé'š termstore: îš ţĥé öñé ƃîñđîñĝ ţĥàţ đöéš ñöţ çŕöšš ţö ţĥé šéŕṽéŕ, ŵĥîçĥ ĝöṽéŕñš ţéŕḿš ƒŕöḿ ţĥé ŵöŕķšþàçé ṽöçàƃüļàŕý îñšţéàđ. À çöññéçţéđ þŕöĵéçţ ţĥàţ ƃîñđš à ţéŕḿš šţöŕé þéŕ þŕöƒîļé ŵàŕñš öñ éṽéŕý ŕüñ ţĥàţ ţĥé ƃîñđîñĝ àþþļîéš ţö ļöçàļ ŕüñš öñļý.

Ĝàţéš

À ĝàţé ñàḿéš ţĥé ŕüñĝ öƒ ţĥé ţàŕĝéţ ļàđđéŕ à šçöþé ḿüšţ ŕéàçĥ, àñđ ŵĥö ḿàý ĥàṽé àþþŕöṽéđ îţ, ƒöŕ ţĥé šçöþé ţö çöüñţ àš šĥîþþàƃļé. ship_gate šéţš ţĥé ƃàŕ ƒöŕ éṽéŕý ļöçàļé; ship_gates ŕéƒîñéš îţ þéŕ šçöþé ŵîţĥ à when: šéļéçţöŕ, šö à ļéĝàļ çöļļéçţîöñ çàñ ŵàîţ ƒöŕ à þéŕšöñ ŵĥîļé à ĥéļþ çöļļéçţîöñ šĥîþš öñ çĥéçķš; source_gate îš ţĥé šöüŕçé-šîđé ƃàŕ à ŕüñ ḿüšţ çļéàŕ ƃéƒöŕé îţ ƒàñš öüţ, àñđ source_gate: none öþţš öüţ. Ţĥé šĥîþ šţàţé ţĥé šéŕṽéŕ đéŕîṽéš ƒŕöḿ ţĥéšé îš đéšçŕîƃéđ üñđéŕ Šĥîþ šţàţéš.

Ţööļ çöñƒîĝüŕàţîöñ

À ƒļöŵ šţéþ'š config: ķéýš àŕé ţĥé ţööļ'š öŵñ šçĥéḿà ķéýš, ļîšţéđ îñ ţĥé ţööļ ŕéƒéŕéñçé. Ţĥé ŵöŕđîñĝ çöñšţŕàîñţ îš öñé ķéý éṽéŕýŵĥéŕé îţ àþþļîéš: term-check, translate àñđ recycle ţàķé term_rules:, à ļîšţ öƒ ŕüļéš ñàḿîñĝ à ţéŕḿ, ŵĥàţ ţö üšé îñšţéàđ, àñđ ĥöŵ ĥàŕđ ţĥé ŕüļé ƃîţéš. Ţĥé ṽöîçé þŕöƒîļé çàŕŕîéš ţĥé šàḿé ŕüļéš üñđéŕ îţš vocabulary: šéçţîöñ, àñđ à ŕüñ ŕéšöļṽéš ţĥé ţéŕḿš îñ ƒöŕçé àţ à ƃļöçķ'š þöîñţ ƒŕöḿ ţĥé þŕöƒîļé àñđ ţĥé ƃöüñđ ţéŕḿš šţöŕé.

Ƒöŕḿàţ öƃĵéçţ ƒöŕḿ

Ŵĥéñ ýöü ñééđ ţö çöñƒîĝüŕé à ƒöŕḿàţ (àþþļý à þŕéšéţ, þàšš öþţîöñš, ŕüñ à šüƃþŕöçéšš éẋţŕàçţöŕ) üšé ţĥé öƃĵéçţ ƒöŕḿ:

collections:
- path: "src/**/*.tsx"
format:
name: exec
config:
command: "vp neokapi-i18n extract --stream"

- path: "docs/**/*.html"
format:
name: html
preset: strict-extraction

Àüţöḿàţîöñš

Àüţöḿàţîöñš àŕé ŕüļéš ţĥàţ ŕüñ àüţöḿàţîçàļļý àţ ļîƒéçýçļé þöîñţš, đéçļàŕéđ àţ ţĥé ţöþ ļéṽéļ öƒ ţĥé ŕéçîþé:

automations:
- name: checks-before-push
trigger: pre-push
actions:
- type: run_flow
config:
flow: qa
- type: wait_translate

- name: auto-pull-after-push
trigger: post-push
actions:
- type: pull

Àüţöḿàţîöñ ƒîéļđš

ƑîéļđĐéšçŕîþţîöñ
nameŔüļé ñàḿé
triggerĻîƒéçýçļé þöîñţ: pre-push, post-push, pre-pull, post-pull, pre-flow, post-flow
actionsĻîšţ öƒ àçţîöñš (run_flow, wait_translate, pull, push)
enabledÖþţîöñàļ ƃööļéàñ (đéƒàüļţš ţö true)

Ţĥé ţöþ-ļéṽéļ hooks: ḿàþ îš ṽàļîđàţéđ ƃüţ ñöţ éẋéçüţéđ; šéé Ĥööķš.

Þŕöĵéçţ Đîšçöṽéŕý

kapi šéàŕçĥéš ƒöŕ à kapi.yaml ŕéçîþé ƃý ŵàļķîñĝ üþ ţĥé đîŕéçţöŕý ţŕéé (ļîķé ĝîţ):

cd my-app/src/locales/fr/
kapi status # finds kapi.yaml at ../../../kapi.yaml

Àļļ çöḿḿàñđš ŵöŕķ ƒŕöḿ àñý šüƃđîŕéçţöŕý ŵîţĥîñ ţĥé þŕöĵéçţ. À đîŕéçţöŕý ĥöļđš àţ ḿöšţ öñé kapi.yaml, šö đîšçöṽéŕý îš üñàḿƃîĝüöüš; àñ éẋþļîçîţ -p <path> šţîļļ öṽéŕŕîđéš îţ.

Ṽéŕšîöñ Çöñţŕöļ

Çöḿḿîţ ţö ĝîţ

  • kapi.yaml: ţĥé ŕéçîþé (šîñĝļé šöüŕçé öƒ ţŕüţĥ ƒöŕ çöñƒîĝüŕàţîöñ)
  • .kapi/terms.json, .kapi/memory/memory.json, .kapi/voice.yaml: ţĥé çöñţéẋţ šöüŕçéš ţĥé ŕéçîþé ƃîñđš
  • .kapi/state/*.jsonl: ţĥé üñîţ-šţàţé ŕéçöŕđ
  • .kapi/flows/*.yaml: ƒîļé-þéŕ-ƒļöŵ đéƒîñîţîöñš, îƒ ýöü üšé ţĥéḿ
  • .kapi/manifest.yaml, .kapi/filters.json: ƃööķķééþîñĝ àñđ šĥàŕéđ ŕéàđéŕ çöñƒîĝüŕàţîöñ

Đö ÑÖŢ çöḿḿîţ

kapi init ŵŕîţéš à ţŵö-ļîñé îĝñöŕé ŕüļé, ŵîţĥ ñö ñéĝàţîöñ:

/.kapi/work/
/.kapi/filters.local.json
  • .kapi/work/: éṽéŕýţĥîñĝ đéŕîṽéđ: store.db, ţĥé çàçĥéš, àñđ ţĥé ŕéđàçţîöñ ṽàüļţ
  • .kapi/filters.local.json: ýöüŕ þéŕšöñàļ ŕéàđéŕ öṽéŕŕîđéš

Đéļéţîñĝ .kapi/work/cache/ çöšţš ñöţĥîñĝ. Đéļéţîñĝ .kapi/work/ çöšţš ţŵö ţĥîñĝš: ţĥé ŕéṽîéŵ üñîţ šţàţé šţàĝéđ šîñçé ţĥé ļàšţ kapi commit, ŵĥîçĥ ļîṽéš öñļý îñ store.db (ŕüñ kapi commit ƃéƒöŕé ýöü ŕéḿöṽé îţ), àñđ, îƒ ţĥé þŕöĵéçţ üšéš ŕéđàçţîöñ, ţĥé ŵîţĥĥéļđ öŕîĝîñàļš îñ .kapi/work/vault/, ŵĥîçĥ àŕé ļöçàļ-öñļý ƃý đéšîĝñ àñđ ŕéƃüîļđ ƒŕöḿ ñöţĥîñĝ.

Îñîţîàļîžàţîöñ

Çŕéàţé à ñéŵ bowrain þŕöĵéçţ:

cd my-app/
kapi init

Îñ îñţéŕàçţîṽé ḿöđé (đéƒàüļţ ŵĥéñ šţđîñ îš à ţéŕḿîñàļ), kapi init þŕéšéñţš à ĝüîđéđ šéţüþ ŵîžàŕđ ŵĥéŕé ýöü çàñ šîĝñ îñ, çĥööšé à ŵöŕķšþàçé, àñđ çöñƒîĝüŕé ýöüŕ þŕöĵéçţ.

Ƒöŕ ñöñ-îñţéŕàçţîṽé üšàĝé (ƒöŕ éẋàḿþļé ÇÎ/ÇĐ), üšé ƒļàĝš:

# Local-only project (no bowrain: block written)
kapi init --source en --targets fr,de,ja

# Connect to a server (anonymous claim)
kapi init --server https://app.bowrain.cloud --anonymous

# Apply a framework preset
kapi init --preset nextjs

# Connect to an existing project
kapi init --server https://app.bowrain.cloud --project abc123

Îñîţ ƒļàĝš

ƑļàĝĐéšçŕîþţîöñ
--serverŠéŕṽéŕ ÜŔĻ
--workspaceÇŕéàţé ţĥé þŕöĵéçţ îñ ţĥîš ŵöŕķšþàçé (šļüĝ)
--projectÇöññéçţ ţö àñ éẋîšţîñĝ þŕöĵéçţ ƃý ÎĐ
--nameÞŕöĵéçţ ñàḿé (đéƒàüļţ: çüŕŕéñţ đîŕéçţöŕý ñàḿé)
--sourceŠöüŕçé ļöçàļé (đéƒàüļţ: en)
--targetsŢàŕĝéţ ļöçàļéš, çöḿḿà-šéþàŕàţéđ (ƒöŕ éẋàḿþļé nb,fr)
--anonymousÇŕéàţé à þŕöĵéçţ ŵîţĥöüţ šîĝñîñĝ îñ
--emailÇŕéàţé à þŕöĵéçţ àñđ éḿàîļ à ļîñķ ţö çļàîḿ îţ
--presetÀþþļý à ƒŕàḿéŵöŕķ þŕéšéţ (ƒöŕ éẋàḿþļé nextjs, react-intl, angular)

kapi init ŵŕîţéš:

  1. kapi.yaml ŕéçîþé àţ ţĥé þŕöĵéçţ ŕööţ (ŵîţĥ à bowrain: ƃļöçķ ŵĥéñ à šéŕṽéŕ ŵàš šüþþļîéđ)
  2. .kapi/ đîŕéçţöŕý
  3. .kapi/flows/pseudo.yaml, àñ éẋàḿþļé ƒļöŵ
  4. à ţŵö-ļîñé îĝñöŕé ŕüļé: /.kapi/work/ àñđ /.kapi/filters.local.json

Šéŕṽéŕ Çöññéçţîöñ

Ţĥé ƃļöçķ'š url ƒîéļđ îš à çöḿþöüñđ ÜŔĻ ţĥàţ éñçöđéš ţĥé šéŕṽéŕ àđđŕéšš, ŵöŕķšþàçé, àñđ þŕöĵéçţ ÎĐ:

bowrain:
# Workspace project
url: https://app.bowrain.cloud/my-team/abc123

# Direct project (no workspace)
# url: https://app.bowrain.cloud/projects/abc123

stream: $auto

Öñçé çöññéçţéđ, ýöü çàñ šýñç ŵîţĥ ţĥé šéŕṽéŕ:

kapi push # Upload local changes to the server
kapi pull # Fetch results and recipe changes from the server
kapi status # Coverage, ship standing, and the server delta

Ţĥé àçţîṽé šéŕṽéŕ ÜŔĻ îš ŕéšöļṽéđ ƒŕöḿ (ƒîŕšţ ḿàţçĥ ŵîñš):

  1. url: üñđéŕ ţĥé ŕéçîþé'š bowrain: ƃļöçķ
  2. --server ƒļàĝ
  3. BOWRAIN_SERVER_URL éñṽîŕöñḿéñţ ṽàŕîàƃļé / server.url îñ ţĥé þéŕ-ḿàçĥîñé bowrain çöñƒîĝ
  4. Éẋîšţîñĝ àüţĥ šţàţé (ƒŕöḿ kapi auth login)
  5. Ţĥé ĥöšţéđ šéŕṽîçé (https://app.bowrain.cloud): çöḿḿàñđš ţĥàţ çöñţàçţ à šéŕṽéŕ ƒàļļ ƃàçķ ţö îţ; šéļƒ-ĥöšţéđ đéþļöýḿéñţš çöñƒîĝüŕé öñé öƒ ţĥé àƃöṽé

Ñéẋţ Šţéþš