The convention
Rousseau does not have a first-class "workspace" concept. It has one state.path in internal/config/config.go (StateConfig) and by default points every process at ~/.local/share/rousseau/sessions.db. All sessions, cron jobs, JID mappings, and the FTS5 recall index live in that single file.
For most operators that's exactly right. When you want isolation — per project, per machine, per client — you point rousseau at a different SQLite file. That file is the workspace.
Switch workspace per invocation
Two knobs, either works:
# 1. flag on any rousseau command
rousseau --config ~/.config/rousseau/acme.yaml chat
# 2. env var (Viper picks it up via ROUSSEAU_STATE_PATH)
ROUSSEAU_STATE_PATH=~/.local/share/rousseau/acme.db rousseau chat
Neither approach requires a rousseau restart when you jump between workspaces — each process opens its own file.
Per-project workspace layout
~/.config/rousseau/
├── acme.yaml # provider = anthropic, state.path = …/acme.db
├── personal.yaml # provider = claudecli, state.path = …/personal.db
└── work.yaml # provider = bedrock, state.path = …/work.db
Each config file overrides state.path:
state:
path: /home/seb/.local/share/rousseau/acme.db
Then launch each session with the right config. The TUI (internal/tui/model.go) surfaces the session id + provider in its status bar — visual confirmation you're in the right workspace.
Sharing history across machines
The session store is a single SQLite file. WAL journaling is enabled by Open() in internal/state/sqlite/store.go, so live snapshots are safe:
# Snapshot laptop-to-desktop (both idle)
rsync -avz --partial \
~/.local/share/rousseau/sessions.db \
desktop:~/.local/share/rousseau/sessions.db
Only one writer at a time. Do not run rousseau whatsapp on two machines against the same SQLite file over NFS — that is undefined. Sync when nothing is writing, or run a single writer with read replicas.
A safer alternative is the .backup snapshot:
sqlite3 ~/.local/share/rousseau/sessions.db ".backup '/tmp/sessions.snap.db'"
scp /tmp/sessions.snap.db desktop:~/.local/share/rousseau/sessions.db
.backup uses SQLite's online backup API and produces a consistent point-in-time file.
Migrating a workspace
Move the whole directory; that's the workspace:
rsync -avz ~/.local/share/rousseau/ new-host:~/.local/share/rousseau/
whatsapp.db (device credentials) is separate — you either bring it too (device stays paired) or leave it behind and re-scan the QR on the new host.
Dropping a workspace's history
rousseau session list # confirm what you're about to lose
rm ~/.local/share/rousseau/acme.db* # includes -wal and -shm sidecars
The next process to open the path will re-create it with the schema in internal/state/sqlite/schema.sql.
If you only want to drop a subset of sessions, use the CLI:
rousseau session delete <id> --yes
rousseau session delete (internal/cli/session.go) calls Store.Delete, which cascades through the FTS5 triggers to keep the recall index consistent. The --yes flag is required — the command refuses to run without it.
Partial deletion via SQL
For bulk cleanup — every session older than 90 days:
sqlite3 ~/.local/share/rousseau/sessions.db <<'SQL'
DELETE FROM sessions WHERE updated_at < datetime('now', '-90 days');
SQL
The FTS5 triggers (sessions_fts_ad in internal/state/sqlite/search.go) fire on the DELETE and keep the index in sync automatically.
Per-workspace approvers
Because config file and state file are both per-workspace, so is the approver:
# work.yaml — strict pattern approver
agent:
approver:
mode: pattern
default: deny
allow:
- {tool: read, match: ".*"}
- {tool: grep, match: ".*"}
state:
path: /home/seb/.local/share/rousseau/work.db
A separate personal.yaml might keep mode: allow_all for interactive work. See Tutorial: Harden the approver.
Related
- Reference: Session store — schema.
- Guides: Multi-provider — the two-config, two-provider pattern.
- Reference: Environment Variables — every path env var.
- User Guide: CLI —
rousseau sessioncommands.