-
Notifications
You must be signed in to change notification settings - Fork 0
Harnesses
Five ways in, so a harness needs no particular capability to be reached — and an explicit note on which of them are verified and which are not.
On this page: What is verified · MCP — any client · Oh My Pi · Hermes · Agent Skill · Reverse proxy
All five reach the same daemon and the same memory, and you can use more than one.
Stated up front, because the difference between "supported" and "seen working" is the whole value of this table.
| Route | Verified | Not verified |
|---|---|---|
| MCP over stdio |
stdio_transport.rs spawns the real binary and speaks JSON-RPC over its pipes. hermes mcp test sakur4 discovers all 17 tools against a real Hermes install. |
— |
| MCP over HTTP |
gateway.rs drives the tool surface over a live HTTP listener using the SDK's own client. |
No MCP reference-client conformance run. |
| Oh My Pi | Native tools driven end-to-end by a live model; verified against OMP 18.2.x (installed build 18.2.11). | The OMP compaction hook has never fired for real — forcing OMP past its context limit is separate work. |
| Hermes | Engine registers, is instantiated by a real Hermes install, talks to a live daemon, and passes 44 contracts. Its MCP transport discovers all 17 tools. | No live agent session through Hermes — its own tool selection is untested, and a session driving a model has not succeeded (Hermes provider routing). |
| Agent Skill | Ships in every release archive and is installed by install.sh into ~/.agents/skills/. |
Nothing exercises it in CI: the harness group needs OMP or the Hermes CLI, and CI has neither. |
| Reverse proxy | Verified against the OMP harness — the full comparison is in docs/verification/proxy-harness.md. |
— |
verify.mjs reports skipped separately from passed, so a run that skipped its live checks is not a green run.
The baseline route, and the one that needs nothing beyond the daemon. config prints ready-to-paste configuration with this binary's absolute path and store baked in, so there is no placeholder to forget:
sakur4d config hermes # ~/.hermes/config.yaml
sakur4d config claude # claude_desktop_config.json
sakur4d config claude-code # one-line CLI registration
sakur4d config generic-http # anything that connects to a URL
sakur4d config generic-stdio # anything that spawns a child process[HARNESS] defaults to hermes, and --binary overrides the path that gets baked in.
| Transport | How the harness reaches it | Use it when |
|---|---|---|
| stdio | Spawns sakur4d and speaks JSON-RPC over its pipes. |
One harness; no port to manage. This is every MCP client, and it is the default. |
| streamable HTTP | Connects to a URL. | Several sessions sharing one store, or a harness on another machine. |
sakur4d serve # stdio — the default
sakur4d serve --transport http --bind 127.0.0.1:8765 # sharedOver HTTP, requests carry the revision in a per-request _meta block, and the SEP-2243 headers MCP-Protocol-Version and Mcp-Method — plus Mcp-Name for tools/call — are required.
Configuration to paste — sakur4d config generic-stdio and sakur4d config generic-http produce exactly these, with real paths:
{
"mcpServers": {
"sakur4": {
"command": "/absolute/path/to/sakur4d",
"args": [
"--db", "/absolute/path/to/sakur4.db",
"--project-root", "/absolute/path/to/project",
"serve", "--transport", "stdio"
]
}
}
}For a shared HTTP server instead, start it once in its own terminal and point the client at the URL:
sakur4d --db /absolute/path/to/sakur4.db serve --transport http --bind 127.0.0.1:8765
# client URL: http://127.0.0.1:8765/Bind to
127.0.0.1unless you mean to expose the store on a network. There is no authentication — localhost binding is the control, and--bind 0.0.0.0exposes the entire Memory Fabric, including writes, to anyone who can reach the port.
For OMP there is no MCP client. It needs a native TypeScript extension instead — which turns out to be an advantage, because an extension can see inside the agent loop and therefore reach hooks a tool provider cannot.
node integrations/omp-plugin/install.mjsThe installer copies the plugin into ~/.omp/plugins/node_modules/omp-sakur4, declares it in ~/.omp/plugins/package.json, enables it in omp-plugins.lock.json, and installs the Agent Skill into ~/.agents/skills/. Options: --no-skill, --skill-only, --dir <omp home>, --uninstall.
Then restart OMP and ask it to list its sakur4_ tools — there should be nine: sakur4_commit, sakur4_pin, sakur4_recall, sakur4_symbol, sakur4_impact, sakur4_fold, sakur4_unfold, sakur4_receipt, sakur4_status.
| Hook | What Sakur4 does with it |
|---|---|
session_start |
Probes the daemon once; reports a missing binary before ten turns go unrecorded; live counts in the status bar. |
before_agent_start |
Injects the working preamble once per session — the instructions that make a model actually pin and fold. |
context |
Retrieves memory for the prompt, capped, and reports its own token cost so the budget stays honest. |
message_end |
Forwards provider token usage every turn, automatically. |
session_before_compact |
Replaces blind summarisation with Sakur4's planned eviction. |
session_shutdown |
Reports stale summaries, because the next session inherits them. |
resources_discover |
Contributes the bundled Agent Skill. |
There is also a /sakur4 command: status, receipt, recall <query>, pin <text>, index [path], map [budget], staleness, dream.
Compaction falls back on purpose. If the daemon is unreachable, the plan is empty, or the plan would not actually reduce the context, the hook returns nothing and OMP performs its normal compaction.
Two install traps the installer avoids. omp install <path> symlinks, which fails on Windows with a bare EPERM: operation not permitted, symlink unless Developer Mode is on — the installer copies instead. And OMP's plugin loader silently skips a lockfile entry that is neither declared in ~/.omp/plugins/package.json nor a symlink, reporting it only as skipping stale lockfile entry in a log — so the plugin appears in omp plugin list and passes omp plugin doctor while never actually loading. Writing both files is the fix.
Configuration to paste — the installer writes these for you; this is what to check if the tools do not appear:
# 1. Put sakur4d on PATH (`cargo install sakur4d`), or name it explicitly:
export SAKUR4_BIN=~/.cargo/bin/sakur4d
# 2. Install, then restart OMP.
node integrations/omp-plugin/install.mjs| Variable | Default | Meaning |
|---|---|---|
SAKUR4_RETRIEVE |
true |
Inject retrieved memory before each turn. |
SAKUR4_REPORT_USAGE |
true |
Report provider usage automatically. |
SAKUR4_OWN_COMPACTION |
true |
Take over compaction. |
SAKUR4_RECALL_BUDGET |
1200 |
Approximate token cap on injected memory. |
SAKUR4_SESSION |
omp-<dir name> |
Session id. |
SAKUR4_PLUGIN_LOG |
unset | Append lifecycle diagnostics to this file. |
Requirements: Oh My Pi 18.2.x, sakur4d 0.1.0 or newer, Node.js 18+ (OMP bundles its own runtime). The plugin declares no version floor at all — its package.json carries "@earendil-works/pi-coding-agent": "*" as an optional peer dependency, the extension API is undocumented, and a minor bump can change it without notice. --no-extensions is how to tell whether a failure is OMP's or this plugin's.
Hermes has its own compaction path, so exposing MCP tools is not enough: its summariser still runs. integrations/hermes-plugin/ replaces it, which also closes a loop MCP alone cannot — update_from_response receives the provider's token accounting on every call, so prompt-cache behaviour is measured automatically instead of reported by hand.
| Hermes hook | What this engine does with it |
|---|---|
update_from_response(usage) |
Forwards the provider's token accounting — including cache read/write counts — to Sakur4 on every call. |
should_compress |
Fires at the same threshold Hermes would, so behaviour stays predictable. |
compress |
Commits every message to the append-only stream, asks Sakur4 what to evict, and replaces exactly those messages with a marker. |
select_context |
Injects the Anchor Set into every request, after the system prompt. |
get_tool_schemas / handle_tool_call
|
Exposes sakur4_recall, so the model can look something up rather than reconstruct it. |
prune_tool_results_only |
Commits but prunes nothing — Sakur4's plan already treats re-runnable tool results as its first eviction candidates, and pruning here as well would evict twice for one saving. |
__deepcopy__ |
Copies budget state and builds a fresh client, because Hermes deep-copies the engine for sub-agents. |
Every daemon call is best-effort. If sakur4d is not running, compress() returns the messages unchanged and Hermes handles the overflow with its own fallback. A context engine that breaks a session when its sidecar is down is worse than no context engine.
Three enabling details, each of which cost time to find:
-
context.enginemust not be the default. The selector returnsNoneimmediately when the engine name iscompressor, so a plugin is never consulted. Any other name takes the plugin path. -
A plugin must be enabled, not merely discovered.
hermes plugins listshowssakur4 … not enabledand the loader agrees untilhermes plugins enable sakur4has run. -
The ContextEngine loader reads the repo, not
HERMES_HOME. The general plugin system at$HERMES_HOME/plugins/can be redirected; that is the path this engine uses.
Configuration to paste:
# 1. Install the plugin.
cp -r integrations/hermes-plugin "$LOCALAPPDATA/hermes/plugins/sakur4"
hermes plugins enable sakur4 # discovery and activation are separate steps
hermes plugins list # should show `sakur4` with source `user`
# 2. Start the daemon the engine talks to.
sakur4d serve --transport http --bind 127.0.0.1:8770 --context-window <your model's window># ~/.hermes/config.yaml
context:
engine: sakur4| Variable | Default | Meaning |
|---|---|---|
SAKUR4_URL |
http://127.0.0.1:8765 |
Where the daemon is listening. |
SAKUR4_THRESHOLD_PERCENT |
0.75 |
Fraction of the window at which compaction fires. |
SAKUR4_BIN |
searched | Path to sakur4d, using the same search order as the OMP extension. |
SAKUR4_SESSION |
hermes |
Session id. |
Pass --context-window, and make it small enough that your history exceeds the trigger. Without it the daemon plans against the backend's reported window — the embedded backend simulates 32,768 — and a plan that correctly reclaims nothing reads as "the engine cannot compact" when it is the test that has not applied enough pressure.
No live Hermes model session has succeeded, and the cause is Hermes' provider resolution rather than this engine: a
--modeloverride that does not resolve fails silently, falling back to the config's cloud default and reporting its credentials.integrations/hermes-plugin/LIVE-TESTING.mdrecords exactly where it stopped so finishing it does not mean repeating that search. Checkhermes statusbefore blaming anything downstream.
skills/sakur4/ is a portable Agent Skills package: a SKILL.md plus a dependency-free Node CLI over the daemon.
~/.agents/skills/ is the standard location, so OMP, Claude Code, Codex and pi all pick it up with no further configuration. Progressive disclosure means only the description sits in context until a task matches.
The CLI locates sakur4d across install layouts, defaults the store to ~/.sakur4/sakur4.db, and spawns with shell: false — so recorded content may contain quotes, newlines or backticks intact. That matters when the primary use is committing the user's words verbatim.
Configuration to paste:
# Install just the skill, without the OMP extension.
node integrations/omp-plugin/install.mjs --skill-only # → ~/.agents/skills/
# Or take it straight from a checkout / the release archive.
node scripts/sakur4.mjs doctor
node scripts/sakur4.mjs doctor --bin /path/to/sakur4dEvery skill command accepts --session, --bin and --db, so the environment variables are conveniences rather than requirements. The CLI's commands are doctor, commit, pin, recall, receipt, usage, fold, unfold, index, map, symbol, impact, staleness and dream.
node scripts/sakur4.mjs commit --role user --content "refactor the auth module"
node scripts/sakur4.mjs pin --kind task_contract --content "keep the public API of src/auth.rs backward compatible"
node scripts/sakur4.mjs recall --query "how did we decide to handle retries" --k 5What the skill deliberately does not do: it does not replace compaction or decide what leaves the context window — that is the harness's job, and Sakur4's eviction engine only ever advises. It does not call a model. And it does not claim to know something it did not store: if recall returns nothing, the honest next step is to read the file.
A harness with none of the above still works. Point it at the proxy instead of at llama-server and nothing else changes.
Requests are forwarded untouched — every unrecognised route included, so a harness calling an endpoint this build has never heard of gets the upstream's own answer rather than a 404 from Sakur4. A transcript that exceeds the window is trimmed on the way through, with a marker left in place of the removed turns, and the provider's token accounting is recorded from the response the proxy already had to read.
sakur4d proxy --bind 127.0.0.1:8090 --upstream http://127.0.0.1:8080
# harness base URL: http://127.0.0.1:8090/v1Configuration to paste:
# 1. Measure first. Forward everything unchanged, record only.
sakur4d proxy --bind 127.0.0.1:8090 --upstream http://127.0.0.1:8080 --observe-only
# 2. Then let it act on real traffic.
sakur4d proxy --bind 127.0.0.1:8090 --upstream http://127.0.0.1:8080--observe-only is the safe way to see what the proxy would have done on your real traffic before letting it act. --session names the session reported to the Memory Fabric.
Do not run the proxy and the OMP extension at the same time. Both manage context, and a turn gets managed twice — OMP hangs before sending its first request. Use the proxy or the extension.
--no-extensionsdisables the extension for a proxied session.
Local memory and context for long agent sessions.
- Home
- Getting Started — install, configure, first session
- Concepts — the vocabulary, if the README was too dense
- Tool Reference — all 17 tools, with arguments and when to call them
- Harnesses — OMP · Hermes · Claude · any MCP client · raw HTTP
- Configuration — every flag and environment variable
- CLI Reference — the terminal surface
- Architecture — how eviction, memory and coherence fit together
- Cache Coherence — why compaction invalidates a prompt cache, and what to do
- Memory Model — the Ledger, the Atlas, and why a model may not write to both
- Benchmarks — what changes with it, and without it
- Verification — the checks, and how to run them
- Limitations — what does not work yet, stated plainly
- Security — threat model, encryption at rest, reporting
- Design Decisions — the trade-offs, including the ones that were wrong first
- Contributing — from checkout to pull request
- Releasing — how a version ships
- Troubleshooting — when something is not working