Skip to main content
A session is one conversation. It survives the process. --continue opens the most recent one and --resume <id> opens a specific one, both with the conversation intact. Sessions are stored in a SQLite database, seri.db, in your profile root. A sessions/ directory of .jsonl files from an older release is imported into it on first use and then only ever read, never written.

Compaction

Compaction is a prefix summarizer. It keeps the newest part of the conversation by token budget and replaces everything older with one recap. The raw prefix is gone after that. /rewind will not step across it. See Checkpoints. It uses the same model as the turn, not a cheaper one.

When it runs

Before every model call, including the first call after --continue or --resume, seri estimates how large the history is. The estimate is max of the last billed input-token count and a local count (ceil(characters / 4) over text, thinking, and JSON-serialized tool arguments and results). If that number is at least half the context window, it tries to compact before sending. The keep budget is about 20,000 tokens of recent messages, not a fixed number of messages. A cut that would leave fewer than four evictable messages is skipped. /compact with too little history prints Not enough history to compact. If the provider still rejects the request as too long, seri compacts once more (when a safe cut exists) and retries that call. A second overflow fails the turn. An automatic compact that fails is fail-soft: the turn continues with the uncompacted messages. The overflow retry is the exception. If that compact fails, the turn fails.

What the recap holds

The evicted messages become one user message with four fields. A recap that already exists is updated, not rewritten from scratch. Finished work moves into progress. Blockers the new turns resolved are dropped. Paths come from the evicted tool calls themselves, not from the summarizer. read_file becomes Read:. write_file and edit become Modified:. A path that was both is listed as modified only. The summarizer is told to quote filenames, paths, numbers and other short literals rather than paraphrase them. Oversized tool payloads are replaced with {elided: true, originalBytes: N} before that extra call, and it is told not to invent the missing contents. The session still drops the raw messages. The elision only keeps the summarizer from ingesting file bodies. A cut never splits a tool call from its result. The boundary is only ever placed immediately before a user or assistant message, never before a tool result, because a tool result is always the second half of a pair.

/compact

/compact runs the same primitives on demand. It does not wait for the 50% trigger. Extra words after the command are focus instructions for the recap.

Compacting is not clearing

They are different resets, and the difference matters when you are choosing. /clear starts a new session rather than deleting the old one. Every /clear leaves the previous session’s file on disk with no retention policy, which is accepted rather than a bug. The checkpoint store is a separate matter. It keeps the 20 most recently touched sessions per project, so clearing repeatedly in one long-lived process can eventually retire an earlier session’s undo history even though its conversation file never goes away. See Checkpoints and undo.

The turn budget

--max-turns <n> caps model turns per task, 500 by default, and /max-turns <n> changes it for the rest of the session. Running out is a run that did not finish, so it exits 1. A subagent does not inherit that budget. It gets 25 turns, because three concurrent children on the session’s own cap would multiply tokens without a ceiling.

What is frozen at session start

The system prompt. AGENTS.md, always-on rules, and your memory files are read once and never edited mid-session, which is what lets a provider reuse its cached prefix on every turn. Anything that arrives later arrives as a message in the conversation instead. A rule that fires on a glob works this way, and so does an approved memory write, which enters the prompt the next time you start seri.

Trajectories

seri records each run locally, on by default. A trajectory holds tool calls and their results, checkpoints, denials with their reason, check results, edit outcomes, token usage, retries and how the turn ended. Large values are elided with their original size recorded rather than stored whole. Recordings go into seri.db in your profile root and never leave your machine. Each recording starts with a header that lists the sampling knobs, OpenRouter pin, reasoning effort and prompt-file hashes that were in force, so two runs can be compared without opening config.json. See Settings. seri ages recordings out at the start of each session. A session in seri.db is pruned once its most recent record is older than the window. A .jsonl file left by an older release goes by the file’s modification time instead. The session being recorded is never pruned, however old its records are.
The environment wins over what /trajectory stored, so a variable set in your shell keeps winning at the next start. seri says so when you set the toggle against a variable that will override it.