Skip to main content

Project file

A Kapi project is a portable .kapi YAML recipe at a project's root that captures a localization workflow: source and target languages, content file patterns, tool pipelines (flows), plugin requirements, and processing defaults. It carries no credentials or state, so it is always safe to commit. For when to use a project versus an ad-hoc run, see Modes & bindings.

Discovery

Like git, kapi walks up the directory tree from where you run it and uses the nearest .kapi recipe — running in project mode with that project's languages, defaults, and flows. An explicit -p <path> overrides discovery, and KAPI_NO_PROJECT=1 disables it so the CLI runs ad-hoc.

Format

version: v1
name: My App Localization

content:
- path: "src/locales/en/*.json"
target: "src/locales/{lang}" # mirror each matched file under the per-language dir

preset: nextjs
plugins:
okapi: "^1.47.0"

flows:
translate:
steps:
- tool: ai-translate
config:
provider: anthropic
model: <provider-model-id>

translate-and-qa:
steps:
- tool: ai-translate
config:
provider: anthropic
- tool: qa-check

pseudo:
steps:
- tool: pseudo-translate
config:
expansionPercent: 30

defaults:
source_language: en-US
target_languages:
- fr-FR
- de-DE
- ja-JP
concurrency: 4
parallel_blocks: 3
encoding: utf-8
exclude:
- "**/*.generated.json"
merge:
conflict_policy: translator-wins
tm:
fuzzy_threshold: 75
segmentation:
source: true
termbase: glossary/terms.db

Fields

Required

FieldTypeDescription
versionstringSchema version, must be "v1"
namestringProject display name

Optional

FieldTypeDescription
contentContentEntry[]File patterns to process (see ContentEntry)
presetstringA framework preset name (e.g., nextjs, react-intl) applied to formats
pluginsmapPlugin requirements keyed by name (e.g., okapi: "^1.47.0")
requiresmapPlugin name → semver constraint that gates loading; the recipe refuses to load without a registered plugin
flowsmapNamed flow definitions (see Flow Steps)
defaultsDefaultsProcessing defaults (see Defaults; source/target languages live here)

ContentEntry

FieldTypeDescription
pathstringGlob pattern for source files (required)
basestringDirectory a matched file's path is made relative to; defaults to the glob's fixed prefix
formatstringFormat ID; auto-detected per file if omitted
targetstringOutput path template (see Source and target paths)

In a named collection, base may be set once on the collection and is inherited by every item that does not set its own.

Source and target paths

path is a doublestar glob: ** matches across directories (e.g. src/**/*.json) and {a,b,c} matches any of the listed alternatives (e.g. input/store/*.{json,yaml,html}). One glob can therefore cover a whole directory of mixed content; the format is auto-detected per file unless you pin format. Patterns resolve relative to the project root.

base is the directory a matched file's path is made relative to. It defaults to the glob's fixed prefix — the literal part of path before the first wildcard (input/docs/ for input/docs/**/*.md). The relative path drives the {relpath} / {path} / {dir} tokens and how much of the source tree a directory-mirror target reproduces.

target is the output-path template, expanded per source file and target language. The supported tokens are:

TokenMeaningExample (base input/, source input/docs/api.md)
{lang}Target languagefr-FR
{relpath}Source path relative to base, with extensiondocs/api.md
{path}Source path relative to base, without extensiondocs/api
{dir}Directory portion of {relpath} (empty at the root)docs
{filename}Filename with extensionapi.md
{name}Filename without extension (alias {basename})api
{ext}Extension without the dotmd

A bare * is legacy shorthand for {name}.

Directory-mirror (the easy default). When target ends with /, or its last segment has no extension and no wildcard/token, it names a directory and the source's {relpath} (under base) is mirrored beneath it. So target: output/{lang} reproduces the source tree under each per-language root — input/docs/api.mdoutput/fr-FR/docs/api.md — with no * and no risk of a doubled extension:

content:
- name: Docs
base: input
items:
- path: "input/**/*.md"
target: "output/{lang}"

Token template (the powerful form). When you need to reshape the layout, use tokens explicitly:

content:
- path: "src/locales/en/*.json"
target: "src/locales/{lang}/{name}.{ext}" # api.json → src/locales/fr-FR/api.json

Defaults

defaults holds project-wide processing settings that individual content items can override. Several of these are governed by AD-017.

FieldTypeDescription
source_languagestringBCP-47 source locale (e.g., en-US)
target_languagesstring[]BCP-47 target locales
locale_formatstringLocale style for the {lang} placeholder: bcp-47 (default) or posix
concurrencyintNumber of files to process in parallel
parallel_blocksintNumber of blocks to process in parallel within a file
encodingstringInput file encoding (default: utf-8)
excludestring[]Glob patterns skipped during content scanning (e.g. **/*.generated.json)
formatsmapPer-format preset, config, and detection priority overrides (see formats)
mergeMergeDefaultsHow kapi merge resolves a translator's target against an existing target or TM entry (see merge)
tmTMDefaultsTM pre-fill on kapi extract and write-back on kapi merge (see tm)
segmentationSegmentationDefaultsOpt-in sentence-level segmentation overlay applied on extract (see segmentation)
redactionRedactionSpecReplace sensitive content with protected placeholders before processing and restore it afterwards (see redaction)
brand_voiceBrandVoiceBindingBind a brand voice profile as standing project context (see brand_voice)
termbasestringPath to a glossary/termbase, resolved relative to the project root; used for project-scoped term enforcement with no --termbase flag

Individual content items can override redaction per entry (ContentItem.redaction).

formats

defaults.formats configures formats by name, so a single wildcard content item (path: "input/*", no format:) can let each file's engine be auto-detected while you still tune individual formats in one place. Each entry takes:

FieldTypeDescription
presetstringA named format preset applied to this format
configmapReader option overrides for this format (merged under, and overridable by, a content item's format.config)
priorityintDetection priority — higher wins when several formats claim the same extension

priority is the engine-pin escape hatch. Most extensions map to one format, but some are claimed by several: .srt by both okf_vtt and okf_regex, .txt by several plain-text engines. Bumping the preferred one steers auto-detection without naming a format on every item:

plugins:
okapi-bridge: "*"
defaults:
formats:
okf_vtt:
priority: 110 # .srt → WebVTT engine (beats okf_regex)
okf_json:
config:
useFullKeyPath: true
content:
- name: Source Files
base: input
items:
- path: "input/*" # every file; engine auto-detected, two pinned above
target: "output/{lang}"

Plugin formats already outrank built-in ones by default (priority 100 vs 50), so declaring okapi-bridge is enough for input/* to resolve to the okf_* engines; priority only matters to break ties between formats from the same source.

merge

FieldTypeDescription
conflict_policystringtranslator-wins (default), existing-wins, or newest-wins

tm

FieldTypeDescription
fuzzy_thresholdintMinimum fuzzy match score (0–100) to pre-fill the target on extract (default: 75)
readstring[]Additional read-only TM files consulted during pre-fill; writes always go to the project TM

segmentation

FieldTypeDescription
sourceboolToggle sentence-level segmentation of source text on extract
srxstringOptional SRX rules file; built-in default rules are used when empty

redaction

The sensitive term list lives in a separate rules file referenced by rules (so it can be gitignored); this spec points at it and selects detection backends.

FieldTypeDescription
enabledboolTurn redaction on for extract/merge
rulesstringPath to a redaction rules YAML file
detectorsstring[]Detection backends: rules and/or entities
placeholderstringOverride the visible stand-in template, e.g. [REDACTED:{category}]

brand_voice

Bind a brand voice profile under defaults.brand_voice. Exactly one source is expected.

FieldTypeDescription
profile_filestringPath to a standalone profile YAML, resolved relative to the project root
profilestringName of a profile in the local brand store
packstringName of a built-in starter pack

Flow Steps

Each flow contains an ordered list of steps. See Flow Steps Format for the full specification.

flows:
my-flow:
steps:
- tool: ai-translate # tool name (required)
config: # tool-specific config (optional)
provider: anthropic
label: "Translate" # display label (optional)

Steps can also define parallel branches:

flows:
parallel-qa:
steps:
- parallel:
- tool: qa-check
- tool: ai-qa

Key Properties

  • No credentials — API keys are never stored in Kapi project files. They come from the OS keychain (Kapi Desktop) or environment variables (CLI).
  • No state — No sync cursors, caches, or timestamps. Kapi project files are always clean and safe to commit.
  • Portable — Save anywhere, have multiple per directory, share via git.
  • CLI-compatiblekapi run flowname -p file.kapi

Using with Kapi CLI

# Run a flow from a Kapi project
kapi run translate -p translation.kapi

# Override defaults with CLI flags
kapi run translate -p translation.kapi --target-lang de --provider openai

# One-shot mode still works without a project
kapi ai-translate -i file.json --target-lang fr

Using with Kapi Desktop

  • File > Open to load a Kapi project
  • File > New to create one from scratch
  • File > Save / Save As for standard document operations
  • Double-click a Kapi project to open it in Kapi Desktop (macOS)
  • Drag and drop Kapi projects onto the app window

See also

  • AD-008: Project model — the architectural decision behind the .kapi recipe and its extension mechanism.
  • .kapi Project File Format — the implementation note: the KapiProject, Defaults, and ContentCollection struct layouts, the named-collection content shape, validation rules, and how platform extensions decode unknown keys.
  • Flow Steps Format — the full step specification used by flows.