Skip to main content

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

FlagDescriptionDefault
--forcePush all blocks, ignoring sync cachefalse
--dry-runShow what would be pushed without sendingfalse
--conceptsSync only local terminology edits to the workspace (direct edits + governed change-set) — no content transport, no hooksfalse
--no-brandSkip uploading the recipe-bound brand voice profile to the workspace brand hubfalse

What Happens

  1. Read local files via FormatRegistry (using the recipe's content: collections)
  2. Extract blocks from each file (streaming Parts -> Blocks)
  3. Compute block hashes using BlockIdentity (SHA-256)
  4. Compare with .kapi/cache/sync-cache.json to identify changed blocks
  5. 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)
  6. Update .kapi/cache/sync-cache.json with 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.)

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

  1. Run kapi status before pushing to see what changed
  2. Pull first if working with a team to avoid conflicts
  3. Use --dry-run when unsure about what will be uploaded