Expand description
Transcript tailer.
tapes’ wire capture yields a complete call inventory but no causal/fork
skeleton — that lives only in the harness’s on-disk transcripts
(~/.claude/projects/<cwd-encoded>/<sid>.jsonl plus each session’s
subagents/ directory). The transcript lane (POST /v1/ingest/transcript)
carries them. This module is the client-side half every capture client needs:
files— discovery of a session’s upload set and JSONL→records conversion. Extracted verbatim from a daemon client, which mirrors the Go reference client, so every client produces byte-identical upload sets for the same on-disk state.trigger— the push state machine: 30 s quiescence, 5 min periodic safety net, and a final push on harness exit.payload— the ingest payload shape, a cross-language contract with the Go server.sweep— a startup scan of the transcript tree, which finds sessions that ended while the client was not running. New here rather than moved: it closes a gap in any purely registry-driven discovery.codex_anchors— Codex’s counterpart for the fork skeleton alone. Codex writes no per-session transcript tree; the spawn edge lives in its rollout files assub_agent_activityrecords, and this module derives the anchor rows that carry it down the same lane.
The seed’s Transcript { path, harness } placeholder is gone;
files::TranscriptFile is the real shape, and it carries the subagent id and
fork metadata that a transcript upload actually needs.
§What stays with each client
Delivery, auth, and retry. The HTTP call, the request timeout, the response parsing, the credential — and the failure backoff schedule — differ per client, and auth differs most of all: a client fronted by its own cloud edge rides a bespoke auth header of its own so that edge admits the request, and no such header is part of the tapes contract. So does each client’s notion of which sessions to track: a daemon client’s registry is fed by its proxy’s per-request attribution, and a standalone client will have a different hook.
§Why the eager design is safe
Every push decision here errs toward pushing again, because the ingest endpoint
is idempotent by construction: the server keys rows on a content hash of the
records array, so unchanged content answers deduped and a grown transcript
appends a new version. The fingerprint driving
trigger::TriggerInput::dirty is deliberately coarse (size + mtime), retries
re-read the files rather than buffering anything, and sweep re-offers
transcripts a previous process may already have sent. The transcript files on
disk are the spool; there is no client-side queue to lose.
Re-exports§
pub use codex_anchors::AnchorKind;pub use codex_anchors::CodexAnchorScanner;pub use codex_anchors::SubAgentAnchor;pub use codex_anchors::anchor_records;pub use codex_anchors::build_anchor_payload;pub use codex_anchors::parse_subagent_anchors;pub use files::FileFingerprint;pub use files::SubagentMeta;pub use files::TranscriptFile;pub use files::fingerprint;pub use files::jsonl_to_records;pub use files::session_files;pub use payload::INGEST_PATH;pub use payload::IngestEnvelope;pub use payload::KIND_INTERACTED;pub use payload::TranscriptPayload;pub use payload::TranscriptSession;pub use payload::build_payload;pub use sweep::SweepOptions;pub use sweep::SweptSession;pub use sweep::sweep;pub use trigger::DEFAULT_PERIODIC;pub use trigger::DEFAULT_QUIESCENCE;pub use trigger::DEFAULT_TICK;pub use trigger::PushReason;pub use trigger::TriggerInput;pub use trigger::TriggerPolicy;pub use trigger::decide;
Modules§
- codex_
anchors - Codex sub-agent-activity anchors: the spawn edge that never reaches the wire.
- files
- Transcript-file discovery and JSONL handling.
- payload
- The transcript-lane wire payload.
- sweep
- Sweep-on-start: find transcripts on disk that no live session would reveal.
- trigger
- The per-session push trigger.