Sessions and compaction¶
A session is one recorded conversation: its messages, its agent events (tool calls, approval decisions, turn limits, errors) and its metadata. Sessions are kept forever; nothing in tau deletes one. /sessions lists them, /resume continues one, /compact carries a long one forward as a summary in a new session. The design is ADR 0003.
Backends¶
[sessions] backend in tau.toml picks the store:
| Backend | Where | Notes |
|---|---|---|
memory |
the process | tests and throwaway runs; the code default when the key is absent |
file |
TAU_DATA_DIR/sessions/<id>/ |
the default in the shipped tau.toml |
a tau.sessions component |
wherever it says | see Components and plugins |
The cloud backend the first design planned (sessions in Cloudflare D1) is retired by ADR 0006: the file store on the hub is the record, and the cloud only holds encrypted backups.
File layout¶
One directory per session. Ids are YYYYMMDD-HHMMSS-xxxx in UTC, for example 20260929-153012-3f9a.
<TAU_DATA_DIR>/sessions/20260929-153012-3f9a/
├── session.json the Strands session record; its updated_at orders /sessions
├── meta.json channel, profile, title, role, compaction links
├── events.jsonl one agent event per line, append-only
└── agents/tau/
├── agent.json Strands agent state (including the conversation manager's state)
└── messages/
├── 000000.json one file per message, in order
└── 000001.json
- JSON files are replaced atomically (temp file, fsync, rename). Directories are
0700, files0600. - Symlinks are never followed; ids must be plain names (letters, digits,
.,_,-, starting with a letter or digit), sotau chat --session ../xends with a notice, not a traceback. - Nothing is deleted. The store has no delete method,
create_messagerefuses to overwrite an existing message, and a crash-truncated event line is skipped on read but left on disk. - A session opened and closed without a message stays on disk but is not listed.
Metadata keys¶
meta.json is a flat object. Keys written by tau today:
| Key | Written when | Meaning |
|---|---|---|
channel |
the agent is built on the session | terminal, tui; later telegram, voice, … The last channel used. |
profile |
the agent is built | the active profile at that time |
title |
the first user message arrives | the first user message, cut to 60 characters |
role |
the agent is built, and on /model |
the model role the session last ran on; /resume comes back on it |
compacted_to |
/compact |
on the old session: the id of the summary session |
compacted_from |
/compact |
on the new session: the id it summarizes |
Resuming rewrites channel, profile and role, so a resumed session moves to the top of the listing.
Listing and resuming¶
/sessionslists the 10 most recent earlier sessions that have messages, newest first, never the current one:n. id date channel title (N messages)./resumeresumes the most recent one;/resume nthe n-th of the last listing (without a listing, of the one/sessionswould print now);/resume <id>that id.tau chat --resume [ID]andtau tui --resume [ID]do the same at start-up.- Resuming rebuilds the agent on the stored session, so Strands restores
agent.messages; the TUI renders the history (user rows, markdown replies, tool cards with the recorded duration, approval and result) and replays the stored agent events into the events pane before live ones. - The TUI keeps the last 40 turns live; older ones fold into one line and PageUp at the top pages them in, 20 at a time.
The context window¶
The store keeps every message; the model sees a window. [agent] context picks it:
| Mode | The model sees | Strands manager |
|---|---|---|
sliding (default) |
the last window_size messages (60) |
SlidingWindowConversationManager |
summarize |
a summary of the older messages plus the last window_size verbatim |
SummarizingConversationManager |
The manager's state (how many messages it dropped) is saved with the session, so a resumed agent restores the same window. /status shows Context: sliding, window 60 · 14 messages in memory.
The mismatch message
A session remembers the manager it was recorded with, and Strands refuses to restore it under the other one. After changing context, an earlier session fails to open, in tau chat --resume, tau tui --resume, /resume and the TUI's picker alike, with:
Session <id> was recorded with a different [agent] context setting; set it back to sliding or start a new session
The current session is kept and nothing is written. Set the value back to open the old session, or start fresh.
When a conversation no longer fits the model's context window at all, the turn ends with The conversation no longer fits the model's context window; start a new session with /new. That is the moment for /compact.
Compaction: /compact [focus]¶
Compaction is how a long conversation goes on without its whole history while every session stays on record. It is never a rewrite of an existing session.
- tau runs a throwaway Strands agent on the session's own model over a copy of the messages, with no tools, no hooks and no session manager, so the tier gate is not involved and the live agent is untouched. The system prompt asks for a continuation summary: facts about the user, decisions, open tasks, tool results that still matter, and the language the user writes in.
focusis appended asFocus on: …. - A new session is opened whose history starts with a two-message seed: a user message
Summary of the previous conversation (session <id>):plus the summary, and the assistant'sUnderstood. I will continue from this summary.The seed goes through the SDK's own append path, so it is part of the session and survives--resume. - The new session's metadata gets the old
titleandcompacted_from = <old id>; the old session getscompacted_to = <new id>and keeps every message./sessionslists both. - The channel prints
Compacted N messages into a summary. New session <new>; the previous session <old> is kept.and the summary.Nis what was summarized: the messages in memory, which the window may have trimmed below the stored count.
An empty history, a failed model call or an empty reply fail with Compaction failed: … and nothing changes. In the TUI the summary runs in a worker: the chrome is busy (✻ Summarizing…), /status still answers, turns and session switches are refused, Esc cancels with Compaction cancelled; the session continues.
Repair turns¶
tau never appends to the history by hand. When a turn leaves the history dangling (a failed model call, the loop guard or token budget after a tool result, a cancel around tool execution, a session restored after a crash, or an assistant message with a toolUse and no result because the hub died while an approval was pending), the next turn sends a two-message prompt: an assistant notice with the last notice in parentheses (or The previous turn did not finish. for a crash-restored session), then your new message. Both go through the SDK, so roles keep alternating and the store gets tracking ids like every other message.
Stop reasons¶
Every turn ends with a TurnEnd(stop_reason); the channels turn some into notices:
| Stop reason | What happened | You see |
|---|---|---|
end_turn |
the model finished | – |
limit_turns |
[agent] max_turns model calls were used; the last call's tools still ran |
I reached the tool-call limit for this turn (N turns). I stopped; tell me if you want me to continue. |
limit_total_tokens |
[agent] max_total_tokens reached |
I reached the token budget for this turn. … |
max_tokens |
the reply hit the provider's output limit; the partial reply is kept | The reply hit the length limit; say so if you want me to continue. |
cancelled |
Ctrl-C or Esc stopped the turn at the next safe point | Turn cancelled. |
interrupt |
a hook kept interrupting; tau cleared the SDK's interrupt state | A tool asked for an interrupt this channel cannot answer; it was refused. |
error |
the model call failed, or the context overflowed | Model call failed: … / the overflow notice above |
busy |
another invocation held the agent; nothing ran | I am still answering the previous turn. |
Agent events¶
events.jsonl holds one JSON object per line. Kinds today: tool_call (every call of every tier: tool, tier, arguments, status, result summary, approval, duration, tool use id), approval (every tier-2 question and its decision), turn_limit, notice and error (with where: model, context, interrupt or tier_gate). Turn events (TextDelta, ToolUseStarted, …) are what a channel renders live and are not stored.
Logs¶
<TAU_DATA_DIR>/logs/tau.log receives INFO and up with tracebacks from every channel and from tau hub run. The terminal also prints WARNINGs to stderr (INFO with -v); the TUI keeps stderr silent while it owns the screen.