Repository navigation
borgmcp 6.0.0
borgmcp 6.0.0
The human representative's host integration is rebuilt as one system. Representative state moves into one SQLite database, and the listener becomes the push engine. The Hermes plugin is now a thin adapter, and one command sets Hermes up. Merged since 5.7.0: #594, #595, #596, #597 and #598.
Breaking
- Node.js 22.13.0 or later is required (
engines.node>=22.13.0, up from>=22.12.0). Representative state uses Node's built-innode:sqlite, which is unflagged from 22.13.0. - Representative state is rebuilt in one SQLite database,
<Borg config>/representative/state/.- Bindings, the request ledger, delivery positions and wake state all live there, under generation directories and a
CURRENTpointer that is replaced by atomic rename. - Every path is checked on every open: owned by you, 0700 directories, 0600 files, never a symlink.
- The borgmcp 5.x files are imported once, when the database is first created. Each valid 5.x binding is imported (a second binding of the same generation is skipped), and its delivery start follows the documented start rule. Until that database exists,
hermes-plugin installmay also read the 5.x bindings, read only and on each run, to find the prepared worktree; it creates nothing. The 5.x files are never written, and never read again once the database exists. - The database is created on first use by
borg representative prepare,mcporlisten. - A database with another schema version refuses with
REPRESENTATIVE_STATE_VERSION.
- Bindings, the request ledger, delivery positions and wake state all live there, under generation directories and a
- The single tools lease is removed. Any number of processes may use the representative tools at once, for example Hermes Desktop, the CLI and the gateway. Each operation takes its own transaction.
borg representative listenspeaks protocol 2 only.- It requires
--protocol 2, and stdin must be a pipe or socket owned by the host. Without these it printsrefusedand exits 2. - It prints
listening,wake,refusedandstoppedevents, with no message body, and reads{wake_id, accepted}acks of at most 1 KiB each on stdin. - EOF on stdin, or SIGTERM/SIGINT, stops it from the first startup step on.
--replay-afterand the inbox replay are removed.- A 5.7.0 plugin, which starts the listener without
--protocol 2, is refused and stops. Upgrade the plugin as below.
- It requires
borg representative hermes-plugin installnow configures Hermes (see New).--forceis removed: a rerun updates an existing install.- The Hermes plugin settings
mcp_server,reinject_after_sandmax_reinjectsare gone. Plugin v2 keeps no state of its own and no longer uses<Hermes home>/plugin-data/borg-representative-push/.
New
- The listener is the push engine.
- Wake state is durable, and one wake batch is outstanding at a time, with a 2-second debounce.
- The ack deadline is 60 seconds, measured absolutely.
- An undelivered reply is woken again after 10 minutes, 1 hour and 6 hours, then every 24 hours.
- A refused wake backs off from 30 seconds, doubling to 30 minutes.
- On start, a bounded startup cohort ends in one
startupwake for replies that are still undelivered. - Delivery is observed from any process; Borg stops waking for a reply once it is delivered.
- Invalid wake state is rebuilt from the delivered checkpoint instead of blocking the listener.
- Hermes plugin v2 (
borg-representative-push2.0.0).- It has three settings:
session_key,worktreeandborg_command. - It starts the listener only inside the messaging gateway and owns the listener's stdin pipe, so the listener exits when the gateway does.
- Each wake becomes one fixed, body-free injected message.
- A listener that does not announce protocol 2 first is never driven: it is closed, then sent SIGTERM, then SIGKILL, and reaped.
- It has three settings:
borg representative hermes-plugin installsets Hermes up in one command.- It installs the plugin files and writes the settings,
allow_gateway_injectionand theborg-representativeMCP entry (lazy: true, the absoluteborgpath) through Hermes's own CLI, reading every value back. - It enables the plugin.
- It restarts the gateway only when it runs as a launchd or systemd service, and confirms the restart by a new PID. For a hand-started gateway it prints the command instead.
- It stops and restarts nothing in Hermes Desktop. It prints "new chats get the Borg tools" for an added MCP entry, and the
/reload-mcp-or-restart line for a changed one. - It never picks the conversation to wake without your confirmation. A
--session-key, or an already configuredsession_keythat is a valid gateway DM key, is used without a prompt and without a refusal. Otherwise, at a terminal it lists every gateway DM candidate and asks[y/N]; without a terminal it refuses and prints the exact--session-keycommand, keeping--hermes-homeand--worktree. config.yamlis backed up first. On failure Borg reverses only its own keys.- Nothing is written before its checks pass, and the installer never creates representative state.
- It reports whether a gateway allow-all switch is set (
gateway.allow_all_users,allow_all_users,GATEWAY_ALLOW_ALL_USERSor<PLATFORM>_ALLOW_ALL_USERS). It does not report other gateway access such as allowlists or pairing. --dry-runonly reads, and--no-restartleaves the activation pending, so a rerun finishes it.
- It installs the plugin files and writes the settings,
borg representative hermes-plugin uninstallremoves only Borg's entries and files. The unload stays pending until the gateway is confirmed to have dropped the plugin.borg updateactivates an installed plugin.- It refreshes the files, settings and MCP entry, and never asks a question.
- An activation that fails or throws produces a warning naming
borg representative hermes-plugin install. It never changes the update's result. An activation left pending on a hand-started gateway is not a failure: it prints the command to restart that gateway.
borg representative statusreports the listener, its wake state and, when the plugin is installed,hermes_plugin: its activation state, a pending Desktop reload, the conversation and the open-gateway report.borg representative reset-stateis disaster recovery for a corrupt state database. It refuses a healthy database and reports exactly what was kept and what was lost.
Fixed
- The Hermes plugin guide's refused-wake wording was qualified to match the 5.7.0 release notes (#594). Plugin v2 in this release replaces that whole mechanism.
- The test suite refuses writes into the real home directory at the file-system layer; only isolated test roots are allowed. This only affects development.
- A failing cross-process state test can no longer hang the suite: its child processes wait with a deadline, and every child still running is killed and reaped after each test (7583e50). This only affects development.
Upgrading
- Make sure Node.js is 22.13.0 or later.
- Run
borg update. With a 5.7.0 plugin installed, it upgrades the plugin, its settings and the MCP entry. It keeps a configuredsession_keywhen that key is a gateway DM key. - Run
borg representative hermes-plugin installwhenborg updatewarns that the activation is incomplete, or to install the plugin for the first time.- An already configured
session_keythat is a valid gateway DM key is kept without a prompt. Otherwise, at a terminal, confirm the gateway DM to wake, or pass--session-key.
- An already configured
- If Hermes Desktop was open, run
/reload-mcpin its open chats, or restart it, when the install says the Borg MCP entry changed. - The shared contract pin is unchanged:
borgmcp-shared2.2.0.