Skip to main content

ctx Coreutils

ctx is the thin userland client for the /ctx ABI.

ctx = CortexFS coreutils

It is not an AI chat product. It is not a daemon. It is not a runtime. It is not a provider SDK. Its first job is to prove that the CortexFS ABI is usable with ordinary Unix-shaped operations.

ctx operates on /ctx. It does not have to live inside /ctx. Install it in the normal system PATH, for example /usr/bin/ctx or ~/.local/bin/ctx.

Stable Commands

Keep the command surface small:

ctx status
ctx abi
ctx env
ctx root
ctx bootstrap
ctx mount

ctx ls
ctx ls model
ctx ls agent
ctx ls tool
ctx ls home
ctx ls shared/project-a

ctx which model openai/gpt-5.6
ctx which agent coder
ctx which tool fs.read

ctx path shared project-a
ctx agent history coder
ctx agent output coder
ctx agent resume coder --session default
ctx agent wait coder work-123 --session default

ctx agent new reviewer --model openai/gpt-5.6 --tool fs.read
ctx agent new reviewer --label reviewer_t --shared project-a:read --mount /work /work ro
ctx agent start reviewer
ctx agent stop reviewer
ctx agent status reviewer
ctx agent env reviewer
ctx agent ps
ctx agent chat reviewer
ctx agent send reviewer --approve example.echo "run the declared echo tool"

ctx terminal create coder [--session default] [--cwd /workspace]
ctx terminal list
ctx terminal status terminal-coder-default
ctx terminal watch terminal-coder-default
ctx terminal attach terminal-coder-default

ctx provider auth methods PROVIDER

ctx cat agent/coder.d/policy
ctx set agent/coder.d/cwd /work
ctx append agent/coder.d/path /ctx/tool
ctx file agent/coder.d/mount
ctx file type tool/fs.read
ctx file check agent/coder.d/mount
ctx schedule status home/1000/agent/coder/session/default/context/plan.json --done plan
ctx schedule advance home/1000/agent/coder/session/default/context/plan.json --done plan
ctx schedule claim home/1000/agent/coder/session/default/context/plan.json work-123
ctx schedule result home/1000/agent/coder/session/default/context/plan.json work-123 done "implemented"

ctx object check tool.yaml
ctx object install --source /var/lib/cortexfs/storage/current tool.yaml --tier system
ctx object inspect --source /var/lib/cortexfs/storage/current tool example.echo --tier system
ctx object upgrade --source /var/lib/cortexfs/storage/current tool-v2.yaml --tier system
ctx object rollback --source /var/lib/cortexfs/storage/current tool-v1.yaml --tier system
ctx object uninstall --source /var/lib/cortexfs/storage/current tool example.echo --tier system
ctx object residue audit --source /var/lib/cortexfs/storage/current
ctx object residue cleanup --source /var/lib/cortexfs/storage/current --path tool/.cortexfs-install-123-0 --dev DEV --ino INO

ctx validate-name coder
ctx doctor

Do not add:

ctx provider
ctx mcp registry
ctx workflow
ctx memory
ctx vector
ctx cluster

Socket conveniences such as ctx send, ctx chat, ctx connect, ctx ping, and ctx cancel may exist, but they must be thin wrappers over the same socket ABI.

ctx bootstrap [SOURCE] updates the reference source tree only; it does not remount /ctx, start a watcher, or add a second refresh boundary.

Optional flags:

ctx bootstrap --check [SOURCE] report tree_version, missing agents, retired leftovers
ctx bootstrap --dry-run [SOURCE] show ordered migrations and reconcile/state actions (no writes)

Default bootstrap materializes architect / coder / reviewer / worker, writes bin/cortexfs.bootstrap.json (schema, tree_version, managed_agents, applied_migrations) only when state differs. Retired base / executor objects are reported and retained for manual review because legacy trees have no manifest proving ownership and full control-tree integrity. Session history under home/ is never deleted by bootstrap.

Top-level agent session shortcuts follow the same current-session default as their ctx agent ... forms:

ctx history AGENT
ctx history AGENT --session SESSION
ctx resume AGENT
ctx resume AGENT --session SESSION
ctx send AGENT INPUT
ctx send AGENT --session SESSION INPUT
ctx agent wait AGENT CHILD [--session SESSION]

Omitting the session reads session/index/current first and falls back to default. ctx send and ctx resume render assistant events the same way as ctx agent send and ctx agent resume; raw socket JSONL is reserved for lower level socket commands and explicit raw agent modes.

ctx agent chat is the human chat UI over the agent socket. It is not the agent terminal and does not enter tsh; humans use ctx agent watch or ctx agent attach for the persistent terminal.

ctx inspect agent/AGENT [--session SESSION] is the consolidated read-only debug view. It prints the Agent definition and control paths, current instance summary and receipt presence, selected durable session, model hard limit and capabilities, policy and mount paths, and visible-tool count. It derives every field from existing controls, supervisor receipts, and session files; it does not create an instance, socket, session, or capability cache. ctx agent inspect AGENT [--session SESSION] is the equivalent agent-domain spelling.

ctx agent send and ctx agent chat accept repeatable --approve TOOL. In non-raw mode the client answers a hosted SDK approval_request with allow_once only when its exact tool name is in this explicit list; every other name is denied. There is no blanket approval or TTY prompt in the stable protocol. Raw clients and clients without this handler close their write half and therefore fail closed for approval=ask.

ctx agent wait is a non-blocking waitpid-shaped reader for a parent-owned child result channel. It reads context/child/<child>/status; pending and active fail with service unavailable, while terminal done, error, and cancelled print child<TAB>status<TAB>agent<TAB>session<TAB>model<TAB>life<TAB>role followed by result.md. Its process exit status follows the child status: done exits 0, error exits 1, and cancelled exits 130. It does not poll, start runtimes, reap history, or delete child state.

Hybrid parent schedules use an explicit single-step command:

ctx schedule status PATH [--done NODE]...
ctx schedule advance PATH [--done NODE]...
ctx schedule claim PATH CHILD
ctx schedule result PATH CHILD done|error|cancelled RESULT [--refs-jsonl JSONL]

PATH must be an agent session context/plan.json. The command reads the parent agent label and policy, derives completed delegated nodes from context/child/<child>/status, applies any explicit local --done node ids, and materializes newly ready delegated handoffs under context/child/<child>/. ctx schedule status is a read-only table over the same state. It prints node<TAB>kind<TAB>agent<TAB>child<TAB>session<TAB>model<TAB>life<TAB>role<TAB>child_parent<TAB>state, where state is one of blocked, ready, pending, active, done, error, or cancelled. The session, model, life, role, and child_parent columns are - for local parent nodes. Delegated child nodes show the explicit child session, or the inherited parent session when the schedule node omits one, plus the selected backing agent model, lifecycle, and backing parent ref. For delegated nodes, the backing agent must exist as both agent/<name> and agent/<name>.d/; schedule commands must not invent main/owned defaults for a missing worker object. Each emitted handoff line includes the child agent, session, selected model from agent/<name>.d/model, life from agent/<name>.d/life, role, a shell-quoted parent='agent:<name> session:<session>' reference, and the stable handoff, result, and refs ABI file paths under context/child/<child>/. A parent can hand these paths to a worker without guessing where the worker should read input, which spark model path and lifecycle it should use, or where it should write compact results. ctx schedule claim marks a materialized child channel active when a worker has claimed the handoff. It is a single status-file transition from pending to active, idempotent while active, and it does not start a runtime. Its output line includes the claimed child agent, session, backing model, backing life, parent reference, and the same stable handoff, result, and refs paths. ctx schedule result writes a terminal child result back to the same parent session child channel: status, result.md, and refs.jsonl. Its output line includes the child agent, session, backing model, backing life, parent reference, and the written result and refs paths. Neither command starts agents, loops in the background, polls, or creates a second submission namespace.

Agent lifecycle conveniences exist as thin wrappers:

Executable extensions use host-side check, new-object-only install, read-only inspect, receipt-managed replacement, and receipt-managed uninstall commands:

ctx object check MANIFEST
ctx object install --source PATH MANIFEST [--tier user|system]
ctx object inspect --source PATH CLASS NAME [--tier user|system]
ctx object replace --source PATH MANIFEST [--tier user|system] [--yes]
ctx object upgrade --source PATH MANIFEST [--tier user|system] [--yes]
ctx object rollback --source PATH MANIFEST [--tier user|system] [--yes]
ctx object uninstall --source PATH CLASS NAME [--tier user|system] [--yes]

ctx object check is read-only and requires no source tree. It performs the same strict manifest, control, artifact type, executable mode, and SHA-256 validation used before publication by install; success prints valid CLASS/NAME. It accepts exactly one manifest path and no install flags.

--source is required and names the durable backing tree that may be written. /ctx, CTX_ROOT, and --root are ABI projections and are never inferred as installation targets. MANIFEST names class tool or agent, binds one executable path to its SHA-256, and supplies class controls. Legacy schema cortexfs.object/v1 strictly accepts neither version nor compatibility. Schema cortexfs.object/v2 requires version as an object SemVer and compatibility.cortexfs as a Cargo-style SemVer requirement. Unknown fields and controls, symlinks, non-regular or non-executable artifacts, digest mismatches, and existing object names are rejected. Relative executable paths resolve against the manifest directory. The manifest cannot specify commands, arguments, wrappers, or install tier.

Both check and install compare a v2 CortexFS requirement with the CortexFS package version compiled into the current ctx. A mismatch is invalid input, exits 2, and performs no writes. Version compatibility is not an authority grant and does not start a runtime.

Agent manifests must include the abi control with exactly sdk-envelope-v1. Missing or other values are rejected before publication.

User-tier tools install under home/<effective-uid>/tool; system tiers use tool and agent. The root ABI retains home/<effective-uid>/agent, but neither manifest schema carries tier identity to the root socket runtime, so the installer rejects user-tier agents and directs callers to system tier. Installation does not grant policy authority. It initializes canonical runtime-owned status/pid/log files but does not create socket state. The complete control directory is staged and synced, then published no-replace before the executable is published last as the visible object commit boundary. Both published receipts are checked again before success is reported. Success or failure may retain a hidden .cortexfs-install-* safety residue for explicit future cleanup.

A cortexfs.object-install/v2 receipt records object_version and cortexfs_requirement; a cortexfs.object-install/v1 receipt records neither. Installation remains new-object-only; replacement is an explicit, separate receipt-managed operation.

ctx object inspect is a read-only check of one exact installer-managed tool or agent; the tier defaults to user. It validates the installer receipt and its identity/version, the recorded class/name/tier, the retained control directory's device/inode/type, and the retained executable's device/inode/regular type, execute bits, and SHA-256. It also rejects executable length, mode, mtime, or ctime changes observed during inspection; the receipt does not bind the complete install-time mode. Success prints:

installed CLASS/NAME tier=T schema=cortexfs.object/v1 sha256=HASH executable=DEV:INO control=DEV:INO
installed CLASS/NAME tier=T schema=cortexfs.object/v2 version=VERSION requires-cortexfs=REQ sha256=HASH executable=DEV:INO control=DEV:INO

Inspection does not claim that mutable control-file contents still match their install-time values. An object with a missing or legacy receipt is unmanaged and is reported as unavailable; inspection never adopts or modifies it. For v2, the compatibility values are recorded facts: inspection does not reject an installed object merely because a later CortexFS build no longer matches them.

replace, upgrade, and rollback all require a v2 candidate manifest for the exact installed class/name and default to a no-write dry-run. --yes applies the transition. replace accepts a receipt-managed v1 or v2 current object without version ordering. upgrade requires current v2 and a strictly higher candidate version. rollback requires current v2 and a strictly lower candidate version; the caller supplies the older manifest and exact artifact because CortexFS keeps no version history.

Success prints one of:

would-replace CLASS/NAME tier=T from=FROM to=TO
would-upgrade CLASS/NAME tier=T from=FROM to=TO
would-rollback CLASS/NAME tier=T from=FROM to=TO
replaced CLASS/NAME tier=T from=FROM to=TO
upgraded CLASS/NAME tier=T from=FROM to=TO
rolled-back CLASS/NAME tier=T from=FROM to=TO

FROM is legacy for a v1 receipt. Applied replacement builds and syncs a same-filesystem candidate stage, hides the old executable first, and publishes the new executable last as the visible commit boundary. Before that commit, a failure automatically restores the exact old pair when safe. Receipt checkpoints do not intentionally overwrite or delete foreign inodes; conflicts may retain audit-visible safety residue. This is not pair atomicity, and it does not close the final pathname syscall race against a same-authority writer.

Before --yes, the caller must quiesce the matching runtime and other writers. The commands do not stop or start runtimes, retain version history, grant policy authority, or create socket state.

ctx object uninstall accepts only one exact installer-receipt-managed tool or agent pair; the tier defaults to user. Its default dry-run performs the same retained-receipt validation as inspection and does not write. Success reports the exact executable and control device/inode pair that would be, or was, removed.

With --yes, uninstall first quarantines the executable on the same filesystem to form the invisible object boundary, syncs and rechecks its receipt, then quarantines the control directory, syncs and rechecks both receipts. It reuses bounded residue cleanup only after the complete exact stage has been verified. This ordering is deliberately not a claim of pair atomicity. At receipt checkpoints, a failure does not intentionally overwrite or delete a foreign replacement; it may leave audit-visible safety residue when safe restoration cannot complete.

Before --yes, the caller must quiesce the matching agent runtime and all other processes under the same Unix authority that can write the backing directory. Receipt checks do not close Linux's final pathname syscall race against such a writer. Uninstall grants no authority, creates no socket, and does not start or stop a runtime. It does not re-run v2 compatibility admission, so a later CortexFS version mismatch cannot strand a receipt-managed object.

Durable residue maintenance is explicit and separate from installation:

ctx object residue audit --source PATH
ctx object residue cleanup --source PATH --path REL --dev DEV --ino INO [--yes]

audit performs a bounded, no-follow, descriptor-relative walk of the durable source. It reports .cortexfs-install-*, .cortexfs-cleanup-*, and .ctx-rollback-* observations in relative-path order, one terminal-safe line per residue, including kind, path, device, inode, file kind, empty/occupied state, and cleanup eligibility. An audit observation is not cleanup authority: a later command must supply the relative path and exact dev/ino receipt explicitly. Audit does not silently skip unreadable, cross-device, or over-limit subtrees; a system backing tree therefore requires an identity that can inspect the complete tree.

Cleanup accepts install-stage directories only under tool/, agent/, home/<decimal-uid>/tool/, or home/<decimal-uid>/agent/. It defaults to a dry-run and prints would-clean ... entries=N; --yes is required to mutate and prints cleaned ... entries=N on success. Applying cleanup first isolates the top path with same-directory no-replace rename and verifies the moved inode. It then handles each preflighted descendant the same way before post-order deletion, without following symlinks. The isolation name is .cortexfs-cleanup-*; retained cleanup quarantine is always audit-only and cannot be supplied as a cleanup target. If a later cleanup step fails, the command tries to restore the original .cortexfs-install-* name only while the quarantined top-level inode still matches the submitted receipt and no-replace restoration is safe. Successful restoration permits a fresh audit and retry. If safe restoration is impossible, the error reports the exact retained .cortexfs-cleanup-* path for later audit. Unknown file kinds, traversal limits, new entries, or sync failures also stop cleanup.

The caller must stop concurrent processes that share write authority to the backing directories before using --yes. Linux has no atomic “unlink only if this path still has dev/ino” operation, so receipt checks cannot protect the final syscall window from a hostile writer in the same Unix authority boundary. Cleanup never intentionally unlinks a receipt mismatch at its checkpoints.

.ctx-rollback-* is always audit-only because it may preserve an inode from a rollback conflict. A retained .cortexfs-cleanup-* is likewise audit-only; only an eligible .cortexfs-install-* path can be submitted to cleanup. This command never deletes rollback residue or owned agent objects. Installation does not invoke residue cleanup automatically.

At runtime, CTX_SOURCE is only an ambient candidate path. Durable writers must authenticate the runtime capability receipt and match its nofollow source directory path, device, inode, and plain-directory type before writing.

ctx agent new NAME [--temp] [--parent PARENT] [--label LABEL] [--model MODEL] [--tool TOOL] [--shared NAME:read|write] [--mount SOURCE TARGET ro|rw]
ctx agent new [NAME] --from PROFILE
ctx agent apply NAME --from PROFILE
ctx agent start NAME
ctx agent stop NAME
ctx agent status NAME
ctx agent env NAME
ctx agent ps
ctx agent children NAME
ctx agent wait NAME CHILD

ctx agent new calls /ctx/tool/agent.create only from a complete agent runtime context (CTX_AGENT, CTX_SESSION, CTX_RUN_ID, and CTX_SOURCE). An ordinary human host invocation creates a standard agent object directly by writing agent/<name>.d/* controls and home/<uid>/agent/<name>/ skeleton directories; this fallback is a supervisor operation, not an agent policy grant. ctx agent new --temp records life=temp in either path. --parent records the ordinary agent/<name>.d/parent control value, such as agent:coder session:default run:r1, so a created worker child has a wait/stop-visible parent without adding a separate process table.

Creation derives agent/<name>.d/perm from the requested core tools; installed legacy manifests without this control default to rwx for compatibility. Use ordinary Unix inspection and mutation on the marker, for example ls -l /ctx/agent/coder.d/perm and chmod 500 /ctx/agent/coder.d/perm.

--from accepts a host-side agent.yaml file, a directory containing one, or a short profile name. New/apply validates profile fields before materializing them into ordinary .d/* controls. Apply preserves unspecified controls and unknown meta.json object keys; it rejects symlink controls and invalid profile or metadata before writing.

ctx agent start starts the explicit runtime for an existing agent. After the runtime terminal socket is reachable, host-side ctx writes agent/<name>.d/status to ready and appends an agent.start event to agent/<name>.d/log. Start output and the agent.start event echo model, life, and role; pid remains numeric-only, and systemd invocation ids are log facts.

ctx agent stop calls /ctx/tool/agent.stop when that tool exists. If the tool is absent, host-side ctx may perform a supervisor stop by writing agent/<name>.d/status to dead, clearing agent/<name>.d/pid, and appending an agent.stop event to agent/<name>.d/log. The same supervisor fallback also marks any existing owned or temp child agents whose parent points at the stopped agent as cancelled/dead, recursively, while leaving their history and control objects inspectable. When the child agent is the backing runtime for a pending or active parent context/child/<child>/ channel, the fallback records that parent-side child result as cancelled so ctx agent wait observes the terminal state. It must not invent a new lifecycle namespace or queue. Retired reference agents base and executor are manual-review objects: child discovery excludes them before reading legacy ownership fields, so stop cascade never changes their controls, status, or child result channels. Before any unit reset or control write, fallback stop validates the complete non-retired descendant plan, detects ownership cycles, and preflights planned controls and existing pending/active child-result channels. It executes the validated plan in post-order, descendants before their parent. ctx agent status reads ordinary agent/<name>.d/* controls and prints the status value first, followed by model=, life=, role=, parent=, children=, pid=, ppid=, uid=, gid=, groups=, root=, and cwd= lines. This keeps the first line usable as the process state while exposing the backing model, worker role, direct child count, parent relationship, Linux identity, and chroot/cwd for worker inspection. The parent= line uses the same normalized parent ref as ctx agent ps, including optional session and run. The children= count includes direct child agents whose effective state is not dead; recorded ready or busy children with stale numeric pids are excluded the same way as ctx agent ps. ctx agent ps may read agent/<name>.d/parent, model, life, status, and pid directly and print the current agent tree with derived worker roles and live ppid= values. Default main model selections and owned lifecycles may stay implicit; non-default worker models and non-owned lifecycles should be visible in the tree. ctx agent env derives the same runtime view as ctx agent start and prints the sandbox environment as KEY=value lines. It is a read-only inspection of existing control files, not a way to inherit host variables or mutate runtime state. ctx agent children reads the parent session context/child/<child>/ table and prints tab-separated child, child-channel status, backing agent, child-channel session, backing agent parent_session, backing agent parent_run, backing agent model, backing agent life, backing agent role, backing agent status, live parent ppid, and backing agent pid (- when absent). role derives from the stable worker-role name convention; the other backing-agent columns are ordinary agent/<agent>.d/* controls, so worker task state and its parent session/run attachment are inspectable without copying runtime state into the parent context. ctx agent wait reads the same child channel. If a child is still active but its backing agent's effective state is dead, has no live pid, and still points back to the waiting parent agent/session, wait records the child channel as cancelled and returns the cancellation exit code. A recorded ready or busy state with a numeric pid that is absent from /proc is treated as no live pid for this read. Terminal output uses the same child-channel agent, session, backing model, and backing life fields as ctx agent children, then prints result.md. This is a synchronous reap, not a background poller.

Installation Boundary

Reserve /ctx/bin for CortexFS ABI-level helper programs needed by runtimes, chroots, or scripts:

/ctx/bin/ctx
/ctx/bin/ctxterm
/ctx/bin/tsh

The first implementation may expose only ctx, but agent terminal runtimes should use ctxterm and tsh when present. The placement rule is:

human CLI system PATH, usually one ctx binary
agent capability /ctx/tool
runtime ABI helper /ctx/bin

ctxterm is the agent terminal emulator. It owns the pseudo-terminal and starts tsh by default. tsh is the tool shell that runs inside that terminal. tsh resolves command names through CTX_PATH, not PATH, and must not execute arbitrary host commands directly. A command such as bash works only when a tool named bash is visible through CTX_PATH.

ctx agent start <agent> --session <session> starts the default agent terminal in a sandbox. Unless overridden, the caller's current working directory is bind-mounted at /workspace with read-write access. If that directory contains .git, .git is over-mounted at /workspace/.git with read-only access. The agent process starts with /workspace as its current directory. The host path is therefore not exposed as the agent's pwd; the agent sees the authorized project mount through the sandbox path. The sandbox home is /home/agent, backed by /ctx/home/<uid>/agent/<agent>, so shell state such as .config, .cache, and .bash_history does not land in the project workspace.

The terminal process starts from an empty environment with a small allowlist such as CTX_ROOT, CTX_HOME, HOME=/home/agent, PATH=/usr/bin:/bin, USER, LOGNAME, SHELL, TERM, and LANG. Host session variables and secrets are not inherited by default.

Additional mounts can be supplied explicitly:

ctx agent start <agent> --session <session> \
--mount /host/path /workspace rw \
--mount /host/input /input ro \
--cwd /workspace

ctxterm --listen SOCKET exposes the PTY for observation and attachment. Session terminals use:

/ctx/home/<uid>/agent/<agent>/session/<session>/terminal/main.sock

The ABI socket may be a symlink to a runtime socket. User-started terminals prefer /run/user/<uid>/cortexfs/terminal/<agent>/<session>/main.sock so ordinary users do not need write access to /ctx or /run/cortexfs. Existing installations may still expose /run/cortexfs/terminal/<uid>/<agent>/<session>/main.sock as historical artifacts, but ctx agent attach does not use this legacy fallback anymore. ctx agent attach should try the ABI path first, then the user runtime path. If both locations are unavailable, it returns a socket-availability error.

The corresponding human commands are:

ctx agent watch <agent> --session <session>
ctx agent attach <agent> --session <session>

For standalone human sessions, tsh reads CTX_HOME/.tshrc before inherited process CTX_PATH when the file exists. The file is data-only and supports a single stable setting:

CTX_PATH=/ctx/tool:/ctx/home/<uid>/tool

Inside an agent terminal, tsh keeps the runtime-provided process CTX_PATH authoritative.

Do not let /ctx/bin become a second /usr/bin.

Path Model

ctx resolves paths under CTX_ROOT, defaulting to /ctx.

Examples:

ctx ls agent
ctx cat model/openai/gpt-5.6.d/cap
ctx file type tool/fs.read
ctx exec agent/coder "fix tests"

Object strings use ABI path form:

model/openai/gpt-5.6
agent/coder
tool/fs.read

Core Commands

ctx status reads /ctx/status.

ctx ls uses readdir. It accepts an ABI path under CTX_ROOT, defaulting to the root when no path is provided. It does not query a database, index, registry, or daemon catalog.

ctx which finds executable objects by ABI class:

ctx which model openai/gpt-5.6
ctx which agent coder
ctx which tool fs.read

ctx tool NAME [ARG...] is a narrow compatibility entrypoint for allowlisted safe CortexFS core tool CLIs that are implemented inside the local ctx binary, for example:

ctx tool tsh.config
ctx tool tsh.config '{"max_loaded_tools":32}'

Before running an allowlisted core tool CLI, ctx tool still resolves NAME through CTX_PATH so the visible ABI object exists. It must refuse ordinary visible tools and authority-bearing core tools such as fs.write and shell.exec; executing those directly from CTX_PATH would bypass CortexFS tool authorization. Non-allowlisted tools are run through tsh, an agent runtime, or another authorized execution path.

ctx cat reads ABI files. It should not interpret much.

ctx set updates by same-directory atomic replacement. ctx append is only for appendable ABI files such as newline lists. ctx file check validates path shape and file syntax where the ABI defines it. Neither ctx set nor ctx append modifies session messages.jsonl or events.jsonl; session history is maintained by the runtime or an authorized FUSE writer.

ctx file inspects CortexFS paths using path shape, stat, readlink, and read-only user.cortexfs.* extended attributes. It prints stable type strings, projected byte size, token estimates, and available CortexFS xattrs. It does not query a registry.

Stable type strings:

ctx.model.exec
ctx.model.socket
ctx.model.control
ctx.agent.exec
ctx.agent.socket
ctx.agent.control
ctx.tool.exec
ctx.tool.socket
ctx.tool.control
ctx.session.dir
ctx.session.messages
ctx.session.events
ctx.shared.dir
ctx.shared.tool.exec
ctx.shared.tool.control
ctx.shared.queue
ctx.shared.result
ctx.home.dir
ctx.symlink
ctx.ordinary
ctx.unknown

cd

An external process cannot change its parent shell cwd. ctx cd must not pretend otherwise.

Correct ordinary usage:

cd "$(ctx path shared project-a)"

If ctx cd exists, it is a shell integration helper:

eval "$(ctx cd project-a --shell)"

Sessions

ctx agent history, ctx agent output, ctx agent trajectory, and ctx agent resume read session files and connect to the relevant socket. They do not keep a private chat database.

When --session is omitted, they use session/index/current first and fall back to default. ctx latest is intentionally not a command; the current session behavior belongs to --session omission.

Examples:

ctx agent history coder
ctx agent output coder
ctx agent trajectory coder
ctx agent resume coder --session default

These commands read:

/ctx/home/<uid>/agent/<agent>/session/index/list
/ctx/home/<uid>/agent/<agent>/session/index/current
/ctx/home/<uid>/agent/<agent>/session/<session>/latest.md
/ctx/home/<uid>/agent/<agent>/session/<session>/messages.jsonl
/ctx/home/<uid>/agent/<agent>/session/<session>/events.jsonl

ctx agent trajectory prints a validated ATIF projection. It correlates tool calls, observations, and token usage by run/call identity and does not create a second durable history. Only tool results carrying a run and a call id matching a canonical tool_call event are projected; unmatched results are dropped. Projection does not invent a tool call or chat message. If validation still fails, the CLI lists actionable issue locations (step/result/call id), capped at 16 entries with the remaining count reported. Session-derived source/call identifiers are escaped for terminal output, field-bounded, and each rendered issue is capped at 256 characters.

Terminals

ctx terminal addresses a durable terminal resource rather than an Agent definition. list and status inspect session-local metadata, watch joins the PTY read-only, and attach joins it with input enabled. PTY bytes and process exit facts are appended to the resource events.jsonl stream for replay and debugging.

The current create form is agent-backed so it reuses the existing supervised launch path. It does not yet claim a new root /ctx/terminal namespace or a detached create bash supervisor; those require a versioned terminal ABI revision.

Provider OAuth

ctx provider oauth is a host-side credential helper. It does not add a /ctx/provider namespace and does not expose tokens through model files.

ctx provider oauth login PROVIDER [--device] [--timeout SECONDS]
ctx provider oauth status PROVIDER
ctx provider oauth refresh PROVIDER

login reads /etc/cortexfs/providers.d/*.json and uses the provider oauth block. The default browser flow creates a PKCE S256 authorization request, waits on the configured localhost redirect_uri, and exchanges the code. With --device, it prints the provider's verification URI and code, then performs bounded device polling. Both flows store normalized tokens in the system keychain:

service=cortexfs:<provider> account=oauth:access
service=cortexfs:<provider> account=oauth:refresh

Provider authentication is declared in provider JSON rather than hardcoded in the model executable. Inspect the normalized declarations with:

ctx provider auth methods PROVIDER

The output is method<TAB>flow<TAB>slot; it is a host-side projection and does not expose credential values or add an /ctx/identity namespace.

Non-Goals

ctx must not:

expose provider keys through /ctx
store private chat history
implement tool calling
parse OpenAI/Anthropic/Gemini request formats
maintain an agent registry
modify messages.jsonl to fake chat
decide policy locally
fallback to another model
hide runtime errors behind product language

Those jobs belong to Rig, the agent runtime, tools, or the CortexFS ABI itself.