hardline-mcp
Hardline-mcp enables local AI coding agents (Claude Code, Hermes, and Codex) to communicate asynchronously via a durable SQLite mailbox and to query each other synchronously or asynchronously through live CLI spawning.
Mailbox Tools
send – Persist messages to a shared SQLite mailbox (WAL mode) for durable async delivery, with optional
deliver=trueto immediately push the message to the recipient’s native CLI (Hermes, Codex, or Claude).inbox – Read messages addressed to an agent, oldest first and unread-only by default.
ack – Mark messages as read (idempotent), respecting session lanes so one Claude session cannot ack another’s messages.
history – View recent messages newest-first, filterable by sender or recipient agent.
Synchronous Queries (Live Ask)
ask_hermes / ask_codex / ask_claude – Spawn a one-shot agent session and return the reply synchronously.
Optional parameters: model selection, effort level (low, medium, high, xhigh, max, ultra), mode (
defaultor isolated read‑onlyadvisory), customworkdir, and opt‑in write access (write=true).Write access requires
HARDLINE_ALLOW_WRITE=1and an explicitworkdir; it is rejected in advisory mode.ask_claudereturns rich telemetry (model, usage, auth, rate‑limit metadata) when options are used.
Asynchronous Queries (Fire‑and‑Forget)
ask_codex_async / ask_claude_async – Dispatch long‑running tasks to a background thread pool, return immediately with a label, and deliver the result to the mailbox (sender=agent, recipient=
from_agent) for later polling withinbox.
Key Capabilities & Safety
Session Lanes – Multiple simultaneous Claude Code sessions get isolated mailbox lanes derived from session ID and project directory, preventing cross‑session interference.
HARDLINE_AGENT_LABELoverrides lane naming.Write Protection –
write=trueis refused unlessHARDLINE_ALLOW_WRITE=1is set, preventing unauthorized unattended file changes.Advisory Mode – Isolated, read‑only environments for Codex/Claude with no provider overrides, neutral workspace, and auth verification telemetry.
Timeout Protection – Configurable timeouts (Hermes: 180s, Claude: 900s, Codex: 14400s) via
HARDLINE_CLAUDE_TIMEOUT_S/HARDLINE_CODEX_TIMEOUT_S.Bounded Concurrency – Async thread pool size configurable via
HARDLINE_ASYNC_MAX_WORKERS(default 4) to prevent resource exhaustion.Configuration Flexibility – Agent CLI paths pinnable via env vars (
HARDLINE_HERMES_CMD,HARDLINE_CLAUDE_CMD,HARDLINE_CODEX_CMD); Codex auto‑discovers the latest binary.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@hardline-mcpask hermes what's the current gateway status?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
hardline-mcp
A single-purpose MCP server that lets local AI coding agents — Claude Code, Hermes, and Codex — message each other on one machine. A durable SQLite mailbox is the backbone; thin live-ask tools let one agent get an answer from another right now.
hardline — in The Matrix, the hardwired lines a crew uses to reach agents in the field; in telecom, a dedicated direct circuit. This is that line, between your agents.
Companion to vram-mcp: same single-purpose, per-machine, install-everywhere shape.
Why
Local agents have mismatched lifecycles — a Claude Code or Codex session is ephemeral, a Hermes gateway is always-on — so a naive "just call each other" bridge drops messages the moment the other side isn't running. hardline-mcp splits the problem:
Mailbox (durable, async).
sendrecords every message to SQLite (WAL mode → safe concurrent writes from every agent's own subprocess). Recipientsinbox/ackon their own rhythm;historyis the audit feed. Survives restarts and lifecycle mismatches — you can message an agent that isn't up yet, and it reads the note when it next runs.Push, no daemon.
send(..., deliver=true)also fires the recipient's native CLI at send time (hermes chat -Q -q/codex exec/claude -p), so it sees the message without polling — real push with zero extra always-on processes.Live ask.
ask_hermes/ask_codex/ask_claudespawn a one-shot session and return the reply synchronously. Heavier than the mailbox; use when you need the answer immediately.
Related MCP server: mcp-comms
Tools
Tool | Behavior |
| Persist; if |
| Messages addressed to |
| Mark read (idempotent). |
| Recent messages newest-first; |
| Live query → |
| Ephemeral live query → |
| Fire-and-forget |
| Live query → |
| Fire-and-forget |
Agents are the fixed set claude, hermes, codex. Identity is self-declared
(from_agent) — convention, not enforced auth; every process runs as the same
user on one machine, so there's nothing to defend against that it couldn't do
directly anyway.
Session lanes
Several Claude Code sessions can run at once, and they'd otherwise all share
the single claude mailbox — every session seeing every other's results, and
able to ack them out of each other's inbox. Since each session spawns its
own hardline process over stdio, the process is the session and derives
its own lane from CLAUDE_CODE_SESSION_ID + CLAUDE_PROJECT_DIR:
claude:fonts.1a2b3c4d.
Nothing to opt into. ask_*_async(from_agent="claude") delivers to the
calling session's lane, inbox(agent="claude") reads that lane plus the
unqualified claude (so broadcasts still arrive), and ack refuses messages
belonging to another session's lane. Keying on the session id rather than the
process means a /mcp reconnect doesn't orphan in-flight results.
Hermes and Codex set neither variable, so they keep their plain identities and
cross-agent messaging is unchanged. HARDLINE_AGENT_LABEL overrides the
derived lane if you want to name one explicitly.
Requirements
Python 3.10+
Whichever agent CLIs you want to reach on PATH (or see Configuration):
claude,hermes,codex.
Install
pip install -e .hardline-mcp is the stdio server console-script entry point.
Configuration
The mailbox lives at ~/.cache/hardline-mcp/mailbox.db — no setup needed. Set
HARDLINE_DB to relocate it, or to run isolated instances (each agent's server
must point at the same file to share a mailbox).
Each agent's CLI must be launchable by hardline-mcp. If a binary isn't on
PATH, pin its executable path (path only — the fixed subcommand is
appended automatically) via env var:
HARDLINE_HERMES_CMD— e.g.C:/Users/you/AppData/Local/hermes/hermes-agent/venv/Scripts/hermes.exeHARDLINE_CLAUDE_CMDHARDLINE_CODEX_CMD— usually unnecessary: Codex installs to a hash-named dir that changes on every update, so hardline-mcp auto-discovers the newestcodex.exerather than relying on a path that rots. Set this only to override discovery.
Resolution precedence per agent: env override → (codex only) auto-discovery →
bare command on PATH.
Live queries are bounded so a hung CLI cannot wedge its MCP caller. Hermes retains a 180-second default. Claude defaults to 900 seconds; Codex defaults to 14400 seconds because deep repository reviews can legitimately run for hours. Override either ceiling with a positive integer number of seconds:
HARDLINE_CLAUDE_TIMEOUT_S=1200
HARDLINE_CODEX_TIMEOUT_S=14400An invalid or non-positive value fails the tool call before spawning the agent.
ask_*_async dispatch through a small fixed-size background thread pool
(default 4 workers) rather than an unbounded thread per call, so repeated or
concurrent dispatches queue instead of piling up unlimited agent subprocesses.
Override the pool size with HARDLINE_ASYNC_MAX_WORKERS — validated the same
way as the timeouts above, except that this one is read once at startup, so an
invalid value fails the server at launch rather than a single tool call.
At shutdown, dispatches still queued are dropped rather than run; one already in flight is awaited, since its agent subprocess can't be interrupted safely mid-call. Without that, teardown would block until every queued dispatch had run in turn — each up to its own configured timeout.
Codex model, effort, isolation, and telemetry
ask_codex(prompt) preserves the original compact ok/reply response,
creates an ephemeral session, and terminates option parsing before the
prompt. Omitting model passes no --model flag at all, so Codex's own
configured default applies — the same posture ask_hermes already has
toward Hermes's default; hardline does not second-guess it. The same path
applies to send(..., to_agent="codex", deliver=true). Hardline therefore
no longer persists one-shot review sessions or interprets a flag-shaped
prompt as a CLI option, while leaving model selection to Codex itself unless
a caller explicitly asks for a specific one.
Pass model, effort, mode, or workdir for the structured path. model
must be Codex's full identifier (gpt-5.6-sol, gpt-5.6-terra, ...), not a
shorthand like "sol" — hardline doesn't validate or expand it against any
alias table, so an unrecognized value is rejected by Codex itself at
execution time rather than silently substituted:
ask_codex(
prompt="Review the cancellation protocol.",
model="gpt-5.6-terra",
effort="xhigh",
workdir="C:/src/project",
)Supported efforts are default, low, medium, high, xhigh, max, and
ultra. default leaves Codex's model-specific reasoning default intact;
other values are transported as model_reasoning_effort. Unsupported values
and unsafe model identifiers fail before the process is spawned. Any explicit
workdir must already exist, is resolved once to an absolute path, and is
passed both as the child cwd and Codex -C (so relative paths are not applied
twice).
Structured calls use codex exec --json and return:
requested_modelandrequested_effort;the final agent message, ephemeral
thread_id, and structured tokenusage;actual_model: nullandeffective_effort: null, deliberately: Codex CLI 0.145 JSONL does not emit either value, so Hardline does not guess;structured
turn.failederrors (including nonzero process exits) instead of a generic subprocess error, while terminal-event ordering prevents a transient retryerrorfrom overriding a later successfulturn.completed.
mode="advisory" is intended for isolated read-only model panels. It requires
the local Codex auth configuration to declare auth_mode: chatgpt, removes
OpenAI/Azure API-provider environment overrides, copies only auth.json into a
temporary CODEX_HOME (so global AGENTS.md/AGENTS.override.md guidance is
not inherited), ignores user configuration and rules, disables session
persistence, uses a separate fresh neutral workspace, selects the read-only
sandbox, and supplies fixed defensive developer instructions.
An explicit workdir is rejected in this mode because it would defeat neutral
isolation. The response reports subscription_configured: true after the local
preflight but leaves subscription_verified: null: unlike Claude, Codex JSONL
does not expose runtime auth-source or overage telemetry. This distinction is
intentional; local configuration is not post-call billing proof. Trusted binary
overrides and platform sandbox enforcement remain outside Hardline's control.
Write access requires an explicit opt-in
write=True (on either ask_codex or ask_claude) is refused outright
unless this hardline-mcp process's environment has HARDLINE_ALLOW_WRITE
set to a recognized truthy value — regardless of what a caller asks for.
Write mode is unattended (stdin is /dev/null, so no approval prompt is ever
answered) and, once a workdir is reachable, no more restricted than what the
OS user running hardline-mcp could already do directly — a categorically
different exposure from every other hardline tool, which only ever runs
read-only or self-contained calls. Without a gate, any hardline registration
with no per-tool allow-list (unlike
vram-mcp's) would let any caller
reach it with zero human approval step — including an always-on registration
driven by inbound messages from an external platform. Set
HARDLINE_ALLOW_WRITE=1 (also accepts true/yes, case-insensitive; 0,
false, no, or unset all mean disabled — anything else fails loud naming
the bad value rather than silently staying disabled) only on registrations
where write access is actually wanted; leave it unset (the default)
everywhere else, e.g. an always-on gateway's registration.
Codex write access and background dispatch
ask_codex is read-only unless write=True is passed explicitly (and
HARDLINE_ALLOW_WRITE=1 is set — see above) — omit write and behavior is
unchanged from before this option existed. write=True requires an explicit
workdir (never an implicit cwd) and is rejected with mode="advisory"
(advisory is fixed read-only by design). It adds --sandbox workspace-write -a never: approvals are disabled because a spawned Codex process's stdin is
/dev/null, so any approval prompt would just hang until timeout instead of
ever being answered — the sandbox boundary is what keeps an unattended,
un-approvable run safe.
ask_codex(
prompt="Add input validation to the login handler.",
workdir="C:/src/project",
write=True,
)For a task that shouldn't block the caller, ask_codex_async dispatches the
same ask_codex through the bounded background thread pool (see
Configuration) and returns {"ok": true, "dispatched": true, "label": ...}
immediately. The result lands in the mailbox as a
message from "codex" to from_agent once the run finishes — poll it the
same way you'd poll for any other mailbox message:
ask_codex_async(
prompt="Refactor the retry loop; write the diff.",
from_agent="claude",
workdir="C:/src/project",
write=True,
label="retry-refactor",
)
# later:
inbox(agent="claude")label is echoed back in the delivered message body so a caller firing
several concurrent dispatches can match each result to its request. This is
fire-and-forget, not durable: if hardline-mcp restarts before a dispatched
task finishes, that task is lost — there is no task table, only the
existing send/inbox mailbox the result is dropped into on completion.
Claude model and effort selection
ask_claude's bare ask_claude(prompt) response shape stays backward
compatible: a prompt with no additional options still returns the plain
ok/reply object, not the fuller telemetry shape. Tool access is not part
of that compatibility promise — see Claude write access and background
dispatch below for the one behavior change (Edit/Write/NotebookEdit are now
denied unless write=True). Omitting model passes no --model flag at
all, so Claude Code's own configured default applies — the same posture
ask_hermes/ask_codex already have toward their own CLI's default;
hardline does not second-guess it. This applies uniformly to
ask_claude(prompt) and to send(..., to_agent="claude", deliver=true)'s
push-notice path — both spawn claude the same way. Passing an explicit
model= (including model="sonnet", which is Claude Code's own tier alias
and tracks whichever model it currently resolves that to) is a different
caller intent than omitting it, so it takes the full telemetry path below
(returning actual_model, usage, etc.) instead of the plain ok/reply
shortcut.
For model-aware calls, set model, effort, or mode:
ask_claude(
prompt="Review this design and identify the highest-risk assumption.",
model="fable",
effort="high",
mode="advisory",
)Supported Claude effort values are default, low, medium, high, xhigh,
and max. default omits Claude Code's --effort flag. Unsupported values
fail before spawning Claude; there is no silent downgrade.
Optioned calls use Claude Code's stream-json output and add:
requested_modeland theactual_modelfrom the final assistant event;requested_effort(effective_effortisnull, because Claude Code does not echo the provider's effective effort);api_key_source, usage, model-usage, and rate-limit metadata;subscription_verified, which istrueonly when advisory telemetry reportsapiKeySource: noneand confirms that overage is not being used;a parsed
fallbackobject when Fable emitsmodel_refusal_fallbackand the request continues on another model.
mode="advisory" is intended for read-only model panels. It disables tools,
slash commands, project customizations, and session persistence; runs in a
fresh neutral directory with a fixed minimal system prompt; and removes
Anthropic API-key/base-URL plus Bedrock/Vertex/Foundry overrides from the child
environment. This reduces accidental API-provider routing, but trusted command
wrappers and admin-managed Claude settings remain outside Hardline's control.
Claude write access and background dispatch
Parity with Codex: unless write=True is passed, every ask_claude call —
including the bare ask_claude(prompt) path — denies Claude the
Edit/Write/NotebookEdit tools (--disallowedTools Edit,Write, NotebookEdit). Read/Grep/Bash and the rest of the built-in toolset still
work, the same way Codex's read-only sandbox permits inspection but not
mutation — this is a closer analog than advisory mode's zero-tools
restriction, which is a separate, stricter concept for isolated opinions.
write=True requires an explicit workdir (never write into hardline-mcp's
own cwd), is rejected with mode="advisory", and is refused unless
HARDLINE_ALLOW_WRITE=1 is set for this process (see Write access requires
an explicit opt-in above). It grants full tool access and adds
--permission-mode bypassPermissions: approvals are disabled because a
spawned Claude process's stdin is /dev/null, so an interactive permission
prompt would hang until timeout instead of ever being answered — the same
rationale as Codex's -a never.
ask_claude(
prompt="Add input validation to the login handler.",
workdir="C:/src/project",
write=True,
)workdir also works without write — Claude has no -C/--cd flag, so
hardline targets it by launching the child process with that directory as
its cwd; omitted, ask_claude inherits whatever directory hardline-mcp
itself was started from, same as before this option existed.
ask_claude_async mirrors ask_codex_async exactly: dispatches ask_claude
through the same bounded background thread pool and delivers the result
through the mailbox (sender="claude", recipient=from_agent) once it
finishes.
ask_claude_async(
prompt="Refactor the retry loop; write the diff.",
from_agent="codex",
workdir="C:/src/project",
write=True,
label="retry-refactor",
)
# later:
inbox(agent="codex")Same caveats as the Codex version: label is echoed back for matching
concurrent dispatches, and this is fire-and-forget — a hardline-mcp restart
before completion loses the task, since only the existing mailbox holds the
eventual result, not a task table.
After execution, advisory calls therefore fail closed unless runtime telemetry
verifies first-party account auth with no overage. This is post-call evidence;
it cannot undo a request already made by a misconfigured trusted wrapper.
Register with an MCP client
Claude Code (or any client using the claude mcp CLI):
claude mcp add hardline-mcp --scope user -- /path/to/hardline-mcpHermes (~/.hermes/config.yaml):
mcp_servers:
hardline:
command: "/path/to/hardline-mcp"
args: []Codex (~/.codex/config.toml — Codex uses its own TOML config):
[mcp_servers.hardline]
command = '/path/to/hardline-mcp'
args = []Example flow
# In agent A (claude), leave a durable note for hermes and push it live:
send(from_agent="claude", to_agent="hermes",
message="deploy finished, logs at /tmp/deploy.log", deliver=true)
# hermes, whenever it runs, reads and acks:
inbox(agent="hermes") -> [{message_id: 7, sender: "claude", ...}]
ack(message_id=7)
# Or ask hermes something and block for the answer:
ask_hermes(prompt="what's the current gateway status?")Development
pip install -e ".[dev]"
python -m pytest -qThe suite includes a headless end-to-end test that launches two real server subprocesses over MCP stdio and does a cross-instance round-trip — no agents needed, runs in CI.
There is also a live integration test (tests/test_live_agents.py) that
spawns the actual hermes / codex / claude CLIs and drives the ask_*
bridges against their real brains. It's off by default (it costs plan tokens
and needs the CLIs installed) — it skips unless HARDLINE_LIVE_TESTS=1, and
skips per-agent when a CLI isn't reachable, so CI never runs it:
# hermes usually isn't on PATH — point at its binary, same as production
HARDLINE_LIVE_TESTS=1 HARDLINE_HERMES_CMD="/path/to/hermes" python -m pytest tests/test_live_agents.py -vThe headless suite includes deterministic MCP-to-executable E2Es that capture
the actual Claude and Codex argv and prove model/effort options survive the full
transport. The live module additionally launches Hardline over stdio, requests
Fable and Sol at low effort in advisory mode, and verifies each CLI's truthful
telemetry contract. Claude does not echo effective effort; Codex JSONL echoes
neither effective effort nor served model. Those fields therefore remain null
rather than being inferred from the requested options. Live tests remain opt-in
and consume plan tokens.
License
MIT — see LICENSE.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceA SQLite-backed message queue system that enables multiple AI agents to communicate with each other via a simple HTTP interface.4Apache 2.0
- Flicense-qualityDmaintenanceEnables multiple AI agents to communicate and coordinate via a shared SQLite-backed message log, supporting directed messages, broadcasts, and session discovery.
- Alicense-qualityCmaintenanceLocal inter-agent messaging for AI coding agents via filesystem relay.2MIT
- AlicenseAqualityAmaintenanceEnables durable message passing between Codex project agents with MCP tools and automatic wake-up delivery, storing messages as JSON on disk.11MIT
Related MCP Connectors
Durable agent-to-agent handoffs and shared scratchpad for multi-agent workflows.
The team layer for AI coding agents: shared contracts, collision alerts, E2EE sessions.
Continuity protocol for autonomous AI agents. Agent messaging with SMTP bridge and LN payments.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/sushiHex/hardline-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server