Skip to content

ctx show

ctx show writes one version of one page to stdout, byte for byte: the base you last synced, the server’s current copy, or the page as it was at a given commit.

When a page is in conflict and you want to see the three sides before you pick one. Your working file is on disk already; --at base gives you the version both of you started from, and --at server gives you what your teammate pushed. Diff them with any tool you like, merge by hand if you want to, then settle it with ctx resolve.

It is also what the VS Code extension uses to fill its read-only diff editors, which is why its output is built for programs: raw bytes, nothing else on stdout, and a JSON error line when something goes wrong.

Terminal window
ctx show <relpath> --at base
ctx show <relpath> --at server
ctx show <relpath> --at <sha>
FlagTypeDefaultDescription
--atstringbase, server, or a commit sha
--jsonbooltruemachine mode (always on)

--at is required and takes exactly one of three forms, described below.

The table also lists --json. It is a hidden flag that is always on: ctx show has no human mode. A bare --json or --json=true is accepted and changes nothing; --json=false is refused as a usage error (exit 3). The table shows it because the docs generator does not filter hidden flags.

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

--at base prints the base snapshot: the bytes ctx recorded the last time this page was synced (pushed, pulled, adopted or resolved). It is read from .contexo/.sync/base/ and makes no network request, so it needs no login and works offline. The bytes come back exactly as stored, CRLF line endings and a byte-order mark included. If the page has no base for its last synced sha, or the base file no longer matches its recorded hash, you get base_unavailable (exit 8) with the advice ctx repair. That is the case for a new page you have never pushed, a page that only exists on the server, and an unverified page.

--at server prints the server’s current copy of the page, cleaned the same way ctx pull cleans what it writes to disk, so it is exactly what a pull would put in your working file. A page the server does not have is page_not_found (exit 8).

--at <sha> prints the page as it was at that commit. The sha is 7 to 64 hex characters, in either case. This needs a server that can read history (the pages.at server capability). An older server that ignores the request is detected, never trusted: ctx refuses with server_unsupported (exit 10, details.missing is ["pages.at"]) rather than hand you the current version as if it were history. A commit the server does not know, or a page that did not exist at that commit, is sha_not_found (exit 8).

<relpath> is the page path relative to .contexo/, for example wiki/entities/billing-worker.md. ctx also accepts the same path with a leading .contexo/, or an absolute path inside .contexo/, and turns backslashes into forward slashes. It is never resolved against your current directory.

The path must end in .md and may not contain an empty, . or .. segment, a segment that starts with - or ., a colon, or a control character. The root index.md and tags.md are refused too, since ctx generates them and never syncs them. Because of these rules, ctx show can never be pointed at .contexo/.sync/, config.json or credentials.json. A path that breaks a rule is invalid_path (exit 3), and that check runs before anything else, even in a project that is not initialized or not logged in.

The base of a page in conflict: the version both sides started from.

Terminal window
ctx show wiki/entities/billing-worker.md --at base
ctx show wiki/entities/billing-worker.md --at base
---
schema: ctx.page.v1
slug: billing-worker
type: entity
author: dev
agent: claude
created: 2026-07-21T09:30:00Z
updated: 2026-07-25T11:20:00Z
parent_sha: ""
tags:
  - billing
---

## What it is

`worker` consumes Stripe webhook events from SQS and retries failed
invoices on the schedule in stripe-subscription.

## Rationale

Considered retrying inside the webhook handler; rejected because Stripe
expects a fast 2xx and redelivers slow webhooks.

The same page on the server. A teammate added one sentence to the first section:

Terminal window
ctx show wiki/entities/billing-worker.md --at server
ctx show wiki/entities/billing-worker.md --at server
---
schema: ctx.page.v1
slug: billing-worker
type: entity
author: dev
agent: claude
created: 2026-07-21T09:30:00Z
updated: 2026-07-25T11:20:00Z
parent_sha: ""
tags:
  - billing
---

## What it is

`worker` consumes Stripe webhook events from SQS and retries failed
invoices on the schedule in stripe-subscription. It runs as one ECS task per region.

## Rationale

Considered retrying inside the webhook handler; rejected because Stripe
expects a fast 2xx and redelivers slow webhooks.

With your working file as the third side, you can see exactly what each of you changed before you choose --ours or --theirs.

The command’s own help text:

Terminal window
ctx show --help
ctx show --help
Print a page's base, server or historical bytes

Usage:
  ctx show <relpath> --at base|server|<sha> [flags]

Flags:
      --at string   base, server, or a commit sha
  -h, --help        help for show

Global Flags:
      --root string   project root directory (default: current directory)

The checks run cheapest first: the argument and flag rules, then the path and --at rules (no I/O at all), then the .contexo/ check, and only for --at server or a sha, the credentials and the repo id. So a bad path is reported as invalid_path whatever state the project is in, and --at base never needs credentials.

ctx show takes no lock and writes nothing. It is safe to run while a push or pull is in progress, and it never creates .contexo/.sync/.

On success, stdout holds only the page bytes, with no newline added, and stderr is empty. On failure, stdout is empty and the last line of stderr is a one-line ctx.error.v1 JSON envelope. Because the command is always in machine mode, it never prints the update nudge either. See JSON output and exit codes for the envelope.

Every failure is an envelope on stderr. The exit codes ctx show can return are 0, 3, 4, 5, 7, 8 and 10 (and 1 for an internal error).

base_unavailable (exit 8): no valid base snapshot. Run ctx repair, or use --at server. This envelope comes from the real binary:

{"schema":"ctx.error.v1","exit_code":8,"error":{"code":"base_unavailable","message":"show wiki/concepts/chargeback-flow.md --at base: syncstate: base unavailable: wiki/concepts/chargeback-flow.md has no base snapshot for its last synced sha","advice":["ctx repair"],"retryable":false}}

page_not_found (exit 8): --at server for a page the server does not have, typically one you have never pushed:

{"schema":"ctx.error.v1","exit_code":8,"error":{"code":"page_not_found","message":"show wiki/concepts/never-pushed.md --at server: sync: page not found","advice":[],"retryable":false,"http_status":404}}

invalid_path (exit 3): the path breaks one of the rules above, for example ../x.md.

usage (exit 3): --at is missing or is not base, server or a 7 to 64 character hex sha, or you passed --json=false.

not_initialized (exit 5): there is no .contexo/ under the root. Pass --root or run ctx init.

not_authenticated (exit 4), server_unresolved or repo_not_configured (exit 5): only for --at server and --at <sha>. Log in with ctx login, or set the repo with ctx remote set-repo.

sha_not_found (exit 8) and server_unsupported (exit 10): see --at <sha> above.