kane-cli context sync shares your .context/ store with your team through a location: a GitHub repository, an S3-compatible bucket, or a folder on a shared drive. Every person keeps their own store on their own machine, and the location holds the team’s shared history. kane-cli context push publishes your new records, kane-cli context pull takes your teammates’, and kane-cli context clone makes a new store from the location. Nothing on a location is ever overwritten or deleted, so a published record can never be un-published by mistake.
Sharing starts from a store you already have. kane-cli context ingest <file> --mode ci creates one from a first document, see Building the context graph. Then:
Three kinds of location
GitHub. Use a dedicated repository, not your code repository, and make it private if the requirements are. Kane CLI needs Git 2.31 or newer on the machine. Setup and
kane-cli context sync add check the repository by writing a few small permanent connection-check files and commits; they never publish your context. The check also pushes to a scratch reference under refs/kane/probe/. When that check cannot finish (SYNC_PROBE_INCONCLUSIVE), repository rules that block the reference are the usual cause: ask the repository owner to allow it, then run the command again. Each push is one ordinary commit on the branch, and nothing is force-pushed, merged or rebased on the server. GitHub does not accept a single object above 100 MB, so when a source document is larger than that, choose an S3-compatible bucket. For HTTPS without a stored login, the GitHub CLI does it in two commands: gh auth login --hostname github.com --git-protocol https --web, then gh auth setup-git --hostname github.com. Another Git server works the same way with that server’s sign-in.
S3-compatible. Ask your storage administrator for an existing bucket and a key pair; Kane CLI creates neither. --credential-env TEAM_S3 reads TEAM_S3_ID and TEAM_S3_SECRET, and --credential-file keys.json reads {"accessKeyId": "…", "secretAccessKey": "…"}. Either way the pair is saved in ~/.testmuai/kaneai/context-sync/<name>.json, readable by you only (mode 0600), and kane-cli context sync remove <name> deletes it. That file belongs to the location’s name, not to one store: every store on this machine whose location is called origin reads the same origin.json, so binding a second bucket as origin from another store replaces the keys the first one uses. When one machine works with more than one bucket, give each its own name (team-s3, archive). KANE_SYNC_S3_ACCESS_KEY_ID and KANE_SYNC_S3_SECRET_ACCESS_KEY, both set, win over the file at use time and are never written to disk, which is the CI form. A key pair the location refuses never replaces one that worked.
kane-cli context sync add when its parent exists.
Guided setup
TTY_REQUIRED and names kane-cli context sync add and kane-cli context clone as the alternatives. It never publishes your context, since publishing is always the separate kane-cli context push. The first screen asks What do you want to do?: Share my context with my team or Join my team’s context.
Share. Setup asks where the shared context should live, GitHub — Recommended, S3-compatible storage or Folder, then for that kind’s details. GitHub: the address of an existing repository, or a row that opens GitHub in the browser so you create a dedicated repository there and come back with its address; missing Git or GitHub CLI shows an installation link and a retry row. S3: the bucket name, the region (prefilled us-east-1), an optional folder inside the bucket, the service (Amazon S3, or another S3-compatible service, which then asks for its endpoint), and how to reach it, either credentials already configured on this computer or the access keys from your storage administrator typed in (the secret access key is masked) and saved in your local Kane CLI credential store, never in the shared context. Folder: the path, and the screen reminds you that everyone needs the same mounted drive.
The location is bound under the name origin. If this store already has a location called origin, setup asks for another name and suggests team. The last screen shows the address, says that the connection check adds small permanent files (and, for a repository, commits) to the location, and waits for Connect location. Setup then reports whether you can publish: with write access it shows the kane-cli context push <name> line to run when you are ready, otherwise it asks you to obtain write access and check the connection again. Then it prints Share this location with teammates: followed by the complete address (for a Git location, the repository address with the branch and prefix you chose), and one closing line saying who can read it. After a refusal, Use a different address re-enters the same prompts with what you typed kept, and Choose a different storage returns to the picker. Esc or Ctrl+C leave setup with exit 3: Setup left. Your context has not been published. Any completed connection checks remain in the location.
Join. Setup asks you to Paste the location your teammate shared, then for a new folder under Download into a new folder (prefilled team-context; a folder that already exists is refused, so none of your files is replaced), then waits for Connect and download. It downloads the verified team context into that folder and closes with Next: open that folder and run kane-cli context sync status. Join never creates a location: an address that holds no records yet is refused until the teammate who shared it has pushed. kane-cli context clone <address> <dir> run by hand is less strict about the folder: it accepts one that already exists as long as <dir>/.context is not there yet, which is how the CI recipe clones into ..
The commands
[name] defaults to the only location; with several, to the one called origin; otherwise the command asks you to name one. Every command takes --mode agent for an NDJSON stream, see Agents and CI.
kane-cli context sync add and kane-cli context clone check a location before binding it: that it can be read, and whether a small test write lands there and reads back. kane-cli context sync add prints added <name>: <kind> tier <n> (<what the checks found>), kane-cli context clone prints bound origin: … in the same shape, and each line of kane-cli context sync list repeats the kind and tier:
Joining an S3-compatible location with keys from the environment:
The everyday loop
Alice shares a store she already built and Bob joins it. Then each of them works, pulls, and pushes. Alice and Bob are normally two machines; here they are two folders side by side, with the location as a third:alice/, Bob in bob-home/, and, once the clone exists, inside bob/.
position 2 is the second record of the shared history, which this page calls record 2:
kane-cli context sync origin at both ends. When a teammate has pushed since you last pulled, a command that writes to the store first prints one advisory line, origin has moved past this machine — run kane-cli context pull origin, or, when both sides moved, this store and origin have diverged — run kane-cli context pull origin --rebase, and carries on. The line is a best-effort courtesy, not a check you can rely on: it refuses nothing, it gives up silently after 1.5 seconds or when the location cannot be reached, and it is not printed under --mode agent (kane-cli context extract, kane-cli design tests and kane-cli maintain reconcile emit a sync_behind event there instead). kane-cli context review prints it unless --json or --mode agent is given, and a test run writes it to its session log. KANE_SYNC_GUARD=0 turns it off.
Ingest, extract, review and design all work the same way; the location only changes where records go afterwards. What a push sends, and what stays on your machine, is listed in What travels.
What travels and what never travels
The sync commands never call the agent: publishing, taking, cloning and a rebase spend no credits. A store that pulls a use-case gets the same records the extractor committed, cited lines included.
When a command refuses
Every sync refusal prints a plain reason, nearly all add anext: line with the command to run, and on the agent stream the same refusal is a sync_error event with a stable code, the reason and the remedy. The common ones:
Exit
3 means a person has to decide something, exit 2 a precondition, and exit 1 a record that cannot be used. A refusal says what stopped, not that nothing happened: kane-cli context sync finishes its pull before its push can be refused, and a push can land before its confirmation is lost. A refusal this table does not list still says what stopped and what to run next. How an agent handles these codes is in Agents and CI, and the entries a person meets most are in Troubleshooting.
When two people changed the same thing
Alice and Bob both worked after the same shared record (record 2). Bob named the sourcebrief “spec” and re-ingested a new version of prd, then pushed. Alice, without pulling, named prd “spec” and retired prd. Now kane-cli context sync status origin says you and origin both added work after position 2 and names the command to run, kane-cli context push origin refuses with the same words (exit 3), and so does a plain pull.
kane-cli context pull origin --rebase does three things: it saves Alice’s records after the shared record in a backup, takes origin’s records, and reapplies the saved records on top, one by one. Nothing on origin is rewritten. On a terminal it asks first, as a panel with the facts and two rows:
kane-cli context pull origin --rebase --yes. --yes confirms exactly this, and never answers a decision. Not now prints no rebase started — run kane-cli context pull origin --rebase when you are ready and exits 3, with nothing saved or taken.
Most saved records reapply without a question, one line each: a record the other side does not touch is reapplied, and a record the other side already made the same way is skipped as already there. A real disagreement about one thing reaches you as a decision card, one at a time. The two sides are always called local and the location’s name:
by is the author id recorded with that change, a person’s user name as the machine reported it, or an agent. someone means the record carried no author, a re-ingested source for one.
Keep origin’s version is always offered and always the default: it writes nothing, and the local change stays in the backup. Apply the local version writes the local change as a new record on top of origin’s, and the row says the consequence. For a newly created item whose match origin has since retired, the card offers add the local version as new, a new node beside origin’s (duplicate check first), in place of apply the local version. Decide later leaves the card open, and kane-cli context sync or kane-cli context pull asks again. v shows the full record under the facts, a leaves every remaining card for later, and Ctrl+C pauses; none of these is an error. Each answered card leaves one line in the scrollback (decision h3: kept origin's version), and the run ends with a summary counting what was reapplied, already there, not reapplied and undecided.
Some saved records cannot be reapplied at all, and their card offers only keep origin’s version: a record this build cannot read or replay, one that refers to an item origin no longer has, or one the store’s own checks refuse. The change stays in the backup, and that piece of work has to be done again once the rebase is finished. Keeping origin’s version can also bring a later card back, since a saved record that was built on the one you set aside is looked at again.
Without a terminal (a pipe, CI, --mode agent) no card is shown. Every open decision is one line, its id, the kind of record, the local change in words, and the answers it takes, and kane-cli context sync status repeats them. When the location cannot be reached, the human output still lists them before the refusal, and --show <n> needs no location at all:
kane-cli context sync status --show <n> prints saved record n in full: what it did, what origin holds instead, the answers it accepts, and the raw detail behind the card.
origin sha256:…, is the saved record’s own hash: the word there means the original record, not the location, and the location’s side is the origin: row below it.
Answer by id with --answer <id>=<choice> on kane-cli context sync or kane-cli context pull, where keep-theirs keeps origin’s version, apply-mine applies the local version, and apply-mine-as-new adds it as new. Each run answers what you gave it, and with cards still open it stops again and says so (not synced: 1 decision waiting — run kane-cli context sync origin to answer it, or kane-cli context sync origin --answer h4=<choice>). The last answer finishes the rebase, and kane-cli context sync then pulls and pushes as usual, while kane-cli context pull only pulls. Here, after --answer h3=keep-theirs in the run before:
kane-cli context sync status --show <n> names the record it became:
kane-cli context push refuses with the same code and the same next: line, and its reason names the rebase, counts the decisions unresolved, and says nothing was pushed. A test run does not refuse: the results it records are kept to the side and land on the first run after the rebase is finished.
kane-cli context sync doctor shows the store’s state and every rebase with its id, open or closed. Three of its words come from the mechanics: a rebase id ends in -reset; the first line, no reset in progress, is about the import step of a rebase, and it reads reset in progress only when an import was interrupted before it finished; and sentinel: absent is the healthy state, where the sentinel is the marker a running import leaves in the store. With the two decisions above still open:
kane-cli context sync doctor --abort closes the open one, keeping what was already reapplied and leaving the unanswered decisions in the backup (exit 3 when decisions were left). From another run, with one decision open:
kane-cli context sync doctor --abort: your records are put back and the store is as it was. Once the import has landed, the rebase can only be finished (SYNC_RESET_IMPORTED): kane-cli context sync or kane-cli context pull finishes it before doing anything else, and then you can close it with kane-cli context sync doctor --abort if you still want to.
The way back. The live store holds records your teammates published, so it is never rewound in place. kane-cli context sync doctor --export <dir> rebuilds your store as it was before the rebase, beside it, as its own store, for inspection or as a fresh start:
kane-cli context list or kane-cli context explain. It has no location bound, so run kane-cli context sync add there first if you want to share from it. Without --from <rebase-id> the export takes the open rebase, or the only one; with several closed rebases, name one. Everything a rebase saves stays under .context/sync/backups/<rebase id>/ and .context/sync/replay/, and a receipt there lists every reapplied, skipped and undecided record.
A _test.md that a reapplied record created is restored, and the summary’s test files … restored line counts them. If that path now holds someone else’s file, Kane CLI leaves it alone and kane-cli context sync status lists it: rename or move that file, then run kane-cli context sync again.
What happens when
origin is the location, and local means the records saved from your store.
For agents and CI
Every sync command in the table above takes--mode agent and speaks NDJSON: sync_status, sync_pull_done, sync_push_done, the sync_rebase_* family, sync_error{code, detail, remedy}, and done last, and a rebase that stops on decisions ends with done carrying paused and exit 3. The contract and the events are in Agents and CI, and the CI recipe with a GitHub token or deploy key is in CI/CD.
FAQ
Two stores that were never connected, can I merge them? No. A location holds one history, a store started separately isa different history, and the answer is to clone one of them and re-ingest the other’s documents into it.
Next Steps
- Building the context graph for ingest, extract and review
- Agents and CI for the headless contract, including the sync verbs
- Configuration for the sync environment variables and on-disk paths
- Troubleshooting for the sync entries