Skip to content

ctx pull

ctx pull downloads pages that changed on the server since your last pull, writes them into .contexo/, and regenerates the local index.

Pull at the start of a session, before you or your agent start editing pages — that’s what keeps a push from turning into a conflict later. Pull again when ctx status reports drifted pages, or when a push comes back with a 409.

The thing to internalise: pull is a fetch-and-overwrite, not a merge. It writes the server’s bytes over your local file with no three-way merge, no prompt and no backup. If a page has both local edits you haven’t pushed and server edits you haven’t pulled, pulling loses your side. Push first (or copy the local version aside), then pull.

Terminal window
ctx pull
ctx pull --full
FlagTypeDefaultDescription
--fullboolfalseignore last_pull_sha and fetch everything

--full ignores the last_pull_sha recorded in .contexo/.sync/state.json and asks for everything tracked at the server’s HEAD, rewriting every page rather than only the changed ones. Reach for it when the local .contexo/ has been edited by hand, partially deleted, or restored from somewhere else and you want a known-good copy of the whole knowledge base.

ctx pull also accepts the global flag:

FlagTypeDefaultDescription
--rootstringproject root directory (default: current directory)

The normal incremental case — everything committed on the server since your recorded sha:

Terminal window
ctx pull
ctx pull
Pulled 1 page(s); HEAD=a4b2c1d3

Re-fetch the entire knowledge base regardless of what the local sync state says:

Terminal window
ctx pull --full
ctx pull --full
Pulled 1 page(s); HEAD=a4b2c1d3

When the server’s HEAD already matches your recorded sha, pull prints Already up to date and writes nothing — but it still advances last_pull_sha if the server’s HEAD moved for reasons that produced no file changes.

  1. Reads repo_id and the server URL from .contexo/config.json, the bearer token from .contexo/credentials.json. A server_url in credentials takes precedence over the one in config.
  2. GET /v1/repos/<repo>/sync/pull?since=<last_pull_sha>, with the header X-Contexo-Client: ctx-cli so the server can attribute the read. With --full the since parameter is omitted.
  3. Server side, since resolves to git diff --name-only <since> HEAD for the incremental case, or the full HEAD tree when since is empty. Each path is read at HEAD and returned with the sha of the last commit that touched it. A pull event is recorded in the repo’s activity feed only if at least one file came back.
  4. Each returned file is written to .contexo/<path>, creating directories as needed, and its sha is recorded in .contexo/.sync/state.json under page_shas. That recorded sha is the parent_sha your next push will send for that page, and the baseline the drift check compares against.
  5. last_pull_sha is set to the server’s HEAD.
  6. .contexo/index.md and .contexo/tags.md are regenerated from everything now on disk, so the always-loaded index reflects the pages you just received. A failure here prints warning: reindex: … on stderr but does not fail the command.

pull: no credentials, run 'ctx auth login' first — no .contexo/credentials.json. Run ctx login.

pull: no server URL configured (run 'ctx remote add') — the message names a subcommand that doesn’t exist; the real one is ctx remote set <url>. See ctx remote.

pull: no repo_id configured in .contexo/config.json — run ctx remote set-repo <id>.

pull: open hub: … (did you run 'ctx init'?) — no .contexo/ in this directory. Check your location or pass --root.

sync: pull failed (403): {"error":"not a member of this repo"} — your token authenticates, but you aren’t a member of that repo. Membership is checked before the repo is looked up, so a typo’d repo_id lands here too, not on a 404. Ask an owner for an invite key and run ctx join, or fix the id with ctx remote set-repo.

sync: pull failed (404): {"error":"repo not found"} — you passed the membership check but the server has no git repo under that id. Repos are created by their first push.

  • ctx push — the other half of the loop; pull is the fix for its 409
  • ctx status — tells you whether a pull is needed
  • ctx_pull — the MCP tool your agent calls
  • Drift and conflicts — when to pull, and what to do about a divergent page