Sessions and goals

Resume, fork, inspect and export your work.

Documentation · Context · Commands

Continue the latest conversation in the current workspace:

sh
octet --continue

Sessions are bounded, append-only JSONL, namespaced by workspace under the configured session directory (--session-dir PATH). Complete semantic boundaries are durable; provisional streaming deltas are not. Parent links preserve branches without rewriting history. Names/tags live in .metadata/ sidecars so the conversation remains readable without changing its format.

Resume and branch#

sh
octet --resume
octet --resume SESSION_ID
octet --fork SESSION_ID
octet --fork

Resume restores model/reasoning, prompt identity, tool panels, branches, and historical prompt colors. Explicit --model/--reasoning override recovered values. --fork <id|path> creates a new session from the selected head before startup; bare --fork opens the picker.

Interactive action Result
/resume [id] Resume directly or open the picker.
/fork Pick an active-branch user message or the whole conversation for a new session.
/clone New session from the current head without a picker.
/name [name] Show or change the readable name.
/export [path] Redacted portable export.

The resume picker supports fuzzy, quoted-phrase, and re: regex filtering, named-only filtering, recent/title/message-count sorting, and optional paths. Tab toggles current/all-workspace scope; Ctrl+S cycles ordering, Ctrl+N filters named sessions, Ctrl+P toggles paths, Ctrl+R renames, and Delete moves to trash. All-workspace browsing is not a cross-workspace transcript index; a differently scoped session cannot be resumed into the same live App.

Commands#

sh
octet sessions list
octet sessions list --query parser
octet sessions inspect SESSION_ID
octet sessions rename SESSION_ID "parser hardening"
octet sessions tag SESSION_ID rust local-model
octet sessions export SESSION_ID
octet sessions export SESSION_ID --output ./handoff.octet-session.json
octet sessions delete SESSION_ID
octet sessions repair SESSION_ID
octet doctor

Listing/search is read-only and uses bounded metadata scans or the disposable catalog. list searches IDs, names, derived titles, tags, internal JSONL paths, and dates encoded in IDs, scoped to the selected workspace store. Modified times appear as relative ages. inspect validates read-only and reports derived active-branch title, size, entries, head, checkpoints, usage, and branch roots/leaves; its connector tree includes abandoned forks without treating them as active context. doctor performs read-mostly prerequisite/provider/model checks without constructing an Agent or starting executable extensions.

Recovery#

Delete moves JSONL and metadata to .trash/, not permanent unlinking. Repair first writes an owner-private backup, then removes only an interrupted final append. Corruption in a completed record is diagnosed, never automatically rewritten. A dropped run never silently replays an unresolved mutating call; its outcome is indeterminate. Cancellation cannot undo an already completed action. Network and effect recovery.

Portable export and redaction#

Export validates and writes an owner-private octet-session-export version 1 JSON package with source identity, readable metadata, and records. Existing paths are not replaced without --force.

Redaction is on by default: credential-like keys and string content in prompts, tool arguments, and results are scanned. The bounded deterministic scanner covers authorization/cookie headers, common API-token prefixes, credential assignments and URL queries, URL userinfo, private-key blocks, and JSON objects or arrays serialized inside strings. It preserves surrounding prose and UTF-8 and reports replaced values/fragments. This is a safety filter, not proof that arbitrary prose or media contains no secret. --include-secrets requests raw export-eligible values with an explicit warning; use only for a trusted destination. Private extension metadata (including annotations with no public flag) is always excluded, for both JSON and HTML, even with --include-secrets. This visibility projection does not modify the private source transcript.

octet sessions export SESSION_ID --format html --output ./session.html writes one owner-private, script-free file with formatted Markdown, bounded code highlighting, branch links, and validated inline raster previews. Author HTML, external links and terminal controls remain inert; audio and remote media are not fetched. Arbitrary metadata keys named Image or Audio remain literal data, not previews. Hosted viewers and cloud sharing are separate from this local export. Media/privacy.

Discovery catalog#

Each workspace store may contain .catalog/sessions-v1.sqlite3, a private, disposable SQLite projection of bounded titles, active-branch message counts, and transcript size/mtime fingerprints. JSONL and .metadata/ remain authoritative. Listing/resume need not scan all transcript bytes: only missing or stale entries are streamed, the active row refreshes on normal app close, and missing sessions lose their rows. The picker enumerates workspace-key directories under the shared root and displays their .workspace markers.

Unavailable, locked, corrupt, oversized, or newer-version catalogs never block access: octet falls back to bounded JSONL scans and rebuilds corrupt SQLite contents. Removing .catalog/ is safe; it is recreated on demand.

JSONL schema#

Each physical line is one JSON object with a type discriminator:

Record Meaning
entry Immutable parent-linked conversation/state.
head Active branch selection and cumulative cost.
checkpoint Completed prompt and exact restorable head.
usage Provider/model/token/cost accounting for one operation.
usage_uncertainty Accepted-attempt exposure whose usage and cost are unknown.

Stable entry envelope:

json
{
  "type": "entry",
  "id": "entry-id",
  "parent": "previous-entry-id",
  "metadata": {
    "prompt_model": "local-model-id",
    "prompt_model_source": "local",
    "prompt_color": "#5a36d6"
  },
  "value": { "type": "message" }
}

parent: null marks a root. Entry values are message, compaction, config, prompt_template_selected, skill_activated, skill_resource_read, and skill_deactivated. Template name/hash stay outside model-visible context. Skill activation/resource events are resumable; compaction snapshots active skills and cumulative Pi-compatible details.readFiles / details.modifiedFiles. Older records missing those fields receive empty lists.

metadata.prompt_color is normalized sRGB, assigned at the original user append, inert, and never provider input. It remains authoritative through resume, checkout, branching, compaction, model switches, and theme reloads. Legacy prompts without it may derive a deterministic fallback from their historical prompt_model, never the currently selected model.

usage kinds include assistant turns, rejected Responses turns, compaction, terminal gates, and delegated_agent. A delegated record names its host-created child, completed turn/tool-call counts, aggregate disjoint token buckets, route/model, exact category cost, and picodollar remainder. Child JSONL remains the detailed transcript; a root mirror is written once before the owning checkpoint. Session cost, /cost, footer, export, resume, and subsequent cost-limit checks therefore include child spend without reopening private paths.

An accepted inference attempt interrupted before authoritative usage is available is recorded separately as usage_uncertainty, not as zero tokens or zero cost. Its record contains only trusted endpoint, model, and operation identifiers, each bounded to 128 ASCII identifier bytes; no endpoint URLs, request/response bodies, prompts, credentials, or error text belong there. Unknown exposure uses the same owner-private, locked, synced append path as known usage. An append failure must stop automatic replacement.

Session::has_uncertain_usage() remains true after later successful turns, checkpoints, compaction, checkout (including another branch or the root), and reopening. It is session-global accounting, never model-visible context or head state. Existing usage and cost totals remain known subtotals, not complete spend; hard cumulative cost/token limits must fail closed while uncertainty is present, including limits enabled after resuming. usage_uncertainty_records() exposes the bounded evidence without inventing missing counts or prices. The writer records each failed physical attempt once, not each retry notification; records are evidence, not provider-confirmed billable-attempt counts. Delegated unknown exposure must also be mirrored into the owning root ledger.

Older sessions without these records retain their existing known ledger; the reader does not fabricate evidence about historical failures. Fork/clone remains a new accounting session: like known usage telemetry, uncertainty is not copied by the active-branch conversation projection. Restoring within the original session never clears its exposure.

The head record is the only branch-selection mutation:

json
{
  "type": "head",
  "id": "entry-id",
  "total_cost_microdollars": 0,
  "total_cost_picodollars_remainder": 0
}

Branching/compaction never rewrites entries. Context walks parents from the selected head and applies compaction boundaries. Completed records are strict UTF-8 and strict JSON; only a final unterminated record is a recoverable torn append. Reads are bounded by bytes and record count. Persistence invariants.