Documentation
¶
Overview ¶
Package session records what an agent was doing, so a different agent can pick it up.
Memory answers "what do you know about X". That is only half of continuity — the other half is "where did we stop, and what had we already ruled out". An agent that has to rediscover the three approaches that failed yesterday is not resuming, it is starting over with a warmer greeting.
The split mirrors git, which is the shape brain is aiming at:
working notes → SQLite → the working tree. Cheap, frequent, disposable. checkpoints → the vault → commits. Durable, readable, diffable.
So a running agent scribbles freely with AddNote and pays nothing, and Commit is the deliberate act that turns that scribbling into a markdown note the vault owns. Working notes are lost if the index is rebuilt; that is not a bug, it is the definition of uncommitted. Checkpoints survive, because the file is the record — see checkpoint.go, which reads them back off disk rather than trusting a table.
Index ¶
Constants ¶
const CheckpointDir = "sessions"
CheckpointDir is where checkpoints live inside the vault. A visible folder, not a dotfile: these are notes you are meant to be able to open, read, and put under version control alongside everything else.
const Schema = `` /* 631-byte string literal not displayed */
Variables ¶
This section is empty.
Functions ¶
func Commit ¶
func Commit(db *sql.DB, vaultDir string, c *Checkpoint) error
Commit writes the checkpoint to the vault and closes the project's open sessions. This is the commit in "working tree, then commit": until it is called, everything the agent recorded lives only in the rebuildable index and is not really saved.
The project's uncommitted working notes are folded in — including any left by an agent that died mid-task — so an agent that only ever called note_progress still produces a useful checkpoint instead of an empty one.
Project is a scope, so "kestrel/feature-x" writes into sessions/kestrel/feature-x/ and closes only that worktree's sessions. The caller decides the scope, exactly as it decides the project — see internal/mcpserver/scope.go.
Types ¶
type Checkpoint ¶
type Checkpoint struct {
Session string
Project string
Agent string
Task string
State string
Decisions []string
Failed []string
// The verified half. Failed says what was ruled out; these three say what the
// next agent may stand on without checking it again.
//
// Prose cannot carry this. "Auth is done" is a claim, and it reads the same
// whether a test demonstrated it or the last agent believed it while its
// context was running out. An arriving agent that cannot tell those apart
// either re-verifies everything or builds on a sentence, and the second is
// how a session inherits a foundation that was never true.
//
// So a verified entry names its evidence alongside the claim ("rejects
// expired tokens — go test ./internal/auth -run TestExpiry"), Commands are
// the invocations that produced it, and Blockers are the standing refutation:
// what is known broken, and what it stops.
Verified []string
Blockers []string
Commands []string
Questions []string
Files []string
Next string
// Git is the repository as it stood, read rather than reported. The half of
// a checkpoint an agent cannot forget to fill in — see the comment in
// Commit, and package gitstate.
Git gitstate.State
// HandoffTo names who this was left for. Empty for a plain checkpoint —
// the difference is intent, not mechanism.
HandoffTo string
Slug string // vault slug, set once written
TS int64
}
A Checkpoint is where an agent stopped, written down well enough that a different agent can start.
Failed is the field that earns its keep. Anyone can restate the goal; the expensive knowledge is the three approaches already ruled out, and it is exactly what gets lost when a session ends. A checkpoint without it saves the next agent a paragraph of reading and costs it an afternoon of rediscovery.
func History ¶
func History(vaultDir, project string, n int) ([]Checkpoint, error)
History returns up to n checkpoints for a project, newest first.
func Latest ¶
func Latest(vaultDir, project string) (*Checkpoint, error)
Latest returns the most recent checkpoint for a project, or nil if there is none.
It reads the vault directory rather than a table on purpose. Checkpoints are the one thing here that must survive `rm -rf .brain` — if resume depended on the index, the markdown would be a souvenir rather than the record. Filenames begin with a sortable timestamp, so "most recent" is a sort, not a query.
func ParseCheckpoint ¶
func ParseCheckpoint(raw string) Checkpoint
ParseCheckpoint reads a checkpoint back from its note. It is forgiving in the same way internal/vault is: a note that has been hand-edited into a shape we did not write should still yield whatever is recognisable, because the alternative is silently losing the record.
func (Checkpoint) Empty ¶
func (c Checkpoint) Empty() bool
func (Checkpoint) Markdown ¶
func (c Checkpoint) Markdown(follows string) string
Markdown renders the checkpoint as a vault note. follows is the session id of the previous checkpoint, linking the chain backwards; empty for the first.
type Mention ¶
type Mention struct {
Checkpoint
// Matched is the path as the checkpoint recorded it, which is rarely
// character-for-character what the caller asked about.
Matched string
}
A Mention is one checkpoint that touched a path, and what was being worked out at the time.
func Touching ¶
Touching finds every checkpoint whose Files list refers to path, newest first.
It searches every project rather than one, because the question "why is this file like this" does not come with a project attached — the caller has a path and nothing else. A file touched by two projects is a real situation and both answers are wanted.
type Note ¶
type Note struct {
ID int64
Session string
// Agent is denormalised from the session because notes outlive the agent
// that wrote them — when work passes between two agents, which of them
// found a thing is part of the finding.
Agent string
Text string
TS int64
}
A Note is one line of progress inside a session. Deliberately unstructured: the moment this needs fields, agents will stop writing them.
func AddNoteAt ¶
AddNoteAt appends a note that happened at a given time rather than now.
Backdating exists for the cases where the writing and the doing are not the same moment: importing a trail from elsewhere, replaying a transcript, or a benchmark that needs "thirteen days ago" to actually be thirteen days ago. Anything that reasons about how old a note is depends on this being real.
func Notes ¶
Notes returns a session's working notes, oldest first — the order they were written is the order they make sense in.
func Uncommitted ¶
Uncommitted returns the working notes for a project that no checkpoint has captured yet — everything written into still-open sessions, whoever wrote them. This is the "uncommitted changes" half of resume: work that happened but was never written down properly, including the work of an agent that died before it could.
type Session ¶
type Session struct {
ID string // "20260814-143207-claude", lexically sortable by time
// Project is the scope the work is filed under: a project name, or
// "project/worktree" when it is happening in a linked git worktree. Two
// parallel worktrees are the same codebase and the same memory, but not the
// same working stretch, and resuming into the other one's checkpoint is a
// wrong handoff rather than an untidy one.
Project string
Agent string // free text: "claude", "cursor", "codex", "pragun"
Task string
Started int64
Ended int64 // 0 while open
Slug string // vault slug of the checkpoint, once committed
}
A Session is one agent's working stretch on one project. It exists to give working notes something to hang off and to record who was at the keyboard — a handoff is meaningless without knowing who is handing off.
func Current ¶
Current returns this agent's open session for a project, opening one if there is none. Agents call note_progress without ceremony; making them manage a session lifecycle would mean they simply wouldn't.
Scoped to the agent, not just the project. A session is one agent's working stretch: when a previous agent died without committing, its session is still open, and handing it to whoever arrives next would file their checkpoint under the dead agent's id — so the record of a handoff would name the wrong author. Their uncommitted notes are still picked up; see Commit.