gjc sdk session is the broker-bound command family for operating live GJC SDK
sessions from the terminal. It replaces the removed gjc daemon session route
(no alias is kept). The command family has seven verbs — list, inspect,
send, status, tail, and elevate — plus the explicit raw hatch
that dispatches one SDK operation as control, query, or global.
The session CLI is advisory tooling over the SDK: every semantic verb resolves sessions through the SDK broker, and output is rendered through a versioned, credential-free DTO. Endpoint credentials are never printed.
list, inspect, send, status, and tail resolve sessions through the
SDK broker. The broker validates the indexed session against its durable
endpoint record (session.get_endpoint) and hands the CLI a connection
credential that the CLI uses for its one connection and never renders. The
broker is started on demand (ensureBroker) when discovery is absent, and a
missing or unreachable broker surfaces as broker_unavailable (exit 1).
--agent-dir selects the broker state directory; --repo selects the
workspace directory used for saved-session resolution (default: the current
directory).
gjc sdk session list queries the broker session.list global and projects
every indexed session into the versioned row DTO (SESSION_ROWS_VERSION). Each
row is credential-free and carries:
sessionIdand thelocator(repo,stateRoot);endpointGeneration,pid,live,deleted(tombstone),indexSeq;hostIncarnationandidentityProvenance(composite|legacy);activity({state: active|idle, at}) andlastHeartbeatAt;terminalUncertain,lifecycleRequestId,endpointMtimeMs;ambiguouswhen the samesessionIdmaps to more than onestateRoot(cross-repo duplicate).
gjc sdk session inspect <sessionId> renders one indexed row. When the broker
is absent, it falls back to a credential-free offline projection from the local
endpoint discovery record (<repo>/.gjc/state/sdk/<sessionId>.json) so a
session can still be inspected without a broker.
gjc sdk session send <sessionId> --text <prompt> submits an ordered
turn.prompt carrying a caller-chosen operation reference (a ULID by default,
or --op-ref). The result envelope reports accepted with the receipt and the
operation reference used for later reconciliation.
--waitpollsturn.prompt_statusuntil the prompt reaches a terminal state or the wait window (--timeout-ms, default 30s) elapses.send --waitnever cancels a running turn; a window that elapses before a terminal state is reported aswait_timeoutwith the last observed status.--textand the JSON input sources (--json-input,--json-input-file— which must be a0600regular file —--json-input-stdin) are mutually exclusive for the prompt body.
gjc sdk session status <sessionId> <opRef> performs a lossless
turn.prompt_status lookup for a previously submitted operation reference and
returns the full reconciliation record plus a summary.completed flag.
See lossless prompt statuses.
gjc sdk session tail <sessionId> replays the retained transcript from the
durable checkpoint and then follows the live event-ring frames, emitting the
default tail kinds (session lifecycle and turn lifecycle events) plus retained
transcript entries.
--strictfails closed withretention_gap(exit 1) when retained history or the event ring dropped entries before the checkpoint.--until-idleexits once the observed event stream reaches a terminal turn state.--all-eventswidens the emitted set to every event-ring kind.--cursorresumes from a saved signed checkpoint claim.session.checkpointverifies the unexpired claim and exchanges it for a fresh connection-owned cursor pinned to the exact prior revision; direct cross-connection cursor consumption remains rejected, so reconnect never echoes or rewinds a cursor.--timeout-msbounds live follow; a session whose lifecycle already ended (terminal orterminalUncertain) replays retained history and exits instead of hanging.
A deleted session has no tail (session_deleted). A stopped session replays
its retained transcript without an endpoint (offline source), bounded to the
most recent retained entries.
gjc sdk session elevate <sessionId> --kind <control|global> --op <operation> --json-input '{...}' --confirm requests an exact-digest, single-use elevation grant. The command requires an attended TTY and writes a private 0600 operator directive that the broker consumes internally; no public elevation.answer operation exists. Use the returned request id with raw control ... --elevation-request-id <id>.
gjc sdk session raw <control|query|global> dispatches exactly one SDK
operation and returns the broker/host response:
raw control <sessionId> --op <operation>— one control operation with--json-input*;--confirmconfirms destructive control operations.raw query <sessionId> --query <operation>— one query;--cursorpasses a continuation cursor.raw global --op <operation>— one broker global. Lifecycle globals (session.create,session.fork,session.resume,session.close,session.delete) require--idempotency-key.
session.get_endpoint is refused by default: it requires
--show-endpoint-credential and (on a TTY) an interactive confirmation, so
credentials are never printed by accident. The raw hatch validates operation
names and adapter dispositions up front and refuses endpoint-disclosure
operations unless explicitly requested.
turn.prompt_status reports accepted, in_flight, terminal_ok, or
failed; only retained-record TTL/capacity eviction yields unknown. A
prompt that is active at process restart is finalized from its durable pending
outcome (or prompt_failed when it has none), so it never reports as
unknown while a record exists.
unknown means uncertainty, never proof of non-execution: do not reuse an
operation reference as a retry mechanism (client_ref_conflict while the
record is retained; after eviction a reused ref may be admitted again with the
prior outcome unknown). Use one fresh operation reference per logical prompt
and reconcile with status.
tail reports a retention_gap when retained history or the event ring
dropped entries before the durable checkpoint: the gap carries the missing
sequence range (missing.from/missing.to) and a resync checkpoint.
--strict turns any gap into retention_gap with exit 1; without --strict,
tail continues from the resync position and reports the gap in the envelope.
Elevation-gated operations — session.close, session.delete,
workflow.gate_answer, workflow.plan_approve — are dispatched only behind
broker-owned single-use grants. The grant digest binds the exact
{kind, sdkId, input} triple, so substituting a different operation or input
changes the digest and the gate fails closed. A crash between claim and
dispatch is replayed truthfully as consumed with outcome unknown
(uncertain), and retry requires a new grant. There is no public
elevation.answer operation; default SDK scope (list/query/send/tail) stays
grant-free.
gjc daemon session is removed and no alias is provided. Migrate:
| Removed route | Replacement |
|---|---|
gjc daemon session list |
gjc sdk session list |
gjc daemon session inspect <sessionId> |
gjc sdk session inspect <sessionId> |
gjc daemon session send <sessionId> --text <prompt> |
gjc sdk session send <sessionId> --text <prompt> |
gjc daemon session tail <sessionId> |
gjc sdk session tail <sessionId> |
| raw control/query dispatch | `gjc sdk session raw control |
The broker-bound surface replaces the daemon-owned routing: sessions are resolved through the SDK broker with validated endpoint identity instead of direct discovery-file reads, and output is versioned and credential-free.
Verbs exit 0 on success and write JSON to stdout. Failures write a JSON error
envelope to stdout with a non-zero exit: usage errors exit 2, operational
failures (broker unavailable, session unavailable, retention gap, wait
timeout) exit 1. Error details are recursively redacted of secret-shaped
fields before rendering.