# CLI reference

Find the right HRA command family, the machine-readable output contract, and the deeper guides for automation and memory.

## Start with command help

```text
hra --help
hra session --help
hra help session send
```

Root help lists the command families. Group and command help give the accepted flags and examples. The full catalog below is checked against the CLI's group help.

- `account` and `project`: provider profiles, sign-in status, Codex usage, and local workspaces.
- `session`: conversation lifecycle, messages, presets, provider changes, schedules, and exports.
- `interaction` and `turn`: local protected inspection and provider-specific approval or question handling.
- `auth`, `device`, `sync`, and `remote`: HRA identity, encrypted pairing, synchronized views, and remote command receipts.
- `work` and `memory`: bounded local agent coordination and working or shared project memory.
- `status`, `doctor`, and `daemon`: local health, prerequisites, and process lifecycle.

## Use structured output for automation

Supported one-shot commands use `--json` for a versioned result. Session watching uses `--jsonl` for an event stream. Read stdout as data and stderr as diagnostics; check the exit status and any bounded result diagnostics.

Secrets and protected interaction documents never belong in command-line arguments. Use the documented protected input descriptor or file for that command. Provider login has a separate foreground or protected-handoff flow; it is not an ordinary background JSON mutation.

For a lost mutation response, preserve its exact key and command ID. Changing a request under an existing key is rejected; submitting a new key can represent new work. Read the terminal and agent contract below before building a caller.

## Go deeper when the task needs it

- [Working and project memory](https://github.com/hraness/hra/blob/main/docs/facts-memory.md): session-scoped notes, explicit sharing, and hosted memory boundaries.
- [Personal-session adoption](https://github.com/hraness/hra/blob/main/docs/session-adoption.md): opt in locally to bring eligible existing provider sessions into HRA.
- [Attachments](https://github.com/hraness/hra/blob/main/docs/attachments.md): supported media, byte limits, and what crosses a device boundary.
- [Cloud retention](https://github.com/hraness/hra/blob/main/docs/retention.md): retention windows and command-receipt recovery.

Recurring conversation tasks are created with `hra session task` and stay bound to that session. The browser displays schedules but does not edit them. The separate `hra work` protocol coordinates bounded local work; it is not cross-device execution or automatic provider failover.

## Command reference

```text
hra init [--yes] [--json]
hra status [--json]
hra doctor [--offline] [--json]
hra auth login --input-stdin|--input-fd <fd>
hra auth status|logout
hra auth delete --acknowledge-erasure
hra notification-hours status [--json]
hra notification-hours set --start <HH:MM> --end <HH:MM> --timezone <IANA-zone> --revision <n> [--json]
hra notification-email status [--json]
hra notification-email enable|disable --revision <n> [--json]
hra device list
hra device pair
hra device key-loss --acknowledge-no-key-holders
hra device approve <device-id-or-prefix> --fingerprint <value> [--idempotency-key <uuidv7>] [--json]
hra device revoke <device-id-or-prefix> [--idempotency-key <uuidv7>] [--json]
hra account add <label>
hra account login <profile> [--provider <codex|claude>] [--device-code] [--handoff-file <absolute-path>] [--idempotency-key <uuid>]
hra account login-cancel <profile> [--provider codex]
hra account login-cancel <profile> --provider claude --attempt-id <attempt-id> --provider-generation <n> --idempotency-key <uuid> --acknowledge-child-exited
hra account login-cancel <profile> --provider devin --attempt-id <attempt-id> --provider-generation <n> --idempotency-key <uuid> --acknowledge-child-exited
hra account logout <profile>
hra account list
hra account show <profile> [--provider <codex|claude>]
hra account show <profile> --provider devin  (retired local history and cleanup only)
hra account usage [profile] [--refresh]
hra account usage-history <profile> [--from <UTC-RFC3339>] [--through <UTC-RFC3339>] [--limit <1..100>] [--cursor <cursor>]
hra account switch <profile>
hra account switch-recover
hra plugin list <account> [--project <project>] [--refresh]
hra plugin show <account> <plugin> [--project <project>] [--refresh]
hra project add --path <directory> [--name <name>]
hra project list
hra project use <project>
hra session list [--account <profile>] [--archived] [--limit <1..100>] [--cursor <cursor>]
hra session adoption status [--provider <codex|claude>]
hra session adoption enable <account> --provider <codex|claude>
hra session adoption disable --provider <codex|claude>
hra session discover [--provider <codex|claude>]
hra session show <session> [--detail]
hra session status <session> [--json]
hra session watch <session> [--cursor <cursor>] [--jsonl]
hra session events <session> [--cursor <cursor>] [--limit <1..200>] [--wait-ms <0..30000>] [--json|--jsonl|--follow]
hra session interactions <session> [--pending] [--limit <1..100>] [--cursor <cursor>]
hra memory status <session> [--json]
hra memory list <session> [--working-only] [--continuation <token>] [--json]
hra memory get <session> <key> [--working-only] [--continuation <token>] [--json]
hra memory search <session> [--working-only] [--continuation <token>] <text> [--json]
hra memory explain <session> <query-id> <row> [--json]
hra memory remember <session> <key> --title <title> --summary <summary> [--language <tag>] [--idempotency-key <uuid>] [--json] -- <body>
hra memory share <session> <key> --reason <reason> [--idempotency-key <uuid>] [--json]
hra memory hosted list [--json]
hra memory hosted create <project> [--idempotency-key <uuid>] [--json]
hra memory hosted attach <project> <hosted-space-id> [--json]
hra memory hosted detach <project> --generation <n> [--json]
hra memory hosted sync <project> [--json]
hra session start <account> [--project <project>] [--provider <codex|claude>] [--preset <low|high|ultra|fable-max>] [--fast] [--idempotency-key <uuid> [--preset-contract <1|2>]]
hra session send|queue|steer <session> [--attach <path>]... <message>
hra session stop|recover|abandon <session>
hra session rename <session> <name>
hra session archive|unarchive <session>
hra session note get|edit|clear <session>
hra session note set <session> <note>
hra session state <session> [--json]
hra session peer-policy get <session> [--json]
hra session peer-policy set <session> <off|inspect|coordinate> --revision <n> [--json]
hra session preset <session> <low|high|ultra|fable-max>
hra session switch <session> --provider <codex|claude> [--preset <low|high|ultra|fable-max>] [--account <account>] [--idempotency-key <uuid> [--preset-contract <1|2>]]
hra session export <session> [--format <trajectory|json>] [--out <path>]
hra session fast <session> <on|off>
hra session project <session> <project>
hra session switch <session> --provider <codex|claude> [--preset <low|high|ultra|fable-max>] [--account <account>]
hra session export <session> [--format <trajectory|json>] [--out <path>]
hra session task list <session>
hra session task show <session> <task-id>
hra session task create <session> --name <name> --every-minutes <15..10080> [--paused] [--idempotency-key <uuid>] -- <prompt>
hra session task edit <session> <task-id> --revision <n> [--name <name>] [--every-minutes <15..10080>] [--pause|--resume] [--idempotency-key <uuid>] [-- <replacement-prompt>]
hra session task delete <session> <task-id> --revision <n> [--idempotency-key <uuid>]
hra work protocol [--operation <kind>|--type <name>|--topic <topic>]
hra work apply --input-stdin|--input-fd <fd>
hra work snapshot <work> [--actor <session>]
hra work task <task> [--history-limit <1..50>] [--history-cursor <cursor>]
hra work poll <work> [--actor <session>] [--cursor <event-cursor>] [--action-cursor <action-cursor>] [--limit <1..50>] [--wait-ms <0..30000>]
hra work events <work> [--cursor <cursor>] [--limit <1..200>] [--wait-ms <0..30000>] [--json|--jsonl|--follow]
hra work watch <work> [--cursor <cursor>]
hra interaction list [session] [--pending] [--limit <1..100>] [--cursor <cursor>]
hra interaction show <interaction-id>
hra interaction inspect <interaction-id> --revision <n> [--handoff-file <absolute-path>]
hra interaction decide <interaction-id> --revision <n> --decision <once|session|decline|cancel>
hra interaction grant|answer <interaction-id> --revision <n> --input-stdin|--input-fd <fd>
hra interaction submit <interaction-id> --revision <n> --action <accept|decline|cancel> [--input-stdin|--input-fd <fd>]
hra autorespond on|workspace|off|default|status [--session <session>] [--json]
hra autorespond gateway set [--from-fd <fd>] [--json]
hra autorespond gateway clear [--json]
hra autorespond-after-hours status [--json]
hra autorespond-after-hours enable|disable --revision <n> [--json]
hra remote list [--limit <1..100>]
hra remote show <cloud-session>
hra remote command <uuidv7>
hra remote send|queue|steer <cloud-session> <message>
hra remote send --or-steer <cloud-session> <message>
hra remote resolve <cloud-session> --interaction <uuid> --revision <n> --decision <decline>
hra remote stop <cloud-session>
hra remote preset <cloud-session> <low|high|ultra|fable-max>
hra remote provider <cloud-session> <codex|claude> [--preset <low|high|ultra|fable-max>]
hra remote fast <cloud-session> <on|off>
hra remote allow|deny <device-commands|account-linking>
hra remote policy
hra turn inspect <session> <turn> [--json]
hra sync status|now
hra sync projection recover <local-session> --acknowledge-gap [--idempotency-key <uuidv7>] [--json]
hra daemon start [--json]
hra daemon status|stop [--json]
hra daemon run
```

Account, project, and local-session selectors accept an exact ID or an unambiguous case-insensitive label. Cloud-session selectors accept an exact public ID, a unique public-ID prefix, or an exact synced name. Device selectors accept an exact ID or unique prefix. Ambiguity lists candidates and performs no effect. The CLI creates and sends an idempotency key before every provider effect; pass `--idempotency-key <uuid>` to reuse one after a lost response. If a local mutation response is uncertain, HRA returns the generated key and the exact replay arguments without repeating the command payload. Put those arguments before any `--` delimiter when rerunning the otherwise unchanged command. A source-sensitive Codex `session start` or provider-switch replay includes both `--idempotency-key` and its immutable `--preset-contract`; do not omit or change either after an update. The preset-contract option is a source-binding field that requires an explicit idempotency key and is rejected for stable requests. With an existing key, a source-matched applied request replays its result and an effect-started request remains recovery-required. With a key that has no stored row, only this build's active source contract may authorize the one fresh effect; the field cannot select a retired route.

An older session-start release did not print the source contract, so its exact historical alias meaning must be supplied explicitly when replaying its key. For a v0.5.0 Codex start that omitted the then-default preset, preserve every other original option and add `--preset high --preset-contract 1`; v0.5.0 High and Ultra both meant Sol. Use `--preset-contract 2` only for an untagged Astra-era request whose original runtime evidence actually meant Astra. Neither selector can resume a contractless prepared row. Contract 2 cannot authorize a fresh effect under the current Sol binding; contract 1 can authorize the exact Sol request when the key has no stored row, just as a newly generated key can. If the originating meaning cannot be proved, use the retained old release rather than guessing. A contractless prepared row has no supported cancellation or retirement command. It must reach a terminal settlement through exact replay under the originating release, or the update remains blocked. Do not use a fresh key or `session abandon` as a workaround; that command applies only to an existing recovery-required session and never cancels prepared start or switch authority. `session preset` has no idempotency-key replay; resolve and inspect it before updating. session recover accepts only exact, kind-specific provider proof. session abandon never retries or deletes provider state and releases only the local recovery authority. Remote mutations require a current UUIDv7 when this option is supplied. With `--json`, stdout contains one versioned object; diagnostics stay on stderr.

`interaction show` lists each safe requested permission category and each exact question ID. Complete live command and permission authority is available only through the revision-bound protected `interaction inspect` path described above. A permission grant reads `{"permissions":["<requested-name>"]}` and a question response reads `{"answers":{"<question-id>":{"answers":["<answer>"]}}}` through protected input. Those permission-name and question-answer document shapes are Codex-specific. The live Codex adapter rehydrates selected permission names to their exact private provider values immediately before the response write; those values never enter display, storage, logs, or sync. Claude Code tool-use requests map to HRA's provider-neutral interaction kinds and accept only the response choices that exact callback offers.

Every admitted callback carries a local deadline anchored when the provider delivered it. HRA caps the pending interval at 30 minutes and honors a shorter valid provider interval, including an immediate zero interval. At the deadline it writes one provider-neutral timeout error through the same write-ahead ledger, never invents an answer or grant, and quarantines the provider generation if the write may have escaped. `interaction show` displays the safe local deadline; nested remote policy version 2 carries the same absolute deadline so readers can suppress an expired control, while the daemon remains authoritative.

For a standard MCP form, interaction show returns the exact public field contract without defaults or answers. Accept reads one protected document shaped as `{"content":{...}}` from nonterminal stdin or a file descriptor. Decline and cancel accept no content. JSON mode never prompts, and validation failures identify the contract failure without echoing a submitted value.

Projection recovery uses the local-session selector rules. It requires `--acknowledge-gap` and a canonical UUIDv7; the CLI generates a current key when it is omitted. A stored exact key remains the only admissible replay while recovery is unsettled. Inside the seven-day window, a prepared replay renews its lease and can apply. After the window, replay reconciles immutable committed lineage or safely settles known-no-effect authority as rejected; status then determines whether to retry with a fresh generated key.

The beta does not expose destructive local profile or project deletion. `account logout` asks Codex app-server to remove that profile's Codex login while HRA preserves its local session history. HRA does not implement Claude Code sign-out; use Claude Code's own authentication flow inside the isolated profile.

## Terminal and agent interfaces

> **Conditional walkthrough.** Current daemon and hosted command-writer rollout remains blocked on capacity. Do not initialize, start, or autostart a current daemon until the hosted operator records protected two-pass zero-debt capacity evidence and its exact .activated readback receipt. Artifact availability and the live sync service do not clear this gate. After activation, complete the update runbook's daemon and target marker-2 proofs before globally enabling hosted writers.

Run `hra` in a TTY to open a persistent shell. Account and session selections stay in the prompt, live updates redraw wrapped partial input without moving its logical cursor, protected answers are read without terminal echo, and `/exit` leaves the daemon running. Pasted command lines use a bounded queue. An overflow or interrupted line flushes the current native terminal queue, retains input custody while discarding through EOF, and exits without executing the tail. Protected terminal documents require a visible stderr TTY plus unpredictable begin and return phrases while raw no-echo mode is active. A failed protected boundary keeps echo disabled while discarding the tail, then closes shell input instead of returning ambiguous bytes to an ordinary prompt. Display loss, termination, and job-control signals restore or fence raw mode before propagation. Live display is buffered while a foreground or protected prompt owns the terminal, and updates from an old session generation are discarded before a new selection is announced. Slow-terminal backpressure drops additional updates behind one explicit omission notice instead of growing memory without bound. One-shot commands provide the same control surface to scripts and agents.

### Bounded local status

`hra status [--json]` is a bounded, effect-free read of local SQLite state. It does not start, stop, or contact the daemon; use the network; attempt provider or cloud observation; open a browser; log in; refresh usage; or run recovery. It returns fixed count fields for account, session, interaction, queue, and latest usage states plus at most 50 ID-and-revision action records. Provider and cloud coverage are explicitly `not_attempted`, and registered and online device counts are unknown rather than zero. The complete JSON result, including its versioned command envelope, is at most 256 KiB.

```text
hra status
hra status --json
```

### Session observation

`hra session status <session> --json` returns status version 2. HRA produces one typed provider-observation result, attempting the bound provider's reviewed observation path only when the current local state makes one applicable, then reads the session, event cut, interactions, and queue from one local SQLite transaction. Codex supports a native app-server observation read. Claude Code uses its live provider-neutral projection while the exact controller is present. If that controller is absent, HRA may establish `--resume` for the exact conversation only after prior-process exit or an already-completed exact process release is proven; ambiguous custody fails closed as recovery required. Retired Devin sessions use local history only and cannot execute. Execution, attention, provider, and queue remain separate axes, so a headline state cannot hide a recovery condition, pending interaction, response in flight, or queued work. Pending and response-in-flight counts are exact. The result includes at most 10 bounded safe summaries for pending interactions and excludes the session note and private provider thread binding. Every provider turn and item identifier becomes a secret-keyed opaque public alias before status, event, or interaction output. Public observation schemas accept only that exact alias form. The same local installation key keeps aliases coherent across surfaces and daemon restarts without making low-entropy provider IDs guessable from public output. If an existing installation loses that key, HRA refuses to replace it and directs the operator to restore the original local secret.

`hra session state <session> --json` returns the daemon's latest classification of who must act next: working, needs approval, needs an answer, needs a human action, done, done with followups, done with caveats, or aborted, with an attention flag, a short reason, and a monotonic revision. The daemon classifies the final assistant text of every completed turn with ordered lexical rules in which human-action cues beat approval cues, so a login or a code from email never reads as consent, and it reclassifies when a provider interaction is requested or resolved. The same classification is appended to the session event stream as a `session_state` event.

Autorespond answers provider approvals on your behalf. By default every session runs in approval mode `auto:all`: command and permission approvals are accepted immediately at once scope, never for the session, and each answer leaves an evidence row with the approval class, decision, mode, latency, and outcome. File-change approvals stay pending because the pinned callback does not expose the exact affected paths. `hra autorespond workspace` leaves command and permission grants pending until a provider adapter can attest their complete private authority as workspace-local; a command class or category label such as `workspace_write` is not that proof. `hra autorespond off` restores manual approvals; add `--session <session>` to override one session and `default` to clear the override. Questions and MCP forms are never answered automatically. The baseline limits are three consecutive answers without a human message, ten in an hour, and forty in a day. `hra autorespond status --session <session>` shows the shared counters and the last twenty evidence rows. Only an actual human-authored message resets the consecutive counter; peer messages, Work and scheduled automation, autorespond, and provider-switch handoff messages do not. Notification consent never enables automatic approvals.

After-hours protocol budgets were admitted in v0.6.3. They use a separate local opt-in, disabled on new and upgraded installations. The v0.7.0 release retains this policy without enabling it. After the applicable artifact admission and daemon rollout gates are satisfied, `hra autorespond-after-hours status` reports that policy and its revision. To opt in explicitly, use `hra autorespond-after-hours enable --revision <revision>`; use `hra autorespond-after-hours disable --revision <revision>` to turn it off. Outside the configured notification hours, otherwise eligible protocol approvals with complete budget history may use six consecutive, twenty rolling-hour, and eighty rolling-day reservations. Inside hours or without eligible evidence, the baseline applies. Prose always stays at three, ten, and forty. Both paths spend the same counters. Policy changes and schedule boundaries never reset or refund them, and no approval category gains authority.

Each automatic approval reserves its budget before provider dispatch. Reservations survive uncertain results, daemon restarts, and pruning of the display log; a reserved attempt can remain charged even if a later step proves unsent. The final storage transaction checks current consent, source eligibility, and shared accounting before charging. Higher limits additionally require one coherent current schedule and proven history; an unreadable schedule selects the baseline, while invalid consent or accounting refuses admission. Upgrading an existing session to local schema 44 pauses automatic approvals for 24 hours because older retained logs cannot prove its complete budget history, and requires a new human message to reopen its consecutive budget. You can send that message during the hold. The schema-46 after-hours migration also requires a newly finalized human message for every pre-44 session before its higher tier can apply, even if the old hold expired or a human reset occurred before that migration. `hra autorespond status --session <session>` reports the hold's end and the consecutive counter. Manual approvals remain available.

Configuring a gateway key explicitly enables the separate prose-approval path. After strict local gates establish that a completed final assistant message asks only for consent, HRA sends at most its final 4,000 characters plus session-state and approval-reason metadata to Vercel AI Gateway model `openai/gpt-5-nano`. It makes one request with a 10-second deadline and no retry. The model cannot create arbitrary text that HRA will send: the daemon emits either `The human has approved. Proceed accordingly.` or a byte-exact substring already present in the assistant message. Immediately before dispatch, HRA checks current consent, the exact completed question, pending interactions, and shared budget again. A newer question or changed authority cancels the stale reply. A timeout, refusal, or other failure leaves the turn for the human. `hra autorespond gateway clear` disables this prose path.

For snapshot-to-stream continuity, start selected-session monitoring at the atomic status cursor. `hra session watch <session> [--cursor <cursor>]` renders a bounded human stream by default; add `--jsonl` for a machine stream. Watch is a presentation alias over the existing session event stream, and it drains each output page before advancing its internal cursor. The shell drains every signed pending-interaction continuation page before following newer committed ledger events from the status cursor. Standalone human watch buffers that initial guidance until enumeration is complete, caps the atomic bootstrap at 1 MiB of UTF-8, and writes none of it if enumeration or the bound fails. Resolution guidance appears only from a complete current interaction record and only for a supported decision; an event-only interaction notice points to the exact show command without proposing a mutation. Those events cover bounded lifecycle, tool, interaction, warning, error, and terminal updates, but the ledger is not a complete wake source for every authority transition. Agents that need exact current authority must also repeat bounded session status or pending-interaction reads. Human watch renders assistant and provider-visible reasoning-summary text only after observing that item's start boundary, then redacts credentials and absolute paths with state carried across chunks and interleaved events. A mid-item join omits ambiguous delta suffixes until the next item starts. Gaps, shutdown, malformed repeated starts, and exhausted redaction capacity discard undecided tails with an explicit notice rather than releasing text whose boundary cannot be proved.

```text
hra
hra session status <session> --json
hra session state <session> --json
hra session watch <session> --cursor <cursor>
hra session watch <session> --cursor <cursor> --jsonl
hra session events <session> --cursor <cursor> --limit <1..200> --wait-ms <0..30000> --json
hra session events <session> --cursor <cursor> --wait-ms 30000 --jsonl
hra session interactions <session> --pending --json
hra interaction inspect <interaction-id> --revision <n> [--handoff-file <absolute-path>]
```

JSON mode writes one versioned document to stdout and diagnostics to stderr. Event following with `--jsonl` writes JSON Lines as the turn progresses; `--follow` remains an equivalent compatibility spelling for `session events`. JSONL delivery is at least once across a pipe or process failure: a crash after an event line but before its page checkpoint can replay that event. Durable consumers deduplicate by `(sessionId, streamEpoch, sequence)` and persist each checkpoint only after durably applying all preceding lines. Signed opaque cursors let an agent resume bounded session-list, event, and interaction pages, and durable interaction records keep approvals, questions, permission grants, and MCP form elicitation visible until they are explicitly resolved.

Exact `hra session wait` is unavailable until every wait predicate has a transactional wake revision that changes in the same commit as the observed state. Use status followed by watch from its cursor, or bounded repeated status polling, when a caller needs to wait.

### Exit status and JSONL

Every one-shot caller must check the process exit status. HRA uses this exact mapping:

- `0`: success. A normally stopped event follower, including a user SIGINT, may also return 0.
- `1`: CONFLICT, AMBIGUOUS, INTERNAL, any other closed failure code, or an unhealthy doctor result.
- `2`: INVALID_INPUT.
- `4`: NOT_FOUND.
- `5`: UNAVAILABLE.
- `6`: INTERACTION_REQUIRED.
- `7`: RECOVERY_REQUIRED.

For non-streaming `--json` commands, stdout contains exactly one versioned success or failure envelope. For `--jsonl` or its equivalent `--follow`, stdout contains only JSONL gap, event, and checkpoint frames. If the follower ends on a command error, HRA leaves all completed frames on stdout and writes exactly one newline-terminated version-1 failure envelope to stderr shaped as `{"ok":false,"version":1,"error":{"code":"<code>","message":"<safe-message>"}}`; the error may also include bounded details. Callers must consume stdout and stderr independently, must not merge the terminal error into the JSONL stream, and must check the process exit status. A normal user stop or SIGINT may exit 0 without a terminal failure envelope.

`interaction show` intentionally returns only a durable safe summary. Before approving a command or permission request, run `hra interaction inspect <interaction-id> --revision <n>` to read the complete authority still held by the live provider callback. A foreground human receives bounded detail on the protected stderr terminal. An agent or other noninteractive caller must first create an empty mode-0600 regular file under a current-user-owned mode-0700 directory and pass its absolute canonical path with `--handoff-file`; ordinary stdout receives only safe binding and cleanup metadata. On macOS, neither the directory nor file may have an extended ACL, and HRA rechecks both held descriptors before and after writing. Detail larger than 64 KiB also requires this file path. Read it within that protected boundary and remove it after deciding. HRA durably admits a bounded file-change prompt so it remains observable and may be declined, but refuses every acceptance because pinned Codex 0.153.2 does not provide the exact affected paths or change detail needed for informed approval.

## Agent work protocol

> **Local release boundary.** These commands are part of the `v0.7.1` admitted local CLI release. Its immutable artifacts passed GitHub and npm release admission. Hosted sync is not required for this local protocol; the current-daemon rollout prerequisite still applies before startup.

The versioned source contract defines a narrow local coordination kernel for agents operating several already-existing provider sessions. It records six bounded objects: work, tasks, attempts, submissions, reviews, and signals. Codex and Claude Code still own their provider-native execution, turns, tools, context, and approvals. HRA does not add a second model loop or a generic executable workflow engine.

```text
hra work protocol [--operation <kind>|--type <name>|--topic <topic>]
hra work apply --input-stdin
hra work snapshot <work> [--actor <session>]
hra work task <task> [--history-limit <1..50>] [--history-cursor <cursor>]
hra work poll <work> [--actor <session>] [--cursor <event-cursor>] [--action-cursor <action-cursor>] [--limit <1..50>] [--wait-ms <0..30000>]
hra work events <work> [--cursor <cursor>] [--limit <1..200>] [--wait-ms <0..30000>]
hra work watch <work> [--cursor <cursor>]
```

The seven commands are agent-only. Non-streaming commands emit compact JSON without requiring `--json`. `work watch` emits resumable JSON Lines. `work apply` is the only mutation entry point. It reads one strict version 1 or version 2 request from nonterminal standard input or an explicit file descriptor. Both versions contain `{protocol,version,requestId,operation}`, and the nested operation carries its UUIDv7 `idempotencyKey`. A version 2 `work.create` that declares a High or Ultra route, or `task.addBatch` that adds a High or Ultra task, also carries the caller-authored top-level `presetContract`; version 2 forbids that field on stable operations. Success and failure echo the admitted request ID and version, and work capabilities are never accepted as argv fields. The request version and any authored preset contract are part of changed-intent detection. Same-key replay of the exact request preserves the durable decision, stable identities, and capabilities without adding a mutation, event, or revision, while mutable public records and the work revision are reprojected from current state. It is not a byte-identical response promise. A retained release tombstone is the exact stored-result exception. `work protocol` is queryable by operation, type, or topic. It returns both accepted apply envelopes, exact field contracts, value syntax, capability semantics, operation kinds, hard bounds, and the closed recovery and process-exit guidance for failures.

Each task carries an exact account ID, project ID, preset, and Fast setting. HRA never chooses another subscription from quota, availability, usage, or incidental ordering. A provider limit blocks or fails that attempt. It does not rotate the task to another account. Explicit tasks on separate accounts may run in parallel.

Each Work also freezes the meaning of its High and Ultra routes when it is created. A fresh affected version 2 request must name the current contract 1 Sol meaning. A fresh affected version 1 request is refused because that format does not identify whether its author meant Sol or Astra; stable version 1 requests remain admissible. An existing contract 2 Work whose coordinator and participating session authorities remain supported keeps Astra for already-declared tasks and remains readable, claimable, reviewable, and settleable. A Work associated with a retired Devin session remains readable but is fenced from mutation and execution. Current tooling does not append a new High or Ultra task to a historical contract 2 Work because the alias now means Sol; create a new Work for a new Sol task graph. Low has the same exact Luna Max meaning under both contracts and remains compatible. Exact same-key replay of an already-applied version 1 or version 2 mutation returns its historical result without adding a task or provider effect. Reusing that key with another version or contract is a conflict, not a request to reinterpret the historical operation.

Readiness is derived from the open work state, time bounds, accepted dependency submissions, and absence of a live or ambiguous attempt. A final assistant message is not completion. The worker submits a bounded structured result and evidence; declared independent reviews and HRA-owned completion gates must accept the exact submission revision.

Dispatch binds one already-existing exact actor session and always starts a new turn. HRA's task graph is the durable task queue; queue and steer are reserved for coordination signals. HRA commits the claim, monotonic fence, route, session binding, request digest, and prepared effect before the provider call. If the provider effect may have started but cannot be proved, the attempt becomes recovery-required. HRA does not redispatch, steal, or reroute it speculatively.

Coordinator, member, and exact-attempt capabilities scope every mutation and never appear in snapshots, polls, or events. Poll action arrays have a separate signed, actor-bound continuation with a frozen projection time; a changed work stream invalidates it instead of returning stale authority.

Signal delivery and recipient acknowledgement are separate facts. `deliveryState` reports pending, accepted, failed, or unknown provider delivery. `acknowledgedAt` records the recipient acknowledgement independently, including when delivery remains pending or unknown.

Snapshots expose bounded recent work-level signals and an omitted count. With no history option, `work task` returns task detail with active and latest attempt lineage, the latest full attempt report, the latest submission and its ordered reviews, and bounded recent task signals. Either `--history-limit` or `--history-cursor` selects a separate task-history page over the task's attempts, reports, submissions, reviews, and task signals; a cursor-only continuation defaults to 20 items. Each complete compact JSON response for snapshot, task detail, and task history, including its envelope and terminating newline, is capped at 512 KiB. Only recent or historical arrays are trimmed, and omitted or remaining counts and continuations make every reduction explicit.

A signed task-history continuation freezes the work stream sequence and epoch, task membership high-water ordinal, task revision, projection time, and next offset. Append-only bounded public projection versions reconstruct every returned record as of that cut. Later mutations and later history memberships are excluded from every continued page, so pagination is coherent even while agents keep working.

Each JSONL gap, event, or checkpoint frame, including its terminating newline and terminal-safe escaping, is capped at 512 KiB. A terminal stream failure is one compact JSON document on stderr capped at 64 KiB. The queryable protocol advertises both wire limits.

Accepted submissions, reviews, evidence references, receipts, and completed tasks are durable prefixes. Later failure or cancellation preserves them. No SQLite writer transaction spans provider reasoning, provider I/O, artifact hashing, or Git inspection. This applies the durable-prefix lesson in [Agent Swarms are a Distributed Systems Problem](https://www.trychroma.com/engineering/transactions) without adopting generic page locking, wound-wait, or speculative replay.

`task.claimNext` records an exact idempotent empty result when no task is ready without appending an event or advancing the work revision. `work.release` is the other stream-neutral mutation. It requires terminal work, the exact coordinator capability and revision, and `acknowledgeDataLoss: true`. Only an unresolved attempt dispatch blocks release. An ambiguous signal delivery may be discarded under that acknowledgement and is counted in the tombstone.

A successful release atomically deletes the work graph and durable history, including the task-history membership index and projection versions, then retains a separately bounded tombstone with the final stream head, terminal and release request digests, discarded-record counts for both history tables and the rest of the graph, and a digest of that release boundary. While the tombstone remains, only the same release idempotency key and canonical request digest have an exact replay result. Replay guarantees for every earlier operation have ended. Tombstones have count, byte, and maximum-age bounds, so their retention timestamp is an upper bound rather than a promise.

This release is an explicit logical destructive purge, not a forensic-erasure promise. SQLite secure deletion is defense in depth, but the command does not promise immediate physical sanitization of prior database pages, WAL frames, backups, snapshots, or storage media.

Local SQLite is the only execution authority for work admission, claims, fences, dispatch receipts, submissions, reviews, signals, and the work-scoped event cursor. The initial work protocol has no cloud execution or cross-device takeover path. Turso is deferred behind a repository boundary and cannot be added as a second authority beside SQLite or encrypted Convex projections.

## Features

- Isolated provider profiles: each named profile has its own user-only `CODEX_HOME` for Codex and `CLAUDE_CONFIG_DIR` for Claude Code. Each provider owns its authentication state; HRA never copies or parses provider credentials.
- Codex usage with provenance: account identity, quota, rate-limit, and token snapshots include their provider source time and freshness. A bounded source-ordered 24-hour ledger supports safe human and JSON pagination without returning raw provider payloads.
- Compact sessions: list sessions, read provider-neutral user and final assistant messages, and inspect elapsed time plus bounded observed file and Git actions. Protected full-turn inspection remains Codex-only.
- Personal-home adoption: opt in to discover recent Codex and Claude Code sessions, plus older Codex threads targeted by present Desktop heartbeat automations, then admit them after bounded account, project, liveness, and exact-resume checks. Active and paused automation records both count until deletion or retargeting. HRA locally parses a bounded automation record but ignores and retains no prompt or working-directory field, keeps later records reachable across daemon restarts, and replaces Desktop's exact fired heartbeat envelope with generic protected text before projection. Account-filtered session lists include admitted rows, which use the same provider-supported public commands, autorespond policy, and approval authority as every HRA session. Provider-specific limits are identical for native and adopted sessions, and provider APIs do not supply a global lease against every later external resume. Read [the session-adoption guide](https://github.com/hraness/hra/blob/main/docs/session-adoption.md).
- Durable controls: send, queue, stop, and keep one editable note per session. Codex and Claude Code can steer an active turn. Provider-native rename remains Codex-only. Provider and desktop effects use exact authority, idempotency keys, and process-generation fencing.
- Named projects: a project is a canonical directory that may contain several repositories. Changing it affects future turns only.
- Stable working and shared project memory: a project-bound session writes to its expiring working lane, reads that lane together with durable project memory, and shares one attested page only through conflict-checked adoption. Bound Codex and Claude Code models use closed HRA tools. Owners use `hra memory status|list|get|search|explain|remember|share` and explicitly enroll canonical project memory through `hra memory hosted list|create|attach|detach|sync`. Existing personal adoptions and legacy sessions without a proved HRA tool binding use the owner memory CLI; adoption does not silently install model tools or replace their conversation. Hosted memory is opt-in and does not upload the working lane. See [working and project memory](https://github.com/hraness/hra/blob/main/docs/facts-memory.md) for the authority, quota, and recovery boundaries.
- Attributed peer coordination: each session owns a revocable `off|inspect|coordinate` policy. Bound Codex and Claude Code tools can list, inspect, and message only bounded same-project peers; every action retains actor and lineage without granting session administration or approval authority. Retired sessions cannot participate.
- Agent work coordination: the frozen beta contract specifies bounded local task graphs, fenced attempts, structured submissions, independent reviews, signals, and a resumable work event stream for exact existing sessions.
- Optional encrypted sync: paired devices share a bounded session projection and submit commands to the one machine holding the execution lease.

### Peer coordination boundary

Peer coordination is separate from Work. It creates no Work, task, attempt, review, or signal membership. The actor and target must be distinct current sessions in the same project. Inspection requires neither policy to be `off`; messaging requires both exact current policy revisions to remain `coordinate`. Changing either policy revokes stale inspection and mutation authority.

`send` starts a new turn only for an idle target. `queue` records bounded untrusted input for later delivery and works for an active target. `steer` addresses one exact active turn and is supported by Codex and Claude Code. Peer input cannot resolve approvals, answer protected questions, administer a session, or inherit an identity.

HRA refuses self-addressing, stale target revisions, causal cycles, and a ninth hop. It admits at most 120 new peer actions per actor and per project in a rolling hour, at most 16 distinct targets per actor in that hour, and at most 64 unsettled inbound queue entries or 1 MiB of their text per target. Complete replay and causal evidence remains for at least seven days. Protected recovery ancestry is never pruned to make room, and the 25,000-action project cap fails closed when protected rows consume it.

Abandoning an uncertain peer delivery does not prove that its message was ignored. HRA refuses new peer messages from an affected active turn while preserving inspection and owner controls, including stop. A subsequent distinct turn can coordinate again. Older unreleased recovery records with no affected-turn identity conservatively fence that provider thread until the owner explicitly replaces it; a new message alone does not repair missing historical evidence.

## Plugin discovery

```text
hra plugin list <account> [--project <project>] [--refresh]
hra plugin show <account> <plugin> [--project <project>] [--refresh]
```

Plugin commands are read-only discovery. They report the exact installed, enabled, availability, authorization, and capability state exposed by the selected isolated Codex profile.

Pinned Codex 0.153.2 has no safely separated install, enablement, and OAuth lifecycle surface: its available lifecycle path can combine installation with enablement and may then open browser authorization. HRA therefore does not expose plugin install, enable, disable, OAuth, or permission effects. The pinned tool-suggestion form that can invoke that compound plugin or connector lifecycle is also rejected before admission. Other standard MCP forms are brokered only when their pinned schema fits HRA's closed primitive-field contract. The interaction exposes bounded field names, types, requiredness, constraints, and allowed choices; titles, descriptions, defaults, and answers stay off the public and durable display. Protected submissions are checked for exact required fields, types, bounds, formats, choices, and the absence of additional properties before response preparation. Opaque openai/form, unsupported schema constructs, and URL elicitation fail before durable admission and receive a safe unsupported-capability response with no schema, submitted value, or URL echo. The schema-11 security migration terminalizes and replaces any prerelease URL record before interaction reads. HRA will keep extended-form and URL handoff unavailable until each has a closed protected path.

## Next

- [Practical session workflows](/docs/sessions/)
- [Provider and release support](/docs/status/)
