Agents / Sessions and memory
Session management
Genesis organizes conversations into sessions. Each message is routed to a session based on where it came from -- DMs, group chats, cron jobs, etc.
How messages are routed
| Source | Behavior |
|---|---|
| Direct messages | Shared session by default |
| Group chats | Isolated per group |
| Rooms/channels | Isolated per room |
| Cron jobs | Fresh session per run |
| Webhooks | Isolated per hook |
DM isolation
By default, all DMs share one session for continuity. This is fine for single-user setups.
If multiple people can message your agent, enable DM isolation. Without it, all users share the same conversation context -- Alice's private messages would be visible to Bob.
The fix:
{
session: {
dmScope: "per-channel-peer", // isolate by channel + sender
},
}
Other options:
main(default) -- all DMs share one session.per-peer-- isolate by sender (across channels).per-channel-peer-- isolate by channel + sender (recommended).per-account-channel-peer-- isolate by account + channel + sender.
If the same person contacts you from multiple channels, use
session.identityLinks to link their identities so they share one session.
The contacts feature can derive these links from the shared
$GENESIS_STATE_DIR/contacts.json store. It is enabled unless
session.contacts.enabled is explicitly false; set session.contacts.unifySessions
to true to apply contact-derived links to DM session keys. When it is omitted
or false, contact-derived links are not used for session keys; configured
session.identityLinks keep their existing behavior.
Verify your setup with genesis security audit.
Session lifecycle
Sessions are reused until they expire:
- Daily reset (default) -- new session at 4:00 AM local time on the gateway host.
- Idle reset (optional) -- new session after a period of inactivity. Set
session.reset.idleMinutes. - Manual reset -- type
/newor/resetin chat./new <model>also switches the model.
When both daily and idle resets are configured, whichever expires first wins.
Sessions with an active provider-owned CLI session are not cut by the implicit
daily default. Use /reset or configure session.reset explicitly when those
sessions should expire on a timer.
Where state lives
All session state is owned by the gateway. UI clients query the gateway for session data.
- Store:
~/.genesis/agents/<agentId>/sessions/sessions.json - Transcripts:
~/.genesis/agents/<agentId>/sessions/<sessionId>.jsonl - Contacts:
~/.genesis/contacts.json(shared by all agents in the active state root)
Contacts are not part of per-agent session isolation. The owner-only contacts
tool and Gateway contacts methods read and write this shared state-root file,
so use a separate profile or state directory when agents must not share
remembered people or messenger identities. Set session.contacts.enabled to
false to disable the contacts tool, auto-capture, routing integration, and
Gateway contacts methods without reading or writing the shared store.
Session maintenance
Genesis automatically bounds session storage over time. By default, it runs
in warn mode (reports what would be cleaned). Set session.maintenance.mode
to "enforce" for automatic cleanup:
{
session: {
maintenance: {
mode: "enforce",
pruneAfter: "30d",
maxEntries: 500,
},
},
}
Preview with genesis sessions cleanup --dry-run.
Inspecting sessions
genesis status-- session store path and recent activity.genesis sessions --json-- all sessions (filter with--active <minutes>)./statusin chat -- context usage, model, and toggles./context list-- what is in the system prompt.
Further reading
- Session Pruning -- trimming tool results
- Compaction -- summarizing long conversations
- Session Tools -- agent tools for cross-session work
- Session Management Deep Dive -- store schema, transcripts, send policy, origin metadata, and advanced config
- Multi-Agent — routing and session isolation across agents
- Background Tasks — how detached work creates task records with session references
- Channel Routing — how inbound messages are routed to sessions