kapi push
Send local file changes to Bowrain Server. Only transfers modified blocks (incremental sync using content hashing).
When the project is claimed into a workspace and a baseline was pulled (see
kapi pull), push also reconciles local terminology edits
in the bound terms store against that baseline. Ordinary edits — definitions, notes,
proposed terms, non-governed relations — apply directly through the concept
endpoints. Governed edits — a term set to forbidden or preferred, an
un-forbidding, a replaced_by relation, a concept delete — are bundled into a
single submitted change-set proposal for review, the same separation of
duties the Brand hub enforces. Push reports
what applied directly versus what was proposed, with a link to review the
change-set.
When the recipe binds a brand voice profile (defaults.brand_voice, or a
brand.yaml at the project root), push also carries it into the workspace
Brand hub, matched by profile name: created on first push, a
no-op when the content is unchanged, and otherwise applied as a new profile
version — the previous server-side state is archived in the version history,
never overwritten, and vocabulary rules the server promoted from corrections
are preserved. Use --no-brand to skip.
Usage
kapi push [paths...] [flags]
Examples
# Push all local changes to server
kapi push
# Push specific files
kapi push src/locales/en/
# Show what would be pushed without uploading
kapi push --dry-run
# Force re-push all blocks (ignoring sync cache)
kapi push --force
# Example output:
# Pushed 47 blocks (scanned 12 files)
# (sent in 1 batches)
Options
| Flag | Description | Default |
|---|---|---|
--force | Push all blocks, ignoring sync cache | false |
--dry-run | Show what would be pushed without sending | false |
--concepts | Sync only local terminology edits to the workspace (direct edits + governed change-set) — no content transport, no hooks | false |
--no-brand | Skip uploading the recipe-bound brand voice profile to the workspace brand hub | false |
What Happens
- Read local files via FormatRegistry (using the recipe's
content:collections) - Extract blocks from each file (streaming Parts -> Blocks)
- Compute block hashes using
BlockIdentity(SHA-256) - Compare with
.kapi/cache/sync-cache.jsonto identify changed blocks - Send changed blocks to server via
POST /api/v1/projects/:id/sync/push- Batched at 1000 blocks per request
- Server enforces batch limits and body size (50MB)
- Update
.kapi/cache/sync-cache.jsonwith new hashes and sync cursor
Content Hashing
kapi uses content-addressed blocks for efficient sync:
content_hash = sha256(normalized_source_text)
Only blocks with changed hashes are transferred. A project with 10,000 blocks where 5 changed will only transfer those 5 blocks.
Sync Cache
Push state is tracked in .kapi/cache/sync-cache.json (auto-gitignored):
{
"server_url": "https://app.bowrain.cloud",
"project_id": "abc123",
"sync_cursor": 4821,
"last_sync": "2026-02-15T10:30:00Z",
"files": {
"_blocks": {
"blocks": {
"greeting": "a1b2c3d4...",
"farewell": "e5f6a7b8..."
}
}
}
}
The sync cache can be safely deleted — it will be regenerated on the next push (which will re-scan and re-push all blocks). The server is the source of truth.
Exit Codes
0— Success (changes pushed or already up to date)1— Error (server rejected, network error, etc.)
Related Commands
kapi pull— Fetch changes from serverkapi status— Show what will be pushedkapi diff— Show detailed changes
When to Use
Push to Bowrain Server to:
- Share translations with your team
- Trigger workflows (AI translation, QA, terminology extraction)
- Send terminology edits — ordinary edits land directly; governed edits travel up as a change-set proposal
- Backup content to the server
- Integrate with CI/CD pipelines
Think of it as git push for content.
Best Practices
- Run
kapi statusbefore pushing to see what changed - Pull first if working with a team to avoid conflicts
- Use
--dry-runwhen unsure about what will be uploaded