Projects
There are two ways to drive Kapi, and it's the same commands either way. What changes is whether Kapi remembers anything between runs.
Ad-hoc: one-off, nothing saved
Run a tool or flow directly on the files you name. Nothing is kept after the run.
Translate this one file to French. · Check this folder for off-brand terms.
This is the quick path for a one-time job, a script, or a CI step. In the CLI you name the files with flags; in Kapi Desktop you pick them as quick tools.
Project: a recipe plus a memory
A project is a small kapi.yaml recipe file (which files count as content, the voice, terms and coordinates that govern them, your flows and defaults, and, if you translate, your languages) plus a store that remembers your work: translations, terminology, and where each block stands in review, ready to reuse on the next run. Kapi finds the project automatically by walking up the folder tree, the way git finds its repo.
Translate this whole repo every release, reusing everything translated last time.
| Ad-hoc | Project | |
|---|---|---|
| Setup | none | a kapi.yaml recipe (commit it) |
| Memory | nothing saved | a store accumulates work (content memory, terms, approvals) |
| Finds your files | you name them | discovered automatically |
| The main verb | kapi <tool> <file> | kapi up, bring the project up to date |
| Best for | one-offs, scripts, CI | a repo you work on repeatedly |
Set one up: your first project. In a project, kapi up runs the default flow until every gated locale is shippable or waits for review, kapi status shows standing, and kapi check --ship enforces the gates; the model behind those verbs is the kapi loop.
The mechanics: source → flow → sink
Kapi has one set of commands, and what changes between ad-hoc and project use is the binding: where content enters (the source) and where results go (the sink), resolved when you run.
| Binding | As source | As sink |
|---|---|---|
file (default) | read + parse a file | write the file back (round-trip via skeleton) |
store | the project store (blocks + overlays) | commit overlays, no file |
| interchange | import XLIFF / PO / a bilingual .kpz | emit one for a translator |
none | n/a | discard (checks/analysis only) |
- Ad-hoc = the
filebinding: you name-i/-o. - In a project, the default sink is the store (a process-only run); an explicit
-oforces a file instead.
A process-only run keeps only working output: the target overlays it produced, in .kapi/work/store.db, until you merge them. A review decision is kept elsewhere: kapi apply records it in the project's context store, and a flow's sink never writes decisions. kapi can rebuild the working output from your files. The decisions are what people authored. See the project store.
--explain prints the resolved binding without running:
kapi run translate-qa -i app.json -o app.fr.json --explain
# → flow translate-qa: file(app.json) → file(app.fr.json)
kapi run translate-qa -i app.json --explain # inside a project
# → flow translate-qa: file(app.json) → store
Two project loops, both ending at merge
1. The kapi loop (the everyday one): kapi up runs the default flow over every locale short of its gate and materializes the translated files; what a machine can't finish waits for review.
2. Interchange loop (hand bilingual files to a translator or CAT tool):
kapi extract --target-lang fr,de # → out/*.xliff (or --format kpz)
# …translate the bilingual files…
kapi merge -i out/ # apply back onto sources, absorb into memory
See the bilingual workflow for the interchange loop in depth.
The .kpz parcel: move work without a server
A .kpz is a portable single file that carries work between machines or people without a server. It comes in two profiles:
# Whole-project snapshot: a runnable "project in a file"
kapi pack -o snapshot.kpz # recipe + content + memory & terms
kapi unpack snapshot.kpz # rehydrate elsewhere
# Bilingual interchange: for a kapi-equipped reviewer
kapi extract --format kpz --target-lang fr
kapi merge bundle.fr.kpz
Source travels as identity + a round-trip skeleton by default; --with-source embeds the raw originals. Pause & resume a big run walks the .kpz workspace lifecycle.
What a snapshot carries
kapi info answers this for the project you are standing in (before you pack it) and for an archive you have been handed. Both list the same parts:
| Part | What it is |
|---|---|
recipe | the project's kapi.yaml, with the venue binding, hooks and automations stripped so they travel inert |
sources | source identity + per-file round-trip skeletons (raw bytes only with --with-source) |
blocks | the extracted content blocks (.kbf.json) |
overlays | committed target overlays, one per locale |
memory | the authoritative content memory (.memory.json) |
terms | the authoritative terms (.terms.json) |
history | an advisory provenance chain (--log) |
A snapshot leaves out .kapi/work/cache/ (parse cache, extractions and collections, which kapi regenerates), credentials (they live in the OS keychain) and server sync tokens. It holds only state kapi cannot recompute, with no secrets and no derived data. A part with nothing in it is absent from the archive.
kapi info # this project: what a snapshot would capture
kapi info handoff.kpz # this archive: what it holds
kapi info --output-format json # either form, machine-readable
Each part reports whether it is present and how many items it holds, measured the way pack collects it. sources counts what the extraction manifests record, not what the recipe tracks, so a project that has never been extracted reports none. A part that is absent says what would produce it.
A workspace .kpz is the ad-hoc parcel with a shadow cache. kapi info work.kpz on one reports its documents, locales and whether the cache holds work not yet packed back into the file.
pack writes exactly the parts info lists and unpack restores exactly those parts: the content memory, the terms, the blocks and overlays, the skeletons, and, with --with-source, the raw source files, which unpack writes back into the tree without overwriting anything already there. To check the round trip, compare kapi info on a project with kapi info on its snapshot. pack refuses to write an archive with no content.
Do the modes mix?
Yes: same commands, different bindings:
| You want… | Use |
|---|---|
| A throwaway job on one file | ad-hoc (kapi <tool> or run -i -o) |
| A repo you work on repeatedly (accumulating memory) | project (add / up / merge) |
| To move work between machines/people | .kpz parcel (pack or extract --format kpz) |
A tool run inside a project (kapi translate src/app.json) still picks up the project's defaults and content memory while working on one file. The one thing to avoid: two stateful stores over the same content, an ad-hoc .kpz workspace and a kapi project for the same files. Inside a project, an explicit -o writes a file and skips the store on purpose; --explain shows which you got.
See also
- The kapi loop: the derived-state model behind
up,status, gates, and review. - Ship gates & CI: enforce the gates with
kapi check --ship. - Flows: authoring composed flows and the source/sink ends.
kapi.yamlproject file: the recipe format.