ctx_status
ctx_status answers “what is this project wired up to, what have I changed, and is anything
blocking a push”. It reads local files only, with no network call, no lock and no writes, so
it is the safe first thing to call when a push or pull just failed and the agent needs to know
why.
When the agent calls it
Section titled “When the agent calls it”The description is deliberately flat, because this tool is diagnostic rather than conversational: “Show local .contexo status: server, repo, auth, local page count, last pull sha, never-pushed pages, per-state page counts, whether a push needs a distilled session first, and conflicts.” Models reach for it when the user asks whether they are logged in, which repo this project syncs to, or whether anything is unshared.
Parameters
Section titled “Parameters”ctx_status takes no parameters.
Response
Section titled “Response”Plain text, one fact per line, in this order. Lines in square brackets appear only when they apply:
Server: <server URL>[Warning: config server_url <config.json server_url> differs from your credentials' server; using <server URL>]Repo: <repo id>User: <name> <<email>>Authenticated: <true or false>Local pages: <N>Last pull: <sha>Never-pushed pages: <N>Pending capture buffers: <N>Pages: <n> unchanged, <n> modified, <n> new, <n> conflict, <n> invalid, <n> deleted locally, <n> unverifiedPush needs a distilled session first: <yes or no>[Conflicts: <path>, <path>][Warning: <message>]Reading each line:
| Line | Meaning |
|---|---|
Server |
The server requests go to (see which server below), or (unresolved — run 'ctx auth login --server <url>') |
Warning: config server_url … |
.contexo/config.json names a different server than your credentials; ctx keeps using the credentials’ server |
Repo |
repo_id from .contexo/config.json, or (none) |
User |
Name and email from the credentials, or (anonymous) |
Authenticated |
true when the credentials hold a token. The token is not checked with the server |
Local pages |
Every parseable page in the store, whatever its origin |
Last pull |
last_pull_sha shortened to 8 characters, or (never) |
Never-pushed pages |
Pages with no recorded sha in .contexo/.sync/state.json: never pushed and never pulled |
Pending capture buffers |
Unarchived session buffers under raw/sessions/_pending/ |
Pages |
The page states ctx computes offline (see below) |
Push needs a distilled session first |
yes when a push of your changed pages would hit the distill guard |
Conflicts |
Every page in state conflict, comma-separated |
Warning |
Other warnings from the status run, such as an unreadable file under .contexo/.sync/ or paths that differ only by letter case |
The Pages line
Section titled “The Pages line”The counts come from the same three-way comparison ctx status --offline makes: each page’s
working file against its base (the version you last synced), with the server side known only
from conflict sidecars. modified and new are what a push would send; conflict pages are
the ones a teammate also changed; unverified pages have a base ctx could not confirm, which
the next online status, pull, push or ctx repair fixes. Pages that only changed on the server
cannot be known offline, so the line has no incoming count: call ctx_pull, or run
ctx status, to see them.
The push gate line
Section titled “The push gate line”Push needs a distilled session first: yes means a ctx_push of the
changed pages would pause with PUSH_PAUSED: the changed pages include a concept or
analysis page, and a pending capture buffer has at least one turn and was modified within
the last 6 hours. It is computed with the same check ctx push and ctx_push use, so it is
the reliable predictor, unlike Pending capture buffers, which counts every unarchived buffer
whatever its age.
Which server
Section titled “Which server”The Server line follows the same rule as every ctx command:
- Credentials that name a server win. If
.contexo/config.jsonnames a different one, ctx still uses the credentials’ server and adds theWarning:line right afterServer; the credentials are never sent to the URL from the project config. - Project credentials without a server use
.contexo/config.json’sserver_url. - Global credentials without a server leave it unresolved: run
ctx auth login --server <url>. - With no credentials, the line shows
config.json’sserver_url, or the default server.
Request
Section titled “Request”{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "ctx_status", "arguments": {} }}The response is one text block holding the lines above.
Errors
Section titled “Errors”Missing config, missing credentials and an empty store render as their placeholder values, so the tool is safe to call inside any Contexo project. Two things still fail:
- an unreadable or corrupt
.contexo/config.jsonor credentials file returns an error result,ctx_status: <error>; - if the offline page classification fails, the lines up to
Pending capture buffersare still returned, followed bySync state unavailable: <code>: <message>instead of thePages, push gate andConflictslines.
Outside a Contexo project there is nothing to call: with no .contexo/ the server runs
dormant and advertises zero tools.
CLI equivalent
Section titled “CLI equivalent”ctx status is online by default. It makes one listing call to the server per run, so it can
also show pages to pull, and it groups the pages that need an action into sections with the
command for each:
contexo ● connected
── REMOTE
server https://contexo.example.com (from credentials)
repo acme-api
user dev <dev@example.com>
auth authenticated (legacy)
── KNOWLEDGE
pages 4 · 2 conflict · 1 incoming · 1 unchanged
last pull a4b2c1d3
captures none pending
── CONFLICTS
wiki/concepts/stripe-subscription.md both_modified
wiki/entities/billing-worker.md both_modified
keep yours ctx resolve <path> --ours
take theirs ctx resolve <path> --theirs
── TO PULL
wiki/concepts/webhook-retries.md new on server
run ctx pullctx status --offline makes the same no-network, no-write comparison as ctx_status. With
--json it writes the full ctx.status.v1 document; offline, remote.source is none and
the server side of a conflict is only the sha recorded in its sidecar:
{
"schema": "ctx.status.v1",
"generated_at": "2026-07-28T09:14:07Z",
"offline": true,
"root": "~/projects/acme-api",
"contexo_dir": "~/projects/acme-api/.contexo",
"project": {
"repo_id": "acme-api",
"config_server_url": "https://contexo.example.com",
"dashboard_url": "",
"last_pull_sha": "e5a3b9c807162534435261708f9e0d1c2b3a4958"
},
"server": {
"url": "https://contexo.example.com",
"url_source": "credentials",
"capabilities_known": false,
"capabilities": []
},
"auth": {
"state": "unchecked",
"credentials_source": "project",
"token_kind": "legacy",
"user_name": "dev",
"user_email": "dev@example.com"
},
"remote": {
"source": "none",
"page_count": 0
},
"counts": {
"unchanged": 2,
"modified": 0,
"new": 0,
"incoming": 0,
"incoming_new": 0,
"conflict": 2,
"deleted_local": 0,
"invalid": 0,
"unverified": 0,
"ahead": 0,
"behind": 0
},
"pages": [
{
"path": "wiki/concepts/stripe-subscription.md",
"state": "conflict",
"conflict_kind": "both_modified",
"type": "concept",
"slug": "stripe-subscription",
"tags": [
"stripe",
"billing",
"proration"
],
"author": "dev",
"agent": "claude",
"updated": "2026-07-24T16:31:00Z",
"reasoning_summary": "How trials, proration and webhooks fit together in acme-api.",
"local": {
"file": "wiki/concepts/stripe-subscription.md",
"hash": "sha256:b466741e47980041e9d1dbc835cd11ab7fbc556de2355bbeb937d7f8ccfbe2d6"
},
"base": {
"sha": "d2f0e617a3b5c7d9e1f2031425364758697a8b9c",
"hash": "sha256:d2d5406cf1ff46eee2577caf20c3509270c93ea29c4a765fe3227446cbe55cde",
"synced_at": "2026-07-28T09:14:07Z",
"stale": false
},
"remote": {
"sha": "f0c47d2196385a7b4c3d2e1f0a9b8c7d6e5f4a3b"
},
"notes": []
},
{
"path": "wiki/concepts/webhook-retries.md",
"state": "unchanged",
"type": "concept",
"slug": "webhook-retries",
"tags": [
"billing"
],
"author": "bob",
"agent": "claude",
"updated": "2026-07-26T08:05:00Z",
"local": {
"file": "wiki/concepts/webhook-retries.md",
"hash": "sha256:c766c671da23b495fe1cca2f37d833f77fef8d9f1514a9a851641d9d5be36526"
},
"base": {
"sha": "7d25c6bf018a3e4d5c6b7a8990f1e2d3c4b5a697",
"hash": "sha256:c766c671da23b495fe1cca2f37d833f77fef8d9f1514a9a851641d9d5be36526",
"synced_at": "2026-07-28T09:14:07Z",
"stale": false
},
"notes": []
},
{
"path": "wiki/entities/billing-worker.md",
"state": "conflict",
"conflict_kind": "both_modified",
"type": "entity",
"slug": "billing-worker",
"tags": [
"billing"
],
"author": "dev",
"agent": "claude",
"updated": "2026-07-25T11:20:00Z",
"local": {
"file": "wiki/entities/billing-worker.md",
"hash": "sha256:e6a61f7de94e56acdcc074437d1700b4b9d6b8a06a140721eb5d9718718b9701"
},
"base": {
"sha": "c1d8a3f50e2b4c6d8f90a1b2c3d4e5f607182930",
"hash": "sha256:8bae15f3fa732a04b87f2c50d5e25834e1f0009bce68dde191409c51a947b828",
"synced_at": "2026-07-28T09:14:07Z",
"stale": false
},
"remote": {
"sha": "3b8e1a0947c2f6d85e90a1b2c3d4e5f60718293a"
},
"notes": []
},
{
"path": "wiki/entities/invoice-service.md",
"state": "unchanged",
"type": "entity",
"slug": "invoice-service",
"tags": [
"billing"
],
"author": "dev",
"agent": "claude",
"updated": "2026-07-26T09:40:00Z",
"local": {
"file": "wiki/entities/invoice-service.md",
"hash": "sha256:4eb24f13bfe77a17a43c54bfd0b0c716f87db53939f5362d791edfd84ead9d87"
},
"base": {
"sha": "e5a3b9c807162534435261708f9e0d1c2b3a4958",
"hash": "sha256:4eb24f13bfe77a17a43c54bfd0b0c716f87db53939f5362d791edfd84ead9d87",
"synced_at": "2026-07-28T09:14:07Z",
"stale": false
},
"notes": []
}
],
"captures": {
"pending": 0,
"fresh": 0,
"blocks_push": false,
"sessions": []
},
"warnings": []
}| Flag | Type | Default | Description |
|---|---|---|---|
--json | bool | false | print the ctx.status.v1 document |
--no-drift | bool | false | alias of --offline |
--offline | bool | false | make no network request |
--no-drift in the table above is a hidden alias of --offline, kept so older scripts keep
working.
Differences worth knowing:
- The CLI shows incoming pages. Online,
ctx statuslists pages to pull underTO PULL;ctx_statusnever contacts the server, so it cannot. - The CLI reports initialization. Outside a Contexo project it fails with
not_initialized(exit 5 with--json), a state the MCP tool can’t be in, since the server runs dormant with zero tools when there is no.contexo/. - Field labels differ: the CLI groups the same facts under
REMOTEandKNOWLEDGE, with acapturesline for pending buffers.
See ctx status for the full command reference and
drift and conflicts for what to do with conflicts.
