Session File Leak: JSON Sessions Never Deleted, Causing Unbounded Disk Growth and Cost Explosion
Summary
Hermes Agent creates session JSON files for every conversation (chat, cron, subagent) but never deletes them. Over time, this leads to:
- Hundreds/thousands of accumulated session files (observed: 728 files, 94MB on single machine)
- Unbounded disk usage
- Exacerbated token costs (large sessions with 500+ messages accumulate context forever)
- 22M+ tokens burned in ~2 hours due to unchecked session growth
Root Cause Analysis
1. Session Reset Creates New Files, Never Deletes Old
In gateway/session.py, the reset_session() function:
- Creates a new
SessionEntry with a new session_id
- Updates the in-memory mapping (
_entries) to point to the new session
- Saves to session store
- Calls
end_session() in SQLite database (marks as ended)
- Does NOT delete the old JSON file
# From session.py:776-800
def reset_session(self, session_key: str) -> Optional[SessionEntry]:
# ... creates new session_id ...
new_entry = SessionEntry(
session_key=session_key,
session_id=session_id, # NEW ID
# ...
)
self._entries[session_key] = new_entry # Updates mapping
self._save()
# Creates NEW session file, old one remains on disk forever
2. Cron Sessions Multiply Rapidly
Each cron execution creates a new session with ID format: cron_{job_id}_{timestamp}. With crons running every 15-45 minutes:
- 1 cron × 96 runs/day × 7 days = 672 session files per week per cron
- Observed: 535 cron session files (73.5% of all sessions)
3. Session Files Are Never Cleaned Up
No deletion mechanism exists:
end_session() in hermes_state.py:252 only marks sessions as ended in SQLite (ended_at, end_reason)
- No
os.remove() call for session JSON files
- No retention policy for filesystem cleanup
- Sessions accumulate indefinitely
4. Large Sessions Retain Full Context
Session files contain complete message history. Observed:
- Sessions with 500-600 messages
- File sizes: 500KB-1MB each
- All tool call results preserved forever
- Context compression happens in-memory but original files remain
Impact
Quantified on SCANNINGPC (Deimos):
- 728 session files accumulated
- 94.33 MB total size
- 535 cron sessions (73.5% of total)
- 418 sessions aged 1-7 days
- 245 sessions aged 6-24 hours
Token Cost Explosion
One session accumulated 602 messages in 107 seconds:
- 209 tool call iterations
- ~102K tokens
- 5.61 messages/second processing rate
- User sent 105 messages (frustrated rapid-fire interaction)
- Assistant responded with 274 messages + 223 tool results
With no session cleanup, context grows exponentially until iteration limit hit.
Reproduction Steps
-
Run Hermes gateway with any cron job (e.g., every 15 minutes)
-
Let run for 24-48 hours
-
Check ~/.hermes/sessions/:
ls -la ~/.hermes/sessions/session_*.json | wc -l
# Returns: 100+ files
-
Observe files are never deleted, only new ones created
Evidence
Session Age Distribution
<1h: 9 files
1-6h: 54 files
6-24h: 245 files
1-7d: 418 files
>7d: 2 files
Cron Session Dominance
- Cron sessions: 535 (73.5%)
- Chat sessions: 193 (26.5%)
Large Session Examples
session_20260325_112518_6995d1.json: 725 KB, 602 messages
session_20260325_110422_70aca0.json: 722 KB, 570 messages
Proposed Solutions
Immediate (Hotfix)
-
Add session file cleanup on reset:
# In reset_session(), before creating new entry:
old_session_file = self._sessions_dir / f"{old_entry.session_id}.json"
if old_session_file.exists():
old_session_file.unlink()
-
Add retention policy:
- Delete session files older than 7 days
- Keep SQLite records for history
- Configurable retention period
Short-term
-
Session size limits:
- Max 1000 messages per session before forced reset
- Max 10MB per session file
- Alert when sessions grow too large
-
Cron session optimization:
- Option for cron sessions to not persist to JSON (SQLite only)
- Automatic cleanup of cron sessions after delivery
Long-term
-
Session archival:
- Compress old sessions to
.gz
- Archive to separate directory
- Background cleanup job
-
Cost controls:
- Per-session token budgets
- Max iterations enforced strictly
- Automatic session kill on threshold breach
Files Affected
gateway/session.py - Session lifecycle management
hermes_state.py - SQLite session tracking
run_agent.py - Session creation
cron/scheduler.py - Cron session creation
Environment
- Hermes Agent version: Latest (as of 2026-03-25)
- Installation: Source (git clone)
- Platforms: Telegram, Discord, CLI, Cron
- OS: Ubuntu (WSL2)
Labels
bug, performance, cost, storage, sessions, priority-critical
Session File Leak: JSON Sessions Never Deleted, Causing Unbounded Disk Growth and Cost Explosion
Summary
Hermes Agent creates session JSON files for every conversation (chat, cron, subagent) but never deletes them. Over time, this leads to:
Root Cause Analysis
1. Session Reset Creates New Files, Never Deletes Old
In
gateway/session.py, thereset_session()function:SessionEntrywith a newsession_id_entries) to point to the new sessionend_session()in SQLite database (marks as ended)2. Cron Sessions Multiply Rapidly
Each cron execution creates a new session with ID format:
cron_{job_id}_{timestamp}. With crons running every 15-45 minutes:3. Session Files Are Never Cleaned Up
No deletion mechanism exists:
end_session()inhermes_state.py:252only marks sessions as ended in SQLite (ended_at,end_reason)os.remove()call for session JSON files4. Large Sessions Retain Full Context
Session files contain complete message history. Observed:
Impact
Quantified on SCANNINGPC (Deimos):
Token Cost Explosion
One session accumulated 602 messages in 107 seconds:
With no session cleanup, context grows exponentially until iteration limit hit.
Reproduction Steps
Run Hermes gateway with any cron job (e.g., every 15 minutes)
Let run for 24-48 hours
Check
~/.hermes/sessions/:Observe files are never deleted, only new ones created
Evidence
Session Age Distribution
Cron Session Dominance
Large Session Examples
session_20260325_112518_6995d1.json: 725 KB, 602 messagessession_20260325_110422_70aca0.json: 722 KB, 570 messagesProposed Solutions
Immediate (Hotfix)
Add session file cleanup on reset:
Add retention policy:
Short-term
Session size limits:
Cron session optimization:
Long-term
Session archival:
.gzCost controls:
Files Affected
gateway/session.py- Session lifecycle managementhermes_state.py- SQLite session trackingrun_agent.py- Session creationcron/scheduler.py- Cron session creationEnvironment
Labels
bug,performance,cost,storage,sessions,priority-critical