Ç-01: Ţĥé þŕöĵéçţ ḿöđéļ
Šüḿḿàŕý
À ķàþî þŕöĵéçţ îš à ƒöļđéŕ çöñţàîñîñĝ à kapi.yaml ŕéçîþé àţ îţš ŕööţ. Ţĥé
ŕéçîþé çàþţüŕéš ţĥé üšéŕ'š đéçļàŕàţîṽé îñţéñţ (îđéñţîţý, çöñţéñţ çöļļéçţîöñš,
ƒļöŵš, ĝöṽéŕñàñçé ƃîñđîñĝš) þļüš àñý éẋţéñšîöñ ƃļöçķš à þļüĝîñ ĥàš ŕéĝîšţéŕéđ à
šçĥéḿà ƒöŕ. Çöḿḿîţ îţ ţöĝéţĥéŕ ŵîţĥ ţĥé àĝéñţ çöñƒîĝüŕàţîöñ àñđ àñý ƒļöŵ ƒîļéš.
Ţĥé þŕöĵéçţ'š çöñţéẋţ ļîṽéš îñ à þéŕ-üšéŕ ŵöŕķšþàçé öüţšîđé éṽéŕý çĥéçķöüţ, öñé đàţàƃàšé þéŕ þŕöĵéçţ, ŕéàçĥéđ ƃý éṽéŕý çļöñé àñđ ŵöŕķţŕéé öƒ îţ (Ç-03).
.kapi/ ĥöļđš çĥéçķöüţ-ļöçàļ đàţà: ţĥé đéŕîṽéđ ƃļöçķ šţöŕé àñđ çàçĥéš üñđéŕ
work/, àñđ ƃéšîđé ţĥéḿ ţĥé þéŕšöñàļ ŕéàđéŕ ƒîļţéŕš, à ṽéñüé'š šýñç šţàţé àñđ
àñý ŕéđàçţîöñ ṽàüļţ. kapi init éẋçļüđéš ţĥé đîŕéçţöŕý ƒŕöḿ ṽéŕšîöñ çöñţŕöļ.
Đéļéţîñĝ work/ ļöšéš ñöţĥîñĝ; ţĥé ƒîļţéŕš, ţĥé šýñç šţàţé àñđ ŵîţĥĥéļđ
öŕîĝîñàļš îñ ţĥé ṽàüļţ ŕéǫüîŕé šéþàŕàţé þŕéšéŕṽàţîöñ.
À ProjectContext ŕéšöļṽéš ţĥé ŕéçîþé îñţö à ŕüñţîḿé çöñƒîĝüŕàţîöñ, àñđ à
Store îñţéŕƒàçé ŵîţĥ þļüĝĝàƃļé þŕöṽîđéŕš ĝîṽéš ţööļš ŕàñđöḿ-àççéšš šţöŕàĝé
ƃéýöñđ ţĥé šţŕéàḿîñĝ þîþéļîñé.
Çöñţéẋţ
Ŕéàļ ŵöŕķ ñééđš ţö þéŕšîšţ ḿöŕé ţĥàñ àñ îñ-ƒļîĝĥţ šţŕéàḿ öƒ þàŕţš. Ţŕàñšļàţöŕš àđđ ţàŕĝéţš öṽéŕ ţîḿé, þéŕ ļöçàļé. Šéṽéŕàļ ţööļš çöñţŕîƃüţé îñđéþéñđéñţ àññöţàţîöñ ļàýéŕš. Ŕé-ŕüññîñĝ à ƒļöŵ ḿüšţ ñöţ ŕé-ţŕàñšļàţé ƃļöçķš ŵĥöšé šöüŕçé ĥàš ñöţ çĥàñĝéđ. Çöñţéñţ çöļļéçţîöñš ĝŕöüþ ĥéţéŕöĝéñéöüš šöüŕçé ƒîļéš ŵîţĥ đéŕéñţ ƒöŕḿàţš, ŵŕîţéŕ öüţþüţš àñđ ļàñĝüàĝé ţàŕĝéţš.
Ţĥé çĥàññéļ-ƃàšéđ Part → Tool → Part ḿöđéļ
(É-01) îš à ƒöŕŵàŕđ-öñļý ţŕàñšƒöŕḿ. Îţ
đöéš ñöţ çöṽéŕ ŕàñđöḿ-àççéšš ŕéàđš, îñçŕéḿéñţàļ ŵöŕķ, öŕ þàŕàļļéļ ţööļš ŵŕîţîñĝ
îñđéþéñđéñţ àññöţàţîöñ ļàýéŕš. À đéçļàŕàţîṽé ŕéçîþé çàþţüŕéš îñţéñţ; à ļöçàļ
šţöŕé çàþţüŕéš ţĥé ŵöŕķîñĝ šţàţé.
Ţĥé þŕöĵéçţ ƒöļđéŕ îš ţĥé đàý-ţö-đàý ŵöŕķîñĝ üñîţ àñđ ţĥé đéƒàüļţ üñîţ üšéŕš
šĥàŕé, ƃàçķ üþ àñđ çöḿḿîţ. Îţ îš đîšçöṽéŕéđ ƃý à ĝîţ-šţýļé üþŵàŕđ ŵàļķ, ñéṽéŕ
ñàḿéđ öñ à çöḿḿàñđ. Šĥàŕîñĝ à þŕöĵéçţ üšüàļļý ḿéàñš šĥàŕîñĝ ţĥé ƒöļđéŕ. Ŵĥéñ à
ƒöļđéŕ çàññöţ ţŕàṽéļ (à ĥàñđ-öƒƒ ţö à ţŕàñšļàţöŕ, àñ àŕçĥîṽé, àñ àîŕ-ĝàþþéđ
ţŕàñšƒéŕ), ţĥé šîñĝļé-ƒîļé .kpz þàŕçéļ çàŕŕîéš ţĥé šàḿé šţàţé ļöššļéššļý
(Ḿ-06), àñđ à ţàšķ-šçöþéđ ƃîļîñĝüàļ
.kpz îš ŵĥàţ ĝöéš ţö à ŕéṽîéŵéŕ
(Ḿ-01). Ţĥé þàŕçéļ îš ƒöŕ
ƃöüñđàŕîéš, ñöţ à çöḿþéţîñĝ ŵöŕķîñĝ ḿöđéļ: ýöü öþéñ îţ îñţö à þŕöĵéçţ, ŵöŕķ îñ
ţĥé ƒöļđéŕ, àñđ þàçķ ţö šĥîþ.
Đéçîšîöñ
Þŕöĵéçţ ļàýöüţ
Öŵñéŕšĥîþ žöñéš àţ ţĥé þŕöĵéçţ ŕööţ:
my-app/
├── kapi.yaml ← RECIPE (user edits; committed)
├── .mcp.json ← agent wiring written by kapi init (committed)
├── .claude/skills/kapi/SKILL.md
├── .kapi/ ← THIS CHECKOUT'S CACHE (ignored as a whole)
│ ├── .gitignore ← `*`, written by kapi init
│ ├── filters.local.json ← personal saved filters
│ ├── vault/ ← withheld originals (C-10), local-only, owner-only
│ │ └── batches/ ← per-batch vault sidecars (C-10)
│ ├── sync/ ← a venue's refs (C-05) and sync cache
│ └── work/ ← free to delete, always
│ ├── store.db ← this checkout's projection (C-03)
│ └── cache/
│ ├── extractions/ ← per-extract batch state (M-01)
│ └── collections/ ← overlay layers per collection
├── flows/ ← file-per-flow definitions named by flows_dir (E-04), when used
├── src/ ← authored sources (user-owned)
└── i18n/ ← writer output (generated)
Öŵñéŕšĥîþ, žöñé ƃý žöñé:
-
kapi.yamlîš ţĥé üšéŕ'š. Ĥàñđ-éđîţéđ ÝÀḾĻ, çöḿḿîţţéđ. À ƒîẋéđ, çöñṽéñţîöñàļ çöñƒîĝ ƒîļéñàḿé îñ ţĥé ƒàḿîļý öƒpackage.jsonöŕ à ÇÎ ŵöŕķƒļöŵ ƒîļé: ƃéçàüšé îţ éñđš îñ.yaml, éṽéŕý éđîţöŕ àñđ éṽéŕý çöđé ĥöšţ'š þŕéṽîéŵ àñđ đ àþþļý ÝÀḾĻ ĥîĝĥļîĝĥţîñĝ ŵîţĥ ñö çüšţöḿ ƒîļé-ţýþé ŕéĝîšţŕàţîöñ. Ŵîđé, žéŕö-çöñƒîĝ ŕéçöĝñîţîöñ ŵàš çĥöšéñ öṽéŕ à ƃŕàñđéđ đöçüḿéñţ ţýþé.Ţĥé šàḿé ŕéàšöñîñĝ ĝöṽéŕñš éṽéŕý öţĥéŕ àŕţîƒàçţ ķàþî ŵŕîţéš: éàçĥ éñđš îñ ţĥé šüƒƒîẋ öƒ ţĥé šéŕîàļîžàţîöñ îţ àçţüàļļý îš. Ŵĥéŕé à ƒîļé àļšö ñééđš ţö šàý ŵĥîçĥ đöçüḿéñţ öƒ ţĥàţ šéŕîàļîžàţîöñ îţ îš, ţĥé ḿàŕķéŕ ĝöéš îñ à šéĝḿéñţ àĥéàđ öƒ ţĥé šüƒƒîẋ (
.kbf.json,.memory.json,.overlays.jsonl), šöjq, đš àñđ ĥîĝĥļîĝĥţîñĝ ķééþ ŵöŕķîñĝ ŵĥîļé ţĥé ñàḿé šţàýš šéļƒ-đéšçŕîƃîñĝ. Öñļý.kpz, à ƃîñàŕý žîþ ñöƃöđý ĥàñđ-éđîţš, ķééþš à đéđîçàţéđ éẋţéñšîöñ. -
Ţĥé àĝéñţ ŵîŕîñĝ îš ţĥé ḾÇÞ éñţŕý àñđ ţĥé šĥöŕţ šķîļļ
kapi initŵŕîţéš ƒöŕ ţĥé çöđîñĝ àĝéñţš ţĥàţ ŵöŕķ îñ ţĥé þŕöĵéçţ (Š-01). Îţ îš çöḿḿîţţéđ ŵîţĥ ţĥé ŕéçîþé. -
.kapi/ĥöļđš đàţà šþéçîƒîç ţö ţĥîš çĥéçķöüţ.work/store.dbîš ţĥé þŕöĵéçţîöñ öƒ ţĥé ŵöŕķîñĝ ţŕéé: ţĥé ƃļöçķ çàçĥé, ţĥé öṽéŕļàýš à ƒļöŵ ŵŕöţé, ţĥé éẋţŕàçţîöñ šţàḿþš (Ç-03), ŵîţĥ ţĥé çàçĥéš ƃéšîđé îţ üñđéŕwork/. Öüţšîđéwork/šîţ ţĥé ŕéđàçţîöñ ṽàüļţ (Ç-10), à ṽéñüé'š šýñç šţàţé àñđ ţĥé þéŕšöñàļ šàṽéđ ŕéàđéŕ ƒîļţéŕš ŵîţĥ ţĥé çĥöîçé öƒ ţĥé àçţîṽé öñé.core/project.EnsureLocalDirŵŕîţéš ţĥé ṽàüļţ àñđ ţĥé šýñç đîŕéçţöŕý öŵñéŕ-öñļý àñđ àđđš éàçĥ ţö.kapi/.gitignoreŵĥéñ ţĥé ƒîļé îĝñöŕéš ļéšš ţĥàñ ţĥé ŵĥöļé đîŕéçţöŕý. Šĥàŕéđ ŕéàđéŕ ƒîļţéŕš àŕé þŕöĵéçţ šéţţîñĝš ķéþţ îñ ţĥé çöñţéẋţ šţöŕé (core/projectdb.SettingSavedFilters), àñđ à þŕöĵéçţ'š ƒļöŵ ƒîļéš šîţ îñ ţĥé çöḿḿîţţéđ đîŕéçţöŕý îţš ŕéçîþé ñàḿéš ŵîţĥflows_dir:(É-04), àñđ ķàþî ŕéàđš ñöţĥîñĝ ƒŕöḿ.kapi/flows/. À šéçöñđ çļöñé àñđ à ĝîţ ŵöŕķţŕéé éàçĥ ķééþ à.kapi/öƒ ţĥéîŕ öŵñ àñđ šĥàŕé öñé çöñţéẋţ šţöŕé. -
Çöñţéẋţ ƒîļéš àŕé àñ îñþüţ ţö ţĥé šţöŕé, ñéṽéŕ à šöüŕçé à ĝàţé ŕéàđš.
kapi store import <dir>ŕéàđš à đîŕéçţöŕý öƒ ţĥéḿ, à ţéŕḿš ƃüñđļé, à ṽöîçé þŕöƒîļé, çöñţéñţ-ḿéḿöŕý ƃüñđļéš àñđ đéçîšîöñ-ŕéçöŕđ šĥàŕđš, îñţö öþéŕàţîöñš (Ç-11). Ţĥé çöñţéẋţ îţšéļƒ ḿöṽéš ƃéţŵééñ ḿàçĥîñéš ţĥŕöüĝĥ à çöñţéẋţ ƃàçķéñđ öŕ à ţŕàñšƒéŕ ƒîļé (Ç-03). Ŵîţĥ ñö þàţĥ, îḿþöŕţ ŕéàđš.kapi/, šö à þŕöĵéçţ ţĥàţ çöḿḿîţš à šñàþšĥöţ ţĥéŕé ķééþš îţš öŵñ.kapi/.gitignore, ŵĥîçĥ ķàþî ñéṽéŕ öṽéŕŵŕîţéš. Ţĥé ŕéçîþé ñàḿéš ñöñé öƒ ţĥéšé ƒîļéš: îţ ƃîñđš ţĥé ṽöîçé àñđ ţéŕḿš ţĥéý çàŕŕý ƃý ñàḿé. -
src/**îš üšéŕ-àüţĥöŕéđ çöñţéñţ. Ŕéƒéŕéñçéđ ƃý ţĥé ŕéçîþé; ñéṽéŕ ḿöṽéđ îñţö.kapi/. -
Ŵŕîţéŕ öüţþüţš àŕé þŕöđüçéđ ƃý ţĥé ƒöŕḿàţ ŵŕîţéŕš ţĥé ŕéçîþé đéçļàŕéš. Ţĥé àþþļîçàţîöñ ŕüñţîḿé çöñšüḿéš ţĥéšé; ķàþî đöéš ñöţ.
Öñé đîŕéçţöŕý, öñé îĝñöŕé ŕüļé
core/project.EnsureLayout ŵŕîţéš .kapi/.gitignore ĥöļđîñĝ öñé ļîñé, *, šö
ţĥé ŵĥöļé đîŕéçţöŕý, ţĥé ŕüļé îñçļüđéđ, šţàýš öüţ öƒ ṽéŕšîöñ çöñţŕöļ. Ţĥé ŕüļé
îš ţĥé çöñšţàñţ core/project.StateGitignore.
Îţ îš ŵŕîţţéñ öñļý îñţö à .kapi/ ţĥàţ îš ñéŵ öŕ ĥöļđš ñöţĥîñĝ ƃüţ ŵĥàţ ķàþî
ķééþš ţĥéŕé. À đîŕéçţöŕý ţĥàţ àļŕéàđý çàŕŕîéš öţĥéŕ ƒîļéš, šüçĥ àš çöḿḿîţţéđ
çöñţéẋţ ƒîļéš, ĥàš àñ îĝñöŕé àŕŕàñĝéḿéñţ öƒ îţš öŵñ, àñđ à ŕüļé ţĥàţ îĝñöŕéđ
éṽéŕýţĥîñĝ ŵöüļđ šîļéñţļý ķééþ ţĥé ñéẋţ öƒ ţĥöšé ƒîļéš öüţ öƒ ţĥé çöḿḿîţ. À
ŕüļé àļŕéàđý þŕéšéñţ îš ñéṽéŕ ŕéŵŕîţţéñ.
Ŵĥàţ đéļéţîñĝ çöšţš, šţàţéđ éẋàçţļý:
rm -rf .kapi/workîš àļŵàýš ƒŕéé ƃéýöñđ à ŕé-éẋţŕàçţîöñ. Éṽéŕýţĥîñĝ üñđéŕ îţ îš ŕéƃüîļţ öñ ţĥé ñéẋţ ŕüñ, àñđ à ĥéļđ-ƃàçķ ļöçàļé'š đŕàƒţš àŕé šéŕṽéđ àĝàîñ ƒŕöḿ ţĥé ŵöŕķšþàçé ĥöḿé (Ç-03).rm -rf .kapiçöšţš ḿöŕé: ţĥé ŕéđàçţîöñ ṽàüļţ üñđéŕ.kapi/vault/ĥöļđš ŵîţĥĥéļđ öŕîĝîñàļš ţĥàţ àŕé ļöçàļ-öñļý àñđ ñöţ ŕéĝéñéŕàƃļé (Ç-10): ñéṽéŕ çöḿḿîţţéđ, ñéṽéŕ šýñçéđ, šö ñöţĥîñĝ àñýŵĥéŕé éļšé ĥàš à çöþý..kapi/sync/ĥöļđš à ṽéñüé'š šýñç šţàţé, àñ àñöñýḿöüš þŕöĵéçţ'š çļàîḿ ţöķéñ àḿöñĝ îţ. Ţĥé þŕöĵéçţ'š ţéŕḿš, ṽöîçé þŕöƒîļéš, çöñţéñţ ḿéḿöŕý àñđ đéçîšîöñš àŕé îñ ţĥé ŵöŕķšþàçé àñđ šţàý (Ç-03).
Ĥöŵ à þŕöĵéçţ îš çŕéàţéđ
kapi init šçàñš ţĥé đîŕéçţöŕý (ĥöñöüŕîñĝ éṽéŕý .gitignore, šķîþþîñĝ ĥîđđéñ,
đéþéñđéñçý, ṽéñđöŕéđ àñđ ƃüîļđ đîŕéçţöŕîéš) àñđ ŵŕîţéš à ŕéçîþé ŵîţĥ à
çöļļéçţîöñ ƒöŕ éàçĥ ķîñđ öƒ çöñţéñţ îţ ŕéçöĝñîšéš. Ţĥé ƒöŕḿàţ ŕéĝîšţŕý đéţéŕḿîñéš
ŵĥàţ à đöçüḿéñţ îš: à ƃüîļţ-îñ ƒöŕḿàţ ŵĥöšé ƒàḿîļý çàŕŕîéš đöçüḿéñţš (ḿàŕķéđ-üþ
ţéẋţ, öƒƒîçé đöçüḿéñţš, ţîḿéđ ţéẋţ) îš çöñţéñţ ŵĥéŕéṽéŕ îţ šîţš, ĝŕöüþéđ ƃý
ţöþ-ļéṽéļ đîŕéçţöŕý àñđ éẋţéñšîöñ, ŵîţĥ à ƒîļé àţ ţĥé ŕööţ àš àñ éñţŕý öƒ îţš
öŵñ. î18ñ çàţàļöĝš àŕé ŕéçöĝñîšéđ ƃý ţĥé ƒŕàḿéŵöŕķ þŕéšéţš' ļàýöüţš, öŕ ƃý à
þàţĥ ţĥàţ ñàḿéš ţĥé šöüŕçé ļàñĝüàĝé; à ƒîļé ñàḿéđ ƒöŕ àñý öţĥéŕ ļàñĝüàĝé îš à
ţŕàñšļàţîöñ àñđ îš ļéƒţ öüţ. Éàçĥ çöļļéçţîöñ çàŕŕîéš à çöḿḿéñţ šàýîñĝ ŵĥàţ îţ
ḿàţçĥéđ. Ţĥé šçàñ îš đéţéŕḿîñîšţîç àñđ àšķš ñöţĥîñĝ (host.ProposeCollections).
Öñ à þŕöĵéçţ ţĥàţ àļŕéàđý ĥàš à ŕéçîþé, kapi init ļéàṽéš îţš çöļļéçţîöñš
àļöñé àñđ ŕéþöŕţš ţĥé çöñţéñţ ñö çöļļéçţîöñ ŕéàđš ýéţ, àš ļîñéš ţö þàšţé.
Ŕéçîþé šçĥéḿà
Ţĥé ŕéçîþé îš à ÝÀḾĻ đöçüḿéñţ þàŕšéđ îñţö core/project.KapiProject:
# kapi.yaml
version: v1
id: prj_k3m7xq2vw9ta5r8ybn4dcp
name: Northsea App
profiles:
northsea:
channels: [app, docs]
voice:
profile: northsea
collections:
- name: ui
channel: northsea/app
content:
- path: "src/**/*.{tsx,jsx}"
format:
name: exec
config:
command: "vp neokapi-i18n extract --stream"
target: "i18n/{lang}.json"
plugins:
okapi: "^1.47.0"
flows:
translate:
steps:
- tool: recycle
config:
fuzzyThreshold: 75
- tool: translate
- tool: qa
defaults:
source_language: en
target_languages: [fr, de, ja]
concurrency: 4
parallel_blocks: 3
encoding: utf-8
tools:
redact:
detectors: [rules]
defaults.tools ĥöļđš þŕöĵéçţ-ļéṽéļ ţööļ þŕéšéţš: þéŕ-ţööļ çöñƒîĝ đéƒàüļţš
àþþļîéđ ŵĥéŕéṽéŕ ţĥàţ ţööļ ŕüñš îñ à þŕöĵéçţ ƒļöŵ. À ƒļöŵ šţéþ'š öŵñ çöñƒîĝ
öṽéŕŕîđéš ţĥé þŕéšéţ þéŕ ķéý, šö à þŕöĵéçţ þîñš îţš ŕéđàçţîöñ ŕüļéš öŕ à
þšéüđö-ţŕàñšļàţîöñ þŕéƒîẋ öñçé ŵĥîļé àñ îñđîṽîđüàļ ƒļöŵ ŕéƒîñéš ţĥéḿ. Ŕéšöļüţîöñ
ĥàþþéñš àţ ţööļ çöñšţŕüçţîöñ, àñđ ţĥé đàţà-ƒļöŵ àñđ þļàçéḿéñţ ĝàţéš
(É-03) ṽàļîđàţé àĝàîñšţ ţĥé šàḿé ḿéŕĝéđ çöñƒîĝ
ţĥé ŕüñţîḿé üšéš: à þŕéšéţ ţĥàţ éñàƃļéš ţĥé ŕéđàçţ ţööļ'š éñţîţý đéţéçţîöñ ḿàķéš
ţĥé üþšţŕéàḿ entity þöŕţ ŕéǫüîŕéđ éẋàçţļý àš àñ îñļîñé çöñƒîĝ ŵöüļđ. À ţööļ'š
çöñƒîĝ ķéýš àŕé îţš ĴŠÖÑ ƒîéļđ ñàḿéš, îñ çàḿéļÇàšé.
Ŕéǫüîŕéđ ƒîéļđš: version: v1, ŵĥîçĥ ḿüšţ éǫüàļ ţĥé çüŕŕéñţ šçĥéḿà ṽéŕšîöñ, àñđ
à ñöñ-éḿþţý path öñ éàçĥ çöñţéñţ îţéḿ. Éṽéŕý ƒļöŵ çöñţàîñš àţ ļéàšţ öñé šţéþ
ŵîţĥ à ñöñ-éḿþţý tool, üñļéšš ţĥé šţéþ üšéš parallel, îñ ŵĥîçĥ çàšé ţĥé
þàŕàļļéļ ƃŕàñçĥéš çàŕŕý ţĥé ţööļš. name îš ţĥé þŕöĵéçţ'š ĥüḿàñ ļàƃéļ. Šîñçé
ţĥé ŕéçîþé ƒîļéñàḿé îš ƒîẋéđ, îţ îš ţĥé öñļý þļàçé ţĥé ļàƃéļ ļîṽéš; kapi init
đéƒàüļţš îţ ţö ţĥé çüŕŕéñţ đîŕéçţöŕý'š ƃàšéñàḿé.
Ţĥé öţĥéŕ ŕéçîþé ƒàḿîļîéš éàçĥ ĥàṽé àñ ÀĐ öŕ à ŕéƒéŕéñçé šéçţîöñ öƒ ţĥéîŕ öŵñ:
defaults.coordinatesàñđ à çöļļéçţîöñ'šcoordinates:þļàçé çöñţéñţ öñ ţĥé đéçļàŕéđ àẋéš öƒ ţĥé çöñţéẋţ šþàçé;profiles:àñđchannel:đéŕîṽé ţĥé šţŕüçţüŕàļ öñéš (Ç-02).source_only: trueöñ à çöļļéçţîöñ àššéŕţš ţĥàţ îţ ĥàš ñö ţàŕĝéţ ļàñĝüàĝé: à ŕüñ ŕéàđš àñđ çĥéçķš îţ àñđ ŵŕîţéš ñöţĥîñĝ ƃàçķ. À çöļļéçţîöñ ţĥàţ šéţš îţ àñđ àļšö çàŕŕîéš à ţàŕĝéţ îš ŕéĵéçţéđ àţ ļöàđ.defaults.flowñàḿéš ţĥé ƒļöŵkapi upŕüñš;defaults.translate_afterĥöļđš éàçĥ ƃļöçķ üñţîļ îţš šöüŕçé ŕéàçĥéš à ļéṽéļ, àñđship_gate,ship_gates,established_gateàñđgatesàŕé ţĥé çöñṽéŕĝéñçé ĝàţéš (Çöñṽéŕĝéñçé).defaults.materializeĝöṽéŕñš đéļîṽéŕý öƒ ţàŕĝéţ-ļàñĝüàĝé ƒîļéš. Ŵîţĥmanual, ţĥé đéƒàüļţ, à þàšš ŵŕîţéš ŵĥéŕé ţĥé ŕéçîþé þöîñţš àš îţ þŕöđüçéš éàçĥ üñîţ, àñđ đéļîṽéŕý îš àñ éẋþļîçîţkapi mergeöŕkapi up --materialize. Ŵîţĥon-convergeţĥé ŕüñ öŵñš đéļîṽéŕý üñđéŕ ţĥé šĥîþ ĝàţé: îţš þàššéš đŕàƒţ îñţö à ŕüñ-ļöçàļ ţŕéé, öñļý à ļöçàļé ŵĥöšé ĝàţéđ šçöþéš àŕé àļļ šĥîþþàƃļé ĥàš îţš ƒîļéš ŵŕîţţéñ ţö ţĥé çöļļéçţîöñ'štarget:þàţĥ, àñđ à ĥéļđ-ƃàçķ ļöçàļé'š đŕàƒţš àŕé ķéþţ îñ ţĥé ŵöŕķšþàçé ĥöḿé üñţîļ à đéļîṽéŕý ŵŕîţéš ţĥéḿ (Ç-03).defaults.annotationsđéçîđéš ŵĥîçĥ šţàñđ-öƒƒ àññöţàţîöñš à ŵŕîţéŕ đŕàŵš îñļîñé;defaults.localesĥöļđš þéŕ-ţàŕĝéţ-ļàñĝüàĝé ţööļ þŕéšéţš;defaults.formatsĥöļđš þéŕ-ƒöŕḿàţ ŕéàđéŕ çöñƒîĝüŕàţîöñ àñđ đéţéçţîöñ þŕîöŕîţîéš (ƃéļöŵ).
Ţĥé þŕöĵéçţ ƒîļé ŕéƒéŕéñçé ļîšţš éṽéŕý ķéý.
Ţĥé ŕéçîþé ĥöļđš þŕöṽîđéŕ ñàḿéš öñļý. Çŕéđéñţîàļš ļîṽé îñ ţĥé ÖŠ ķéýçĥàîñ (Š-01) öŕ ţĥé éñṽîŕöñḿéñţ. Ñöţĥîñĝ îñ ţĥé ŕéçîþé îš šéçŕéţ; îţ îš šàƒé ţö çöḿḿîţ.
Đîšçöṽéŕý îš ĝîţ-šţýļé: ķàþî ŵàļķš üþ ƒŕöḿ ţĥé çüŕŕéñţ đîŕéçţöŕý üñţîļ îţ ƒîñđš à
ƒîļé ñàḿéđ éẋàçţļý kapi.yaml (core/project.ResolveLayout). À đîŕéçţöŕý ĥöļđš
àţ ḿöšţ öñé, šö đîšçöṽéŕý îš üñàḿƃîĝüöüš; àñ éẋþļîçîţ -p <path> öṽéŕŕîđéš îţ,
àñđ KAPI_NO_PROJECT=1 öþţš öüţ öƒ đîšçöṽéŕý éñţîŕéļý.
Þŕöĵéçţ îđéñţîţý
id: îš ţĥé šţàƃļé þŕöĵéçţ îđéñţîţý; name: îš àñ éđîţàƃļé đîšþļàý ļàƃéļ.
Ţĥé îđ îš ḿîñţéđ öñçé, ƃý kapi init, öüţ öƒ crypto/rand àñđ ñöţĥîñĝ éļšé.
Ñö þàŕţ öƒ îţ îš đéŕîṽéđ ƒŕöḿ ţĥé ñàḿé, ţĥé ƒöļđéŕ öŕ ţĥé ŕéþöšîţöŕý'š öŕîĝîñ,
šö éđîţîñĝ àñý öƒ ţĥöšé ļéàṽéš îţ àļöñé. Ţĥé ƒöŕḿ îš prj_ ƒöļļöŵéđ ƃý
ļöŵéŕçàšé ŔƑÇ 4648 ƃàšé32 öƒ 128 ŕàñđöḿ ƃîţš, ŵĥîçĥ ļéàṽéš ţĥé ṽàļüé
çàšé-îñšéñšîţîṽé àñđ ƒŕéé öƒ éṽéŕý çĥàŕàçţéŕ ţĥàţ ñééđš ǫüöţîñĝ îñ ÝÀḾĻ, à ÜŔĻ
öŕ à šĥéļļ ŵöŕđ (core/project.NewID, çĥéçķéđ öñ ļöàđ ƃý ValidateID).
Éṽéŕýţĥîñĝ ķàþî ŕéçöŕđš àƃöüţ à þŕöĵéçţ ļöçàļļý îš ķéýéđ öñ
KapiProject.Identity(), ţĥé îđ ŵĥéñ ţĥé ŕéçîþé çàŕŕîéš öñé. Ţŵö ķéýš đéŕîṽé
ƒŕöḿ îţ: ţĥé ŵöŕķšþàçé'š ProjectKey, ŵĥîçĥ đéçîđéš ŵĥîçĥ çöñţéẋţ šţöŕé ţĥé
þŕöĵéçţ ŕéàçĥéš (Ç-03), àñđ ţĥé çöñţéẋţ
ĝŕàþĥ'š šçöþé ţüþļé, ŵĥîçĥ host.ProjectScope ŵŕîţéš éṽéŕý ñöđé àñđ éđĝé îđ
üñđéŕ. Ŵĥàţ à þŕöĵéçţ çàñ đö ŵîţĥöüţ đîšţüŕƃîñĝ éîţĥéŕ ƒöļļöŵš đîŕéçţļý:
- Ŕéñàḿé îţ. Ţĥé ļàƃéļ îš öñé ļîñé îñ ţĥé ŕéçîþé, àñđ éđîţîñĝ îţ ļéàṽéš éṽéŕý đéŕîṽéđ ķéý ŵĥéŕé îţ šţàñđš.
- Ḿöṽé ţĥé ƒöļđéŕ, öŕ çļöñé ţĥé ŕéþöšîţöŕý šöḿéŵĥéŕé éļšé. Ñö ķéý îš đéŕîṽéđ ƒŕöḿ à þàţĥ.
- Ŵöŕķ îñ ţŵö çĥéçķöüţš àţ öñçé. Ƃöţĥ çàŕŕý ţĥé šàḿé ŕéçîþé àñđ ţĥéŕéƒöŕé ţĥé šàḿé îđ, šö à þéŕ-üšéŕ šţöŕé ķéýéđ ƃý þŕöĵéçţ ŕéàđš ţĥéḿ àš öñé þŕöĵéçţ.
Identity() ƒàļļš ƃàçķ ţö name: ƒöŕ à ŕéçîþé ţĥàţ çàŕŕîéš ñö id:. Šüçĥ à
þŕöĵéçţ ķééþš ŵöŕķîñĝ ŵîţĥ ţĥé ñàḿé àš îţš ķéý àñđ ñö ŵàŕñîñĝ àƃöüţ îţ, àñđ
kapi init --mint-id ŵŕîţéš àñ îđ îñţö îţ ţĥŕöüĝĥ ţĥé öŕđîñàŕý ŕéçîþé šéţţéŕ
(project.SetField, šàṽéđ öṽéŕ core/yamledit), šö ţĥé ƒîļé ķééþš îţš
çöḿḿéñţš, îţš ƃļàñķ ļîñéš àñđ îţš ķéý öŕđéŕ. À ŕéçîþé šţàţîñĝ ñéîţĥéŕ îš ķéýéđ
ƃý ţĥé çĥéçķöüţ îţ ŵàš ƒöüñđ àţ (workspace.KeyForCheckout, àñ at_ þŕéƒîẋ
öṽéŕ à đîĝéšţ öƒ ţĥé ñöŕḿàļîžéđ þàţĥ), šö îţ šţîļļ ĥàš à çöñţéẋţ šţöŕé öƒ îţš
öŵñ, àñđ à šéçöñđ çĥéçķöüţ öƒ îţ ĝéţš à šéçöñđ öñé. Ḿîñţîñĝ àñ id: îš ŵĥàţ
ĵöîñš ţĥéḿ.
Ţĥé šéţţéŕ ŕéĵéçţš çļéàŕîñĝ öŕ ŕéþļàçîñĝ àñ éẋîšţîñĝ îđ, ŵĥîçĥ ŵöüļđ đîšçöññéçţ
ţĥé þŕöĵéçţ ƒŕöḿ îţš ŕéçöŕđéđ çöñţéẋţ. Ţüŕñîñĝ à çöþîéđ ŕéçîþé îñţö à ĝéñüîñéļý đéŕéñţ þŕöĵéçţ ḿéàñš
đéļéţîñĝ ţĥé id: ļîñé àñđ ḿîñţîñĝ à ƒŕéšĥ öñé.
Üñķñöŵñ ţöþ-ļéṽéļ ķéýš àŕé þŕéšéŕṽéđ ŕàţĥéŕ ţĥàñ ŕéĵéçţéđ (šéé Ŕéçîþé éẋţéñšîöñ
ḿéçĥàñîšḿ), šö à ķàþî ŕéļéàšé ƃüîļţ ƃéƒöŕé ţĥîš
ƒîéļđ ŕéàđš à ŕéçîþé çàŕŕýîñĝ àñ id: àñđ îđéñţîƒîéš ţĥé þŕöĵéçţ ƃý îţš ñàḿé.
Ţĥé ñéàŕ-ḿîšš ŕéþöŕţéŕ šţàýš ǫüîéţ àƃöüţ îţ àš ŵéļļ, šîñçé id ŕéšéḿƃļéš ñö
ƒîéļđ öƒ KapiProject.
Çöñţéñţ þàţĥš
Éàçĥ çöñţéñţ îţéḿ'š path îš à
đöüƃļéšţàŕ ĝļöƃ: ** ḿàţçĥéš àçŕöšš
đîŕéçţöŕîéš àñđ {a,b,c} ḿàţçĥéš àļţéŕñàţîṽéš, šö à šîñĝļé ĝļöƃ çöṽéŕš à
đîŕéçţöŕý öƒ ḿîẋéđ çöñţéñţ ŵîţĥ ţĥé ƒöŕḿàţ đéţéçţéđ þéŕ ƒîļé.
À çöļļéçţîöñ'š base îš ţĥé đîŕéçţöŕý îţ ļîṽéš îñ: éṽéŕý path, target àñđ
îţéḿ base ƃéļöŵ îţ îš ŵŕîţţéñ ŕéļàţîṽé ţö ţĥàţ đîŕéçţöŕý àñđ ĵöîñéđ öñţö îţ, šö
à çöļļéçţîöñ ŕéàđš àš ţĥé ţŕéé îţ ĝöṽéŕñš ŕàţĥéŕ ţĥàñ àš à þŕéƒîẋ ŕéþéàţéđ öñ
éṽéŕý ļîñé. Àñ îţéḿ'š öŵñ base îš ţĥé ñàŕŕöŵéŕ ţĥîñĝ, ţĥé đîŕéçţöŕý à ḿàţçĥéđ
ƒîļé'š þàţĥ îš ḿàđé ŕéļàţîṽé ţö, ŵĥîçĥ đŕîṽéš ţĥé þàţĥ ţöķéñš. Îţ đéƒàüļţš ţö ţĥé
ĝļöƃ'š ƒîẋéđ þŕéƒîẋ.
target îš à þàţĥ ţéḿþļàţé éẋþàñđéđ þéŕ ƒîļé àñđ ļàñĝüàĝé. Ţĥé çöḿḿöñ çàšé îš
đîŕéçţöŕý-ḿîŕŕöŕ: ŵĥéñ ţĥé ţàŕĝéţ ñàḿéš à đîŕéçţöŕý, ţĥé šöüŕçé þàţĥ ŕéļàţîṽé
ţö base îš ŕéþŕöđüçéđ üñđéŕ îţ, šö target: output/{lang} ţüŕñš
input/docs/api.md îñţö output/fr/docs/api.md. Ƒöŕ çüšţöḿ ļàýöüţš, ţöķéñš
({lang}, {relpath}, {path}, {dir}, {filename}, {name}/{basename},
{ext}) ŕéšĥàþé ţĥé þàţĥ éẋþļîçîţļý. Ţĥé ŕéšöļṽéŕ îš
core/project.ResolveTargetPath; ţĥé ţöķéñ ŕéƒéŕéñçé ļîṽéš îñ ţĥé
þŕöĵéçţ ƒîļé ŕéƒéŕéñçé.
Ŕéçîþé éẋţéñšîöñ ḿéçĥàñîšḿ
KapiProject çàŕŕîéš àñ Extras map[string]yaml.Node ƒîéļđ ŵîţĥ yaml:",inline"
öñ KapiProject, Defaults, Collection àñđ ContentItem. Üñķñöŵñ ÝÀḾĻ ķéýš
àŕé çàþţüŕéđ àš ŕàŵ ñöđéš; à ļàýéŕ ƃüîļţ öñ ţĥé ƒŕàḿéŵöŕķ đéçļàŕéš îţš öŵñ ţýþéđ
šçĥéḿà àñđ đéçöđéš ƒŕöḿ Extras àţ ļöàđ ţîḿé. Ţĥé ƒŕàḿéŵöŕķ ķñöŵš ñöţĥîñĝ àƃöüţ
ţĥöšé éẋţéñšîöñš àñđ ŕöüñđ-ţŕîþš ţĥéḿ ṽéŕƃàţîḿ.
À þàçķàĝé ŕéĝîšţéŕš šçĥéḿàš àţ init():
coreproj.RegisterExtensionGroup("myplugin", []coreproj.Extension{
{Name: "myplugin", Scope: coreproj.ScopeProject, Decoder: venueDecoder, Venue: true},
{Name: "hooks", Scope: coreproj.ScopeProject, Decoder: hooksDecoder},
})
Scope đîšţîñĝüîšĥéš ŵĥîçĥ Extras ḿàþ à ķéý ƃéļöñĝš ţö: ScopeProject,
ScopeDefaults, ScopeCollection öŕ ScopeItem. Éàçĥ (Scope, Name) ƃîñđš ţö
öñé đéçöđéŕ. KapiProject.Validate() ŵàļķš éṽéŕý Éẋţŕàš ḿàþ àñđ ŕüñš ţĥé
ḿàţçĥîñĝ đéçöđéŕ; ķéýš ŵîţĥ ñö đéçöđéŕ ŕéĝîšţéŕéđ ŕöüñđ-ţŕîþ ŵîţĥöüţ éŕŕöŕ, šö
ƃîñàŕîéš ŵîţĥ đéŕéñţ þļüĝîñ šéţš ļîñķéđ îñ šţàý ƒöŕŵàŕđ-çöḿþàţîƃļé. Àñ
üñķñöŵñ ķéý ţĥàţ îš öñé éđîţ àŵàý ƒŕöḿ à ķñöŵñ ƒîéļđ öƒ ţĥé šàḿé šţŕüçţ îš à
ļîķéļý ţýþö ŕàţĥéŕ ţĥàñ àñ éẋţéñšîöñ, àñđ KapiProject.KeyWarnings ŕéþöŕţš îţ
ŵîţĥ ţĥé ƒîéļđ îţ ŕéšéḿƃļéš.
À ŕéçîþé đéçļàŕéš à ĥàŕđ đéþéñđéñçý ŵîţĥ requires:, à ḿàþ öƒ þļüĝîñ ñàḿé ţö
ṽéŕšîöñ çöñšţŕàîñţ ("*" ƒöŕ àñý ṽéŕšîöñ; šéḿṽéŕ ƒöŕḿš šüçĥ àš ^1.0 àŕé àļšö
àççéþţéđ). Ṽàļîđàţîöñ ƒàîļš ŵĥéñ ñö éẋţéñšîöñ üñđéŕ ţĥé ñàḿéđ ĝŕöüþ ĥàš ƃééñ
ŕéĝîšţéŕéđ:
version: v1
requires:
myplugin: "*"
myplugin:
url: https://platform.example.com/team/proj
À ƃîñàŕý ţĥàţ đöéš ñöţ ļîñķ ţĥé myplugin éẋţéñšîöñš ŕéĵéçţš ţĥîš ŕéçîþé ŵîţĥ àñ
àçţîöñàƃļé éŕŕöŕ ŕàţĥéŕ ţĥàñ šîļéñţļý îĝñöŕîñĝ ţĥé ƃļöçķ. À ŕéçîþé ŵîţĥöüţ
requires: ļöàđš îñ àñý ƃîñàŕý àñđ ţĥé éẋţŕàš þàšš ţĥŕöüĝĥ.
Ţĥé ṽéñüé çļîéñţ îñ host/venue ŕéĝîšţéŕš öñé çöļļéçţîöñ-šçöþéđ éẋţéñšîöñ ķéý
öƒ îţš öŵñ, preview: ŵĥéŕé à çöļļéçţîöñ'š šţŕîñĝš çàñ ƃé ŕéàđ îñ þļàçé (à
çöḿþöñéñţ éẋþļöŕéŕ öŕ à ŕüññîñĝ šîţé), àš à ķîñđ àñđ à ÜŔĻ. Îţ îš đéçöđéđ öñļý
ŵĥéñ ţĥé ŕéçîþé àļšö çàŕŕîéš ţĥé ṽéñüé ķéý, îţ ţŕàṽéļš öñ ţĥé çöļļéçţîöñ'š
çöñţéẋţ éñţŕý ŵîţĥ ţĥé çööŕđîñàţéš àñđ ţĥé ĝöṽéŕñàñçé, àñđ îţ îš ƒöļđéđ îñţö
ţĥàţ éñţŕý'š ĥàšĥ šö ţĥàţ ŕé-þöîñţîñĝ à çöļļéçţîöñ ŕéçöñçîļéš. À ƃîñàŕý ŵîţĥöüţ
ţĥé ṽéñüé çļîéñţ ŕöüñđ-ţŕîþš îţ ļîķé àñý öţĥéŕ éẋţŕà.
Îḿþļéḿéñţàţîöñ đéţàîļ (ţĥé Scope éñüḿ, ţĥé đéçöđéŕ ĥéļþéŕš àñđ à ŵöŕķéđ
éẋàḿþļé) ļîṽéš îñ Ñöţé: Þļüĝîñ ḿöđéļ.
Çöñṽéŕĝîñĝ šöḿéŵĥéŕé éļšé
Ţĥé ƒŕàḿéŵöŕķ đéƒîñéš ţĥé šýñç ŵîŕé (core/venue: ţĥé çöñţéẋţ çöñţéñţ ţýþé,
ŕ郚 àñđ ţŕéé šĥàþéš ƃöţĥ šîđéš ĥàšĥ ţĥé šàḿé ŵàý) àñđ à çļîéñţ ƒöŕ îţ
(host/venue), ƃüţ ñö ṽéñüé ķéý öƒ îţš öŵñ. Šéŕṽéŕ, àççöüñţ àñđ ṽéñüé àŕé ñöţ
ŕéçîþé ƒîéļđš. À ļàýéŕ ţĥàţ àđđš öñé ƃüîļđš îţ öñ ţĥé ĝéñéŕîç ḿéçĥàñîšḿ àƃöṽé: îţ
ŕéĝîšţéŕš à ScopeProject éẋţéñšîöñ üñđéŕ îţš öŵñ ñàḿé àñđ ĝàţéš îţ ŵîţĥ
requires:, šö à ŕéçîþé çàŕŕýîñĝ ţĥé ķéý îš ḿéàñîñĝƒüļ öñļý ŵĥéŕé ţĥàţ þļüĝîñ
îš îñšţàļļéđ.
Öñé ţĥîñĝ ţĥé ƒŕàḿéŵöŕķ đöéš ñééđ ƒŕöḿ šüçĥ à ķéý îš ŵĥéţĥéŕ ţĥé þŕöĵéçţ
çöñṽéŕĝéš šöḿéŵĥéŕé öţĥéŕ ţĥàñ ţĥîš ḿàçĥîñé. Îţ àšķš ţĥé ŕéĝîšţŕý ŕàţĥéŕ ţĥàñ
ļööķîñĝ ƒöŕ à ñàḿé. Àñ éẋţéñšîöñ ŕéĝîšţéŕéđ ŵîţĥ Venue: true çļàîḿš ţĥàţ ŕöļé
(à þļüĝîñ ḿàñîƒéšţ đéçļàŕéš îţ àš "venue": true öñ à šçĥéḿà éẋţéñšîöñ), àñđ ţĥé
ƒŕàḿéŵöŕķ ţĥéñ ŕéàđš éẋàçţļý ţŵö ƒîéļđš öüţ öƒ ţĥé ƃļöçķ, url: àñđ converge:,
ţĥŕöüĝĥ KapiProject.Venue(). Ŵĥîçĥ ļàýéŕ þŕöṽîđéš ţĥé ṽéñüé, àñđ ŵĥàţ îţš ķéý
îš çàļļéđ, šţàýš ţĥàţ ļàýéŕ'š ƃüšîñéšš: à ŕéçîþé ķéý ķàþî çàññöţ ñàḿé îš à ķéý îţ
çàññöţ ĝŕöŵ àñ öþîñîöñ àƃöüţ. Àñ üñŕéĝîšţéŕéđ ķéý öƒ ţĥé šàḿé ñàḿé ŕéþöŕţš ñö
ṽéñüé àñđ ñö öþîñîöñ.
À þüšĥ çàŕŕîéš ţĥé ŕéçîþé'š þŕöĵéçţ šéţţîñĝš ţö ţĥé ṽéñüé ƃéšîđé ţĥé çöñţéẋţ
çöñţéñţ ţýþé (core/venue.ProjectSettings): ţĥé ṽéñüé'š converge: þöļîçý,
defaults.translate_after àñđ ţĥé ţéŕḿ ŕüļéš ţĥé ŕéçîþé đéçļàŕéš
(core/profile.RecipeTermRules, šéé Ç-08),
éàçĥ ŕéšöļṽéđ ţö îţš 郃éçţîṽé ṽàļüé šö àñ üñšéţ ķéý ţŕàṽéļš àš îţš đéƒàüļţ.
Ţĥé ṽéñüé ŕéþöŕţš ţĥé šéţţîñĝš îţ ĥöļđš ŵĥéñ ţĥé þüšĥ ñéĝöţîàţéš, àñđ ŵĥîçĥ öƒ
ţĥé ŕéçîþé'š îţ ŵöüļđ ñöţ àþþļý ƒöŕ ţĥîš þüšĥéŕ; ţĥé þüšĥ šéñđš öñļý à šéţţîñĝ
ţĥàţ đéŕš àñđ îš ñöţ ŕéƒüšéđ, àñđ ŕéþöŕţš ţĥé ŕéšţ. À ṽéñüé àþþļîéš šéţţîñĝš
öñļý ƒŕöḿ à þüšĥ ţö ţĥé þŕöĵéçţ'š đéƒàüļţ šţŕéàḿ. Ţĥéŕé, à šéţţîñĝ ţĥàţ
ţîĝĥţéñš (à šţŕîçţéŕ šöüŕçé ĥöļđ, à ḿàñüàļ çöñṽéŕĝé þöļîçý, ţéŕḿ ŕüļéš ţĥàţ ķééþ
éṽéŕý ŕüļé ţĥé ṽéñüé ĥöļđš) àþþļîéš ƒöŕ àñýöñé ŵĥö ḿàý þüšĥ, àñđ öñé ţĥàţ
ļööšéñš (îñçļüđîñĝ à đŕöþþéđ öŕ çĥàñĝéđ ţéŕḿ ŕüļé) àþþļîéš öñļý ƒöŕ à þüšĥéŕ ŵĥö
ḿàý ḿàñàĝé ţĥé þŕöĵéçţ. À ŕéƒüšéđ šéţţîñĝ ļéàṽéš ţĥé ṽéñüé'š ṽàļüé îñ ƒöŕçé àñđ
ŕéàçĥéš ţĥé þüšĥéŕ àš à venue.SettingRefusal ñàḿîñĝ ţĥé ŕéàšöñ àñđ ŵĥàţ ŵöüļđ
àþþļý îţ.
Çöñţéñţ çöļļéçţîöñš
À Collection ļîšţš ţĥé šöüŕçé þàţţéŕñš ķàþî éẋţŕàçţš ƒŕöḿ àñđ ţĥé ŕéàđéŕ üšéđ
ƒöŕ éàçĥ. Éẋţŕàçţéđ ƃļöçķš ƒļöŵ ţĥŕöüĝĥ ţĥé þŕöĵéçţ'š éẋéçüţöŕ; þéŕšîšţéñţ ƃļöçķ
šţàţé (ĥàšĥéš, þéŕ-ļöçàļé ţàŕĝéţš, àññöţàţîöñš) ļîṽéš îñ ţĥé þŕöĵéçţ šţöŕé.
Ƒöŕ šüƃþŕöçéšš-ƃàšéđ éẋţŕàçţöŕš, ţĥé ƒöŕḿàţ îš exec: ķàþî ŕüñš ţĥé đéçļàŕéđ
çöḿḿàñđ öñçé þéŕ çöļļéçţîöñ ŵîţĥ éṽéŕý ḿàţçĥéđ ƒîļé þàţĥ šţŕéàḿéđ öñ šţđîñ
(ÑÜĻ-šéþàŕàţéđ) àñđ ŕéàđš ÑĐĴŠÖÑ ƃļöçķ ŕéçöŕđš ƒŕöḿ šţđöüţ. Ţĥé đéṽéļöþéŕ þîçķš
ţĥé þàçķàĝé ḿàñàĝéŕ öŕ ƃîñàŕý þàţĥ. ķàþî ŕüñš ŵĥàţéṽéŕ command šàýš ṽéŕƃàţîḿ,
ŵĥîçĥ îš ŵĥý ţĥé éẋéç çļàšš îš ĝàţéđ ƃý éẋþļîçîţ çöñšéñţ
(É-06).
Ţĥé šţöŕé îñţéŕƒàçé
Ƒļöŵš àñđ ţööļš ŕéàđ àñđ ŵŕîţé ƃļöçķš àñđ öṽéŕļàýš ţĥŕöüĝĥ ţĥé Store àñđ
Session îñţéŕƒàçéš (core/blockstore), ñöţ ţĥŕöüĝĥ ŕàŵ çĥàññéļš. Ţĥé šţŕéàḿîñĝ
çöñţŕàçţ îš þŕéšéŕṽéđ àš öñé çàþàƃîļîţý àḿöñĝ šéṽéŕàļ.
type Store interface {
Begin(ctx context.Context) (Session, error)
Capabilities() Capabilities
Close() error
}
type Session interface {
Capabilities() Capabilities
Blocks(filter BlockFilter) iter.Seq2[*Block, error]
GetBlock(hash string) (*Block, error)
PutBlock(collection string, b *Block) error
GetOverlay(kind, blockHash string) (Overlay, error)
PutOverlay(s Overlay) error
ListOverlays(kind string) iter.Seq2[Overlay, error]
Commit() error
Rollback() error
Close() error
}
type Capabilities struct {
RandomAccess bool
Concurrent bool
Remote bool
Writable bool
Persistent bool
}
Ţŵö þŕöṽîđéŕš ƃàçķ îţ: àñ éþĥéḿéŕàļ ḿàþ-ƃàšéđ öñé ƒöŕ ţéšţš àñđ àđ-ĥöç ÇĻÎ
îñṽöçàţîöñš, àñđ ţĥé ƃļöçķ ţàƃļéš îñšîđé .kapi/work/store.db ƒöŕ ļöñĝ-ļîṽéđ
þŕöĵéçţ ŵöŕķ. Ţööļš ñéṽéŕ öþéñ ţĥé đàţàƃàšé đîŕéçţļý; ţĥéý öþéŕàţé öñ à šéššîöñ.
Îñ ţĥé ƃŕöŵšéŕ ţĥé ƃļöçķ šţöŕé îš à þàţĥ-ķéýéđ îñ-ḿéḿöŕý îḿþļéḿéñţàţîöñ
(Ç-03); ñöţĥîñĝ àƃöṽé ţĥé Store îñţéŕƒàçé
ñöţîçéš.
À ţööļ ţĥàţ ñééđš ŕàñđöḿ àççéšš îḿþļéḿéñţš ţĥé öþţîöñàļ SessionTool éẋţéñšîöñ
(core/tool/session.go), ŵĥîçĥ àđđš à šéššîöñ ĥàñđļé àļöñĝšîđé ţĥé šàḿé
šţŕéàḿîñĝ çĥàññéļš:
type SessionTool interface {
Tool
SessionProcess(
ctx context.Context,
sess blockstore.Session,
in <-chan *model.Part,
out chan<- *model.Part,
) error
}
Ţĥé éẋéçüţöŕ öþéñš öñé šéššîöñ þéŕ ŕüñ, đîšþàţçĥéš éàçĥ šţàĝé ţĥŕöüĝĥ
SessionProcess ŵĥéñ ţĥé ţööļ îḿþļéḿéñţš îţ, àñđ öŵñš ţĥé ţŕàñšàçţîöñ ƃöüñđàŕý:
ţööļš ḿüšţ ñöţ çàļļ Commit/Rollback ţĥéḿšéļṽéš. SessionTool îš ţĥé þàţĥ ƒöŕ
ţéŕḿ éñƒöŕçéḿéñţ, ḿüļţî-þàšš šţàţîšţîçš àñđ çĥéçķš ţĥàţ ŕéàđ ţĥé ŵĥöļé šţöŕé.
ÞŕöĵéçţÇöñţéẋţ
À ProjectContext (core/project) ƃŕîđĝéš ţĥé šţàţîç ŕéçîþé àñđ ţĥé ļîṽé
ŕüñţîḿé. Éṽéŕý çöñšüḿéŕ ţĥàţ ŕüñš îñ þŕöĵéçţ ḿöđé çöñšţŕüçţš öñé:
type ProjectContext struct {
Project *KapiProject
ProjectDir string
SourceLocale model.LocaleID
TargetLocales []model.LocaleID
AllowedSources []string
Encoding string
Concurrency int
ParallelBlocks int
LocaleFormat string
FormatDefaults map[string]FormatDefaults
}
AllowedSources đéŕîṽéš ƒŕöḿ ţĥé plugins šéçţîöñ. Îţ àļŵàýš îñçļüđéš
"built-in" þļüš éàçĥ đéçļàŕéđ þļüĝîñ ñàḿé; à þŕöĵéçţ ŵîţĥöüţ à plugins
šéçţîöñ šééš ƃüîļţ-îñ ƒöŕḿàţš öñļý.
Þŕöĵéçţ-šçöþéđ đéţéçţîöñ. ProjectContext.DetectFormat đéļéĝàţéš ţö
FormatRegistry.Detect(path, DetectOptions{AllowedSources, PriorityOverrides}).
Đéţéçţîöñ îš çöñţéñţ-àŵàŕé, šîñçé ţĥé ƒîļé ĥéàđ đîšàḿƃîĝüàţéš à šĥàŕéđ
éẋţéñšîöñ, àñđ ţàķéš þéŕ-çàļļ þŕîöŕîţý öṽéŕŕîđéš. Ŵĥéñ à þļüĝîñ îš îñšţàļļéđ
ĝļöƃàļļý ƃüţ ţĥé þŕöĵéçţ đöéš ñöţ đéçļàŕé îţ, îţš ƒöŕḿàţš àŕé éẋçļüđéđ àñđ
ƃüîļţ-îñš àŕé üšéđ îñšţéàđ. Éẋþļîçîţļý đéçļàŕéđ ƒöŕḿàţš öñ à çöñţéñţ îţéḿ ƃýþàšš
đéţéçţîöñ éñţîŕéļý.
Ţĥé öṽéŕŕîđéš çöḿé ƒŕöḿ defaults.formats.<format>.priority: ŵĥéŕé àñ éẋţéñšîöñ
îš çļàîḿéđ ƃý šéṽéŕàļ ƒöŕḿàţš àţ éǫüàļ þŕîöŕîţý, à ŕéçîþé šţééŕš đéţéçţîöñ ƃý
ƃüḿþîñĝ ţĥé þŕéƒéŕŕéđ éñĝîñé. Ţĥîš ļéţš à šîñĝļé ŵîļđçàŕđ çöñţéñţ îţéḿ
àüţö-đéţéçţ ţĥé ŕîĝĥţ éñĝîñé þéŕ ƒîļé îñšţéàđ öƒ þîññîñĝ öñé ƒöŕḿàţ þéŕ
éẋţéñšîöñ. Ţĥé öṽéŕŕîđé îš àþþļîéđ þéŕ đéţéçţîöñ çàļļ ŕàţĥéŕ ţĥàñ ƃý ḿüţàţîñĝ ţĥé
ŕéĝîšţŕý, šö çöñçüŕŕéñţļý öþéñ þŕöĵéçţš ŵîţĥ đéŕéñţ þŕîöŕîţîéš đö ñöţ ŕàçé.
Çöñţéñţ ŕéšöļüţîöñ. ProjectContext.ResolveContent ḿàţçĥéš çöñţéñţ þàţţéŕñš
àĝàîñšţ ţĥé ƒîļéšýšţéḿ, àþþļîéš îĝñöŕé ŕüļéš, đéţéçţš ƒöŕḿàţš àñđ ŕéţüŕñš
[]ResolvedFile. Ƃöţĥ ţĥé ÇĻÎ àñđ ţĥé đéšķţöþ àþþ üšé ţĥîš öñé îḿþļéḿéñţàţîöñ.
Ŕéàđéŕ àñđ ŵŕîţéŕ çöñƒîĝüŕàţîöñ. ConfigureReader àþþļîéš à ƒöŕḿàţ'š
FormatDefaults.Config öṽéŕŕîđéš ƒŕöḿ defaults.formats.<format> öñţö ţĥé
ŕéàđéŕ'š çöñƒîĝ; îţ ţàķéš ţĥé Configurable îñţéŕƒàçé (àñý çöḿþöñéñţ éẋþöšîñĝ
Config() format.DataFormatConfig) àñđ îš à ñö-öþ ŵĥéñ ţĥé þŕöĵéçţ đéçļàŕéš ñö
đéƒàüļţš ƒöŕ ţĥàţ ƒöŕḿàţ. ConfigureWriter šéţš ţĥé ŵŕîţéŕ'š éñçöđîñĝ ƒŕöḿ ţĥé
þŕöĵéçţ đéƒàüļţš. Þŕéšéţ šéļéçţîöñ îš ŕéšöļṽéđ šéþàŕàţéļý, ţĥŕöüĝĥ
resolver.ResolveFormatConfig, ŵĥîçĥ ḿéŕĝéš ţĥé ñàḿéđ þŕéšéţ'š çöñƒîĝ ƃéƒöŕé ţĥé
ŕéàđéŕ îš öþéñéđ.
Ŕéàđéŕ çöñƒîĝ đéçîđéš ŵĥîçĥ ţéẋţ à ŕéàđéŕ éḿîţš àţ àļļ, šö îţ îš þàŕţ öƒ à
çöñţéñţ üñîţ'š îđéñţîţý ŕàţĥéŕ ţĥàñ à đéţàîļ öƒ öñé çöđé þàţĥ: ţĥé çöñƒîĝ à
çöļļéçţîöñ đéçļàŕéš îš defaults.formats.<format>.config öṽéŕļàîđ ƃý ţĥé
çöñţéñţ îţéḿ'š öŵñ format.config, àñđ éṽéŕý þàţĥ ţĥàţ ŕéàđš à đéçļàŕéđ ƒîļé
ŕéàđš îţ üñđéŕ ţĥàţ ḿéŕĝéđ çöñƒîĝ. Ţĥàţ çöṽéŕš ţĥé ƒļöŵ ŕüñ, éẋţŕàçţ, ḿéŕĝé, àñđ
éǫüàļļý ţĥé ḿéàšüŕéḿéñţ þàţĥš (çöṽéŕàĝé, šţàţüš, ţĥé ŕéṽîéŵ ǫüéüé, ţĥé ƃîļîñĝüàļ
çĥéçķš), ŵĥîçĥ ŕéšöļṽé îţ þéŕ üñîţ àš ţĥéý ŕéšöļṽé çöñţéñţ. À ḿéàšüŕéḿéñţ ƃļîñđ
ţö ţĥé çöñƒîĝ çöüñţš à đéŕéñţ šéţ öƒ üñîţš ţĥàñ ţĥé ŕüñ þŕöđüçéđ, šö ţĥé
þéŕçéñţàĝé îš à ƒŕàçţîöñ öṽéŕ ţŵö đéñöḿîñàţöŕš.
Þļüĝîñ šçöþîñĝ ĝéñéŕàļîžéš ƃéýöñđ đéţéçţîöñ: AllowedTools() ƒîļţéŕš ţĥé ţööļ
ŕéĝîšţŕý ţö ţööļš ƒŕöḿ đéçļàŕéđ þļüĝîñš þļüš ƃüîļţ-îñš, þŕéšéţš ƒŕöḿ üñđéçļàŕéđ
þļüĝîñš àŕé éẋçļüđéđ ƒŕöḿ þŕéšéţ šéļéçţöŕš, àñđ ƒļöŵš ŕéƒéŕéñçîñĝ ţööļš ƒŕöḿ
üñđéçļàŕéđ þļüĝîñš þŕöđüçé ŵàŕñîñĝš đüŕîñĝ ṽàļîđàţîöñ.
Ƃööķķééþîñĝ
.kapi/work/cache/extractions/<batch-id>/manifest.yaml ŕéçöŕđš éàçĥ kapi extract ŕüñ (Ḿ-01): ţĥé éḿîţţéđ
šöüŕçé→öüţþüţ þàîŕš, þéŕ-ƒîļé šöüŕçé ŠĤÀ-256, ļéṽéŕàĝé çöüñţš, ţĥé ƃîļîñĝüàļ
ƒöŕḿàţ ṽéŕšîöñ àñđ ţĥé šķéļéţöñ ƒîļéñàḿéš. Ţĥé ƃàţçĥ îđ îš šţàḿþéđ îñ éàçĥ
éḿîţţéđ ƃîļîñĝüàļ ƒîļé šö kapi merge ŕéšöļṽéš à ŕéţüŕñîñĝ ƒîļé ƃàçķ ţö ţĥé
ŕîĝĥţ éẋţŕàçţîöñ ŵîţĥöüţ ĝüéššîñĝ ƒŕöḿ îţš ñàḿé.
Çöñšéǫüéñçéš
- Îñçŕéḿéñţàļ ŵöŕķ: ŕé-ŕüññîñĝ à ƒļöŵ ţŕàñšļàţéš öñļý ƃļöçķš ŵĥöšé šöüŕçé ĥàšĥ îš ñöţ àļŕéàđý ŕéçöŕđéđ ƒöŕ ţĥé ţàŕĝéţ ļöçàļé.
- Çöñçüŕŕéñţ ţööļš: ţéŕḿ ḿàţçĥ àñđ ḿéḿöŕý ļööķüþ ŕüñ îñ þàŕàļļéļ, éàçĥ ŵŕîţîñĝ àñ îñđéþéñđéñţ öṽéŕļàý ļàýéŕ.
- Ţŕàñšàçţîöñ šéḿàñţîçš ṽàŕý þéŕ þŕöṽîđéŕ, àñđ ţööļš çàļļîñĝ
GetBlockþéŕ ƃļöçķ àŕé šļöŵ àĝàîñšţ à ŕéḿöţé šţöŕé. - Ţĥé ŕéçîþé îš àļŵàýš ƒŕéé öƒ çŕéđéñţîàļš, šö îţ îš šàƒé ţö çöḿḿîţ àñđ ţö šĥàŕé.
- Ţĥé ŕéçîþé ƃîñđš ƃý ñàḿé ŵĥàţ ĝöṽéŕñš à þöîñţ (
defaults.voice,profiles.<n>.termstore) àñđ ñàḿéš ñö çöñţéẋţ ƒîļé. À ŕéçîþé ţĥàţ ñàḿéš öñé ƒàîļš ţö ļöàđ ŵîţĥ ţĥé îḿþöŕţ ţĥàţ ŕéàđš îţ. Ñö ƃîñđîñĝ ŕéàçĥéš à çĥéçķöüţ öñ à ŕéàđ þàţĥ, šö ţŵö ƃŕàñçĥéš öƒ öñé þŕöĵéçţ àñšŵéŕ ţĥé šàḿé ǫüéšţîöñ ţĥé šàḿé ŵàý.
Šéé àļšö
- Ç-02: Çööŕđîñàţéš àñđ ĝöṽéŕñàñçé: ţĥé þöîñţ à çöļļéçţîöñ šîţš àţ àñđ ŵĥàţ ĝöṽéŕñš îţ.
- Ç-03: Ţĥé çöñţéẋţ šţöŕé àñđ ĝŕàþĥ:
.kapi/work/store.dbàñđ ţĥé ŵöŕķšþàçé ĥöļđîñĝ ţĥé öţĥéŕ ĥàļƒ. - Ç-04: Ƃļöçķ šţàţé àñđ ţĥé đéçîšîöñ ŕéçöŕđ: ţĥé ļéđĝéŕ àñđ ţĥé šĥàŕđš à šñàþšĥöţ ŵŕîţéš.
- É-01: Þŕöçéššîñĝ Éñĝîñé: ƒļöŵ éẋéçüţîöñ.
- É-03: Ţööļ Šýšţéḿ: ţĥé
ToolàñđSessionToolîñţéŕƒàçéš. - Ƒļöŵ šţéþš ƒöŕḿàţ: ţĥé šĥàŕéđ ƒļöŵ šýñţàẋ.
- ķàþî.ýàḿļ þŕöĵéçţ ƒîļé: ţĥé šçĥéḿà ŕéƒéŕéñçé.