- Status: current supported behavior
- Last updated: 2026-07-22
Generated sessions --help owns exact current flags. This document owns behavior
and compatibility. Planned commands are labeled explicitly.
Development schemas from before 0.1.0 are unsupported. The 0.0.0 bootstrap
seed establishes no CLI contract. Compatibility begins with the 0.1.0 CLI.
sessions
sessions --help
sessions --version
sessions doctor [--format human|json]
sessions paths [--format human|json]
sessions index [--source codex|cursor] [--format human|json]
sessions list [--source SOURCE] [--instance INSTANCE]
[--native-id NATIVE-ID]
[--source-state present|missing|unknown] [--workspace WORKSPACE]
[--activity-after TIME] [--activity-before TIME]
[--captured-after TIME] [--captured-before TIME]
[--observed-after TIME] [--observed-before TIME]
[--session CANONICAL-ID] [--limit N] [--cursor TOKEN]
[--format human|json|jsonl]
sessions search <text> [--source SOURCE] [--instance INSTANCE]
[--match all|any]
[--native-id NATIVE-ID]
[--source-state present|missing|unknown]
[--workspace WORKSPACE]
[--activity-after TIME] [--activity-before TIME]
[--captured-after TIME] [--captured-before TIME]
[--observed-after TIME] [--observed-before TIME]
[--session CANONICAL-ID]
[--entry-after TIME] [--entry-before TIME]
[--actor ACTOR] [--origin ORIGIN] [--kind KIND]
[--tool-name NAME] [--tool-namespace NAMESPACE]
[--limit N] [--context N] [--cursor TOKEN]
[--format human|json|jsonl]
sessions entries [--source SOURCE] [--instance INSTANCE]
[--native-id NATIVE-ID]
[--source-state present|missing|unknown]
[--workspace WORKSPACE]
[--activity-after TIME] [--activity-before TIME]
[--captured-after TIME] [--captured-before TIME]
[--observed-after TIME] [--observed-before TIME]
[--session CANONICAL-ID]
[--entry-after TIME] [--entry-before TIME]
[--actor ACTOR] [--origin ORIGIN] [--kind KIND]
[--tool-name NAME] [--tool-namespace NAMESPACE]
[--select all|first|last]
[--limit N] [--cursor TOKEN]
[--format human|json|jsonl]
sessions manifest [--source SOURCE] [--instance INSTANCE]
[--native-id NATIVE-ID]
[--source-state present|missing|unknown]
[--activity-after TIME] [--activity-before TIME]
[--captured-after TIME] [--captured-before TIME]
[--observed-after TIME] [--observed-before TIME]
[--session CANONICAL-ID]
--format json|jsonl
sessions show <canonical-id> [--entry N --context N | --from-entry N --to-entry N]
[--expected-document-digest DIGEST]
[--format human|json|jsonl]
sessions export <canonical-id> --format json|jsonl
[--full | --from-entry N --to-entry N]
[--expected-document-digest DIGEST]
sessions forget <canonical-id> [--format human|json]
sessions data repair-orphans [--format human|json]
sessions data compact [--format human|json]
sessions data clear --yes [--format human|json]
The bare command prints help. index is the only ordinary command that reads
rollout content or initializes the durable library. forget mutates only a
current initialized library. data repair-orphans and data compact are
provider-free maintenance over an existing current library; neither resolves a
source. List, search, entries, manifest, show, and export are provider-free reads
of the retained library. doctor and paths inspect runtime, library, and
registered-source readiness without indexing or creating persistent state.
Paths is a readiness report, not a canonical or FTS integrity proof. Doctor is
the explicit exact integrity audit: it reads Sessions-owned retained canonical
content, but neither command opens provider transcript content.
Without --source, index skips valid unavailable providers before writer open
and attempts the rest. If all are skipped, it exits 0 without creating the
library. Unreadable, invalid, or throwing probes fail. Explicitly selecting an
unavailable provider exits 1; an unknown source is usage exit 2. Any
incomplete attempted source exits 1; otherwise indexing exits 0. Successful
captures remain durable, complete later absence marks a session missing, and
incomplete discovery leaves source state unknown.
During index, the first SIGINT or SIGTERM requests a cooperative stop.
Sessions finishes the current atomic application operation, closes the writer,
and exits silently with 130 or 143. Already committed complete replacements
remain durable; an unfinished source run is recorded as interrupted with
unknown coverage, so partial discovery never proves a session missing. An index
or writer-cleanup failure retains precedence over the signal exit. A second
signal, SIGKILL, or a process crash is not cooperative and keeps the existing
conservative recovery behavior.
list defaults to 50 and accepts 1 through 200. Activity is
updatedAt, falling back to createdAt; missing activity sorts last, then
activity descends, then the raw source/instance/native tuple ascends with binary
collation. When another page exists, output ends with the copyable
Next cursor: <token> line. A fresh library renders No sessions found., then
the uninitialized-capture warning described below, exits 0, and does not create
state or resolve a provider. JSON emits an empty page bundle; JSONL emits one page record.
Every non-empty result includes one query-derived known retained root or
unknown.
search requires non-blank text, defaults to --match all and 20 primary hits,
and accepts 1 through 200. --context defaults to 0 and accepts 0 through 10
adjacent entries on each side. A no-match result renders No matches found.,
then a capture warning when the page scope is not complete, and exits 0.
Search, list, entries, manifest, and show read one immutable retained-library
snapshot per operation and never resolve or reopen a provider. An empty search
uses one JSON page bundle or one JSONL page record.
entries requires no search text. It defaults to --select all and 50 records,
and accepts 1 through 200. all returns every qualifying entry. first and
last return the minimum or maximum canonical entry ordinal per session after
all filters are applied. Every mode orders by binary source kind, source
instance, native ID, then entry ordinal ascending; timestamps never reorder
evidence. A fresh library renders No entries found., then the
uninitialized-capture warning, exits 0, and creates no state or provider
object. JSON emits an empty page; JSONL emits one page record.
manifest returns one complete transcript-free cohort from one immutable
retained-library snapshot. It accepts the shared session filters except
--workspace, orders revisions by binary source kind, source instance, and
native ID, and requires explicit --format json or --format jsonl. It has no
human format, cursor, pagination, or truncating limit. Exactly 10,000 matching
retained revisions can succeed; 10,001 or more fail operationally and require
narrower source, identity, state, or time filters. An uninitialized library
returns an empty manifest with uninitialized capture scope, exits 0, and
creates no state or provider object.
Each revision includes canonical identity and stored document digest,
capture/source state and timestamps, freshness, adapter version, lineage
coverage, known/unknown root, and exact stored relation, entry, segment,
omitted-segment, and logical text-byte counts. Logical bytes count every text
segment occurrence and exclude title. The result includes normalized active
filter values, fixed ordering and cohort bound, and one same-snapshot capture
scope. It excludes title, transcript content, workspace, paths, locators,
content hashes, relation graphs, and internal library/writer state. A manifest
does not pin its document bodies. A later show/export can supply the revision's
digest through --expected-document-digest; mismatching content fails before
transcript output and requires a new manifest or an explicit re-key.
show defaults to the first 50 entries. --entry N focuses one entry with 3
entries of context on each side by default; --context accepts 0 through 100 and
requires --entry. --from-entry N and --to-entry N select both inclusive
endpoints and must be supplied together. A range contains at most 200 entries and
cannot combine with --entry or --context. Missing session/entry values,
including either range endpoint outside the retained document, are operational
failures; ranges are never clamped.
Incomplete, reversed, oversized, or conflicting ranges exit 2 before library
inspection.
--expected-document-digest accepts exactly the 64 lowercase hexadecimal
characters from the manifest's fixed sha256-sessions-document-jcs-v1 digest.
Malformed values exit 2 before library inspection. A valid mismatch exits 1
with no stdout and a sanitized diagnostic that exposes neither expected nor
current digest. It takes precedence over an out-of-document entry or range, but
an absent identity remains session-not-found. A matching guard changes no
successful human, JSON, or JSONL output and works with every existing show or
export selection mode.
List/search/entries/show default to human and accept JSON or JSONL. Manifest and
export require JSON or JSONL. Human output escapes and bounds untrusted terminal
content. Machine output uses the exact closed schema-1 records in the
structured output contract. All formats report
applicable freshness/source-state/capture evidence and omit diagnostic locators
and workspace metadata.
export requires an explicit JSON or JSONL format and reads one retained
canonical snapshot. Default export is bounded; --full removes presentation
bounds and the aggregate encoded-output cap only for export-eligible fields in
that snapshot. Export accepts the same paired inclusive range and 200-entry
maximum, but a range cannot combine with --full. Export never resolves a
provider or follows relations.
forget idempotently deletes one retained Sessions copy and returns forgotten
or absent. data repair-orphans requires no confirmation and deletes only
canonical content that no retained occurrence reaches. data compact requires
no confirmation and reclaims reusable whole SQLite pages without deleting
retained rows. data clear requires --yes and deletes all known Sessions-owned
state. All leave provider data untouched.
sessions doctor --format json writes one JSON document:
{
"schemaVersion": 1,
"command": "doctor",
"ok": true,
"checks": [
{
"id": "node-runtime",
"label": "Node.js runtime",
"ok": true,
"summary": "Node.js 26.4.0 satisfies >=24.16.0",
"details": {
"version": "26.4.0",
"minimumVersion": "24.16.0"
}
}
]
}Check IDs, field names, and schemaVersion are machine-facing. Summaries are human-facing. Checks run in declared order and continue after failure. A thrown probe becomes a sanitized failed check.
The current check order is node-runtime, sqlite-fts5, library-state,
source-codex, then source-cursor. The SQLite check reports sqliteVersion and fts5SecureDelete
(supported or unsupported) in details; lack of FTS5 fails. An uninitialized
library passes. Every non-ready initialized state fails.
For ready, the library check uses an immutable snapshot and adds
canonicalIntegrity, foreignKeys, contentReachability,
orphanContentRows, orphanContentBytes, ftsStructure, ftsContent,
ftsSecureDelete, ftsRemediation, pageReclamation, runRecords,
writerLease, activeRuns, interruptedRuns, and the capture details described
below to details. Checks are
ok | failed; content reachability is ok | orphaned | inspection-failed;
orphan counts are exact non-negative decimal strings, or unknown when
inspection fails. Page reclamation is incremental | invalid; FTS secure delete
is enabled | missing | unsupported; remediation is
not-needed | rebuild-required; writer lease is free | index-live | forget-live | repair-live | compact-live | clear-live | expired | invalid;
remaining counts are non-negative decimal strings. Canonical, foreign-key,
content-reachability, or run corruption fails. FTS-only damage reports
rebuild-required without describing canonical loss. An active run is healthy
only with an index-live lease. ftsContent compares exact retained terms,
positions, and docsize with a complete contentless TEMP FTS index built from
canonical rows in bounded keyset reads and loaded under one private savepoint.
The expected index is memory-only. Doctor streams the retained and expected row
vocabularies in binary term order, requires equal terms, document counts, and
occurrence counts, then runs the bidirectional instance comparison in ranges of
at most 1,000,000 occurrences per side. One term above that target forms one
oversized range. This partitioning does not spill to disk or make total memory
constant because the complete expected index remains corpus-sized. Doctor also
reconstructs, validates, hashes, and checks metrics for every retained canonical
document. These exact whole-library checks can take minutes and use substantial
memory on a large library. Doctor never opens a writer or applies migrations.
The ready-library capture details are exactly captureStatus,
trackedSessions, retainedCurrentSessions, retainedStaleSessions,
unindexedSessions, sourceStatePresentSessions,
sourceStateMissingSessions, sourceStateUnknownSessions,
sourceCoverageComplete, sourceCoverageUnknown,
latestFailureUnavailable, latestFailureUnreadable,
latestFailureMalformed, latestFailureSourceChanged,
latestFailureUnsupportedFormat, and latestFailureRepositoryWrite.
captureStatus is complete | incomplete | inspection-failed; every other
capture detail is a non-negative decimal string, or unknown when capture
inspection fails. An incomplete scope keeps the library check healthy and uses
the summary Index schema N is ready; evidence may be incomplete. A capture
inspection failure fails the check. Any failed health condition keeps the
existing Index schema N failed health checks summary instead of the incomplete
warning.
All-pass and failed-check reports go to stdout. All-pass exits 0; any failed
check exits 1. When stderr is interactive, doctor may write a fixed initial
notice followed by fixed best-effort notices for library state, canonical
documents, capture scope, foreign keys, content reachability, FTS structure,
FTS coverage, FTS semantics, FTS deletion support, page reclamation, run records,
and writer lease health. Only phases reached by that library state are printed.
Redirected stderr stays empty for normal success and failed-check reports. These
notices never change check order, report fields, stdout, health decisions, or
exit codes. Invalid usage writes to stderr and exits 2. An unexpected failure
outside probe aggregation writes a concise stderr diagnostic and exits 1
without fabricating a report.
With SESSIONS_DOCTOR_TIMINGS=1, doctor writes one additional best-effort
sessions:doctor-timings JSON record to stderr after success or failure,
including when stderr is redirected. Its fixed phase keys are
sourceResolution, libraryState, canonicalIntegrity, captureScope,
foreignKeys, contentReachability, ftsStructure, ftsContent,
ftsSemantic, ftsSecurity, pageReclamation, runRecords, writerLease,
and total. Each phase contains only calls and elapsedMs. The diagnostic
contains no identities, paths, fingerprints, timestamps, errors, or retained
content values; it is not stored and does not change command behavior.
sessions paths --format json writes one schema-1 document. The exact schema and
example are in Current machine-readable contracts below.
Schema 1 reports the Sessions-owned application-data library, scratch workspace,
known database/sidecar paths, state, schema support, and admitted source probes.
Current state values are uninitialized, ready, migration-required,
newer-schema, incompatible, recovery-required, and unsafe.
The current retained-library storage schema is 3. Schema 2 adds exact canonical
document metrics used by manifest. Schema 3 adds one rebuildable operational
receipt for certified index-generation recovery and does not backfill proof from
older state. A schema-1 or schema-2 library is migration-required for read-only
commands; the next explicitly authorized sessions index writer applies each
pending data-preserving migration transactionally, performs full validation, and
creates a receipt only after writer setup succeeds. Readers, doctor, and paths
never migrate it implicitly.
The human format presents the same fields. An incompatible state is still a paths
report and exits 0; doctor evaluates health. Resolution/inspection failure emits
no partial report and exits 1. A pre-release migration-checksum mismatch fails
closed with recovery guidance: select a fresh SESSIONS_DATA_DIR, or back up and
remove only the obsolete Sessions-owned directory reported by sessions paths,
then index again. data clear does not claim that incompatible database.
Paths reports readiness and registered-source probes without reconstructing retained documents or checking exact FTS semantics. Consumers that need deep integrity proof must run doctor explicitly. Retained list, search, entries, and manifest results provide same-snapshot capture scope for evidence-availability decisions; paths does not replace that query evidence.
Markdown is deferred beyond V1 and --format md is not accepted today. Planned
routes are added to generated help only when implemented and contract-tested.
sessions index creates or refreshes the latest successful normalized canonical
snapshot as durable local user data. A complete later scan may mark the retained
session missing but never deletes it. Unavailable, unreadable, malformed, or
incomplete discovery proves no absence. No TTL or automatic pruning applies.
sessions forget deletes one Sessions-owned canonical snapshot/tracking record,
its owned evidence, identity-bearing historical run-item details, and now-unused
derived content without touching the provider. Aggregate run diagnostics and
incoming relation references owned by other retained snapshots remain; forget is
not a global text/reference erasure operation. If the provider still exposes the
session, a later explicit index can capture it again. Doctor reports exact
aggregate canonical content reachability. sessions data repair-orphans is the
explicit provider-free route for deleting content that no retained occurrence
reaches. It scans to completion through fixed internal committed batches under a
dedicated repair lease and reports deleted row and logical UTF-8 payload totals.
The command has no public limit, cursor, partial result, or progress contract. A
failed invocation emits no success report; already committed batches remain
durable and a fresh invocation safely restarts. A later doctor can verify that
reachability is healthy.
Against an absent library, orphan repair returns unchanged with zero totals,
creates no storage, and does not resolve a provider.
sessions data clear requires --yes and removes only the known Sessions
library database/WAL/SHM files plus the exact ephemeral scratch subtree.
Rebuilding derived FTS/query state is a different, non-destructive operation and
is not a public command. An explicit leased index writer verifies the canonical
library first and repairs FTS-only structure/content damage from canonical
content. Doctor remains read-only and reports rebuild-required; canonical
corruption fails closed instead of invoking projection repair. Orphan repair
never rebuilds FTS and fails closed when a candidate lacks its expected derived
FTS row.
Index lease acquisition marks its generation dirty. A normal index close may seal and release only that exact generation, then publishes a private database-stat-bound post-close proof after database cleanup succeeds. A matching clean seal and proof allow the next ready, sidecar-free, current-schema writer to use constant-size schema/FTS structure checks plus proportional changed-document verification.
A schema-3 receipt may certify an exact expired index generation when its lease, generation, schema version, SQLite schema cookie, and bounded FTS structure all match and no migration ran or is pending. Acquisition interrupts the abandoned run and clears its receipt before advancing ownership; the new invocation still discovers and indexes from the beginning. Certified recovery skips global canonical, foreign-key, FTS content, and FTS semantic scans. Missing, malformed, stale, free, maintenance, migration-era, or structurally invalid proof uses the complete validation/repair path. Live, clear-only, unsafe, incompatible, and newer-schema states retain their existing busy or fail-closed results.
This is an internal performance path: it adds no CLI flag, machine-readable
output field, or exit code. Direct SQLite edits outside Sessions are unsupported
and are not guaranteed to be found by either bounded open mode; sessions doctor remains the explicit full-library semantic audit.
Forget is logical deletion: freed whole pages become reusable, but the command
does not promise that the main database file shrinks. sessions data compact
is the separate physical maintenance route. It checkpoints WAL and runs bounded
incremental-vacuum transactions until the current freelist is empty. Every
committed batch is durable; a later failure emits no success report and rerunning
is safe. It reclaims whole free pages only, never repacks partially used pages,
and reports observed main-database file lengths rather than guaranteed savings.
On a fresh uninitialized library, sessions list, cursor-free sessions search,
and cursor-free sessions entries exit 0, write their format-specific empty result to stdout,
and leave stderr empty. Human writes the normal empty-result line, a blank line,
and exactly Warning: retained evidence may be incomplete (capture scope is uninitialized).;
JSON uses an empty page bundle with captureScope; JSONL uses one page record
with captureScope. They do not create storage, run
migrations, open a reader, or resolve/probe an adapter. Initialized-but-empty
uses the same output through a normal read snapshot. A supplied cursor against
absent/recreated state is stale. Other initialized non-ready states remain
operational failures. show and export of an absent identity, including in an
uninitialized library, remain sanitized not-found operational failures.
The current operational reports are exact test-backed contracts. The separate structured output contract owns transcript-bearing list/search/entries/show/export JSON and JSONL.
sessions index --format json emits the current schema-1 report. A complete
representative report is:
{
"schemaVersion": 1,
"command": "index",
"startedAt": "2026-07-14T12:00:00.000Z",
"finishedAt": "2026-07-14T12:01:00.000Z",
"counts": {
"discovered": 2,
"unchanged": 0,
"updated": 1,
"failed": 1,
"missing": 1,
"stale": 1
},
"sources": [
{
"schemaVersion": 1,
"source": {
"kind": "codex",
"instanceId": "local-sha256-v1:0000000000000000000000000000000000000000000000000000000000000000"
},
"status": "completed",
"coverage": {
"status": "complete",
"observedAt": "2026-07-14T12:00:00.000Z"
},
"startedAt": "2026-07-14T12:00:00.000Z",
"finishedAt": "2026-07-14T12:01:00.000Z",
"counts": {
"discovered": 2,
"unchanged": 0,
"updated": 1,
"failed": 1,
"missing": 1,
"stale": 1
},
"items": [
{
"identity": {
"canonicalId": "codex@local-sha256-v1%3A0000000000000000000000000000000000000000000000000000000000000000:changed-thread",
"source": {
"kind": "codex",
"instanceId": "local-sha256-v1:0000000000000000000000000000000000000000000000000000000000000000"
},
"nativeId": "changed-thread"
},
"outcome": "failed",
"failure": "source-changed"
},
{
"identity": {
"canonicalId": "codex@local-sha256-v1%3A0000000000000000000000000000000000000000000000000000000000000000:missing-thread",
"source": {
"kind": "codex",
"instanceId": "local-sha256-v1:0000000000000000000000000000000000000000000000000000000000000000"
},
"nativeId": "missing-thread"
},
"outcome": "missing"
}
],
"omittedItemCount": 0
}
],
"incompleteSources": 0,
"skippedSources": 0,
"omittedItemCount": 0
}Counts are non-negative safe integers and use exactly discovered, unchanged,
updated, failed, missing, and stale. discovered = unchanged + updated + failed; missing is reconciliation rather than discovery. Items contain a
identity with exact canonicalId, source, and opaque nativeId, and are
either missing, or failed with one of
unavailable, unreadable, malformed, source-changed,
unsupported-format, or repository-write. A source is either completed with
complete coverage and no failure, or incomplete with unknown coverage and one
of source-unavailable, source-unreadable, probe-failed, discovery-failed,
interrupted, or repository-write. An implicitly unavailable source is
skipped with reason: "source-unavailable", zero counts/items,
coverage: { "status": "not-attempted" }, and observed start/finish timestamps.
skippedSources counts skipped sources; incompleteSources counts attempted
failures. Source reports sort by raw source tuple; items retain persisted
run-item order. Top counts and omissions are safe sums.
Forget, orphan repair, physical compaction, and all-data deletion emit these exact schema-1 shapes:
{
"schemaVersion": 1,
"command": "forget",
"identity": {
"canonicalId": "codex@local:thread-id",
"source": { "kind": "codex", "instanceId": "local" },
"nativeId": "thread-id"
},
"outcome": "forgotten"
}outcome is forgotten | absent.
{
"schemaVersion": 1,
"command": "data-repair-orphans",
"outcome": "repaired",
"deletedContentRows": "2",
"deletedContentBytes": "1536"
}outcome is repaired | unchanged. Unchanged reports both aggregate values as
the exact string "0"; repaired reports a positive deleted-row count. Both
values are canonical non-negative decimal strings so totals are not constrained
by JavaScript safe integers. deletedContentBytes is the exact logical UTF-8
payload of deleted canonical text, not database length, filesystem allocation,
or reclaimed storage. Human output reports the same aggregates. The command
processes fixed internal batches to completion and exposes no public limit,
cursor, partial outcome, or progress token. Failure emits no report; a fresh
invocation safely resumes from remaining canonical state.
{
"schemaVersion": 1,
"command": "data-compact",
"outcome": "compacted",
"databaseBytesBefore": 8192,
"databaseBytesAfter": 4096,
"reclaimedDatabaseBytes": 4096
}outcome is absent | unchanged | compacted. Absent reports three zeroes;
unchanged reports equal before/after values and zero reclaimed bytes. The values
are exact non-negative safe-integer main-database file lengths observed after
required checkpoints. They are not page estimates, filesystem block allocation,
or a guaranteed amount. Human output reports the same aggregates without paths.
{
"schemaVersion": 1,
"command": "data-clear",
"outcome": "cleared",
"scratchRemoved": true,
"databaseRemoved": true,
"walRemoved": true,
"shmRemoved": false
}outcome is cleared | absent; each file boolean reports the named known file,
and scratchRemoved reports the exact owned subtree. absent requires every
boolean to be false. Orphan scratch without its lease-bearing database is a
recovery-required failure, not a successful report.
Paths schema 1 uses library and includes admitted source probes:
{
"schemaVersion": 1,
"command": "paths",
"library": {
"directory": "/home/user/.local/share/sessions",
"scratch": "/home/user/.local/share/sessions/.scratch",
"database": "/home/user/.local/share/sessions/sessions.sqlite3",
"wal": "/home/user/.local/share/sessions/sessions.sqlite3-wal",
"shm": "/home/user/.local/share/sessions/sessions.sqlite3-shm",
"initialized": false,
"state": "uninitialized",
"schemaVersion": null,
"supportedSchemaVersion": 2
},
"sources": [
{
"source": {
"kind": "codex",
"instanceId": "local-sha256-v1:0000000000000000000000000000000000000000000000000000000000000000"
},
"probe": {
"status": "ready",
"locations": [
{ "role": "codex-home", "uri": "file:///home/user/.codex" },
{ "role": "sqlite-home", "uri": "file:///home/user/.codex" }
]
}
},
{
"source": {
"kind": "cursor",
"instanceId": "local-sha256-v1:1111111111111111111111111111111111111111111111111111111111111111"
},
"probe": {
"status": "ready",
"locations": [{ "role": "cursor-home", "uri": "file:///home/user/.cursor" }]
}
}
]
}Library state values remain uninitialized, ready, migration-required,
newer-schema, incompatible, recovery-required, and unsafe. An admitted
probe status is ready | unavailable | unreadable; sources sort by raw identity
tuple. Locations retain their adapter-declared order. A malformed/thrown probe becomes
{ "status": "failed", "failure": "invalid-probe" | "probe-error", "locations": [] }
without failing paths. Failure before a stable source identity exists, or library
inspection failure, emits no partial report and exits 1.
Doctor schema 1 uses { schemaVersion, command: "doctor", ok, checks } and each
{ id, label, ok, summary, details } check. Check order is node-runtime,
sqlite-fts5, library-state, source-codex, source-cursor. The ready library-state string
details are exactly state, initialized, schemaVersion,
supportedSchemaVersion, canonicalIntegrity, foreignKeys,
contentReachability, orphanContentRows, orphanContentBytes, ftsStructure,
ftsContent, ftsSecureDelete, ftsRemediation, pageReclamation, runRecords,
writerLease, activeRuns, interruptedRuns, captureStatus,
trackedSessions, retainedCurrentSessions, retainedStaleSessions,
unindexedSessions, sourceStatePresentSessions,
sourceStateMissingSessions, sourceStateUnknownSessions,
sourceCoverageComplete, sourceCoverageUnknown,
latestFailureUnavailable, latestFailureUnreadable,
latestFailureMalformed, latestFailureSourceChanged,
latestFailureUnsupportedFormat, and latestFailureRepositoryWrite; non-ready
states retain the first four and add only applicable reason/target.
canonicalIntegrity,
foreign-key, FTS structure/content, and run-record values are ok | failed;
content reachability is ok | orphaned | inspection-failed; orphan rows and
logical UTF-8 bytes are exact decimal strings, or unknown after an inspection
failure. FTS secure-delete is enabled | missing | unsupported; FTS remediation
is not-needed | rebuild-required; writer-lease values are free, index-live,
forget-live, repair-live, compact-live, clear-live, expired, or
invalid. Ready-library capture values follow the health and warning semantics
defined in Doctor JSON above.
An admitted source-codex or source-cursor check has only probeStatus with value
ready | unavailable | unreadable. Ready and optional unavailable pass;
unreadable fails. A malformed or thrown probe fails with exactly
{ "probeStatus": "failed", "failure": "invalid-probe" | "probe-error" }.
Doctor never duplicates the roots owned by paths. Summaries and labels are
human-facing; IDs, order, detail keys/values, and schema version are
machine-facing.
Supported storage schema 3 includes the writer clean-seal state, canonical
document digests, exact document metrics, and the rebuildable index-generation
receipt. The schema-2-to-3 migration preserves retained evidence but manufactures
no receipt; the first schema-3 writer must prove the library through full
validation. There is no
compatibility migration from earlier development checksums; they fail closed
and require the documented fresh data-directory or exact Sessions-owned-directory
reset and reindex. Supported releases beginning with 0.1.0 use ordered,
data-preserving migrations.
Canonical printable IDs use
<kind>@<percent-encoded-instance-id>:<percent-encoded-native-id>, for example
codex@default:opaque-id. Kind is an open lowercase adapter slug. Instance and
native IDs are case-sensitive opaque values; delimiters are escaped and values
are never Unicode-normalized.
Each filter accepts one value; different filters combine with AND. Exact values use their case-sensitive canonical representation:
--sourceselects an exact source kind.--instanceselects an exact source instance and requires--source.--native-idselects an exact provider-native session ID. It can be used alone and can return multiple retained canonical sessions because native IDs are unique only within a source instance.--sourceand--instancenarrow the match.--source-stateacceptspresent,missing, orunknown.--workspaceselects the exact retained workspace value for list, search, and entries. Manifest intentionally does not accept or disclose it.--activity-after/--activity-beforebound effective provider activity.--captured-after/--captured-beforebound successful capture time.--observed-after/--observed-beforebound effective source-observation time.--sessionselects one exact canonical identity. Combining it with--native-iduses the same AND rule; contradictory identities return an empty successful result.
Native IDs are non-empty, case-sensitive opaque values. Sessions does not parse,
normalize, prefix-match, or send them through transcript FTS. List results expose
the canonical identity required by show, export, and forget; manifest
revisions expose the same identity without transcript content. Those singular or
destructive commands do not auto-resolve native IDs across source instances.
Times must be canonical UTC with milliseconds, such as
2026-07-14T12:00:00.000Z. Every after/before bound is exclusive; equal or
inverted pairs are invalid usage. A missing timestamp does not satisfy either
bound.
Effective provider activity is updatedAt, falling back to createdAt only
when updatedAt is absent. A session missing both does not match an activity
bound. Capture, source-observation, and entry time are never substituted.
Effective source state is unknown while the source instance's latest coverage
is unknown; otherwise it is that retained session's present/missing tracking
state. Effective source-observation time follows the same evidence boundary: use
the source coverage observation while coverage is unknown, otherwise use the
session presence observation. lastSeenAt, capture time, and provider activity
time are never substituted.
Every list, search, and entries result carries one page-level captureScope;
manifest carries one cohort-level captureScope.
The query rows and this aggregate are read from the same retained-library
snapshot. It measures what Sessions has captured or failed to capture; it is not
another result count and contains no session identities, filter values, paths,
workspace values, transcript text, or other private fields.
status is uninitialized for an absent library. In an initialized library it
is complete only when at least one applicable registered source exists, all
applicable source coverage is complete, and every assessed tracked session has
a current canonical snapshot. Every other initialized scope is incomplete.
The count partitions are exact:
trackedSessionsequalsretainedSessions.current + retainedSessions.stale + unindexedSessions;trackedSessionsalso equalssourceState.present + sourceState.missing + sourceState.unknown; andretainedSessions.stale + unindexedSessionsequals the sum of the sixlatestFailurescounts.
Source state uses the effective coverage boundary described above. A first-seen
failure is counted as unindexed even when its retained tracking presence is
missing. Source coverage counts registered source instances, not sessions.
Latest failures use unavailable, unreadable, malformed, sourceChanged,
unsupportedFormat, and repositoryWrite.
Capture aggregation can apply exact source, instance, native-ID, source-state,
and canonical-session filters to tracking evidence. Their structured names are
source, instance, nativeId, sourceState, and session. Active workspace,
activity/capture/observation time, entry time, actor, origin, entry-kind, tool,
and search-text filters are listed in unassessedFilters; Sessions does not
classify an unindexed session as matching or not matching canonical content it
does not have. appliedFilters and unassessedFilters use one fixed canonical
order and report names only. Search text is therefore always unassessed, even
though it remains active for selecting search hits.
Human output is silent for a complete page scope. An incomplete or uninitialized
scope appends one sanitized warning after the normal result, including empty
results. JSON includes the aggregate once in the page or manifest bundle; JSONL
includes it once in the page or manifest envelope and never repeats it on
session, hit, entry, or revision records.
Search support remains query-wide evidence about matching retained text.
captureScope instead describes capture availability, so zero hits never by
itself proves that the providers contain no matching evidence.
Search and entries share exact entry filters:
- exclusive
--entry-after/--entry-beforecanonical entry timestamps; - exact
--actorvalueshuman,model,tool,system, orunknown; - exact
--originvalueshuman,injected,delegated,replayed-copied,model,tool,system, orunknown; - exact
--kind,--tool-name, and--tool-namespacevalues.
Entry time, actor, kind, and tool fields apply to the canonical entry. Tool name
and namespace combine with AND and select observed tool-call entries only. A
call without a namespace does not match a namespace filter. Text mentions,
injected catalogs, and agent claims never manufacture a call or prove a named
skill or workflow ran.
Origin applies to canonical segments. For entries, any matching segment qualifies, including an omitted segment; an empty entry does not. Search requires a matching text occurrence, so omitted content cannot be a primary search match. All exact filters combine with AND.
sessions entries selects entry structure without a text predicate or FTS. The
selection is applied after every session and entry filter. first and last
choose the lowest or highest qualifying canonical ordinal in each session, not
the earliest or latest timestamp.
Each result includes its retained session summary, exact entry coordinate and
observed tool/linkage fields, exact text and omitted-segment counts, one optional
preview, and root attribution. Without --origin, the lowest-ordinal text
segment supplies the preview. With --origin, only the lowest-ordinal matching
text segment can supply it. If only omitted content matches, the result has no
preview rather than showing unrelated text. A preview is bounded to 512 UTF-8
bytes and keeps the full text content hash. The unpreviewed count is the number
of retained text segments not represented by that one preview.
Root attribution is either one known retained session reference or unknown,
using the lineage rules below. It is query-derived evidence only and does not
change canonical documents, document digests, exports, filters, or ordering.
Human output prints the escaped session/entry heading, root, preview or
(no text preview), content counts, and any next cursor.
Search splits well-formed input on Unicode whitespace, joins it with single
spaces, and admits at most 32 terms and 4,096 UTF-8 bytes of that canonical text.
It quotes every term as literal FTS data. --match all is the default and joins
terms with logical AND; --match any joins them with logical OR. Quotes, FTS
keywords, paths, opaque IDs, operators, and punctuation are never interpreted as
public FTS syntax. CLI argument parsing happens first: use
sessions search -- "-term"
when search text begins with a dash. Without the delimiter, a leading-dash token
is an unknown option and invalid usage. Blank input is invalid usage. Non-blank
input that yields no tokens under the fixed FTS5 unicode61 tokenizer succeeds with no matches.
Lexical case/diacritic behavior follows that tokenizer; it is distinct from the
case-sensitive exact filters below.
Filters constrain the primary matching occurrence/entry; returned context need not satisfy them. Origin applies to the matching text occurrence.
Every hit reports matchedTerms in first-query order, with exact unique query
terms that matched an eligible text occurrence in that entry. An origin filter
also constrains this evidence. Matched terms are derived from candidate-local
term checks, never parsed from the snippet. In all mode they are the query's
unique terms.
Qualifying text occurrences group by canonical session identity and entry ordinal, yielding one primary hit per entry. The best-ranked matching segment, then its lowest segment ordinal, supplies the snippet; the hit reports other matching segments without duplicating the entry. Page limits count primary hits, not matching segments or context.
Entry rank uses the best content-level FTS5 BM25 value, then effective session
activity (updatedAt, falling back to createdAt) descending with missing values
last, then binary source kind/instance/native identity ascending, then entry
ordinal. Repeated occurrences do not improve relevance. These tie rules make the
same retained snapshot and query deterministic.
Each snippet and context body is at most 512 UTF-8 bytes and marks truncation.
Human rendering uses the … [truncated] suffix.
--context N adds at most N neighboring entries on each side. Independently,
search adds direct inbound/outbound relation partners only when the observed pair
is one tool-call and one tool-result. Linked expansion is non-recursive,
deduplicated, ordinal-sorted, capped at 20 additions, and reports truncation.
Turn/lifecycle and every other relatedEntryOrdinal pairing are excluded.
Results retain their relation but never inherit call name or namespace. When the
linked cap is exceeded, output includes
Linked context: truncated at 20 entries.
Search support is calculated after all filters and before page slicing:
- matching text-segment occurrences;
- distinct collision-safe canonical content values;
- distinct resolved known session roots; and
- distinct matching sessions whose root cannot be resolved.
Canonical documents record lineage coverage as complete or unknown.
High-confidence parent, fork, and continuation targets point rootward; child
targets are outward and do not change the current root. Complete coverage with no
rootward edge proves the session is its own root. Unknown coverage/kind,
non-high-confidence ancestry, a missing retained target, a cycle, or ancestry
paths that diverge to different roots stays unknown. Paths that converge on one
root remain known. Equal text/hash and inverse-relation inference never create
lineage, and one support unit is never substituted for another.
List results, search hits, and entry inventory records each expose that same
query-derived known root or unknown. Attribution can point to a retained root
outside the current filters. It does not change filtering, ranking, ordering,
canonical documents, document digests, show, or export.
List, search, and entries expose an opaque next cursor only when more primary rows exist.
The token binds its command, the complete normalized query/order contract, a
random library instance identity, the current writer generation, and the next
offset. Changing query text, term mode, filters, bounds, limit, or context makes the cursor
query-mismatched. Malformed, wrong-command, and query-mismatched cursors are
invalid usage (exit 2). A cursor from a recreated library or any later admitted
writer generation—including a no-op index writer—is stale (exit 1). Cursors
are continuation tokens, not durable bookmarks or public encoded schemas.
- Stdout: requested human, JSON, JSONL, or transcript data.
- Stderr: usage diagnostics, warnings, and operational errors that are not the requested report.
- Exit
0: success, including an empty result set. - Exit
1: operational or capability failure. - Exit
2: invalid command, flag, value, or required argument.
sessions index, sessions data repair-orphans, and sessions data compact
write one startup notice to interactive stderr warning that the operation may
take a couple of minutes. Redirected or captured stderr remains quiet on
success. Interactive indexing also names its writer-open mode (fast, new
library preparation, bounded certified-generation recovery, or full-library
verification) and each active
full-validation phase. These best-effort messages are non-versioned and
non-semantic. They expose no path, identity, fingerprint, transcript value,
percentage, elapsed time, work total, ETA, cursor, partial outcome, or
machine-readable progress contract.
The contributor diagnostic SESSIONS_INDEX_TIMINGS=1 sessions index ... is the
only exception to quiet redirected stderr on successful indexing. It adds one
prefixed aggregate JSON timing record to stderr after the operation while
leaving stdout, the index report, and the exit code unchanged. It is not a
versioned public DTO or progress contract and contains only fixed phase names,
call counts, and elapsed milliseconds. Writer-open work is split into canonical,
foreign-key, FTS structure, FTS content, FTS semantic, and FTS rebuild phases.
Other values and commands ignore the switch.
Unknown flags and values fail. Color is optional and honors NO_COLOR.
Concurrent index/forget/repair/compact/clear ownership is a sanitized
Session library is busy operational failure; lease tokens, owners, and timing
details are never rendered.
Every list/search/entries/manifest/show/export JSON/JSONL record has numeric schemaVersion: 1, a
command, a record type, and disposition: "untrusted-history". JSON is one
bundle. JSONL is an ordered set of compact, independently attributable records. The exact closed DTOs,
optional/null rules, record order, UTF-8 selection accounting, examples, and
16 MiB fail-before-output limit are in the
structured output contract.
Entry-bearing records preserve canonical coordinates, available exact tool/linkage values, segment provenance, and full canonical content hashes. Omitted non-text values include only their admitted broad class and canonical source-type token—never payload bytes, URLs, local paths, placeholder text, or a hash. Library records distinguish freshness from source state and include the latest successful capture, source observation, last-good adapter version, and document digest.
JSON/JSONL never mixes progress or warnings into stdout. The complete encoded
result is validated before the first write. Every bounded machine result at or
below 16 MiB succeeds; one byte over exits 1 with no stdout. List/search/entries/manifest can be
narrowed. Show is always bounded. Default export is bounded, while explicit
export --full is the sole structured route exempt from the aggregate cap.
Show/export ranges choose an exact contiguous entry window before the existing segment/text bounds run. Therefore selected entries can still report omitted segments or truncated text. Range selection does not alter the complete-document digest. The current reader reconstructs and validates the complete retained document before selecting the requested window; ranges bound returned evidence, not SQLite read cost.
An expected-document guard is checked against that complete verified document before actual entry bounds are resolved. It identifies equal canonical public content, not an indexing generation or all manifest attribution: freshness, source state, observation time, adapter version, and root attribution may change while the digest still matches. The guard is neither a lease nor historical revision storage, and every later hydration must supply it again.
Export reads exactly one retained canonical snapshot and never probes or reopens a provider source. Known relations are metadata only and do not recursively include other session bodies. Generated metadata excludes source/input locators, source metadata, provider roots, workspace, and attachment paths. Faithful title or transcript text is not automatically path- or secret-redacted. Sessions does not import, upload, paste, call provider APIs, create a destination conversation, manage destination context limits, or infer transfer lineage from equal text or matching digests.
Markdown remains deferred post-V1 presentation work. It is not a current format and any later design may not change the eligible evidence or document-digest semantics defined by JSON/JSONL.