works.iterative.claude.core.log

Members list

Type members

Classlikes

case class ArchiveConfig(vendorProjectsDir: Path, archiveDir: Path, cwd: Path)

Configuration for ConversationArchive.

Configuration for ConversationArchive.

Value parameters

archiveDir

destination root the session tree is mirrored into.

cwd

the known working directory a session ran under; the record is located by encoding this cwd, never by decoding a directory name.

vendorProjectsDir

the Claude projects directory holding per-cwd session trees. Configurable because CLAUDE_CONFIG_DIR relocates it (e.g. /home/mph/.claude-iw, not ~/.claude). Use ArchiveConfig.locating to derive it from a config-dir override and home directory.

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object ArchiveConfig

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
enum ArchiveError extends Throwable

Errors surfaced by ConversationArchive operations. Extends Throwable so an implementation may also let it propagate through effect types whose error channel is Throwable.

Errors surfaced by ConversationArchive operations. Extends Throwable so an implementation may also let it propagate through effect types whose error channel is Throwable.

Attributes

Supertypes
trait Enum
trait Product
trait Equals
class Throwable
trait Serializable
class Object
trait Matchable
class Any
Show all
object ArchivePaths

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type

Reads the last complete lines of a byte region without scanning it from the start.

Reads the last complete lines of a byte region without scanning it from the start.

The region is a file being appended to by the CLI. Lines are delimited by 0x0A; because no byte of a multi-byte UTF-8 sequence is ever 0x0A, splitting on the raw byte never severs a character, so each line's byte slice decodes as UTF-8 independently. A single trailing \r is stripped so a CRLF-terminated line reads the same as an LF-terminated one.

Torn-final-line rule: bytes after the last 0x0A in the region are a line whose terminating newline has not been written yet — a live append in progress — and are excluded from the tail. A region that ends exactly on a newline (or on a previous page's cursor, which is always a line start) has no such remainder.

Blocks are read backward from the region end, only far enough to expose the requested number of complete lines, so cost is proportional to the page, not the region.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
trait ConversationArchive[F[_]]

Custody of a session's record: locate it, read its conversation entries (main thread and sub-agent sidechains), and mirror the whole tree into an archive directory.

Custody of a session's record: locate it, read its conversation entries (main thread and sub-agent sidechains), and mirror the whole tree into an archive directory.

Every locate and read resolves the session vendor-first, falling back to the archive mirror once the vendor tree has been pruned; the located record's root names which one won. Locating encodes a known cwd into a project directory — never decodes a directory name, which is ambiguous — and looks for that directory under the vendor projects tree first, then under the mirror. The record is a tree (the main .jsonl plus the sub-agent .jsonl and .meta.json sidechains), so the mirror copies the tree, not a single file. Entry reads tolerate vendor drift by degrading unrecognized lines to raw entries rather than losing them.

Following a session while it is being written is deliberately not here. Its shape is an interval and a stream of batches, both of which name the effect system in a way none of the reads below do, and there is one interpreter to serve. It lives on that interpreter instead — works.iterative.claude.zio.log.ZioConversationArchive.follow — and a second interpreter is the moment to decide whether the port should carry it.

Type parameters

F

the effect type; the abstract EntryStream lets each backend pick its own streaming type.

Attributes

Supertypes
class Object
trait Matchable
class Any
trait ConversationLogIndex[F[_]]

Attributes

Supertypes
class Object
trait Matchable
class Any
trait ConversationLogReader[F[_]]

Attributes

Supertypes
class Object
trait Matchable
class Any

Reads the complete lines appended to a file after a byte offset.

Reads the complete lines appended to a file after a byte offset.

The region is a file the CLI is still writing. Lines are delimited by 0x0A; because no byte of a multi-byte UTF-8 sequence is ever 0x0A, splitting on the raw byte never severs a character, so each line's byte slice decodes as UTF-8 independently. A single trailing \r is stripped so a CRLF-terminated line reads the same as an LF-terminated one — the same rules BackwardLineReader reads a tail by, so a transcript read once at the end and then followed says the same thing either way.

Torn-final-line rule: bytes after the last 0x0A are a line whose terminating newline has not been written yet. They are left unread and the returned cursor stops before them, so the next read starts at that line and sees it whole once the writer finishes it. An entry is therefore never shown half-written, and never shown twice.

The cursor is the whole of what a follower has to remember: it is a byte position into an append-only file, so feeding it back is what makes reading resumable without holding on to anything that was read.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
object LiveEntries

A session's live stream, written as the entries its transcript will hold.

A session's live stream, written as the entries its transcript will hold.

A page reads a conversation from the transcript, and a transcript is only what the CLI has finished writing down. The same conversation is also coming past on the process's own stream, ahead of the file — so this puts it in the transcript's shape, and everything downstream (the reader, the rendering, the follow) stays one code path with one encoding.

That is the whole point: it does not render, and there is no second way for a row to be drawn. A live entry and the file's entry for the same turn produce the same row, so a page that has been shown the live one and then re-reads the file sees nothing move.

Two kinds of message carry conversation and become entries. Everything else on the stream — the session's own bookkeeping, keep-alives, control replies, anything unparsed — is not a turn and yields nothing, the same as the bookkeeping lines a transcript file holds.

The end-of-turn envelope is the exception, and only when the turn ended badly. A turn that dies has no words to write down, so the transcript stops mid-conversation and says nothing about why; the envelope is the only account of the ending anyone gets, and a reader who is not shown it is left waiting for an answer that is never coming.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type

One planned mirror operation for a single file, keyed by its path relative to the tree root.

One planned mirror operation for a single file, keyed by its path relative to the tree root.

Attributes

Supertypes
trait Enum
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
case class MirrorPlan(actions: Seq[MirrorAction])

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
object MirrorPlanner

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
object PageSize

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
PageSize.type

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type

One line of a transcript, as the bytes on either side of it say it is.

One line of a transcript, as the bytes on either side of it say it is.

A transcript is read in two directions — backward for a page, forward for a follow — and the two must agree on what a line is, or a line read one way and the same line read the other would not be the same string.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type