hermes-lean-ctx
lean-ctx as Hermes' active context engine. This plugin replaces Hermes
Agent's built-in ContextCompressor with deterministic, prompt-cache-friendly
compaction and injects lean-ctx's code-intelligence + cross-session memory tools
natively into the agent's tool list.
Instead of being "just another MCP server the agent might call", lean-ctx owns the context window: it decides what to keep verbatim, offloads older turns into durable memory, and gives the agent first-class recall tools to page that memory back in losslessly.
Why lean-ctx over the alternatives
built-in ContextCompressor |
hermes-lcm | hermes-lean-ctx | |
|---|---|---|---|
| Strategy | summarize + drop | DAG + SQLite + FTS | BM25 + graph + knowledge + semantic + LITM placement |
| Recall after compaction | lossy | lossless (grep/expand) | lossless (ctx_search/ctx_semantic_search/ctx_expand/ctx_read/ctx_knowledge) |
| Cross-session memory | no | per-project | yes (sessions, knowledge, handoff ledgers) |
| Determinism / prompt-cache | n/a | partial | deterministic, byte-stable output (prompt-cache friendly) |
| Engine location | in-agent | in-plugin | in the lean-ctx daemon (Single Source of Truth) |
Compaction logic lives in the daemon's ctx_transcript_compact tool, so every
client (this plugin, the CLI, other editors) gets identical, tested behaviour.
How it works
Hermes agent loop
└─ ContextEngine ABC ── LeanCtxEngine (this plugin, thin adapter)
└─ leanctx SDK ── HTTP /v1 ── lean-ctx daemon
└─ ctx_transcript_compact,
ctx_search, ctx_knowledge, …
compress(messages)keeps the system preamble and a fresh tail verbatim, and replaces older turns with a compact, recoverable summary. It calls the daemon'sctx_transcript_compact(which also offloads the raw turns into session memory for recall). If the daemon is unreachable it falls back to a pure-Python compaction so the agent loop never breaks.tool_call/tool_resultpairs are never split across the compaction boundary — this invariant is enforced and tested on both the daemon and plugin side.- Native tools (
get_tool_schemas/handle_tool_call) exposectx_search,ctx_semantic_search,ctx_read,ctx_expand,ctx_knowledge,ctx_summaryso the agent can page detail back in on demand. - Cross-session persistence via session lifecycle hooks:
resumeon start,ctx_summary+ a deterministicctx_handoffledger on end.
Requirements
- A running lean-ctx daemon exposing the HTTP
/v1tools API (lean-ctx serve). See Setup. - The
leanctxPython SDK in Hermes' environment:pip install lean-ctx-client. - Optional:
tiktokenfor exact token counts (a char-based estimate is used otherwise). - A Hermes Agent build that supports context-engine plugins
(
context.engine+register_context_engine).
Setup
# 1. Install the plugin (symlinks this checkout into ~/.hermes/plugins).
./scripts/install.sh
# 2. Start the lean-ctx HTTP tools API (serves /v1; default port 8080).
# NOTE: the always-on proxy (port 4444+) does NOT serve /v1/tools — use serve.
lean-ctx serve --host 127.0.0.1 --port 8080
# 3. Install the SDK in Hermes' Python.
pip install lean-ctx-client
# 4. Activate the engine in ~/.hermes/config.yaml:
# context:
# engine: "lean-ctx"
If your server is not on the default, point the plugin at it:
export LEANCTX_BASE_URL=http://127.0.0.1:8080
export LEANCTX_TOKEN=<token> # only if you ran serve with --auth-token
Only one context engine can be active, so lean-ctx and hermes-lcm cannot be enabled at the same time.
Configuration (LEANCTX_* env vars)
| Variable | Default | Meaning |
|---|---|---|
LEANCTX_BASE_URL |
http://127.0.0.1:8080 |
lean-ctx /v1 base URL |
LEANCTX_HTTP_PORT |
8080 |
Port used when LEANCTX_BASE_URL is unset |
LEANCTX_TOKEN |
– | Bearer token (if serve --auth-token) |
LEANCTX_TIMEOUT |
30.0 |
HTTP timeout (seconds) |
LEANCTX_CONTEXT_LENGTH |
200000 |
Context window used until the host calls update_model |
LEANCTX_THRESHOLD_FRACTION |
0.75 |
Fraction of the window at which compaction fires |
LEANCTX_PROTECT_FRACTION |
0.25 |
Recent fraction kept verbatim (the fresh tail) |
LEANCTX_PROTECT_MIN_MESSAGES |
6 |
Minimum recent messages kept verbatim |
LEANCTX_PROTECT_MIN_TOKENS |
2000 |
Minimum tail token budget |
LEANCTX_ENABLE_TOOLS |
1 |
Inject native recall tools into the agent |
LEANCTX_CORE_COMPACTION |
1 |
Prefer the daemon's ctx_transcript_compact (fallback: local) |
LEANCTX_WORKSPACE_ID / LEANCTX_CHANNEL_ID |
– | Optional routing for multi-workspace daemons |
Model context windows are inferred from the model name when the host does not
provide one (see presets.py); Hermes' explicit update_model(context_length=…)
always wins.
Testing
# Hermetic unit tests (no daemon required):
python -m pytest
# Live integration against a real daemon:
lean-ctx serve --host 127.0.0.1 --port 8080 --auth-token test-token &
LEANCTX_LIVE_URL=http://127.0.0.1:8080 LEANCTX_LIVE_TOKEN=test-token \
python -m pytest tests/test_live_daemon.py -v
No mock data is used: unit tests exercise the real compaction logic and a recording gateway; live tests hit a real daemon.
Benchmarks
benchmarks/ contains a real, runnable head-to-head harness (token savings,
compress() latency, recoverable-recall). See benchmarks/README.md.
License
Apache-2.0 — see the lean-ctx repository.