?

Session lifecycle

A session is one agent.Session value persisted as a row in the sessions table (internal/state/sqlite/schema.sql). It has an id, a title, a chronologically-ordered slice of Message values, and timestamps. Once created, it exists until you delete it.

Sessions are created on-demand by every entry point:

  • rousseau chat — one session per TUI session (a new one on each chat invocation; you'd have to build a session-picker to reuse an existing one).
  • Every transport (whatsapp, slack, …) — one session per JID, via the JID map (internal/state/sqlite/jidmap.go).
  • rousseau cron — each fire is a one-shot session bounded to that run.

Enumerate

rousseau session list --limit 10

Output (from newSessionListCmd in internal/cli/session.go):

<short-id>  <messages>  <updated_at>  <title>

--limit 0 returns unlimited rows.

Search

FTS5 across every recorded message:

rousseau session search 'retry logic'
rousseau session search '"exponential backoff" AND anthropic'
rousseau session search 'retr*'                # prefix

The command wraps Store.Search (internal/state/sqlite/search.go) with SearchOptions{Limit: N}. Ranking is BM25; snippets are trimmed to ~200 characters.

Show

rousseau session show <session-id>

Prints the full transcript with → tool_use(name, input) and ← tool_result markers between assistant messages. Useful for auditing an unattended daemon's session.

Delete

rousseau session delete <session-id> --yes

The --yes flag is required (newSessionDeleteCmd). Deletion cascades through the FTS5 triggers so the recall index stays consistent.

Compression triggers

When agent.compression.enabled: true in config.yaml, the LLMCompressor (internal/agent/compressor.go) checks two conditions before each turn:

  • len(s.Messages) >= trigger_messages (default 60).
  • len(s.Messages) > keep_recent (default 8).

If both hold, the compressor summarises the oldest slice into one synthetic user message prefixed with the marker [rousseau-compressed], then keeps the last keep_recent messages verbatim. The rewritten session replaces the original in memory and is persisted on the next Store.Save.

A second compression on an already-compressed session is skipped unless the session has grown to more than 2 * trigger_messages — this bounds runaway growth without paying to re-summarise every turn.

Log line:

INFO agent.compressed messages=68

Restoration

Sessions restore automatically. The transport router (internal/transport/router.go) looks up the JID → session id mapping on inbound, then Store.Load unmarshals the JSON payload back into an agent.Session. No manual step.

If a mapping is stale — session id exists in jid_sessions but not in sessions — you'll see router.stale_mapping (WARN), and the router creates a fresh session. Legacy artefact from a partial delete; safe to ignore.

Manual restoration from a backup

To roll back the entire session store from a .backup snapshot:

systemctl --user stop rousseau-agent
cp /backup/sessions.db.2026-07-12.bak ~/.local/share/rousseau/sessions.db
rm -f ~/.local/share/rousseau/sessions.db-wal ~/.local/share/rousseau/sessions.db-shm
systemctl --user start rousseau-agent

The -wal and -shm files must be dropped alongside the primary; SQLite reconstructs them on next open.

Bulk deletion by age

There is no built-in "delete sessions older than X" CLI. Drop through SQLite:

sqlite3 ~/.local/share/rousseau/sessions.db <<'SQL'
DELETE FROM sessions WHERE updated_at < datetime('now', '-90 days');
SQL

FTS5 triggers keep the recall index consistent.

Preserving privacy

Since session content is stored plaintext in a JSON blob, treat sessions.db as sensitive. Options:

  • Filesystem-level encryption. LUKS on Linux, FileVault on macOS.
  • Encrypted backups. restic and borg both encrypt at rest.
  • Delete-on-completion for one-shot sessions. For cron-driven daemons, a post-run hook could rousseau session delete the just-completed session id. Not built-in today; see Guides: Enterprise Onboarding for the review.

Full rousseau session command reference

List sessions, newest first:

rousseau session list
rousseau session list --limit 100
rousseau session list --json

Columns: ID, Title, Messages, UpdatedAt. The --json flag emits one object per line for scripted consumers.

Troubleshooting

session not found

The ID you passed does not exist. Case-sensitive. Use rousseau session list to see valid IDs.

FTS5 search returns nothing

The index might be out of date on legacy sessions imported before FTS5 was wired. Rebuild by running any content-mutating operation (a delete triggers reindex), or reindex manually via SQLite.

database is locked on read

Another daemon is holding a WAL write lock. Use a read-only DSN (?mode=ro) if you only need to read.

Session store growing too fast

Enable compression (agent.compression.enabled: true) and periodically VACUUM the SQLite file to reclaim space.

Restore from backup produces stale state

Ensure you dropped -wal and -shm before starting the daemon. SQLite will replay the WAL if -wal is present, potentially undoing your restore.

Related pages

Further reading

  • internal/cli/session.go — CLI wiring.
  • internal/state/sqlite/store.go — DSN, WAL, indexes.
  • internal/agent/session.go — the Session struct.
  • internal/agent/compressor.goLLMCompressor.
  • internal/agent/recall.goSQLiteRecall.

Type to search 150+ pages. Ranking: BM25 with title/description boost.