Repository navigation
v1.0.0 — measure, export, continue
A long-session handoff for Hermes Agent: when a chat approaches the token limit that ends it, this measures how close it really is, exports the whole session to disk, and continues in a fresh chat that reads the parent transcript in full before doing anything else.
git clone https://github.com/IRDcode/hermes-agent-session-handoff
cd hermes-agent-session-handoff
python install.py --dry-run # see every change first
python install.py # then restart HermesPython 3.8+, no dependencies. python install.py --uninstall removes exactly what it added.
What it does
- Measures context against the exact wall. Not row counts — tokens, against the point where Hermes compacts (or where the provider refuses, with compression off). Verified against Hermes' own log: window 1,000,000 at threshold 0.50 gives 500,000, and Hermes logged
~501,079 tokens >= 500,000 thresholdwhen it fired. - Exports five files. Every user message verbatim and deduped, every substantial assistant message, the full transcript, an index of counts, and — because Hermes archives compacted turns rather than deleting them — the context earlier compactions already removed, recovered from disk.
- Verifies the read. The continuation is created and seeded headlessly; it must reply with counts that match the index. A count that does not match means the read was partial and the handoff is not done.
- Pins what does not persist. Model, provider, endpoint and iteration budget are written onto the child row and read back, because
-mdoes not persist and--max-turnsfreezesmax_iterationson the row. - Names the continuation in its own language.
Refactor auth (cont. 2),ربات ثبتنام — ادامه ۲,تحليل البيانات (الجزء ٢),重构登录流程(续 2),ログイン改修(続き 2). Titles are written directly to the database becausehermes sessions renamestrips U+200B–U+200F, which includes the ZWNJ — a letter-level character in Persian, Arabic and Urdu.
Three measurement bugs fixed, with the numbers
- Archived rows counted as live context. Hermes compacts in place and keeps the replaced turns (
active = 0, compacted = 1). On real sessions the total ran 2 to 4 times the live set — worst case 3,389 rows on disk against 832 live. Onlyactive = 1is context now. - Elapsed time scored as working time. One session reported a 15.98 hour span of which a single gap was 14.43 hours of sleep — 1.55 hours of actual work. Working time is the sum of gaps under 10 minutes.
- Compaction markers counted by substring.
content LIKE '%CONTEXT COMPACTION%'matches the agent's own tool output the moment anyone greps for it: 35 tool rows in one real database, and a session that had never been compacted scored 3 compactions. Counted structurally now.
And one that cannot be fully solved: the chars/4 estimate is about 28% low on its own, because tool schemas ride every request and appear in neither the session store nor the message list. Measured live: 297,239 reported prompt tokens against a 214,715 estimate (0.72x). The fix differences sessions.input_tokens / api_call_count between two turns — the provider's own exact count — and learns the per-session overhead.
The 62% gate
Nothing is offered below 62% of the wall, whatever else tripped. Re-scoring 21 real firings of the pre-gate detector, 6 sat below 40%; the worst had 1,685 rows and 5.2 active hours while its live context was 157,759 of a 500,000 wall — 32%. Migrating there abandons ~340,000 tokens of paid-for headroom.
Verified
152 assertions across three suites, green on Linux, macOS and Windows against Python 3.8, 3.11 and 3.13, plus a real install/uninstall cycle on each platform.
python tests/test_session_weight.py # 51 — arithmetic, the gate, the three traps
python tests/test_handoff.py # 72 — export, naming, plugin hook, chain log
python tests/test_compat.py # 29 — syntax floor, entry points, other PythonsDocs: how it works · troubleshooting · security · README in 简体中文, 日本語, Español, فارسی
Also for Claude Code: claude-code-session-handoff.