In the previous chapter, Command Architecture, we learned how to make the agent perform actions. But an action without memory is fleeting. If you close your terminal, does the agent forget it wrote a file? Does it forget which Git branch it was on?
This chapter introduces Session & Transcript Persistence.
Most chat apps store a "Diary":
User: "Hi"
Bot: "Hello"
Our agent needs a Ship's Log. It needs to record the exact state of the "ship" (your environment) at every turn.
Imagine you are debugging a crash. You don't just want to know what was said. You need to know:
cwd)index.ts before crashing?By storing this rich data, we enable the Resume capability. You can quit the application, restart it, and the agent picks up exactly where it left offโvariables, history, and context intact.
To achieve this, we don't just save strings of text. We save a database of Entries.
Every interaction begins with a unique ID. However, we don't just use a plain string. We use "Branded Types" to prevent mistakes (like mixing up a User ID with a Session ID).
// From ids.ts
export type SessionId = string & { readonly __brand: 'SessionId' }
// We use a helper to generate or cast these
export function asSessionId(id: string): SessionId {
return id as SessionId
}
SessionId before the compiler lets you use it. It prevents bugs!
The transcript is a list. But it's not a list of strings; it's a list of Entry objects. An Entry can be a chat message, but it can also be a hidden system event.
Here are a few "flavors" of entries found in logs.ts:
Even a standard text message carries heavy baggage. We call this a SerializedMessage.
export type SerializedMessage = Message & {
cwd: string // Where were we?
timestamp: string // When did it happen?
gitBranch?: string // What code version?
sessionId: string // Which conversation?
}
cwd. If you are currently in /home/user, but the last message was in /home/user/project, the agent knows it needs to switch directories back.Let's walk through a scenario: The User asks the Agent to fix a bug, then closes the window.
As the agent works, it generates a stream of mixed events.
TranscriptMessageWorktreeStateEntryFileHistorySnapshotMessage (Backup created)TranscriptMessageThese are saved to a JSON structure on the disk.
[
{ "type": "message", "text": "Fix the bug", "cwd": "/src" },
{ "type": "worktree-state", "branch": "fix/login-bug" },
{ "type": "file-history-snapshot", "file": "login.ts", "content": "..." },
{ "type": "message", "text": "I fixed it", "cwd": "/src" }
]
When the user types claude resume:
Entry UnionHow does TypeScript handle a list containing so many different types of objects? We use a Discriminated Union.
This is the core definition in logs.ts. It acts as a router for data types.
export type Entry =
| TranscriptMessage
| SummaryMessage
| WorktreeStateEntry
| FileHistorySnapshotMessage
| PRLinkMessage
// ... and many others
Let's look at two specific entry types to see how specialized they are.
WorktreeStateEntry)This entry allows the agent to handle complex git setups involving worktrees (checking out multiple branches at once).
export type WorktreeStateEntry = {
type: 'worktree-state' // The "Discriminator"
sessionId: UUID
worktreeSession: {
originalCwd: string
worktreePath: string
worktreeBranch?: string
} | null
}
worktreeSession is stored, the resume logic knows to cd into that specific folder. If it is null, it knows the user exited that mode.AttributionSnapshotMessage)In a multi-agent world (or when working with a human), we need to know who wrote which line of code.
export type AttributionSnapshotMessage = {
type: 'attribution-snapshot'
messageId: UUID
fileStates: Record<string, {
claudeContribution: number // How many chars did the AI write?
}>
}
The Session & Transcript Persistence layer is the brain's long-term memory. By treating history as a database of structured eventsโrather than just a text logโwe allow the agent to:
Now that our agent can execute commands and remember the results, we need to ensure it doesn't do anything dangerous.
Next Chapter: Permission & Safety System
Generated by Code IQ