sessions

package module
v1.6.0 Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 2 Imported by: 0

README

agent-ouija

Read AI-agent session state off disk. A standalone, dependency-free Go library that knows where Claude Code keeps everything — transcripts, subagents, teams, debug logs, hook payloads, settings, the live-session registry, the statusline stdin schema — and parses all of it losslessly.

Every Claude Code format change lands here once, instead of once per tool.

go get github.com/kylesnowschwartz/agent-ouija

Quick start

import (
    "github.com/kylesnowschwartz/agent-ouija/claude/claudedir"
    "github.com/kylesnowschwartz/agent-ouija/claude/discover"
    "github.com/kylesnowschwartz/agent-ouija/claude/transcript"
)

root, _ := claudedir.DefaultRoot()                     // ~/.claude

// Which sessions exist for this project?
sessions, _ := discover.DiscoverProjectSessions(root.ProjectDirFor("/path/to/project"))

// Read one, fully processed for display.
chunks, _ := transcript.ReadSession(sessions[0].Path)

// Or tail it live: incremental reads + chunk rebuilds.
msgs, offset, _ := transcript.ReadSessionIncremental(sessions[0].Path, 0)
_ = transcript.BuildChunks(msgs)
_ = offset // resume from here on the next file event

Everything returns plain Go structs. JSON exists only at the boundaries the library reads.

Two tiers

Provider-neutral core (package sessions, module root) — for consumers that enumerate sessions across agent products: Provider, SessionRef, Query, Registry, and optional capabilities probed by type assertion (LiveTracker). Claude Code and Codex CLI are its two providers today; more slot in without forcing either one's fidelity through the neutral interface.

Lossless Claude subtree (claude/...) — for consumers that know they're reading Claude Code state and want full fidelity. The parsing pipeline is never squeezed through an interface.

You need Import
Parse transcripts (entries → chunks) claude/transcript
Find sessions, titles, previews claude/discover
Subagents, teams, workflows claude/agents
~/.claude path conventions claude/claudedir
Hook stdin payloads claude/hooks
settings.json (read + hook registration) claude/settings
Live pane → session resolution claude/registry
Statusline stdin schema claude/statusline
Debug logs claude/debuglog
Incremental offsets across process restarts offsetstore
Raw JSONL primitives, bounded tail reads jsonl
Git main-worktree resolution gitroot

Codex subtree (codex/...) — the Codex CLI counterpart, for consumers reading $CODEX_HOME rollout transcripts.

You need Import
Rollout entries, trailing state, claim reconciliation, final assistant output, session snapshot codex/rollout
Find rollout files, resolve thread names codex/discover
$CODEX_HOME path conventions codex/codexdir
sessions.Provider adapter codex

Design commitments

  • Stdlib only. No dependencies, ever. Enforced in CI.
  • Injected roots. Nothing calls os.UserHomeDir() behind your back.
  • Lossless by default, tolerant by design. Unknown entry types, block types, and attachment subtypes degrade silently; raw bytes stay reachable (jsonl, Payload.Raw) so new fields are readable without a release.
  • Drift alarm. A gated corpus test (CLAUDE_CORPUS_DIR) asserts every line of a real transcript corpus parses and every key is known.
  • Two partial-write rules, both pinned. Resident watchers keep a parseable unterminated tail; per-tick processes defer it. Regression tests name the consumer each rule protects.

Used by tail-claude, tail-claude-hud, and gearshifter.

Status

v0.x: the API moves when the consumers need it to; breaking changes bump the minor version and are listed in CHANGELOG.md.

License

MIT — see LICENSE. Parsing-logic lineage: tail-claude, which ports ideas from claude-devtools and agentsview (see that repo's ATTRIBUTION.md).

Documentation

Overview

Package sessions defines the thin provider-neutral core of agent-ouija: just enough surface for a cross-provider consumer to enumerate agent sessions, plus optional capability interfaces discovered by type assertion.

Everything lossless and provider-specific lives in ordinary subpackages (claude/transcript, claude/discover, ...) that provider-specific consumers import directly. This core is deliberately NOT a funnel for rich data: forcing a provider's full fidelity through a neutral interface loses information (the lossy-normalization mistake). A consumer that knows it is talking to Claude Code should use the claude packages; a consumer that works across providers uses this one.

Capabilities follow the io.ReaderAt pattern: a provider advertises an optional capability by implementing its interface, and consumers probe with a type assertion. A fat mandatory interface would force future providers to stub methods they cannot honor.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type LiveSession

type LiveSession struct {
	Ref SessionRef // at minimum Provider, ID, and CWD are set
	PID int
}

LiveSession is a currently-running agent process associated with a session.

type LiveTracker

type LiveTracker interface {
	LiveSessions() ([]LiveSession, error)
}

LiveTracker is an optional capability: providers that maintain a live-process registry can report which sessions are running right now. Probe with a type assertion:

if lt, ok := provider.(sessions.LiveTracker); ok { ... }

type Provider

type Provider interface {
	// Name returns a stable, lowercase provider identifier ("claude").
	Name() string

	// Discover returns sessions matching the query, sorted by ModTime
	// descending. A query matching nothing returns an empty slice, not
	// an error.
	Discover(Query) ([]SessionRef, error)
}

Provider enumerates recorded sessions for one agent product.

type Query

type Query struct {
	// ProjectDir limits results to sessions belonging to this absolute
	// project path. Empty means all projects.
	ProjectDir string

	// Title filters to sessions whose title matches case-insensitively
	// (substring). Empty means no title filtering.
	Title string

	// Limit caps the number of results after sorting. 0 means no cap.
	Limit int
}

Query narrows a Discover call. The zero value matches everything.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry aggregates providers and fans Discover out across them.

Example

Cross-provider consumers enumerate sessions through the neutral core; optional capabilities are probed by type assertion.

package main

import (
	"fmt"

	sessions "github.com/kylesnowschwartz/agent-ouija"
	"github.com/kylesnowschwartz/agent-ouija/claude"
	"github.com/kylesnowschwartz/agent-ouija/claude/claudedir"
)

func main() {
	root, err := claudedir.DefaultRoot()
	if err != nil {
		return
	}
	reg := sessions.NewRegistry(claude.New(root))

	refs, _ := reg.Discover(sessions.Query{ProjectDir: "/work/proj", Limit: 10})
	for _, r := range refs {
		fmt.Println(r.Provider, r.ID, r.Title)
	}

	if p, ok := reg.Provider("claude"); ok {
		if lt, ok := p.(sessions.LiveTracker); ok {
			live, _ := lt.LiveSessions()
			_ = live // currently-running sessions with pids
		}
	}
}

func NewRegistry

func NewRegistry(providers ...Provider) *Registry

NewRegistry returns a Registry over the given providers.

func (*Registry) Discover

func (r *Registry) Discover(q Query) ([]SessionRef, error)

Discover queries every provider and merges the results, sorted by ModTime descending. Provider errors are skipped (a broken provider must not hide the others); the first error is returned alongside whatever was gathered.

func (*Registry) Provider

func (r *Registry) Provider(name string) (Provider, bool)

Provider returns the registered provider with the given name.

func (*Registry) Providers

func (r *Registry) Providers() []Provider

Providers returns the registered providers in registration order.

type SessionRef

type SessionRef struct {
	// Provider is the Name() of the provider that produced this ref.
	Provider string

	// ID is the provider-scoped session identifier.
	ID string

	// Path is the on-disk location of the session's primary artifact
	// (for Claude Code, the transcript JSONL). May be empty for
	// providers without a file-per-session model.
	Path string

	// Title is the human-readable session title, when one exists.
	Title string

	// CWD is the working directory the session ran in, when known.
	CWD string

	// ModTime is the last-activity timestamp used for recency ordering.
	ModTime time.Time

	// Ongoing reports whether the provider believes the session is still
	// in progress.
	Ongoing bool
}

SessionRef is a provider-neutral reference to one recorded agent session: enough to list, rank, and open it — no conversation content.

Directories

Path Synopsis
Package claude implements the sessions.Provider interface for Claude Code — a thin adapter over the native packages (claudedir, discover, registry).
Package claude implements the sessions.Provider interface for Claude Code — a thin adapter over the native packages (claudedir, discover, registry).
claudedir
Package claudedir locates the on-disk state of a Claude Code installation.
Package claudedir locates the on-disk state of a Claude Code installation.
hooks
Package hooks defines the stdin payload and stdout output shapes for Claude Code hook events.
Package hooks defines the stdin payload and stdout output shapes for Claude Code hook events.
registry
Package registry reads Claude Code's live-session process registry ({root}/sessions/*.json) and resolves which session belongs to a given terminal pane.
Package registry reads Claude Code's live-session process registry ({root}/sessions/*.json) and resolves which session belongs to a given terminal pane.
settings
Package settings reads and patches Claude Code settings.json files.
Package settings reads and patches Claude Code settings.json files.
statusline
Package statusline models the JSON document Claude Code pipes to a statusline command's stdin on every tick.
Package statusline models the JSON document Claude Code pipes to a statusline command's stdin on every tick.
transcript
Package transcript is the lossless parsing pipeline for Claude Code session JSONL files:
Package transcript is the lossless parsing pipeline for Claude Code session JSONL files:
Package codex implements the sessions.Provider interface for Codex CLI -- a thin adapter over the native packages (codexdir, discover, rollout).
Package codex implements the sessions.Provider interface for Codex CLI -- a thin adapter over the native packages (codexdir, discover, rollout).
codexdir
Package codexdir locates the on-disk state of a Codex CLI installation.
Package codexdir locates the on-disk state of a Codex CLI installation.
discover
Package discover enumerates Codex CLI rollout transcripts on disk and resolves their thread names.
Package discover enumerates Codex CLI rollout transcripts on disk and resolves their thread names.
rollout
Package rollout parses Codex CLI rollout transcripts: the JSONL files Codex CLI writes at $CODEX_HOME/sessions/YYYY/MM/DD/rollout-<timestamp>-<uuid>.jsonl, one JSON object per line.
Package rollout parses Codex CLI rollout transcripts: the JSONL files Codex CLI writes at $CODEX_HOME/sessions/YYYY/MM/DD/rollout-<timestamp>-<uuid>.jsonl, one JSON object per line.
Package gitroot resolves git repository roots, including worktrees and submodules, without invoking the git binary.
Package gitroot resolves git repository roots, including worktrees and submodules, without invoking the git binary.
internal
pat
Package jsonl provides line-oriented IO primitives for JSONL files that may be appended to while being read.
Package jsonl provides line-oriented IO primitives for JSONL files that may be appended to while being read.
Package offsetstore persists byte offsets for incremental JSONL reads between short-lived process invocations, so each tick reads only the new bytes written since last time (O(delta) vs O(n)).
Package offsetstore persists byte offsets for incremental JSONL reads between short-lived process invocations, so each tick reads only the new bytes written since last time (O(delta) vs O(n)).
Package sessionstest provides a fake provider and a conformance suite for implementations of the sessions core interfaces.
Package sessionstest provides a fake provider and a conformance suite for implementations of the sessions core interfaces.

Jump to

Keyboard shortcuts

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