@marketintellabs/hermes-paperclip-adapter
v0.9.8-mil.0
Published
MarketIntelLabs fork of the Paperclip adapter for Hermes Agent — with adapter-owned status transitions, an in-process MCP tool server (paperclip-mcp) that replaces curl-in-prompt with structured tool calls, MIL heartbeat prompt templates, and OpenRouter m
Maintainers
Readme
@marketintellabs/hermes-paperclip-adapter
Actively maintained by MarketIntelLabs. This package is a MarketIntelLabs fork of the upstream
hermes-paperclip-adapterby Nous Research, published to npm as@marketintellabs/hermes-paperclip-adapter.All production deploys at MarketIntelLabs consume this fork. Upstream credit for the core adapter design goes to Nous Research; all fork-specific behaviours (listed under MIL-specific features below) are maintained here. See
UPSTREAM.mdfor the fork point, divergence list, and sync policy.
A Paperclip adapter that lets you run Hermes Agent as a managed employee in a Paperclip company.
Hermes Agent is a full-featured AI agent by Nous Research with 30+ native tools, persistent memory, session persistence, 80+ skills, MCP support, and multi-provider model access.
Recent releases
This fork's current workstream is reliability of the MCP tool plane —
the paperclip-mcp stdio server that replaced curl-in-prompt for every
Paperclip read/write — plus model-routing controls for the OpenRouter
fleet. Only the most recent releases are summarised here; see
CHANGELOG.md and the
GitHub Releases
page for the full history.
0.9.5-mil.0 — OPENROUTER_MODE toggle (production | hybrid | free_only).
Process-wide, env-controlled mode that maps each agent's tier to a paid or
free model. production is identity (deploy is a no-op until an operator
opts in). See src/server/openrouter-mode.ts.
0.9.6-mil.0 — per-tier fast free models. Replaced the openrouter/free
meta-router (which landed on slow Nemotron free endpoints at random) with a
specific fast, tool-calling free slug per tier.
0.9.7-mil.0 — re-baselined free-model defaults from a live smoke test.
Chose free slugs for availability (the popular "fast" slugs are essentially
always 429'd upstream), settling on the OpenAI gpt-oss family + z-ai/glm-4.5-air.
0.9.8-mil.0 — fixed the create_sub_issue(s) priority retry-loop (F6).
priority was a 0..4 integer schema, but the Paperclip API expects a string
enum (critical | high | medium | low) and the MCP SDK rejected the enum
string — a no-win that sent the model into a fix-args loop and timed out
delegation. New src/mcp/tools/priority.ts
accepts any input (string | number, never rejects) and coerces to the API
enum or drops it.
MIL-specific features
Features you get in this fork that upstream doesn't ship:
- Adapter-owned status transitions (
builtin:mil-heartbeat-v2+) — the adapter PATCHes the issue toin_progressbefore spawning Hermes and transitions it to the terminal status the LLM signalled via aRESULT:marker, instead of trusting the LLM to run the statusPATCHitself. Seesrc/server/result-marker.ts. - MCP tool server (
builtin:mil-heartbeat-v3, 0.7.0+) — thepaperclip-mcpstdio server that replaced curl-in-prompt. Seesrc/mcp/server.ts. - Per-run
HERMES_HOME(0.7.0+) — race-free per-run configuration for the MCP server. Seesrc/server/hermes-home.ts. - MCP tool audit + bypass + death detection (0.8.0+) — every run
that used the MCP tool plane gets a trustworthy record of which
tools were invoked (
resultJson.toolCalls), a flag when the LLM tried to bypass it withcurl(errorCode: tool_bypass_attempt), and a flag when the stdio subprocess died mid-run (errorCode: tool_server_died). Seesrc/server/mcp-telemetry.ts,src/server/bypass-detector.ts. update_issue_statusMCP tool (0.8.0+) — structured status transitions enforced byPAPERCLIP_ISSUE_IDscope. Replaces theRESULT:marker as the preferred signal; marker stays as a fallback.- Session-id poisoning guard (0.8.2+) — the legacy session-id regex is anchored and validated so Hermes' own error prose can't be mis-captured as a session id.
- OpenRouter model-prefix hints —
anthropic/,openai/,x-ai/,zai-org/model IDs route toprovider: openrouterautomatically. - MIL heartbeat prompt templates shipped in the package
(
templates/mil-heartbeat{,-v2,-v3,-v4}.md) selectable viapromptTemplate: "builtin:<name>". - Benign-stderr classifier (0.4.1+) — stderr only flips
errorMessageon strong failure signatures, not substring matches. - Run-context resolution (0.4.2+) — per-run fields resolved from
ctx.context(the modern Paperclip shape) withctx.configfallback. - Runtime hot-patch deploy path — the maintainer's infra ships a
scripts/upgrade-adapter.shthat overlays a new adapter tarball onto running containers without a full image rebuild, cutting deploy time significantly. Requires a companion entrypoint hook on the consumer side. - Release workflow —
.github/workflows/release.ymlpublishes to npm on everyv*tag push.
Key upstream features (unchanged)
- 8 inference providers — Anthropic, OpenRouter, OpenAI, Nous, OpenAI Codex, ZAI, Kimi Coding, MiniMax
- Skills integration — Scans both Paperclip-managed and Hermes-native skills (
~/.hermes/skills/), with sync/list/resolve APIs - Structured transcript parsing — Raw Hermes stdout is parsed into typed
TranscriptEntryobjects so Paperclip renders proper tool cards with status icons and expand/collapse - Rich post-processing — Converts Hermes ASCII banners, setext headings, and
+--+table borders into clean GFM markdown - Comment-driven wakes — Agents wake to respond to issue comments, not just task assignments
- Auto model detection — Reads
~/.hermes/config.yamlto pre-populate the UI with the user's configured model - Session codec — Structured validation and migration of session state across heartbeats
- Session source tagging — Sessions are tagged as
toolsource so they don't clutter the user's interactive history - Filesystem checkpoints — Optional
--checkpointsfor rollback safety - Thinking effort control — Passes
--reasoning-effortfor thinking/reasoning models
Hermes Agent Capabilities
| Feature | Claude Code | Codex | Hermes Agent | |---------|------------|-------|-------------| | Persistent memory | ❌ | ❌ | ✅ Remembers across sessions | | Native tools | ~5 | ~5 | 30+ (terminal, file, web, browser, vision, git, etc.) | | Skills system | ❌ | ❌ | ✅ 80+ loadable skills | | Session search | ❌ | ❌ | ✅ FTS5 search over past conversations | | Sub-agent delegation | ❌ | ❌ | ✅ Parallel sub-tasks | | Context compression | ❌ | ❌ | ✅ Auto-compresses long conversations | | MCP client | ❌ | ❌ | ✅ Connect to any MCP server | | Multi-provider | Anthropic only | OpenAI only | ✅ 8 providers out of the box |
Installation
npm install @marketintellabs/hermes-paperclip-adapterThe package also ships a paperclip-mcp bin for the MCP tool server,
which the adapter launches automatically when a run resolves to
builtin:mil-heartbeat-v3. You shouldn't need to invoke it directly.
Prerequisites
- Hermes Agent installed (
pip install hermes-agent) - Python 3.10+
- Node 24+ (the MCP tool server uses Node 24-compatible APIs; see
enginesinpackage.json) - At least one LLM API key (Anthropic, OpenRouter, or OpenAI)
Quick Start
1. Register the adapter in your Paperclip server
Add to your Paperclip server's adapter registry (server/src/adapters/registry.ts):
import * as hermesLocal from "@marketintellabs/hermes-paperclip-adapter";
import {
execute,
testEnvironment,
detectModel,
listSkills,
syncSkills,
sessionCodec,
} from "@marketintellabs/hermes-paperclip-adapter/server";
registry.set("hermes_local", {
...hermesLocal,
execute,
testEnvironment,
detectModel,
listSkills,
syncSkills,
sessionCodec,
});2. Create a Hermes agent in Paperclip
In the Paperclip UI or via API, create an agent with adapter type hermes_local:
{
"name": "Hermes Engineer",
"adapterType": "hermes_local",
"adapterConfig": {
"model": "anthropic/claude-sonnet-4.5",
"promptTemplate": "builtin:mil-heartbeat-v3",
"timeoutSec": 300,
"persistSession": true,
"enabledToolsets": ["terminal", "file", "web"]
}
}The promptTemplate values you can pick from:
| Value | Behaviour |
|-------|-----------|
| builtin:mil-heartbeat | Legacy. LLM drives status transitions via curl. Kept for back-compat. |
| builtin:mil-heartbeat-v2 | Adapter-owned status. LLM signals outcome via a RESULT: marker; adapter PATCHes status. Still uses curl for Paperclip reads/writes. |
| builtin:mil-heartbeat-v3 | MCP tool server. All Paperclip interactions go through structured tools; curl-in-prompt removed. Adapter-owned status inherited from v2. |
| (omitted) | Upstream default template. |
| <any other string> | Treated as a literal template with {{var}} substitution. |
3. Assign work
Create issues in Paperclip and assign them to your Hermes agent. On each heartbeat, Hermes will:
- Receive the task instructions
- Use its full tool suite to complete the work
- Report results back to Paperclip
- Persist session state for continuity
Configuration Reference
Core
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| model | string | anthropic/claude-sonnet-4.5 | Model in provider/model format |
| provider | string | (auto-detected) | API provider: auto, openrouter, nous, openai-codex, zai, kimi-coding, minimax, minimax-cn |
| timeoutSec | number | 300 | Execution timeout in seconds |
| graceSec | number | 10 | Grace period before SIGKILL |
Tools
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| toolsets | string | (all) | Comma-separated toolsets to enable (e.g. "terminal,file,web") |
Available toolsets: terminal, file, web, browser, code_execution, vision, mcp, creative, productivity
Session & Workspace
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| persistSession | boolean | true | Resume sessions across heartbeats |
| worktreeMode | boolean | false | Git worktree isolation |
| checkpoints | boolean | false | Enable filesystem checkpoints for rollback |
Advanced
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| hermesCommand | string | hermes | Custom CLI binary path |
| verbose | boolean | false | Enable verbose output |
| quiet | boolean | true | Quiet mode (clean output, no banner/spinner) |
| extraArgs | string[] | [] | Additional CLI arguments |
| env | object | {} | Extra environment variables |
| promptTemplate | string | (built-in) | Custom prompt template or builtin:<name> (see above) |
| paperclipApiUrl | string | http://127.0.0.1:3100/api | Paperclip API base URL |
| paperclipMcpTools | string[] | (all) | Per-agent MCP tool allowlist. [] = deny-all; absent = register every tool. See CHANGELOG.md (0.8.8-mil.0) for the design rationale. |
| auxiliaryModels | object | (none) | Per-agent override for Hermes' auxiliary-task models (compression, vision, session_search, title_generation, …). Passed through to config.yaml auxiliary: block. Slot-level merge with ~/.hermes/config.yaml. No-op against Hermes < v2026.4.23. See 0.8.9 entry above. |
| preflightSkip | boolean | true | Skip the Hermes spawn when no work is assigned. Set false per-agent to opt out. See 0.8.7 entry above. |
| softTimeoutWarn | boolean | true | Emit a [hermes] WARN: soft-timeout reached at <N>s … line when the run crosses softTimeoutThreshold × timeoutSec (one-shot, observational only — never modifies run behaviour). Set false per-agent to opt out. See 0.8.15 entry above. |
| softTimeoutThreshold | number | 0.8 | Fraction of timeoutSec at which the soft-timeout warning fires. Must be strictly between 0 and 1; out-of-range values fall back to 0.8. Warning is also skipped if the resulting delay is < 5 s (too noisy to be useful at very short timeouts). |
Test mode (per-issue UX + process-wide big-hammer)
Two ways to flip the adapter into test mode (both produce the same overrides — only the LLM endpoint is swapped to a free OpenRouter model). Activation priority: env > issue-marker > issue-intent > production.
1. Per-issue (recommended day-to-day, 0.8.11+). Add ANY of the following to the issue title or body:
- The explicit marker
<!-- mode: test -->(canonical, zero false-positive risk). - One of the intent phrases:
smoketest,smoke test,smoke-test,test mode,low-cost validation,test flow.
The adapter probes each spawn's task title + body and routes that one issue's work tree to the free model. Sub-issues created via create_sub_issue (or create_sub_issues for bulk delegation, 0.8.16+) while in this mode automatically inherit the marker, so the whole delegation tree stays free until it terminates.
An operator prompt that reliably trips the override:
Run a smoketest of the system in low-cost validation mode. Validate pipeline integrity end-to-end (wake-on-assign, MCP tool calls, status reconciliation, sub-agent delegation). Don't worry about output quality — free models are inconsistent under tool-use load.
2. Process-wide env vars (operator big-hammer, incident response). Set on the adapter process. Apply to every spawn while present, regardless of per-agent adapterConfig or issue contents. See the 0.8.10 entry above for full semantics.
| Env var | Default | Description |
|---------|---------|-------------|
| PAPERCLIP_ADAPTER_TEST_MODE | unset | Truthy values (1, true, yes, on) activate test-mode override; anything else (including unset) leaves per-agent config untouched. |
| PAPERCLIP_ADAPTER_TEST_MODEL | openrouter/free | Model slug to use while test mode is active. The default is OpenRouter's meta-router that auto-selects free models supporting tool calling. |
| PAPERCLIP_ADAPTER_TEST_PROVIDER | openrouter | Provider to use while test mode is active. |
| PAPERCLIP_ADAPTER_TEST_AUXILIARY_MODEL | (same as _TEST_MODEL) | Optional. Override the auxiliary-slot model independently of the main model. All four slots (compression, vision, session_search, title_generation) are forced to this value. |
The *** TEST MODE ACTIVE *** banner emitted at the top of each spawn includes a source=<env|issue-marker|issue-intent> field plus the matched marker / phrase, so a single grep tells you which path activated test mode for that run.
Prompt Template Variables
Use {{variable}} syntax in promptTemplate:
| Variable | Description |
|----------|-------------|
| {{agentId}} | Paperclip agent ID |
| {{agentName}} | Agent display name |
| {{companyId}} | Company ID |
| {{companyName}} | Company name |
| {{runId}} | Current heartbeat run ID |
| {{taskId}} | Assigned task/issue ID |
| {{taskTitle}} | Task title |
| {{taskBody}} | Task instructions |
| {{projectName}} | Project name |
| {{paperclipApiUrl}} | Paperclip API base URL |
| {{commentId}} | Comment ID (when woken by a comment) |
| {{wakeReason}} | Reason this run was triggered |
Conditional sections:
{{#taskId}}...{{/taskId}}— included only when a task is assigned{{#noTask}}...{{/noTask}}— included only when no task (heartbeat check){{#commentId}}...{{/commentId}}— included only when woken by a comment
Architecture
Paperclip Hermes Agent
┌──────────────────┐ ┌──────────────────┐
│ Heartbeat │ │ │
│ Scheduler │───execute()──▶│ hermes chat -q │
│ │ │ │
│ Issue System │ │ 30+ Tools │
│ Comment Wakes │◀──results─────│ Memory System │
│ │ │ Session DB │
│ Cost Tracking │ │ Skills │
│ │ │ MCP Client │──▶ paperclip-mcp
│ Skill Sync │◀──snapshot────│ ~/.hermes/skills│ (v3 agents only,
│ Org Chart │ │ │ scope-bound per run)
└──────────────────┘ └──────────────────┘The adapter spawns Hermes Agent's CLI in single-query mode (-q). Hermes
processes the task using its full tool suite, then exits. The adapter:
- Captures stdout/stderr and parses token usage, session IDs, and cost
- Parses raw output into structured
TranscriptEntryobjects (tool cards with status icons) - Post-processes Hermes ASCII formatting (banners, setext headings, table borders) into clean GFM markdown
- Reclassifies benign stderr (MCP init, structured logs) so they don't show as errors
- Tags sessions as
toolsource to keep them separate from interactive usage - Reports results back to Paperclip with cost, usage, and session state
Session persistence works via Hermes's --resume flag — each run picks
up where the last one left off, maintaining conversation context,
memories, and tool state across heartbeats. The sessionCodec validates
and migrates session state between runs.
Skills Integration
The adapter scans two skill sources and merges them:
- Paperclip-managed skills — bundled with the adapter, togglable from the UI
- Hermes-native skills — from
~/.hermes/skills/, read-only, always loaded
The listSkills / syncSkills APIs expose a unified snapshot so the
Paperclip UI can display both managed and native skills in one view.
MCP Tool Server (v3 agents)
For agents on builtin:mil-heartbeat-v3, the adapter additionally:
- Builds a per-run
HERMES_HOMEat/tmp/paperclip-run-<runId>-XXXXXX/. - Symlinks
sessions/,skills/,.env, and other entries from the real~/.hermes/into it (so session resume + skills keep working). - Writes a fresh
config.yamlinto the per-run dir that contains the base config plus anmcp_servers.paperclipblock whoseenvblock carries this run'sPAPERCLIP_API_KEY(JWT),PAPERCLIP_AGENT_ID,PAPERCLIP_COMPANY_ID, and — critically —PAPERCLIP_ISSUE_ID(the scope boundary for writes). - Spawns Hermes with
HERMES_HOMEpointing at the per-run dir. - Teardown (
rm -rf) runs infinally, so the temp dir is cleaned up even on timeout or crash.
Hermes spawns the paperclip-mcp subprocess over stdio. All tool calls
go through that subprocess with a server-side MAX_TOOL_CALLS=20 cap,
structured per-call logging ([paperclip-mcp-log]), and scope
enforcement. 0.8.0+ additionally writes two sidecar files inside the
per-run HERMES_HOME:
mcp-tool-calls.ndjson— onetool_call_start/tool_call_endJSON record per invocation.execute.tsreads this after the run and fillsresultJson.toolCalls/toolCallCount/toolErrorCount.mcp-server.pid— written at startup, removed on clean exit.execute.tschecks it post-run to detect a crashed tool plane (errorCode: tool_server_died).
Both files' paths are passed to the subprocess via
PAPERCLIP_MCP_AUDIT_LOG / PAPERCLIP_MCP_LIVENESS_FILE env vars set
directly on the Hermes process (Hermes does not forward the per-server
env block in config.yaml to stdio subprocesses — 0.8.1 fix).
Development
git clone https://github.com/marketintellabs/hermes-paperclip-adapter
cd hermes-paperclip-adapter
npm install
npm run build
npm test # 107 tests across 24 suitesSee AGENTS.md for the source tree layout and
UPSTREAM.md for the fork's divergence from upstream +
sync policy.
License
MIT — see LICENSE. Inherited from upstream unchanged.
Links
- Hermes Agent — the AI agent this adapter runs (upstream)
- Paperclip — the orchestration platform
- MarketIntelLabs — maintainer of this fork
- Nous Research — upstream adapter author
- Paperclip Docs — Paperclip documentation
