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
- func FirstCwd(path string) string
- func Harnesses() []string
- func IsTxcriptSource(source string) bool
- func MayBelongTo(harness, path, project string) bool
- func Sessions(harness string) ([]string, error)
- func SourceFile(source string) string
- func StillOpen(harness string) func(path string) bool
- type Availability
- type Session
- type SkipReason
- type Turn
Constants ¶
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.
const LogosCodexSessionsEnv = "LOGOS_CODEX_SESSIONS"
LogosCodexSessionsEnv overrides the Codex sessions directory for tests.
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.
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 FirstCwd ¶ added in v0.5.0
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
IsTxcriptSource reports whether a candidate's source names a txcript session.
func MayBelongTo ¶ added in v0.4.9
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 ¶
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
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
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.
type SkipReason ¶
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.