Storage Root

The storage root is a directory. Everything the project keeps is under it, in two halves: what was collected, one directory per session, and what was assembled, one directory per conversation.

<root>/
  <session-id>/
    session.state                        next_seq, liveness, last scan
    .lock                                one collector per session
    streams/
      main/
        transcript.cursor                how far the source has been read
        transcript-<collected-at>-<seq>.sd
      <agent-id>/                        one directory per child agent
        transcript.cursor
        transcript-<collected-at>-<seq>.sd
        meta.cursor
        meta-<collected-at>-<seq>.sd
    runs/
      <run-id>/                          one directory per workflow run
        journal.cursor · journal-…sd
        manifest.cursor · manifest-…sd
        script.cursor · script-…sd
    index/
      entries.bin                        the derived index
      index.state
  _conversations/
    <conversation-id>/
      conversation.state                 the head pointer, outside every digest
      .lock
      rounds/
        r000001-<digest>.sf
        r000002-<digest>.sf

Child streams are flat siblings of main, keyed by agent id. The storage path deliberately does not mirror the source tree: a path must not encode a relationship the pipeline is supposed to derive.

Landed files

A landed file is Session Data: one header line and then one record per source record. It is written once, to a temporary name, synced, renamed into place and made read-only. It is never appended to and never rewritten. A source that keeps growing produces more files, each starting where the previous cursor stopped.

The sequence number in the name is issued per session and is monotonic across every stream in it. That is what lets assembly track progress with one watermark instead of one entry per stream, and it is why a session is collected single-threaded under its lock. The filesystem is the authority on the counter: on start, a collector raises its counter above the highest sequence already on disk, so a crash between writing a file and saving state cannot reissue a number.

A file lands before its cursor is committed. A crash between the two lands the same records twice in the next pass, and assembly removes the duplicate. The reverse order would lose data.

The index

index/ holds identifiers and roles, never text: which record is in which stream, which call a fragment belongs to, which tool use a result answers, which child a launch started. Assembly reads this and never the payloads. It is derived and disposable. Delete it and the next collect or parse rebuilds it from the landed files; a schema change discards it rather than migrating it.

The chain

_conversations/<id>/rounds/ holds Session Flow: an append-only chain of immutable rounds. The conversation is the fold of every round; there is no other state. The file name carries the round number and the first twelve characters of the round’s digest. conversation.state is a cache of the head. It is rebuilt by listing the directory, because a crash between publishing a round and saving state must not lose the round.

What travels

A storage root is complete on its own. A copy of it can be listed, verified, re-parsed and read on another machine with no source files and no collector: the landed files name the adapter that wrote them, so the index rebuilds from them alone, and the chain head is recovered from the rounds directory. asz verify checks every landed file against its digest and every round against its commit digest without touching the source.

Size

Measured on 2026-09-03 on one machine’s storage root of 48 Claude Code sessions:

Files Size Against the source
landed .sd 6,615 800 MB describes 1.2 GB of source records
rounds .sf 97 105 MB 8.9%
index 48 52 MB 4.5%
cursors and state 6,766 3 MB

The landed data is smaller than its source because a record keeps its content and its provenance, not its envelope. Of the transcript content, 550 MB is carried verbatim; 64,667 reasoning parts are marked unavailable because Claude Code stores only a signature for them, and each record says so. The store had also outlived its source: it held 48 sessions where the source directory still had 44.

Retention

The session directory is the unit of retention: removing it purges everything collected for that session. Removing index/ costs a rebuild. Removing a conversation’s rounds loses the structure only; a new parse rebuilds it from the landed files, and because a round carries no wall-clock time, the same landed range and the same parser version reproduce the same bytes and the same digest.