Skip to main content
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. Each person keeps their own store on their own machine, and the location holds the history the team shares.
  • kane-cli context push publishes your new records to the location.
  • kane-cli context pull takes your teammates’ new records from it.
  • kane-cli context clone creates a new store from the location.
Nothing on a location is ever overwritten or deleted, so you cannot un-publish a record by mistake.
Requires Kane CLI 0.8.14 or later.
You share a store you already have. If you do not have one yet, kane-cli context ingest <file> --mode ci creates one from a first document; see Building the context graph. Then run:
Two rules stand behind every command here: never merge .context/ with git, and never edit it by hand. Sharing goes through a location, and only through the commands on this page.

Three kinds of location

GitHub

  • Use a dedicated repository, not your code repository, and make it private if your requirements are private.
  • Git 2.31 or newer must be installed on the machine.
  • Connection check. Setup and kane-cli context sync add test 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/. If the check cannot finish (SYNC_PROBE_INCONCLUSIVE), the usual cause is a repository rule that blocks that reference: ask the repository owner to allow it, then run the command again.
  • How pushes land. Each push is one ordinary commit on the branch. Nothing is force-pushed, merged, or rebased on the server.
  • Size limit. GitHub does not accept a single object larger than 100 MB. If a source document is larger than that, use an S3-compatible bucket instead.
  • Signing in over HTTPS. If you have no stored login, the GitHub CLI sets one up in two commands: gh auth login --hostname github.com --git-protocol https --web, then gh auth setup-git --hostname github.com.
Other Git servers work the same way, using that server’s sign-in.

S3-compatible storage

Ask your storage administrator for an existing bucket and a key pair. Kane CLI does not create either one.
  • Passing the keys. --credential-env TEAM_S3 reads TEAM_S3_ID and TEAM_S3_SECRET. --credential-file keys.json reads {"accessKeyId": "…", "secretAccessKey": "…"}.
  • Where the keys are saved. Either way, the pair is saved in ~/.testmuai/kaneai/context-sync/<name>.json, readable only by you (mode 0600). kane-cli context sync remove <name> deletes it.
  • Keys belong to the location’s name. The file is tied 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 store uses. If one machine works with more than one bucket, give each its own name (team-s3, archive).
  • Keys from the environment (CI). When KANE_SYNC_S3_ACCESS_KEY_ID and KANE_SYNC_S3_SECRET_ACCESS_KEY are both set, they take priority over the file and are never written to disk. Use this form in CI.
  • A refused key pair never replaces a working one.

Folder

A mounted shared drive works for a team. A path on your own disk works only for you, because sharing the path does not share its contents. If the folder does not exist yet, kane-cli context sync add creates it, as long as its parent folder exists.

Guided setup

Setup needs a terminal. When run headless it refuses with TTY_REQUIRED and points you to kane-cli context sync add and kane-cli context clone instead. Setup never publishes your context; publishing is always a separate kane-cli context push. The first screen asks What do you want to do? with two choices: 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. It then asks for the details of that kind:
  • GitHub: the address of an existing repository. Or choose the row that opens GitHub in your browser, create a dedicated repository there, and come back with its address. If Git or the GitHub CLI is missing, you see an installation link and a row to retry.
  • S3: the bucket name; the region (prefilled with 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 connect. You can use credentials already configured on this computer, or type in the access keys from your storage administrator. The secret access key is masked as you type, and the keys are saved in your local Kane CLI credential store, never in the shared context.
  • Folder: the path. 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 and tells you that the connection check adds small, permanent files to the location (and, for a repository, commits). It then waits for you to choose Connect location. After connecting, setup tells you whether you can publish:
  • With write access, it shows the kane-cli context push <name> line to run when you are ready.
  • Without write access, it asks you to get write access and check the connection again.
Setup then 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. If the location refuses the connection, Use a different address takes you back through the same prompts with what you typed kept, and Choose a different storage returns you to the storage picker. Press Esc or Ctrl+C to leave setup with exit 3: Setup left. Your context has not been published. Any completed connection checks remain in the location.

Join

  1. Setup asks you to Paste the location your teammate shared.
  2. Under Download into a new folder, it asks for a folder (prefilled with team-context). A folder that already exists is refused, so none of your files is replaced.
  3. Choose Connect and download. Setup downloads the verified team context into that folder and closes with Next: open that folder and run kane-cli context sync status.
Joining never creates a location. If the address holds no records yet, it 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 a folder that already exists as long as <dir>/.context is not there yet, which is how the CI recipe clones into ..

The commands

Two terms appear in the output of these commands:
  • Witness: the last record this machine saw on a location. Kane CLI keeps it to detect a location that has been rolled back.
  • Tier: what the connection checks proved about a location. Tier 1 can publish; tiers 2 and 3 can only be downloaded from. The tier table below explains each one.
If you leave out [name], the command uses the only location. If there are several, it uses the one called origin. Otherwise it asks you to name one. Every command takes --mode agent for an NDJSON stream; see Agents and CI.

What the tier means

Before binding a location, kane-cli context sync add and kane-cli context clone check two things: that the location can be read, and whether a small test write lands there and reads back. The result is reported as a tier:
  • 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 format.
  • Each line of kane-cli context sync list repeats the kind and tier.

Joining an S3-compatible location

To clone an S3-compatible location with keys from the environment:

The everyday loop

In this example, Alice shares a store she already built and Bob joins it. Then each of them works, pulls, and pushes. Normally Alice and Bob would be on two machines; here they are two folders side by side, with the location as a third:
Alice runs her commands in alice/, Bob in bob-home/, and, once the clone exists, inside bob/.
In the push and clone lines, blobs are the source-document snapshots the records cite, and proposals are the extraction files behind those records. Both travel with the records; see What travels. A proposal travels when its file exists, and a missing one never holds up a push or a pull. Next, Bob ingests a second document and publishes it. Alice, who has not pulled yet, tries to push. In the output, position 2 is the second record of the shared history, which this page calls record 2:
One habit avoids almost every refusal: pull before you start, and push when you finish. Or run kane-cli context sync origin at both ends. If a teammate has pushed since you last pulled, any command that writes to the store first prints one advisory line and then continues:
  • origin has moved past this machine — run kane-cli context pull origin when only the location moved.
  • this store and origin have diverged — run kane-cli context pull origin --rebase when both sides moved.
This line is a best-effort reminder, not a check you can rely on. It never refuses anything, and it gives up silently after 1.5 seconds or when the location cannot be reached. It is not printed under --mode agent; there, kane-cli context extract, kane-cli design tests and kane-cli maintain reconcile emit a sync_behind event instead. kane-cli context review prints it unless you pass --json or --mode agent, and a test run writes it to its session log. Set KANE_SYNC_GUARD=0 to turn it off. Ingest, extract, review, and design all work as usual. The location only changes where the 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, so publishing, taking, cloning, and rebasing cost no credits. A store that pulls a use-case gets the same records the extraction committed, including the cited lines.

When a command refuses

Every sync refusal prints a plain-language reason, and nearly all add a next: line with the command to run. On the agent stream, the same refusal is a sync_error event with a stable code, the reason, and the fix. The most common refusals are: Exit codes:
  • 3: a person has to decide something.
  • 2: a precondition is not met.
  • 1: a record cannot be used.
A refusal tells you what stopped; it does not mean 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 not listed in this table still tells you 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

Here is an example. Alice and Bob both worked after the same shared record (record 2):
  • Bob named the source brief “spec”, 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 resolves this in three steps:
  1. It saves Alice’s records that come after the shared record in a backup.
  2. It takes origin’s records.
  3. It reapplies the saved records on top, one by one.
Nothing on origin is rewritten. On a terminal, the rebase asks first, showing a panel with the facts and two rows:
Without a terminal, the same command refuses and tells you what to run: kane-cli context pull origin --rebase --yes. --yes confirms only the rebase itself; it never answers a decision. Choosing 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, with one line each. A record the other side did 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 comes to you as a decision card, one at a time. The two sides are always called local and the location’s name:
The name after by is the author id recorded with that change: a person’s user name as their machine reported it, or an agent. someone means the record has no author, as with a re-ingested source. The answers on a card:
  • Keep origin’s version is always offered and is 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. The row tells you the consequence.
  • Add the local version as new replaces apply the local version when the item is newly created and origin has since retired its match. It creates a new node beside origin’s (duplicate check first).
  • Decide later leaves the card open, and kane-cli context sync or kane-cli context pull asks again.
Press v to show the full record under the facts, a to leave every remaining card for later, or Ctrl+C to pause. 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 that counts 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. This happens with a record this version of Kane CLI cannot read or replay, a record that refers to an item origin no longer has, or a record the store’s own checks refuse. The change stays in the backup, and you need to redo that piece of work after the rebase is finished. Keeping origin’s version can also bring back a later card, because any saved record built on the one you set aside is checked again. Without a terminal (a pipe, CI, or --mode agent), no card is shown. Each open decision is one line with its id, the kind of record, the local change in words, and the answers it accepts. kane-cli context sync status repeats them. If the location cannot be reached, the human-readable output still lists them before the refusal, and --show <n> works without the location:
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.
The second line, 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. To answer by id, pass --answer <id>=<choice> to kane-cli context sync or kane-cli context pull:
  • keep-theirs keeps origin’s version.
  • apply-mine applies the local version.
  • apply-mine-as-new adds the local version as new.
Each run applies the answers you gave it. If cards are still open, it stops again and tells you (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. After that, kane-cli context sync pulls and pushes as usual, while kane-cli context pull only pulls. In this example, --answer h3=keep-theirs was given in the previous run:
To see what an answer did, show the saved record again after the rebase is closed. kane-cli context sync status --show <n> names the record it became:
While a rebase is open, the store takes no other change, exactly like git mid-rebase. kane-cli context extract, kane-cli design tests, kane-cli maintain reconcile, kane-cli context ingest, kane-cli context review, kane-cli context name, kane-cli context retire and kane-cli context revert refuse until the rebase is finished or closed, all with the same code (SYNC_REBASE_PENDING) and the same two ways out.
kane-cli context push refuses with the same code and the same next: line. Its reason names the rebase, counts the unresolved decisions, and says nothing was pushed. A test run does not refuse: the results it records are set aside 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 terms in its output come from how a rebase works internally:
  • A rebase id ends in -reset.
  • The first line, no reset in progress, refers to the import step of a rebase. It reads reset in progress only when an import was interrupted before it finished.
  • sentinel: absent is the healthy state. 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 rebase. It keeps what was already reapplied and leaves the unanswered decisions in the backup (exit 3 when decisions were left). From another run, with one decision open:
If a rebase was interrupted before origin’s records were imported, the same kane-cli context sync doctor --abort undoes it: your records are put back and the store returns to how 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 you can then close it with kane-cli context sync doctor --abort if you still want to. Getting back the store as it was. The live store holds records your teammates published, so it is never rewound in place. Instead, kane-cli context sync doctor --export <dir> rebuilds your store as it was before the rebase in a separate folder, as its own store. Use it to inspect the old state or as a fresh start:
Give the export a new folder outside the live store and its backups; a folder that already holds a store is refused. The exported folder is a store like any other: open it and run 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 uses the open rebase, or the only one. If there are several closed rebases, name one. Everything a rebase saves stays under .context/sync/backups/<rebase id>/ and .context/sync/replay/, where a receipt lists every reapplied, skipped, and undecided record. A _test.md file created by a reapplied record is restored, and the summary’s test files … restored line counts these files. If someone else’s file is now at that path, 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 emits NDJSON events: sync_status, sync_pull_done, sync_push_done, the sync_rebase_* events, sync_error{code, detail, remedy}, and done last. A rebase that stops on decisions ends with done carrying paused, and exit 3. Agents and CI describes the events in full, and CI/CD has the CI setup with a GitHub token or deploy key.

FAQ

Can I merge two stores that were never connected? No. A location holds one history, and a store started separately is a different history. Instead, clone one of them and ingest the other’s documents into it again.

Next Steps