Skip to content

borgmcp 6.0.2

Choose a tag to compare

@TheodorStorm TheodorStorm released this 30 Sep 08:07
· 53 commits to main since this release
a8de7db

borgmcp 6.0.2

This release fixes the order of borg representative hermes-plugin install and closes gaps in the Claude wake path. 6.0.1 was prepared but never published, so 6.0.2 is the first release after 6.0.0 and carries both changes. Merged since 6.0.0: #601, #602 (the unpublished 6.0.1 preparation), #603 and #605 (CI only: a manual workflow trigger and a public-source scan in PR CI; no installed behaviour changes).

Fixed: hermes-plugin install asks only after everything that can refuse has been checked

On 6.0.0, with two gateway DMs and three prepared worktrees, install asked the operator to pick a DM and confirm it [y/N]. Only after that did it refuse because several worktrees were prepared, and it printed a bare path list with no command to retry.

  • Install now runs as plan, validate, ask, apply.
    • Plan: it lists every candidate worktree and conversation, and builds the exact values it would write.
    • Validate: it checks every candidate's plan with the same checks the writes apply, before any question. These are the value encoding (for example, a path containing a newline), the gateway DM key and the absolute borg path. The same pass also checks, read only, whether plugins, config.yaml, the backup directories and Borg's state path are usable.
    • Ask: only then does it ask, at a terminal.
    • Apply: it writes. After a question, install can stop only on an invalid or declined answer, a Hermes command's reply, or a write that fails.
  • When a selection is needed, install asks at a terminal: for the worktree when several selectable worktrees are prepared, then for the DM, then for the [y/N] confirmation (default no). A --worktree, or a configured worktree that is still prepared, and a --session-key, or a configured valid DM key, are reused without a question, including without a terminal and on borg update.
  • Candidates that would fail are not offered. They are shown as not selectable, with the reason. A single selectable worktree is used without a question.
  • Without a terminal (including borg update), a selection that is still needed is refused with exact retry commands. Ambiguous worktrees get one borg representative hermes-plugin install command per selectable worktree, keeping --hermes-home and a given --session-key. An unconfirmed DM gets one command per candidate with --session-key, keeping --hermes-home and a given --worktree. Every value in these commands is shell-quoted.
  • Control, C1 and bidi characters are removed from: displayed worktree and borg paths, the planned configuration values, and failure and rollback text (which can quote Hermes config values or replies). Other displayed paths, such as the Hermes home and the backup path, are printed as they are.
    • Retry commands are printed separately, with their exact bytes, so they round-trip even when a path contains a newline or other control characters.

Fixed: the Claude wake path

  • One wake-path text for every Claude surface. The SessionStart hook, /clear, the borg launch prompt, the borg_regen wake-path warning and the borg_stream-status self-arm section now render the same wake-path and recovery instructions from one source.
  • Re-arm before draining. A new Monitor starts at the end of the inbox, so after its exit notification, or when none is armed, a drone now re-arms the Monitor first and then drains borg_read-log unread_only=true.
  • A /loop fallback when the Monitor cannot be armed.
    • If a permission prompt blocks the Monitor call, or it times out, gets no classifier verdict or errors: the drone does not stop or wait. It invokes /loop with no arguments, and on each tick re-arms the Monitor, then drains. With a Monitor armed, the loop is only a fallback.
    • If a human denies the Monitor call: the drone never requests it again. It invokes /loop with no arguments, each tick only drains, and it tells the cube's coordinating role once, through borg_log, that the Monitor was denied and the seat is polling.
  • borg-inbox-monitor replays entries written while no Monitor was armed. This applies to the supported --state-root form; the legacy positional form is unchanged.
    • The monitor keeps a replay cursor, <state root>/<hash>.monitor.cursor, mode 0600. It holds a hash of the last handled entry line, that line's timestamp and an arm boundary, and no message text.
    • At arm it announces the entries written after the previous monitor for the same inbox stopped. At most the newest 20 are shown; when more are waiting, one notice line says how many were not shown and to drain borg_read-log unread_only=true.
    • Delivery is at least once, not exactly once: after a crash or kill, an entry can be announced again at the next arm.
    • A state root with no cursor, including the first arm after upgrading, skips history as before.
    • A cursor that is unusable is ignored with a warning. A cursor that cannot be written is reported once and never stops delivery.
    • Orphan inbox cleanup removes the cursor with the monitor's other state files.
  • The SessionStart and /clear orientation stays within its preview. The harness shows about 2 KB of hook output. The orientation now puts every fixed instruction first. The cube, drone and role follow, fitted to the remaining bytes. The Monitor command comes last. When the whole text would reach 2048 bytes, the command is replaced by a pointer to borg_stream-status. The orientation's title is now # Borg drone orientation, and the cube, drone and role lines come after the instructions.
  • borg_stream-status always shows a Claude seat its exact Monitor command, as inbox Monitor command.
  • Codex and OpenCode wake-path instructions are unchanged.
  • The two stream-owner tests that failed when TMPDIR is not a canonical path (as on macOS) now use a canonical test root. This only affects development.

Upgrading

  1. Run borg update.
  2. Restart each Claude seat: exit it and launch it again. On launch, the SessionStart hook loads the new wake-path instructions, the seat's borg MCP server loads 6.0.2, and the seat arms a 6.0.2 inbox Monitor. /clear is not enough: it restarts neither the running Monitor process nor the borg MCP server, and a re-armed monitor yields to the pre-update monitor that still holds the inbox. The first 6.0.2 arm has no cursor yet and skips history; later arms replay what they missed.
  3. If a 6.0.0 borg representative hermes-plugin install stopped before it finished, run it again. A 6.0.0 run that refused on the worktrees had not written Borg's plugin files, Hermes configuration or activation record. Hermes's own startup maintenance, which runs with its config get commands, may still have run.
  4. The shared contract pin is unchanged: borgmcp-shared 2.2.0.