Help us shape the future of Go! Take the 2026 Go Developer Survey

sessions

package
v0.1.1361 Latest Latest
Warning

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

Go to latest
Published: Oct 23, 2026 License: MIT Imports: 58 Imported by: 0

Documentation

Overview

Package sessions lists the agents' recent sessions from their own session files — Claude Code's projects/*/<id>.jsonl (and Qoder's, the same kind), Codex's rollout files, OpenCode's database (or its older JSON files) and ZCode's, Pi's session files and omp's, DeepSeek Harness's, Cline's, Grok Build's, WorkBuddy's and CodeBuddy Code's, Droid's, Cursor CLI's and Alma's chat stores — with the tokens each spent, what that cost at the effective price, and the command that resumes it. It only ever reads the agents' folders.

The files grow long (hundreds of MB), so each one's parse is kept by path, size and time, and a file that only grew is read on from where it was left. The parses are kept on disk too, in magpie's cache folder.

Index

Constants

View Source
const ActiveWindow = time.Minute

ActiveWindow is how recently a session's file may have been written for it to count as in use, and not be deleted.

View Source
const All = 5000

All is what a listing that means every session asks List for: the count a page or a command shows beside the list is taken from every session, so the list has to be as long as the count, and this is long past any history a computer has. Limit stays what it is because traceRecentFiles sizes gateway attribution by it.

View Source
const GatewayRetention = 7 * 24 * time.Hour
View Source
const Limit = 200

Limit is how many sessions, the latest by last activity, List reads when the caller asks for no particular number. traceRecentFiles sizes the window gateway attribution is judged over by it too, so it is not raised to make a listing longer: a caller that wants more asks for more.

Variables

View Source
var ErrActive = errors.New("the session was written to in the last minute; it may still be running")

ErrActive is a session still being written: its agent may be running it.

View Source
var ErrNoSubagent = errors.New("no such subagent in this session")

ErrNoSubagent is a subagent the session doesn't have.

View Source
var ErrNoTranscript = errors.New("this agent's conversations can't be shown")

ErrNoTranscript is a session whose conversation magpie can't read: an agent that keeps it in a database, or in a form not read here.

View Source
var PriceOf = priceOf

PriceOf is the effective price of a model as a session names it, at the settings given. Tests swap it; the settings are the ones the listing read, so a swapped one prices against the same copy as the default does.

View Source
var TraceIdentityTTL = 2 * time.Second

TraceIdentityTTL is how long Visible reuses a discovery scan, a miss included, before scanning the transcripts again. Tests that need a cached miss to stay cached for a whole request lengthen it.

View Source
var WSLHomes func() []WSLHome

WSLHomes are the WSL distros to read sessions in; nil (none) unless internal/agent sets it, which it does where there is WSL.

View Source
var WSLOff func() bool

WSLOff is whether Settings' Detect agents in WSL is off (#1264); set by internal/agent. Off, no distro's sessions are listed, not even those listed before.

View Source
var WSLRunning func(distro string) bool

WSLRunning is whether a distro runs now, as wsl.exe said a few seconds ago at most; internal/agent sets it. A listing's Running is as old as the listing (up to wslRelist and more): a distro the user stopped since (wsl --shutdown, to repair WSL) would be started again by reading its files, so a file is read only while this says it runs.

Functions

func AgyDir added in v0.1.1233

func AgyDir() string

AgyDir is agy's data folder, ~/.gemini/antigravity-cli.

func AlmaDir added in v0.1.752

func AlmaDir() string

AlmaDir is Alma's data folder.

func Ask added in v0.1.1200

func Ask() (done func())

Ask marks a page waiting on sessions until done is called: reading goes at full speed while it waits.

func CachePath

func CachePath() string

CachePath is where the parses are kept between runs.

func ClaudeDir

func ClaudeDir() string

ClaudeDir is Claude Code's folder: $CLAUDE_CONFIG_DIR, else ~/.claude.

func ClineSessionDir added in v0.1.310

func ClineSessionDir() string

ClineSessionDir is Cline's sessions folder: $CLINE_SESSION_DATA_DIR, else sessions in $CLINE_DATA_DIR, else in data in $CLINE_DIR, else in ~/.cline/data.

func CodeBuddyDir added in v0.1.1214

func CodeBuddyDir() string

CodeBuddyDir is CodeBuddy Code's folder: $CODEBUDDY_CONFIG_DIR, else ~/.codebuddy, as internal/agent's codebuddy.go finds it.

func CodexDir

func CodexDir() string

CodexDir is Codex's folder: $CODEX_HOME, else ~/.codex.

func CodexIdentities added in v0.1.1238

func CodexIdentities() map[string]CodexIdentity

CodexIdentities returns an independent snapshot of the native thread identities.

func CodexPromptDigest added in v0.1.840

func CodexPromptDigest(prompt string) string

CodexPromptDigest keeps prompt evidence comparable across restarts without publishing a guessable hash. The key stays in Magpie's local config directory.

func CodexProviderIn added in v0.1.999

func CodexProviderIn(home string) string

CodexProviderIn is the provider the Codex of a folder uses now, whose sessions its history lists: config.toml's model_provider, its profile's when it chooses one, else "openai".

func CodexThreadProviders added in v0.1.1134

func CodexThreadProviders(home string) []string

CodexThreadProviders is every provider the threads of a Codex folder were started on, as its state databases keep them: the Codex app resumes a thread on that one, whatever config.toml's model_provider is now, and fails to load its config for it when config.toml has no table of that id (#1372). A database without the threads table, or one that can't be read, says nothing.

func CodexTitleDigest added in v0.1.840

func CodexTitleDigest(name string) string

func CodexTitleRecipients added in v0.1.840

func CodexTitleRecipients(digests []string) map[string][]TitleApplication

CodexTitleRecipients includes chats whose requests never crossed Magpie. They still count as conflicting recipients of a generated title.

func CodexTitles added in v0.1.591

func CodexTitles(ids []string) map[string]string

CodexTitles reads only the append-only name index. It caches unchanged files and reads newly appended complete lines from the previous offset.

func CursorDir added in v0.1.661

func CursorDir() string

CursorDir is Cursor's CLI config folder: $CURSOR_CONFIG_DIR, else cursor in $XDG_CONFIG_HOME, else ~/.cursor.

func Deletable added in v0.1.593

func Deletable(agent string) bool

Deletable says whether magpie can move an agent's sessions to its trash: those kept as files of their own, in a layout magpie knows whole.

func DesktopDataDirs added in v0.1.579

func DesktopDataDirs() []string

DesktopDataDirs are the folders whose session metadata belongs to this index.

func DesktopTitles added in v0.1.1220

func DesktopTitles(ids []string) map[string]string

DesktopTitles reads Code and Cowork names from Desktop's local metadata, even when the CLI transcript is absent. Only IDs explicitly recorded there are named; prior CLI runs keep their own usage identity and share the name.

func Dirs added in v0.1.289

func Dirs() []string

Dirs are the folders the sessions are read from: Claude Code's and Codex's, and the other agents' where they keep sessions on this computer.

func DshDir added in v0.1.310

func DshDir() string

DshDir is dsh's folder: $DSH_HOME, else ~/.dsh.

func Duration added in v0.1.265

func Duration(sec int64) string

Duration is active seconds in hours and minutes: 3h 12m, 40m, <1m; — when not kept.

func FactoryDir added in v0.1.720

func FactoryDir() string

FactoryDir is Droid's folder: $FACTORY_HOME_OVERRIDE/.factory, else ~/.factory.

func GatewayHidden added in v0.1.1151

func GatewayHidden() func(agent, id string, last time.Time) bool

GatewayHidden says whether a gateway session was deleted: true when it was, and had no request after its last one then.

func GatewayRecordingGeneration added in v0.1.1146

func GatewayRecordingGeneration() uint64

GatewayRecordingGeneration returns the current consent generation. A request captures it when recording starts and must present the same value when saving, so clearing and re-enabling recording cannot resurrect old data.

func GatewaySizes added in v0.1.1151

func GatewaySizes() func(agent, id string) int64

GatewaySizes is what conversation text magpie keeps of each gateway session, in bytes, read in one walk of the store.

func GatewayTitle added in v0.1.1213

func GatewayTitle(agent, id string) string

GatewayTitle is what a gateway session was first asked, made one short line, from the first turns magpie recorded of it; "" when it recorded none or nothing the user wrote.

func GrokDir added in v0.1.313

func GrokDir() string

GrokDir is Grok Build's folder: $GROK_HOME, else ~/.grok.

func HasGatewayConversations added in v0.1.1150

func HasGatewayConversations() bool

HasGatewayConversations says whether any gateway conversation text is kept, so the Sessions page offers to delete it only when there is something to delete. A folder that can't be read counts as holding some: the reader can still ask to clear it.

func HasTranscript added in v0.1.940

func HasTranscript(agent string) bool

HasTranscript says whether an agent's sessions can be read as a transcript.

func HermesDir added in v0.1.669

func HermesDir() string

Hermes stores canonical, non-overlapping input/cache buckets. Reasoning is already included in output. session_model_usage includes auxiliary tasks and multiple billing routes; sessions supplies only unattributed main-loop usage. These tables contain aggregates, not individual API request usage.

func HermesDirs added in v0.1.669

func HermesDirs() []string

HermesDirs includes the default store and live named profiles. A selected profile home resolves back to its root, as Hermes's profile resolver does.

func KimiCodeDir added in v0.1.1220

func KimiCodeDir() string

KimiCodeDir is Kimi Code's folder: $KIMI_CODE_HOME, else ~/.kimi-code, as internal/agent's KimiDir finds the new Kimi Code's (which this package cannot import). The old Python kimi-cli's ~/.kimi has no usage records.

func MiniMaxDir added in v0.1.1188

func MiniMaxDir() string

MiniMaxDir is MiniMax Code's data folder: MINIMAX_DATA_DIR, or ~/.minimax (as internal/agent's MiniMaxDir, which this package cannot import).

func NativeIDs added in v0.1.1289

func NativeIDs(agents map[string]bool) map[string]map[string]bool

NativeIDs are the ids of every session the agents named keep themselves, by agent: one nothing was said in too, as ListAgent lists it. It tells a gateway session an agent keeps from one only magpie saw. Only the named agents' files are looked at, and of those only the ones whose session id is inside the file are read when they changed.

func NeedleOf added in v0.1.1213

func NeedleOf(q string) string

NeedleOf is a query as it is matched: lowered, its spaces made one.

func OmpDir added in v0.1.490

func OmpDir() string

OmpDir is omp's agent folder, ~/.omp/agent, as magpie's omp agent has it.

func OpenCodeDir added in v0.1.289

func OpenCodeDir() string

OpenCodeDir is OpenCode's data folder: $XDG_DATA_HOME/opencode, else ~/.local/share/opencode — on Windows too, where OpenCode keeps it there.

func PIDesktopDir added in v0.1.1227

func PIDesktopDir() string

PIDesktopDir is where PI-Desktop keeps its data: $PI_DESKTOP_DATA_DIR, else ~/.pi-desktop (a packaged install's, its 04-data-storage.md).

func PIDesktopTitles added in v0.1.1227

func PIDesktopTitles(ids []string) map[string]string

PIDesktopTitles are the titles PI-Desktop gave the chats ids name, those it has one for. pi.sqlite is only read: opened immutable, or from a copy when its write-ahead log holds what isn't in it yet, as Cursor's store.db is (openCursorStore). A database that can't be read leaves the names last read standing: unknown, not untitled.

func PiDir added in v0.1.289

func PiDir() string

PiDir is Pi's agent folder: $PI_CODING_AGENT_DIR, else ~/.pi/agent.

func PruneGatewayConversations added in v0.1.1146

func PruneGatewayConversations(now time.Time) error

PruneGatewayConversations removes expired date buckets even while recording is off. Reads enforce the exact cutoff too, between periodic cleanup passes.

func Purge added in v0.1.615

func Purge(key string) error

Purge erases a trashed session for good: its folder in magpie's trash, files and note. Only when the reader asks for it (#487); nothing is ever erased by itself. A key that isn't a trashed session's, or whose folder (or its agent's) is a link that could lead out of the trash, is refused.

func QoderDir added in v0.1.310

func QoderDir(id string) string

QoderDir is the folder of Qoder's build of this id: $QODER_CONFIG_DIR, else ~/.qoder, for qoder; $QODERCN_CONFIG_DIR, else ~/.qoder-cn, for qoder-cn.

func Reset

func Reset()

Reset forgets the kept parses, in memory only.

func ResumeCommand

func ResumeCommand(agent, id, cwd string) string

ResumeCommand is the shell line that picks a session up again in its folder, or "" for an id that isn't plain.

func SaveGatewayTurn added in v0.1.1146

func SaveGatewayTurn(turn GatewayTurn) error

SaveGatewayTurn keeps a bounded, scrubbed exchange. Recording is checked again under the same lock as disable-and-clear, so in-flight requests cannot refill it.

func SaveGatewayTurnGeneration added in v0.1.1146

func SaveGatewayTurnGeneration(turn GatewayTurn, generation uint64) error

func Saved added in v0.1.417

func Saved()

Saved waits for the index being saved, so a process about to end leaves it on disk.

func SessionGlob added in v0.1.579

func SessionGlob(pattern string) ([]string, error)

SessionGlob is filepath.Glob for session discovery, with directory listings cached by metadata. It never caches file contents or suppresses new entries.

func SetGatewayRecording added in v0.1.1146

func SetGatewayRecording(on, clear bool) error

SetGatewayRecording changes only this machine's consent. Clear disables first.

func SubagentOf added in v0.1.1165

func SubagentOf(p string) string

SubagentOf is the subagent a Claude Code file is the conversation of, by its name: <agent> of <id>/subagents/agent-<agent>.jsonl or a workflow's <id>/subagents/workflows/<run>/agent-<agent>.jsonl — the agentId its lines carry, and the x-claude-code-agent-id Claude Code sends the gateway for it. "" for a session's own file, and any other agent's.

func SubagentParent added in v0.1.1165

func SubagentParent(p string) string

SubagentParent is the subagent that started the one whose Claude Code file p is: the parentAgentId of its agent-<agent>.meta.json beside it, which Claude Code writes for a subagent a subagent started (spawnDepth 2 and on), the x-claude-code-parent-agent-id it sends the gateway. "" for one the conversation itself started, and for a file that is no subagent's. A meta file once read is kept; one not read is read again.

func Titles added in v0.1.1118

func Titles(keys []string) map[string]string

Titles is the title of each session named by key (agent:id, as Get takes it) that has its files on this computer: the name it was given, else the agent's own title, else its first prompt. A key with no files, or a session with no title, is left out. Desktop's local metadata can name a session without its CLI transcript. The Routing page uses this too (#1293).

func ToolCategory added in v0.1.410

func ToolCategory(name string) string

ToolCategory is the kind of tool a name is, Claude Code's and Codex's alike: Bash, Edit, Read, Write, Glob, Grep, Task (subagents and plans), Tool (an MCP server's) or Other.

func TraceAgent added in v0.1.679

func TraceAgent(agent string) bool

TraceAgent lists formats with an interaction and tool-aware trace adapter.

func TraceID added in v0.1.679

func TraceID(parts ...string) string

func TraceSessionVisible added in v0.1.701

func TraceSessionVisible(agent, id string) bool

TraceSessionVisible resolves a first request before the next reader tick. Only formats with an authoritative header are eligible; filenames alone cannot establish that a usable local transcript exists.

func TrashDir added in v0.1.593

func TrashDir() string

TrashDir is where deleted sessions are kept: <magpie dir>/trash/sessions.

func Warm added in v0.1.1200

func Warm(fn func())

Warm runs fn, the reads nobody waits on yet, with few readers.

func WorkBuddyDir added in v0.1.313

func WorkBuddyDir() string

WorkBuddyDir is WorkBuddy's folder: $WORKBUDDY_CONFIG_DIR, else ~/.workbuddy.

func WriteGatewayMarkdown added in v0.1.1169

func WriteGatewayMarkdown(w io.Writer, s Session, name string, t Transcript) error

WriteGatewayMarkdown writes a session magpie's gateway recorded (t, from GatewayTranscript) as WriteMarkdown writes one read from the agent's own file: for a session whose agent ran on another machine, as one that reaches this magpie through a remote magpie does (akic404 on Discord), there is no file here, only what the gateway kept. It says so, and says when older turns or the end of a long part weren't kept.

func WriteMarkdown added in v0.1.1116

func WriteMarkdown(w io.Writer, s Session, name string) error

WriteMarkdown writes s's conversation, read whole from its file, as Markdown: a heading with what the session is, then each turn under who said it. Thinking, a tool's result and what the agent put in itself are folded (<details>); a tool's call is its name and arguments. name is the agent as the reader knows it. The file is only read.

func ZCodeDir added in v0.1.310

func ZCodeDir() string

ZCodeDir is ZCode's folder, ~/.zcode, under Go's home. Its CLI's database stays there, USERPROFILE on Windows, even where the app keeps the rest under a HOME the user set (appdir.ZCodeHome): ZCode 3.14.3 for Windows, run with both, wrote cli\db\db.sqlite under USERPROFILE and v2 under HOME.

Types

type Active added in v0.1.239

type Active struct {
	Agent   string `json:"agent"`
	Cwd     string `json:"cwd"`
	Seconds int64  `json:"seconds"`
	// Hours is Seconds again by the local hour of the day (24, or none)
	Hours []int64 `json:"hours,omitempty"`
}

Active is the time an agent's sessions in one folder were at work on a day, in seconds (see day.Active for how it is told).

type AgentCount added in v0.1.593

type AgentCount struct {
	Agent     string `json:"agent"`
	Count     int    `json:"count"`
	Deletable bool   `json:"deletable"`
}

AgentCount is an agent with sessions on this computer, and how many.

func Agents added in v0.1.593

func Agents() []AgentCount

Agents are the agents with sessions on this computer, by how many.

type Call added in v0.1.579

type Call struct {
	ResponseID string    `json:"response_id,omitempty"`
	Time       time.Time `json:"t"`
	Agent      string    `json:"agent"`   // claude (Claude Code's CLI), claude-desktop (Desktop's Code tab and Cowork), codex
	Session    string    `json:"session"` // the id the agent sends the gateway as its session header
	ThreadID   string    `json:"thread_id,omitempty"`
	Model      string    `json:"model"` // the model the file names: for Claude, the one the vendor answered
	// Requested: the model Claude Code was running as (its identity note) when it made
	// the call, as it was asked for: claude-opus-5[1m] for claude-opus-5 with the long context
	Requested string `json:"requested,omitempty"`
	Tokens
	Reasoning int    `json:"reasoning,omitempty"`  // Codex: inside Output already
	Effort    string `json:"effort,omitempty"`     // the thinking effort: Codex's, of the turn; Claude's, of the line
	RequestID string `json:"request_id,omitempty"` // Claude's
	// Codex's session metadata identifies its configured provider and creator.
	// These identify the historical session, not whichever account is signed in now.
	Upstream  string `json:"upstream,omitempty"`
	AccountID string `json:"account_id,omitempty"`
	UserID    string `json:"user_id,omitempty"`
	Error     string `json:"error,omitempty"`      // Claude: the API error's kind (rate_limit, server_error …); such a call has no tokens
	ErrorText string `json:"error_text,omitempty"` // its message, the first 400 characters
	// Codex: the turn's own figures, set only when the turn made just this call
	TTFT int64 `json:"ttft_ms,omitempty"`
	// Compaction is Codex's explicit marker that this response compacted the context.
	Compaction bool `json:"compaction,omitempty"`
	// Millis: how long the call took. Codex's, of a turn that made this call alone, is what
	// it says; the rest are told from the file's times, the call's last line less the line
	// that asked for it (a prompt, a tool's result), and so a little more or less than it was
	Millis int64 `json:"ms,omitempty"`
	// Compact: how long a compaction of the context kept the agent waiting, in ms.
	// Codex's is on the compaction's own call (its Millis); Claude Code's is the
	// durationMs its compact_boundary line says, on the first call after it
	Compact int64  `json:"compact_ms,omitempty"`
	Cwd     string `json:"cwd,omitempty"`
	// Where the call is in its file, for reading what was said in it (ContentOf): the file,
	// from where what it was asked began — after the reply before it — to where it ended,
	// and for Claude Code the id of its message
	File string `json:"file,omitempty"`
	From int64  `json:"from,omitempty"`
	To   int64  `json:"to,omitempty"`
	Msg  string `json:"msg,omitempty"`
}

Call is one model call as an agent's own session file records it.

func AgentCalls added in v0.1.1258

func AgentCalls(since time.Time, agent string) []Call

AgentCalls is Calls of one agent's session files only: Codex's model and effort per thread need Codex's calls, not a read of every agent's.

func Calls added in v0.1.579

func Calls(since time.Time) []Call

Calls reads per-file request shards, separately from the session summaries. Only changed files are scanned, and only a bounded number of parses stay in memory. Conversation text is read by ContentOf when a detail is opened.

Over a long history a read decodes every shard (#2278: 68k of them, 415 MB), so callers asking at once share one read of the same files, and only one read of every file runs at a time: the Sessions page's requests arriving together each held a whole read's calls, and the app grew to 85 GB.

func FindCall added in v0.1.579

func FindCall(session string, from, to, at time.Time) (Call, bool)

FindCall is the call of a session made between two times that ended nearest at (a call's Time is its last line's), if the session files have one. A gateway request's window can hold the next calls of a quick tool loop too; the newest of them would be another request's.

func ReadCallSource added in v0.1.579

func ReadCallSource(s CallSource) []Call

ReadCallSource returns immutable calls for one source. Independent files can be read concurrently; disk IO never holds callsMu.

type CallSource added in v0.1.579

type CallSource struct {
	Path, Key, Agent string
	Size             int64
	Modified         time.Time
}

CallSource identifies a raw local request log without reading its contents.

func CallSources added in v0.1.579

func CallSources() []CallSource

type Carry added in v0.1.940

type Carry struct {
	Agent   string `json:"agent"`
	Command string `json:"command"`
}

Carry is another agent a session can be carried on in, and the shell line that does it in the session's folder.

type ClaudeRelocation added in v0.1.1224

type ClaudeRelocation struct {
	From  string `json:"from"`
	To    string `json:"to"`
	WSL   string `json:"wsl,omitempty"`
	Token string `json:"token,omitempty"`
}

ClaudeRelocation moves an entire project within one Claude Code config directory. Token is the preview's fingerprint; an empty token only previews.

type ClaudeRelocationResult added in v0.1.1224

type ClaudeRelocationResult struct {
	From     string `json:"from"`
	To       string `json:"to"`
	WSL      string `json:"wsl,omitempty"`
	Sessions int    `json:"sessions"`
	Files    int    `json:"files"`
	Bytes    int64  `json:"bytes"`
	Token    string `json:"token"`
	Backup   string `json:"backup,omitempty"`
}

func RelocateClaudeProject added in v0.1.1224

func RelocateClaudeProject(in ClaudeRelocation) (ClaudeRelocationResult, error)

RelocateClaudeProject does not touch Desktop's stores, global history, or session-ID-keyed files (file-history, todos and session-env). IDs stay intact. Clients must be closed: the in-process lock cannot exclude Claude itself.

type CodexIdentity added in v0.1.1238

type CodexIdentity struct {
	ID            string `json:"id"`
	Role          string `json:"role"`
	ParentSession string `json:"parent_session,omitempty"`
	RootSession   string `json:"root_session,omitempty"`
}

CodexIdentity is a Codex thread's confirmed role and parent chain.

type CodexMove added in v0.1.999

type CodexMove struct {
	ID     string   `json:"id"`
	From   string   `json:"from"`
	To     string   `json:"to"`
	Files  []string `json:"files"`
	Backup string   `json:"backup"` // its files as they were
	DB     []string `json:"db,omitempty"`
}

CodexMove is one session moved to another provider.

func MoveCodexProvider added in v0.1.999

func MoveCodexProvider(id, to string) (CodexMove, error)

MoveCodexProvider moves a Codex session to the provider to: the model_provider of each session_meta in its files, and of its row in Codex's state database. A session written to in the last minute is left as it is (ErrActive), as Codex may be running it. Each file is copied to <magpie dir>/trash/codex-provider/ before it is changed, and rewritten whole into a file beside it that then takes its place, keeping its time.

func MoveCodexThreads added in v0.1.1333

func MoveCodexThreads(home, from, to string) ([]CodexMove, error)

MoveCodexThreads moves every thread of a Codex folder its state database keeps on the provider from to the provider to, each as MoveCodexProvider moves one: its files' session_meta and its row, a copy of the files kept in magpie's trash first. Codex lists only the threads of the provider it is on (app-server thread/list, the TUI's resume picker), so the threads started while magpie was Codex's provider were gone from Codex's lists once Codex was off magpie (kaizaoji on X: "the context doesn't exist"). A thread written to in the last minute is left for the next call, and so is one whose files can't be found; it says what it moved and the first error it met, having gone on past it.

type CodexPort added in v0.1.1303

type CodexPort struct {
	Rewritten []string // rollouts written portable
	Held      []string // rollouts with magpie's item a Codex holds, left for a later pass
	Done      bool     // every rollout due was looked at
}

CodexPort is what a pass did.

func PortCodexRollouts added in v0.1.1303

func PortCodexRollouts(ctx context.Context, home string) (CodexPort, error)

PortCodexRollouts makes the rollouts of the Codex home home portable, those written since the last whole pass and those it left before, until ctx ends. The first pass reads every rollout written since magpie began to compact; later ones only what changed since.

type Content added in v0.1.579

type Content struct {
	Input  []Part `json:"input"`
	Output []Part `json:"output"`
	Cut    bool   `json:"cut,omitempty"` // there was more than is kept here
}

Content is what a call was given and what it said, in the order of the file.

func ContentOf added in v0.1.579

func ContentOf(c Call) (Content, error)

ContentOf reads what was said in a call from its file.

type Day added in v0.1.239

type Day struct {
	Date   string   `json:"date"`
	Usage  []Usage  `json:"usage"`  // by agent, folder and model
	Active []Active `json:"active"` // by agent and folder
}

Day is one local date's usage, cut fine enough for the page to filter it by agent, model and folder itself.

type DayTotal added in v0.1.265

type DayTotal struct {
	Date string `json:"date"`
	Tokens
	Cost   float64 `json:"cost"`
	Active int64   `json:"active"` // seconds; -1 under a model
}

DayTotal is one date's usage under a Rollup's filters.

type ExternalDayUsage added in v0.1.1146

type ExternalDayUsage struct {
	Date, Agent, Cwd, Model string
	Tokens
	Cost   float64
	Priced bool
}

MergeExternalStats appends external daily usage and session summaries to a Stats snapshot. It is deliberately data-only so callers can keep their own source and pricing policy.

type ExternalModel added in v0.1.1146

type ExternalModel struct {
	Model string
	Tokens
	Cost   float64
	Priced bool
}

ExternalModel and ExternalSession are read-only session projections from a request ledger such as the gateway. They intentionally carry no file or resume capability.

type ExternalSession added in v0.1.1146

type ExternalSession struct {
	Agent, ID   string
	Title       string // what it was first asked (GatewayTitle); its id when ""
	Start, Last time.Time
	Models      []ExternalModel
	Daily       []ExternalDayUsage
	Tokens
	Cost     float64
	Unpriced int
}

type GatewayTurn added in v0.1.1146

type GatewayTurn struct {
	Agent   string    `json:"agent"`
	Session string    `json:"session"`
	Time    time.Time `json:"time"`
	Model   string    `json:"model"`
	Status  int       `json:"status"`
	Input   []Part    `json:"input"`
	Output  []Part    `json:"output"`
	Cut     bool      `json:"cut,omitempty"`
}

GatewayTurn is one captured client-facing exchange. Input may include replayed history; Output is only this request's reply. It is not a native session.

type Hit added in v0.1.1213

type Hit struct {
	Role   string `json:"role"`
	Kind   string `json:"kind"`
	Before string `json:"before"`
	Match  string `json:"match"`
	After  string `json:"after"`
}

Hit is where a session said what was searched for: a few words either side of the match, on one line.

func SearchGateway added in v0.1.1213

func SearchGateway(ctx context.Context, agent, id, needle string) (Hit, bool, error)

SearchGateway finds needle in what magpie recorded of a gateway session, the parts as its transcript shows them.

func SearchSession added in v0.1.1213

func SearchSession(ctx context.Context, s Session, needle string) (Hit, bool, error)

SearchSession finds needle (from NeedleOf) in what a session said, read from its agent's own file; ErrNoTranscript for an agent whose conversations aren't read.

type ManageView added in v0.1.1289

type ManageView struct {
	Agents   []AgentCount
	Native   map[string]map[string]bool
	Agent    string
	Sessions []Managed
}

ManageView is the session management page, read in one pass over every agent's files: the agents with sessions, the ids of the sessions of those asked for (as NativeIDs), and the agent shown with its sessions (as ListAgent).

func Manage added in v0.1.1289

func Manage(native map[string]bool, pick func([]AgentCount, map[string]map[string]bool) string) ManageView

Manage reads the management page. pick, given the counts and the native ids of the agents in native, names the agent to list ("" for none); it runs under the sessions lock and must not call back into this package. Only native's agents and the one picked are read: a change to another agent's sessions waits for a page that shows it (#2776).

type Managed added in v0.1.593

type Managed struct {
	Session
	Size      int64 `json:"size"`
	Messages  int   `json:"messages"`
	Files     int   `json:"files"`
	Deletable bool  `json:"deletable"`
	// Codex: the provider the session was made with, and the one its Codex
	// uses now, whose sessions alone its history lists (#887)
	Provider     string `json:"provider,omitempty"`
	UsesProvider string `json:"uses_provider,omitempty"`
}

Managed is a session as the management page lists it: what List has, and how big its files are, how many messages it has, and whether it can be deleted.

func ListAgent added in v0.1.593

func ListAgent(agent string) []Managed

ListAgent is every session of one agent, the most recently active first, with no limit; one nothing was said in is listed too, to be cleared away.

type Model

type Model struct {
	Model string `json:"model"`
	Tokens
	Cost   float64 `json:"cost"`
	Priced bool    `json:"priced"`
}

Model is one model's share of a session.

type ModelEffort added in v0.1.1238

type ModelEffort struct {
	Model  string `json:"model"`
	Effort string `json:"effort"`
	Tokens
	Reasoning int     `json:"reasoning"`
	Cost      float64 `json:"cost"`
	Priced    bool    `json:"priced"`
}

ModelEffort is one model and reasoning effort's share of a session.

type Overview added in v0.1.410

type Overview struct {
	Count  int   `json:"count"`
	Median int   `json:"median"` // tokens (in and out) of the middle session
	P90    int   `json:"p90"`    // … of the one nine in ten spent no more than
	Days   []int `json:"days"`   // sessions at work each day, from Stats.From to To
	// Top are the sessions that spent the most, by tokens, cost and
	// active time, n of each
	Top map[string][]Summary `json:"top"`
	// Messages and Output are the messages and output tokens each day,
	// as Days
	Messages []int `json:"messages"`
	Output   []int `json:"output"`
	// Shape is how many sessions came to how much: by messages, by
	// minutes at work and by tool calls a prompt (autonomy)
	Shape  map[string]Shape `json:"shape"`
	Tools  ToolUse          `json:"tools"`
	Skills SkillUse         `json:"skills"`
}

Overview is what the sessions of a range come to under the page's filters.

type Part added in v0.1.579

type Part struct {
	Role string `json:"role"`           // user, assistant or tool
	Kind string `json:"kind"`           // text, thinking, tool_use, tool_result, context or image
	Name string `json:"name,omitempty"` // the tool's, of its call
	Text string `json:"text"`
	Cut  int    `json:"cut,omitempty"` // the characters left off its end
	// Model is the model an assistant part's own line names (#2253):
	// Claude Code's message.model, the model the reply came back from,
	// and Codex's turn_context.model, the one its turn was sent to. ""
	// where the file names none; never one guessed from elsewhere.
	Model string `json:"model,omitempty"`
}

Part is one thing said in a call.

type Progress added in v0.1.410

type Progress struct {
	Indexing bool  `json:"indexing"`
	Files    int64 `json:"files"`
	Done     int64 `json:"done"`
	Bytes    int64 `json:"bytes"`
	Read     int64 `json:"read"`
}

Progress is how far the sessions being read have got; Indexing is false when none are.

func Indexing added in v0.1.410

func Indexing() Progress

Indexing is the reading's progress.

type Rollup added in v0.1.265

type Rollup struct {
	From   string `json:"from"`
	To     string `json:"to"`
	Model  string `json:"model,omitempty"`
	Folder string `json:"folder,omitempty"`
	Tokens
	Cost     float64  `json:"cost"`     // USD at the effective price, of the priced models
	Unpriced []string `json:"unpriced"` // models that spent tokens and have no known price
	// Active is the seconds the sessions were at work; -1 under a model,
	// as active time isn't kept by model.
	Active   int64      `json:"active"`
	DaysUsed int        `json:"days_used"` // dates with usage
	Days     []DayTotal `json:"days"`      // every date From…To, empty ones too
	Models   []Share    `json:"models"`    // under the folder, the most tokens first
	Folders  []Share    `json:"folders"`   // under the model, the most tokens first
}

Rollup is Stats summed under a model and a folder ("" for every one), as the app's Sessions view sums them: for the CLI and the TUI.

type Session

type Session struct {
	ReadOnly bool `json:"read_only,omitempty"`
	// Gateway: seen only through magpie's gateway, with no file of the
	// agent's on this computer (external.go)
	Gateway       bool          `json:"gateway,omitempty"`
	Agent         string        `json:"agent"` // magpie agent id: claude, codex, opencode, pi, omp, zcode, dsh, cline, qoder, qoder-cn, grok, workbuddy, codebuddy, droid, cursor, hermes, alma, kimi
	ID            string        `json:"id"`
	Cwd           string        `json:"cwd"`
	Title         string        `json:"title"` // the name it was given, else the agent's own title, else the first prompt
	Nickname      string        `json:"nickname,omitempty"`
	Start         time.Time     `json:"start"`
	Last          time.Time     `json:"last"`
	Role          string        `json:"role,omitempty"`
	ParentSession string        `json:"parent_session,omitempty"`
	RootSession   string        `json:"root_session,omitempty"`
	ModelEffort   []ModelEffort `json:"model_effort,omitempty"`
	Models        []Model       `json:"models"`
	Tokens
	Cost     float64 `json:"cost"`     // USD at the effective price, for the priced models
	Unpriced int     `json:"unpriced"` // models that spent tokens but have no known price
	Resume   string  `json:"resume"`   // the command that picks the session up again
	Path     string  `json:"path"`     // its (main) file
	// Carry are the other agents that can carry the session on, reading its
	// file as it is (carry.go)
	Carry []Carry `json:"carry,omitempty"`
	// Transcript says its conversation can be read (TranscriptOf)
	Transcript bool `json:"transcript,omitempty"`
	// Subagents are the conversations its agent started inside it, each
	// read with SubagentTranscript (subagents.go)
	Subagents []Subagent `json:"subagents,omitempty"`
	// WSL is the WSL distro the session ran in, its files read through
	// \\wsl.localhost (see wsl.go); "" for this computer's own
	WSL string `json:"wsl,omitempty"`
	// Convs are the ids magpie's gateway keys the session's requests by
	// when they carry no session id of their own (dshConvs)
	Convs []string `json:"-"`
}

Session is one agent session.

func Find

func Find(agent, id string) (Session, bool)

Find is a session by agent and id: a listed one, else one Get finds under agent:id. One nothing was said in is found too, as ListAgent lists it: the Sessions page shows it, and its conversation, Markdown and Terminal open from it as from any other (#2273).

func Get added in v0.1.410

func Get(key string) (Session, bool)

Get is the session whose files are grouped under key (a Summary's Key), however long ago it was at work.

func List

func List(limit int) []Session

List reads the latest sessions of every agent, the most recently active first, at most limit of them (Limit when 0).

func MergeExternal added in v0.1.1146

func MergeExternal(native []Session, external []ExternalSession) []Session

MergeExternal adds external sessions to a file-backed listing. Native sessions win on the exact Agent+ID identity and external entries are kept read-only (no file of the agent's to resume or open) with a gateway transcript reader; magpie's own record of one is deleted by DeleteGateway.

type Shape added in v0.1.410

type Shape struct {
	Edges  []int `json:"edges"`
	Counts []int `json:"counts"`
	Total  int   `json:"total"`
}

Shape counts sessions into buckets: Counts[i] those from Edges[i] up to the next edge, the last one open.

type Share added in v0.1.265

type Share struct {
	Name string `json:"name"`
	Tokens
	Cost float64 `json:"cost"`
}

Share is one model's or folder's part of a Rollup.

type Skill added in v0.1.410

type Skill struct {
	Name     string         `json:"name"`
	Calls    int            `json:"calls"`
	Sessions int            `json:"sessions"`
	Last     string         `json:"last"`     // the date it was last called
	Agents   map[string]int `json:"agents"`   // calls by agent
	Projects []ToolStat     `json:"projects"` // the folders that called it most, by name
}

Skill is one skill's calls.

type SkillUse added in v0.1.410

type SkillUse struct {
	Calls int     `json:"calls"`
	Top   []Skill `json:"top"`
	Count int     `json:"count"` // skills called at all
}

SkillUse is the skills the sessions called up.

type Stats added in v0.1.239

type Stats struct {
	From string `json:"from"` // the first date, local: the range's, or for all time the first with anything
	To   string `json:"to"`   // today
	Days []Day  `json:"days"` // the dates with anything, in order
	// Sessions are the sessions at work in the range, each with what it
	// spent in it, the most recently active first. Too many to send the
	// page over a long range: Overview sums them up.
	Sessions []Summary `json:"-"`
	// Keys are those sessions' keys, agent:id, in the same order: which of
	// the sessions the page lists were at work in the range. The list is
	// every session ever, so without them it guessed from each one's last
	// line — and a session whose last line is a setting or a fork's seed,
	// written long after its last call, was listed but not counted.
	Keys []string `json:"keys"`
}

Stats is what every session spent, day by day: all of them, not only the latest List reads.

func MergeExternalStats added in v0.1.1146

func MergeExternalStats(st Stats, days []ExternalDayUsage, external []ExternalSession) Stats

func StatsAndNative added in v0.1.1289

func StatsAndNative(days int) (Stats, map[string]bool)

StatsAndNative is StatsFor, and the agent|id of every session List would list, with no limit: what tells a gateway session the agent keeps too from one only magpie saw. Both come of one pass over the files, as the overview asks for both on every poll (#2776).

func StatsAt added in v0.1.265

func StatsAt(days int, now time.Time) Stats

StatsAt is StatsFor as if it were now.

func StatsFor added in v0.1.239

func StatsFor(days int) Stats

StatsFor reads the usage of the last days days up to today, today included (every day when 0), from every session file there is. Only the files written to since the range began are looked at; what is read is kept, as List's is.

func (Stats) Overview added in v0.1.410

func (st Stats) Overview(agent, model, cwd string, n int) Overview

Overview sums up st's sessions of agent, with model and in folder cwd ("" for any), with the n that spent the most each way.

func (Stats) Sum added in v0.1.265

func (s Stats) Sum(model, folder string) Rollup

Sum rolls the stats up under a model and a folder, "" for every one.

type Subagent added in v0.1.1246

type Subagent struct {
	ID    string `json:"id"`
	Title string `json:"title,omitempty"`
	// Kind is the agent it ran as: Claude Code's agentType ("Explore"),
	// OpenCode's agent ("general"), Kimi Code's subagentName ("coder")
	Kind string `json:"kind,omitempty"`
	// Parent is the subagent that started it, "" when the session did
	Parent string    `json:"parent,omitempty"`
	Start  time.Time `json:"start,omitzero"`
	Last   time.Time `json:"last,omitzero"`
	// Path is the file its conversation is in (OpenCode's database)
	Path string `json:"-"`
}

Subagent is a conversation a session's agent started inside it, which its agent keeps beside the session's own and counts in it (#2261): a Claude Code (or Qoder) subagent's agent-<id>.jsonl, an OpenCode child session, a Kimi Code agents/agent-<n>/wire.jsonl. Codex's subagents are sessions of their own, which name theirs in ParentSession instead.

type Summary added in v0.1.410

type Summary struct {
	Key           string        `json:"key"` // agent:id as its files are grouped, for Get
	Agent         string        `json:"agent"`
	ID            string        `json:"id"`
	Cwd           string        `json:"cwd"`
	Title         string        `json:"title"`
	Nickname      string        `json:"nickname,omitempty"`
	Last          time.Time     `json:"last"`
	Role          string        `json:"role,omitempty"`
	ParentSession string        `json:"parent_session,omitempty"`
	RootSession   string        `json:"root_session,omitempty"`
	ModelEffort   []ModelEffort `json:"model_effort,omitempty"`
	// Gateway: magpie knows the session only from the gateway's records
	// (MergeExternalStats). The agent left no file magpie reads, so it has
	// no folder, and no prompt unless gateway conversations were recorded
	// (#2285: a Pi subagent's DeepSeek turns read as "(no prompt)").
	Gateway bool `json:"gateway,omitempty"`
	Tokens
	Cost   float64  `json:"cost"`
	Priced bool     `json:"priced"` // every model it used has a price
	Active int64    `json:"active"` // seconds
	Models []string `json:"models"` // the models it used in the range, the most used first
	Days   []int    `json:"days"`   // the dates it was at work on, as days after From
	// Prompts and Replies are the messages each way, ToolCalls the tools
	// it called, in the range (Claude Code's, Codex's, Pi's and omp's sessions)
	Prompts   int `json:"prompts"`
	Replies   int `json:"replies"`
	ToolCalls int `json:"tool_calls"`
	// contains filtered or unexported fields
}

Summary is one session's share of a range.

type TitleApplication added in v0.1.840

type TitleApplication struct {
	Digest  string
	Updated time.Time
}

TitleApplication is an actual name write, not just a chat's current name. Keeping old writes lets an association survive a later manual rename.

type Tokens

type Tokens struct {
	Input      int `json:"input"`
	Output     int `json:"output"`
	CacheRead  int `json:"cache_read"`
	CacheWrite int `json:"cache_write"`
	// CacheWrite1h is how many of CacheWrite were written to be kept for an
	// hour, where the agent says (Claude Code's cache_creation)
	CacheWrite1h int `json:"cache_write_1h,omitempty"`
}

Tokens is a count of tokens. Input excludes what was read from cache.

func (Tokens) Spent added in v0.1.265

func (t Tokens) Spent() int

Spent is the tokens a Rollup counts: input and output, as the app does.

type ToolStat added in v0.1.410

type ToolStat struct {
	Name     string `json:"name"`
	Category string `json:"category,omitempty"`
	Calls    int    `json:"calls"`
	Sessions int    `json:"sessions"`
}

ToolStat is one tool's (or category's) calls.

type ToolUse added in v0.1.410

type ToolUse struct {
	Calls      int        `json:"calls"`
	Sessions   int        `json:"sessions"`
	Top        []ToolStat `json:"top"`        // the most called
	Categories []ToolStat `json:"categories"` // by category, the most called first
	// Weeks are the calls week by week, from Monday, by category
	Weeks []ToolWeek `json:"weeks"`
}

ToolUse is what the sessions called their tools for.

type ToolWeek added in v0.1.410

type ToolWeek struct {
	Start string         `json:"start"` // its Monday
	Calls map[string]int `json:"calls"`
}

ToolWeek is one week's calls by category.

type TraceReader added in v0.1.679

type TraceReader struct {
	Since time.Time
	// contains filtered or unexported fields
}

TraceReader follows supported local agent stores modified since activation. Existing lines establish ancestry, but events older than Since aren't emitted. Deterministic IDs make resumed rollouts and copied session branches idempotent.

func NewTraceReader added in v0.1.679

func NewTraceReader(since time.Time) *TraceReader

func (*TraceReader) Poll added in v0.1.679

func (r *TraceReader) Poll(bodies bool) []TraceSpan

Poll reads appended complete lines only. It limits watched files to the most recent sessions; a partial last line remains for the following poll.

func (*TraceReader) SetSessionIndex added in v0.1.701

func (r *TraceReader) SetSessionIndex(index *TraceSessionIndex)

Share request-side discovery with this reader's regular polling.

func (*TraceReader) VisibleSessions added in v0.1.701

func (r *TraceReader) VisibleSessions() []TraceSession

VisibleSessions is refreshed on Poll; old transcripts only contribute their identity, not completed historical operations.

type TraceSession added in v0.1.701

type TraceSession struct{ Agent, ID string }

TraceSession names a readable local transcript, independently of whether it has produced any observations. Header inspection never emits history/bodies.

type TraceSessionIndex added in v0.1.701

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

TraceSessionIndex shares one discovery snapshot across all request IDs and polling. The caller that wins refresh performs directory I/O; other concurrent requests use the snapshot without waiting for that scan. Its zero value is usable; no state is shared between exporters or stores.

func (*TraceSessionIndex) Visible added in v0.1.701

func (x *TraceSessionIndex) Visible(agent, id string) bool

func (*TraceSessionIndex) VisibleFresh added in v0.1.776

func (x *TraceSessionIndex) VisibleFresh(agent, id string) bool

VisibleFresh bypasses the discovery TTL for the one check before exporting a request's first attempt. Join an in-progress scan rather than trusting a cached miss; normal request-start checks remain nonblocking and cached.

type TraceSpan added in v0.1.679

type TraceSpan struct {
	Agent, Session, Turn, ID, Parent, Name, Kind, Model, Provider, Served string
	Start, End                                                            time.Time
	Input, Output                                                         string
	Tokens                                                                Tokens
	Reasoning                                                             int
	Error, Inferred                                                       bool
	Update                                                                bool
	Pending                                                               bool // ancestry only; export the root when the interaction finishes
}

TraceSpan is a recorded agent operation, model response, or tool execution.

type Transcript added in v0.1.940

type Transcript struct {
	Parts    []Part `json:"parts"`
	Cut      bool   `json:"cut,omitempty"` // there was more than is kept here
	Source   string `json:"source,omitempty"`
	Captured int    `json:"captured,omitempty"`
}

Transcript is what was said in a session, in the order it was said.

func GatewayTranscript added in v0.1.1146

func GatewayTranscript(agent, id string) (Transcript, error)

GatewayTranscript reads recent captured exchanges. Only a full matching previous history prefix is removed, never equal text found elsewhere in a chat.

func SubagentTranscript added in v0.1.1246

func SubagentTranscript(s Session, sub string) (Transcript, error)

SubagentTranscript is the conversation of the session's subagent sub.

func TranscriptOf added in v0.1.940

func TranscriptOf(s Session) (Transcript, error)

TranscriptOf reads a session's conversation from its (main) file.

type Trashed added in v0.1.593

type Trashed struct {
	Key     string    `json:"key"` // its folder in the trash, <agent>/<name>
	Agent   string    `json:"agent"`
	ID      string    `json:"id"`
	Title   string    `json:"title"`
	Cwd     string    `json:"cwd"`
	Last    time.Time `json:"last"`
	Deleted time.Time `json:"deleted"`
	Size    int64     `json:"size"`
	Items   []moved   `json:"items"`
	// Gateway: a session seen only through magpie's gateway, whose items
	// are the conversation text magpie recorded of it (gateway_delete.go)
	Gateway bool `json:"gateway,omitempty"`
}

Trashed is a deleted session in magpie's trash.

func Delete added in v0.1.593

func Delete(agent, id string) (Trashed, error)

Delete moves a session's files to magpie's trash: its own file, the folder of its subagents and tool results beside it, its other files (a Codex session's later segments, its subagents' elsewhere) and, for Claude Code, the file history, todos and environment it keeps by the session's id. A session any file of which was written in the last minute is not touched (ErrActive). One in a WSL distro is moved out of it over \\wsl.localhost the same way, its Claude Code files from the distro's ~/.claude, and Restore puts it back there.

func DeleteGateway added in v0.1.1151

func DeleteGateway(agent, id string, title string, last time.Time) (Trashed, error)

DeleteGateway deletes a gateway session as described above: last is its last request as listed. One that had a request in the last minute may still be going on, and is left (ErrActive).

func Restore added in v0.1.593

func Restore(key string) (Trashed, error)

Restore moves a trashed session's files back where they were. Nothing is moved when any of those places is taken again.

func Trash added in v0.1.593

func Trash() []Trashed

Trash is what is in magpie's session trash, the latest deleted first.

type Usage added in v0.1.239

type Usage struct {
	Agent string `json:"agent"`
	Cwd   string `json:"cwd"`
	Model string `json:"model"`
	Tokens
	Cost   float64 `json:"cost"` // USD at the effective price, when priced
	Priced bool    `json:"priced"`
}

Usage is what one model spent for one agent in one folder on a day.

type WSLHome added in v0.1.773

type WSLHome struct {
	Distro  string
	Home    string
	Running bool
}

WSLHome is a WSL distro magpie found agents in: its name, its user's home as magpie opens it (\\wsl.localhost\Ubuntu\home\me), and whether it runs.

Jump to

Keyboard shortcuts

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