transcript

package
v0.5.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 9, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package transcript reads other coding agents' on-disk session logs and normalises them into a common shape.

It is the front half of `logos ingest`. The thesis is "read transcripts, never replay them": a raw transcript resumed as context hands the next agent every abandoned approach as a live option, which is the stale-answer failure the continuity benchmark measures. So this package's job stops at reading — no model, no vault writes, no network. Distillation into a checkpoint candidate happens in distil.go and the queue in internal/session.

Everything a reader returns is untrusted. A transcript is other agents' full text including whatever they read off the web, and it is the most hostile input this codebase accepts. Callers that put a Session in front of a model must frame it as evidence, never instructions (see internal/untrusted).

Reading is strictly read-only: no function here opens a source file for write, ever. TestIngestNeverWritesToTheSourceTranscript asserts the mtimes.

Index

Constants

View Source
const LogosClaudeProjectsEnv = "LOGOS_CLAUDE_PROJECTS"

LogosClaudeProjectsEnv overrides the Claude Code projects directory, so a test points at a fixture tree instead of the real one. Same pattern as LOGOS_VAULT.

View Source
const LogosCodexSessionsEnv = "LOGOS_CODEX_SESSIONS"

LogosCodexSessionsEnv overrides the Codex sessions directory for tests.

View Source
const LogosCursorStorageEnv = "LOGOS_CURSOR_STORAGE"

LogosCursorStorageEnv overrides the Cursor globalStorage directory, so a test points at a fixture instead of the developer's real chat history.

View Source
const TxcriptPrefix = "txcript:"

TxcriptPrefix marks a source held by txcript rather than a file on disk. Anything that stats or copies a candidate's source has to check for it first: there is no file there, and the session is not gone.

Variables

This section is empty.

Functions

func ClaudeConfigDir added in v0.5.7

func ClaudeConfigDir() string

ClaudeConfigDir is where Claude Code keeps everything it writes: CLAUDE_CONFIG_DIR when it is set, as Claude Code reads it, otherwise ~/.claude. ~/.claude holds none of a moved user's sessions, rules or memory, so every reader of Claude Code's files asks here, and they cannot disagree about where it lives. Empty when neither can be named.

func ClaudeProjectsRoot added in v0.5.8

func ClaudeProjectsRoot() string

ClaudeProjectsRoot and CodexSessionsRoot are where each host keeps its transcripts, as every reader here resolves them — moved config directories and the test overrides included — so a reader outside this package (the spend dashboard) cannot look somewhere the importers do not. Empty when the host's directory is not there.

func CodexSessionsRoot added in v0.5.8

func CodexSessionsRoot() string

func FirstCwd added in v0.5.0

func FirstCwd(path string) string

FirstCwd is the working directory a Claude Code transcript records, read from its first lines only, or "" when none of them carries one.

#196: MayBelongTo rules a folder out by its slug, and a slug only holds the path. A repository checked out as code/web whose .logos-project marker says storefront files its checkpoints under storefront, so every one of its transcripts was ruled out unread and a killed session there was never swept. The cwd settles it, and it is on nearly every line, so this stops at the first one that has it rather than parsing a transcript that may run to a hundred megabytes. Measured on a real machine: two such transcripts in the sweep's window, ten lines read between them, under three milliseconds.

func Harnesses

func Harnesses() []string

Harnesses lists every harness name ingest knows how to try, for help text and error messages.

func IsTxcriptSource added in v0.4.9

func IsTxcriptSource(source string) bool

IsTxcriptSource reports whether a candidate's source names a txcript session.

func MayBelongTo added in v0.4.9

func MayBelongTo(harness, path, project string) bool

MayBelongTo reports whether the transcript at path could be a session of project, without reading it. It answers false only when it is sure: a Claude Code transcript sits in a folder named for its launch directory with every separator turned into "-", which cannot be decoded but can rule a project out, and parsing a week of them to learn their cwd took over a second on every resume. Other harnesses keep no project in the path, so every one of theirs may belong.

func Sessions

func Sessions(harness string) ([]string, error)

Sessions lists discoverable session file paths for one harness. An unknown harness, or one whose format needs txcript when txcript is absent, returns a SkipReason error naming the fix rather than an empty slice.

func SourceFile added in v0.4.5

func SourceFile(source string) string

SourceFile returns the file on disk that a recorded source path names.

Cursor addresses a session as <storage file>#<chat id>, so a caller asking the plain question "is this transcript still there?" cannot just stat the string: every Cursor session would read as deleted while its database sat untouched. The addressing scheme was invented here, so the answer lives here too, rather than in each caller reinventing the split.

func StillOpen added in v0.4.9

func StillOpen(harness string) func(path string) bool

StillOpen reports, for a harness, which of its transcripts belong to a session that is still running. A harness that does not say is never open: the caller falls back to how long a transcript has gone unwritten.

That fallback is a guess, and a bad one for a window left idle: past it, a session still open was recorded as ended, and the work it went on to do was never recorded, because its transcript was already settled. Claude Code keeps a file per running process, in sessions/ beside projects/, naming the session the process is on — so for it this is a fact, not a guess.

Types

type Availability

type Availability struct {
	Harness  string
	Root     string
	Found    bool
	Reason   string // when !Found: why it was skipped, per invariant 3
	Sessions int    // discoverable session files, best effort
}

Availability describes one harness and whether ingest can read it here.

func Available

func Available() []Availability

Available reports every known harness and its status on this machine, sorted by name. A harness with a reader but no session directory, and a harness with no native reader and no txcript, both say why rather than vanishing from the list.

type Session

type Session struct {
	Harness string // "claude-code", "codex", "cursor", ...
	ID      string // harness-native session id
	Path    string // absolute path to the source file
	Project string // best-effort repo/dir the session ran in
	// Cwd is the directory the host recorded the session running in, "" when
	// it recorded none. Project is only its basename; a caller that names
	// projects the way the server does needs the directory itself.
	Cwd     string
	Started int64
	Ended   int64
	Turns   []Turn
	Hash    string // content hash of the source, for idempotence

	// Skipped counts lines the reader could not parse but stepped over rather
	// than failing the whole session on. Surfaced, never swallowed (invariant
	// 3): a session with Skipped > 0 is reported as partially read.
	Skipped int

	// Private counts the <private> spans kept out of the turns. Each one is
	// replaced by secret.PrivateMarker when the file is read, so nothing
	// downstream — the auto record, harvest, the evidence served to a
	// distilling agent — ever holds the text.
	Private int
}

Session is one agent session, normalised across harnesses.

func ReadFile

func ReadFile(harness, path string) (*Session, error)

ReadFile parses one session file with the reader for harness.

func ReadInterchange

func ReadInterchange(r io.Reader) (*Session, error)

ReadInterchange parses txcript Simple interchange JSON from r into a Session. No file is touched; the source pointer is whatever the caller records.

type SkipReason

type SkipReason struct {
	Harness string
	Why     string
}

SkipReason is the "named and skipped, not silently dropped" error (invariant 3). It carries the harness and a sentence a user can act on.

func (*SkipReason) Error

func (e *SkipReason) Error() string

type Turn

type Turn struct {
	Role   string // "user" | "assistant" | "tool" | "host" (text the host wrote into the user's turn, where it says so)
	Text   string
	Tool   string // tool name, when Role == "tool"
	Status string // "ok" | "error", when known
	// Input is the tool invocation — the shell command, the file path — carried
	// on the tool turn so a harvest can list commands run and files touched
	// without a model. Empty when the harness did not record it.
	Input string
}

Turn is one exchange in a session, in wall-clock order.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL