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

Ƃöŵŕàîñ Þŕöĵéçţ Ḿöđéļ

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

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

my-app/
├── kapi.yaml # the recipe (committed); fixed, conventional filename
├── .mcp.json # agent wiring written by kapi init (committed)
├── .kapi/ # this checkout's cache, ignored as a whole
│ ├── .gitignore # `*`, written by kapi init
│ ├── filters.local.json # personal saved reader filters
│ ├── vault/ # withheld redaction originals (local-only)
│ ├── sync/ # the tree last declared to the server, and the refs
│ └── work/ # free to delete: rebuilt on the next run
│ ├── store.db # this checkout's projection of its working tree
│ └── cache/
│ ├── extractions/
│ └── collections/
├── flows/ # file-per-flow definitions, named by flows_dir (optional)
└── src/
└── locales/
├── en/
│ └── messages.json
└── fr/
└── messages.json

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

  • kapi.yaml: ĥàñđ-éđîţéđ àñđ çöḿḿîţţéđ ţö ĝîţ. Ţĥé ŕéçîþé ĥöļđš ţĥé þŕöĵéçţ çöñƒîĝüŕàţîöñ. Àñ àẋîš àþþŕöṽéđ öñ ţĥé šéŕṽéŕ àļšö ŕéàçĥéš îţ: ţĥé ñéẋţ kapi pull éđîţš defaults.coordinates, ƒöŕ ŕéṽîéŵ îñ ĝîţ.
  • .kapi/: ţĥîš çĥéçķöüţ'š çàçĥé, ķéþţ öüţ öƒ ĝîţ. work/store.db ĥöļđš ţĥé çĥéçķöüţ'š çöþý öƒ îţš ŵöŕķîñĝ ţŕéé: ţĥé ƃļöçķ çàçĥé, ţĥé öṽéŕļàýš à ŕüñ ŵŕöţé àñđ ţĥé éẋţŕàçţîöñ šţàḿþš. Îţ ŕéƃüîļđš ƒŕöḿ ţĥé çöñţéñţ ƒîļéš. work/cache/ ĥöļđš ƒîļéš ķàþî çàñ ŕéĝéñéŕàţé çĥéàþļý, àñđ ýöü çàñ đéļéţé îţ àţ àñý ţîḿé. Ýöü àüţĥöŕ ñöţĥîñĝ ţĥéŕé: ƒîļé-þéŕ-ƒļöŵ đéƒîñîţîöñš šîţ îñ ţĥé çöḿḿîţţéđ đîŕéçţöŕý ţĥé ŕéçîþé ñàḿéš ŵîţĥ flows_dir:, àñđ ķàþî ŕéàđš ñöţĥîñĝ ƒŕöḿ .kapi/flows/.
  • Ţĥé þŕöĵéçţ'š çöñţéẋţ šţöŕé: ķéþţ ƃý ķàþî îñ à ŵöŕķšþàçé üñđéŕ ýöüŕ đàţà đîŕéçţöŕý, öüţšîđé ţĥé çĥéçķöüţ. Îţ ĥöļđš ţĥé ţéŕḿš, ţĥé çöñţéñţ ḿéḿöŕý, ţĥé ṽöîçé þŕöƒîļéš àñđ ţĥé đéçîšîöñ ļéđĝéŕ. Éṽéŕý çĥéçķöüţ öƒ ţĥé þŕöĵéçţ šĥàŕéš îţ, àñđ éṽéŕý ĝàţé àñđ ļööķüþ ŕéàđš ƒŕöḿ îţ. kapi context sync šĥàŕéš îţ ţĥŕöüĝĥ ţĥé ƃàçķéñđ ţĥé ŕéçîþé đéçļàŕéš üñđéŕ context:, àñđ kapi store export ŵŕîţéš îţ ţö öñé ƒîļé.

À þŕöĵéçţ çàñ àñšŵéŕ ţĥé šàḿé ǫüéšţîöñš àš Ƃöŵŕàîñ öṽéŕ îţš öŵñ çöñţéẋţ, ƒöŕ öñé þŕöĵéçţ àñđ öñé šţŕéàḿ. Ƒöŕ éẋàḿþļé, ķàþî çàñ ļîšţ ŵĥîçĥ ƃļöçķš üšé à ĝîṽéñ ţéŕḿ, ƃý çöļļéçţîöñ àñđ çööŕđîñàţé, ŵîţĥ ñö šéŕṽéŕ.

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

Ţĥé ŕéçîþé îš à ÝÀḾĻ đöçüḿéñţ. Ƃöŵŕàîñ þŕöĵéçţš ļàýéŕ à 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/**"
voice:
profile: acme-docs
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:
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 šö à þļàîñ ķàþî ƃîñàŕý ŕéƒüšéš ţĥé ŕéçîþé
flowsḿàþÎñļîñé ƒļöŵ đéƒîñîţîöñš
flows_diršţŕîñĝÀ đîŕéçţöŕý, ŕéļàţîṽé ţö ţĥé ŕéçîþé, ĥöļđîñĝ öñé ÝÀḾĻ ƒîļé þéŕ ƒļöŵ. Ñö đéƒàüļţ
ship_gateĝàţéŢĥé ƃàŕ à ļöçàļé ḿüšţ çļéàŕ ţö ƃé šĥîþþàƃļé (šéé Ĝàţéš)
ship_gatesļîšţÞéŕ-šçöþé šĥîþ ĝàţéš, éàçĥ à when: šéļéçţöŕ þļüš à ĝàţé
source_gateĝàţéŢĥé çöṽéŕàĝé ƃàŕ ţĥé šöüŕçé ḿüšţ çļéàŕ ƒöŕ kapi check --ship
established_gate, established_gatesĝàţé, ļîšţŢĥé ƃàŕ ƒöŕ à ļöçàļé ţö šĥîþ àþþŕöṽéđ: à þéŕšöñ àþþŕöṽéđ ţĥé çöñţéñţ
gatesḿàþÑàḿéđ ĝàţéš ţĥé ŕüļéš àƃöṽé ḿàý ŕéƒéŕéñçé
bowrainöƃĵéçţƂöŵŕàîñ-šéŕṽéŕ çöññéçţîöñ çööŕđîñàţéš (ṽéñüé ķéý)
automationsļîšţĻöçàļ àüţöḿàţîöñ ŕüļéš (šéé Àüţöḿàţîöñš)
assetsöƃĵéçţÀššéţ (îḿàĝé/ƃîñàŕý) þöļîçý
brand_voiceöƃĵéçţÀ ṽéñüé ķéý ţĥé šéŕṽéŕ àļšö àççéþţš ƒöŕ à þŕöƒîļé àñđ çĥàññéļ ƃîñđîñĝ; ƃîñđ ţĥé ṽöîçé ŵîţĥ defaults.voice öŕ à þŕöƒîļé'š voice: îñšţéàđ

defaults ƃļöçķ​

ƑîéļđŢýþéĐéšçŕîþţîöñ
source_languagešţŕîñĝƂÇÞ-47 šöüŕçé ļàñĝüàĝé (ƒöŕ éẋàḿþļé en)
target_languagesļîšţƂÇÞ-47 ţàŕĝéţ ļàñĝüàĝéš; éḿþţý ƒöŕ à šöüŕçé-öñļý þŕöĵéçţ
collectionšţŕîñĝĐéƒàüļţ çöļļéçţîöñ ñàḿé ƒöŕ öŕĝàñîžîñĝ çöñţéñţ
excludeļîšţĜļöƃ þàţţéŕñš ţö šķîþ đüŕîñĝ šçàññîñĝ
formatsḿàþÞéŕ-ƒöŕḿàţ đéƒàüļţ þŕéšéţš àñđ çöñƒîĝ öṽéŕŕîđéš
voiceƃîñđîñĝŢĥé ṽöîçé þŕöƒîļé éṽéŕý çöļļéçţîöñ îš ĝöṽéŕñéđ ƃý üñļéšš à þŕöƒîļé ƃîñđš àñöţĥéŕ. profile: ñàḿéš öñé îñ ţĥé þŕöĵéçţ'š ṽöîçé šţöŕé
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

Šĥàŕîñĝ ţĥé þŕöĵéçţ'š çöñţéẋţ öñ Ƃöŵŕàîñ​

Ŵĥéñ ţĥé þŕöĵéçţ'š çöñţéẋţ ļîṽéš öñ Ƃöŵŕàîñ, éṽéŕý çĥéçķöüţ àñđ éṽéŕý ţéàḿḿàţé ŕéàđš ţĥé šàḿé ţéŕḿš, ķéþţ àñđ đŕöþþéđ šüĝĝéšţîöñš, àñđ đéçîšîöñš. Îñ ţĥé ƃŕöŵšéŕ àñđ îñ Ķàþî Đéšķţöþ, Ŕüļéš šĥöŵš ţĥàţ ŕéçöŕđ (šéé Ḿàþ, Ŕéàđéŕ àñđ Ŕüļéš). Ƒŕöḿ ţĥé çöḿḿàñđ ļîñé, kapi context sync ķééþš îţ îñ šţéþ ŵîţĥ ţĥé Ƃöŵŕàîñ þŕöĵéçţ ţĥé bowrain: ƃļöçķ çöññéçţš ţö.

kapi share --via bowrain çöññéçţš ţĥé þŕöĵéçţ àñđ ļéàṽéš ţĥé çöñţéẋţ ŵĥéŕé îţ îš, šö ñàḿé ţĥé bowrain ƃàçķéñđ îñ ţĥé ŕéçîþé'š context: ƃļöçķ ýöüŕšéļƒ:

context:
backend: bowrain
bowrain:
url: https://app.bowrain.cloud/my-team/abc123

Ţĥé context: ƃļöçķ ţàķéš ñö öţĥéŕ ƒîéļđ ƒöŕ ţĥîš ƃàçķéñđ. Ţĥé þŕöĵéçţ çöḿéš ƒŕöḿ bowrain.url, àñđ ţĥé ÜŔĻ ḿüšţ ñàḿé à ŵöŕķšþàçé þŕöĵéçţ (<server>/<workspace>/<project-id>). À þŕöĵéçţ ĥàš öñé çöñţéẋţ, šö éṽéŕý šţŕéàḿ ŕéàđš ţĥé šàḿé öñé. À ŕéçîþé ţĥàţ ñàḿéš ţĥé bowrain ƃàçķéñđ ŵîţĥöüţ à bowrain: ƃļöçķ îš ŕéƒüšéđ, ŵîţĥ ţĥé ƃļöçķ ţö àđđ.

Ţĥé šýñç šîĝñš îñ àš ţĥé þéŕšöñ kapi auth login šţöŕéđ, öŕ îñ ÇÎ ŵîţĥ BOWRAIN_AUTH_TOKEN àñđ BOWRAIN_SERVER_URL ţöĝéţĥéŕ. Ţĥé šîĝñ-îñ ŕéàçĥéš öñļý ţĥé šéŕṽéŕ îţ ñàḿéš: à ŕéçîþé ŵĥöšé bowrain.url ñàḿéš àñöţĥéŕ šéŕṽéŕ îš ŕéƒüšéđ ƃéƒöŕé àñý ŕéǫüéšţ, àñđ šö îš à ÇÎ ţöķéñ ŵîţĥ ñö šéŕṽéŕ ÜŔĻ. Ţĥé ÜŔĻ ḿüšţ üšé https://, éẋçéþţ ƒöŕ à šéŕṽéŕ öñ localhost. Ŕéàđîñĝ ţĥé çöñţéẋţ ñééđš ṽîéŵ àççéšš ţö ţĥé þŕöĵéçţ; šĥàŕîñĝ çĥàñĝéš ƃàçķ ñééđš þéŕḿîššîöñ ţö ḿàñàĝé ţéŕḿš. BOWRAIN_PROJECT_URL þöîñţš ţĥé çöñţéẋţ àţ àñöţĥéŕ þŕöĵéçţ, àš îţ đöéš ƒöŕ kapi push. kapi share ñàḿéš ţĥîš þļàçé Ḿàñàĝéđ öñ Ƃöŵŕàîñ.

Šéţţîñĝš à þüšĥ çàŕŕîéš​

Ţĥŕéé ŕéçîþé šéţţîñĝš ĝöṽéŕñ ŵĥàţ ţĥé šéŕṽéŕ đöéš ŵîţĥ ţĥé þŕöĵéçţ: bowrain.converge, defaults.translate_after àñđ ţĥé term_rules: ţĥé ŕéçîþé đéçļàŕéš öñ îţš ƒļöŵ šţéþš àñđ ţööļ þŕéšéţš. Éṽéŕý þüšĥ çàŕŕîéš àļļ ţĥŕéé, àţ ţĥéîŕ 郃éçţîṽé ṽàļüéš, šö à ķéý ţĥé ŕéçîþé ļéàṽéš üñšéţ îš šéñţ àš îţš đéƒàüļţ (on-push, written àñđ ñö ţéŕḿ ŕüļéš). Ţĥé þüšĥ çöḿþàŕéš ţĥéḿ ŵîţĥ ţĥé ṽàļüéš ţĥé šéŕṽéŕ ĥöļđš àñđ šéñđš öñļý à šéţţîñĝ ţĥàţ đéŕš, šö àñ üñçĥàñĝéđ ŕéçîþé çöšţš ñö éẋţŕà ŕéǫüéšţ àñđ þŕîñţš ñöţĥîñĝ.

Ţĥé šéŕṽéŕ ĥöļđš îţš ţéŕḿîñöļöĝý ĝàţé àñđ îţš ţŕàñšļàţîöñš ţö ţĥé ŕéçîþé'š ţéŕḿ ŕüļéš ƃéšîđé ţĥé ŵöŕķšþàçé ţéŕḿš, àš kapi check --ship đöéš, šö à ļàñĝüàĝé ţĥé ŕüļéš ñàḿé îš ĝöṽéŕñéđ öñ ƃöţĥ šîđéš àñđ à ţŕàñšļàţîöñ ţĥàţ ḿîššéš à ŕüļé ĥöļđš ţĥé ļàñĝüàĝé ƃàçķ üñļéšš ţĥé ŕüļé îš advisory.

Ţĥé šéŕṽéŕ àþþļîéš ţĥéšé šéţţîñĝš öñļý ƒŕöḿ à þüšĥ ţö ţĥé þŕöĵéçţ'š đéƒàüļţ šţŕéàḿ (main üñļéšš ţĥé þŕöĵéçţ ŕéçöŕđš àñöţĥéŕ). À þüšĥ ţö àñý öţĥéŕ šţŕéàḿ çàŕŕîéš ţĥéḿ, àñđ ţĥé šéŕṽéŕ ķééþš îţš öŵñ ṽàļüéš àñđ šàýš šö îñ ţĥé þüšĥ öüţþüţ.

Öñ ţĥé đéƒàüļţ šţŕéàḿ, ŵĥàţ à þüšĥ ḿàý çĥàñĝé đéþéñđš öñ ţĥé đîŕéçţîöñ:

ŠéţţîñĝŠţŕîçţéšţ ţö ļööšéšţ
translate_afterestablished, written, none
convergemanual, on-push
term_ruleséṽéŕý ŕüļé ţĥé šéŕṽéŕ ĥöļđš, ķéþţ üñçĥàñĝéđ, ŵîţĥ àñý àđđéđ; à ŕüļé đŕöþþéđ öŕ çĥàñĝéđ

À çĥàñĝé ţöŵàŕđ ţĥé šţŕîçţ éñđ àþþļîéš ƒöŕ àñýöñé ŵĥö ḿàý þüšĥ ţĥé þŕöĵéçţ, îñçļüđîñĝ à ŵöŕķšþàçé ḿéḿƃéŕ öŕ à ÇÎ ţöķéñ ŵîţĥ ţĥé contribute šçöþé. À çĥàñĝé ţöŵàŕđ ţĥé ļööšé éñđ àþþļîéš öñļý ŵĥéñ ţĥé þüšĥéŕ ḿàý ḿàñàĝé ţĥé þŕöĵéçţ (à ŵöŕķšþàçé öŵñéŕ öŕ àđḿîñ). Ƒöŕ àñýöñé éļšé ţĥé šéŕṽéŕ ķééþš îţš ṽàļüé, àñđ kapi push àñđ kapi up þŕîñţ à ļîñé šüçĥ àš:

Server setting translate_after stays established: the recipe asks for none, which allows more than the project does. A workspace owner or admin (manage_project) applies it by pushing the recipe.

Éṽéŕý þüšĥ ŕéþéàţš ţĥé ļîñé üñţîļ ţĥé ŕéçîþé àñđ ţĥé šéŕṽéŕ àĝŕéé. Ţĥé šéŕṽéŕ ŕéçöŕđš éàçĥ çĥàñĝé îţ àþþļîéš îñ ţĥé àüđîţ ļöĝ, ŵîţĥ ţĥé þüšĥéŕ àñđ ţĥé ṽàļüé ƃéƒöŕé àñđ àƒţéŕ. Îţš ŕüñš ŕéàđ ţĥé ṽàļüé îţ ĥöļđš.

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

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

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

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

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

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:
profile: acme-docs
acme-labs:
channels: [app]
voice:
profile: acme-labs
termstore: acme-labs-terms
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Ţĥé þŕöƒîļé'š ṽàļîđîţý ŵîñđöŵ

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

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

Ĝàţéš​

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

  • ship_gate šéţš ţĥé ƃàŕ ƒöŕ éṽéŕý ļöçàļé.
  • ship_gates ŕéƒîñéš îţ þéŕ šçöþé ŵîţĥ à when: šéļéçţöŕ, šö à ļéĝàļ çöļļéçţîöñ çàñ ŵàîţ ƒöŕ à þéŕšöñ ŵĥîļé à ĥéļþ çöļļéçţîöñ šĥîþš öñ çĥéçķš.
  • source_gate îš ţĥé šöüŕçé-šîđé çöṽéŕàĝé ƃàŕ kapi check --ship éṽàļüàţéš.
  • defaults.translate_after îš ţĥé þéŕ-ƃļöçķ ĥöļđ ƃéƒöŕé à ŕüñ ţŕàñšļàţéš, àñđ translate_after: 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)

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

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

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

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

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

Çöḿḿîţ ţö ĝîţ​

  • kapi.yaml: ţĥé ŕéçîþé (šîñĝļé šöüŕçé öƒ ţŕüţĥ ƒöŕ çöñƒîĝüŕàţîöñ)
  • ţĥé àĝéñţ ŵîŕîñĝ kapi init ŵŕöţé (.mcp.json, .claude/skills/kapi/SKILL.md, àñđ ţĥé öţĥéŕ ĥöšţš' ƒîļéš ŵĥéŕé îţ ŵŕöţé ţĥéḿ)

Đö ÑÖŢ çöḿḿîţ​

.kapi/: kapi init ŵŕîţéš .kapi/.gitignore ŵîţĥ öñé ļîñé, *, šö ñöñé öƒ ţĥé çàçĥé ŕéàçĥéš ĝîţ.

Đéļéţîñĝ .kapi/work/ çöšţš à ŕé-éẋţŕàçţîöñ àñđ ñöţĥîñĝ éļšé. Đéļéţîñĝ .kapi/ àļšö ļöšéš ţĥé šýñç šţàţé îñ .kapi/sync/ àñđ, îƒ ţĥé þŕöĵéçţ üšéš ŕéđàçţîöñ, ţĥé ŵîţĥĥéļđ öŕîĝîñàļš îñ .kapi/vault/. Ţĥöšé öŕîĝîñàļš àŕé ļöçàļ-öñļý àñđ çàññöţ ƃé ŕéƃüîļţ. Ýöüŕ çöñţéẋţ îš îñ ţĥé ŵöŕķšþàçé àñđ šüŕṽîṽéš. Đéļéţîñĝ ţĥé ŵöŕķšþàçé ļöšéš éṽéŕý þŕöĵéçţ'š ţéŕḿš, ṽöîçé þŕöƒîļéš, çöñţéñţ ḿéḿöŕý àñđ đéçîšîöñš, šö ƃéƒöŕé ýöü ŕéḿöṽé îţ, þüšĥ éàçĥ þŕöĵéçţ'š çöñţéẋţ ţö îţš ƃàçķéñđ öŕ ţàķé à çöþý ŵîţĥ kapi store export -o <file>.kpz.

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

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

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/, ţĥé çĥéçķöüţ'š çàçĥé, ŵîţĥ à .gitignore öƒ * ţĥàţ ķééþš ţĥé ŵĥöļé đîŕéçţöŕý öüţ öƒ ṽéŕšîöñ çöñţŕöļ

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

Ţĥé ƃļöçķ'š 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 îñ ţĥé þéŕ-ḿàçĥîñé ƃöŵŕàîñ çöñƒîĝ
  4. Éẋîšţîñĝ àüţĥ šţàţé (ƒŕöḿ kapi auth login)
  5. Ţĥé ĥöšţéđ šéŕṽîçé (https://app.bowrain.cloud): çöḿḿàñđš ţĥàţ çöñţàçţ à šéŕṽéŕ ƒàļļ ƃàçķ ţö îţ; šéļƒ-ĥöšţéđ đéþļöýḿéñţš çöñƒîĝüŕé öñé öƒ ţĥé àƃöṽé

Ñéẋţ Šţéþš​