Skip to content

Release 0.7.0 — MCP confirmations + wake_remote + install.sh#11

Closed
ThinkOffApp wants to merge 11 commits intomainfrom
feat/mcp-wake-ide
Closed

Release 0.7.0 — MCP confirmations + wake_remote + install.sh#11
ThinkOffApp wants to merge 11 commits intomainfrom
feat/mcp-wake-ide

Conversation

@ThinkOffApp
Copy link
Copy Markdown
Owner

Summary

Cuts a 0.7.0 release that bundles all the post-PR-#10 work from today's session into a single mergeable PR for petrus to land in the morning.

See CHANGELOG.md for the complete rundown. Headline additions:

  • request_confirmation MCP tool + iak-mcp-daemon (HTTP listener on 8788 + chat-reply poller).
  • POST /intent and POST /wake HTTP endpoints on the daemon.
  • wake_remote MCP tool for cross-machine Claude-Code-to-Claude-Code nudge (verified end-to-end mini ↔ MacBook tonight).
  • metadata.actions + metadata.intent_id on GroupMind announcements (paired with antfarm PR #13, already merged + deployed, which renders inline Approve/Deny buttons).
  • scripts/claudecode-stop-resume.sh — Stop-hook auto-resume alternative to AppleScript wake (no Accessibility permission required).
  • scripts/install.sh — one-shot macOS bootstrap.
  • docs/auto-wake.md setup guide.
  • Configurable mcp.sessions array.
  • read_session MCP tool.

Test plan

  • npm test — full suite green (76/76 verified by @claudemb and @CodexMB during PR feat: MCP server for waking and driving IDE / agent tmux sessions #10 round).
  • End-to-end real intent settle verified via web UI on Wear OS browser, GroupMind chat-reply poller, and CodeWatch app's notification action.
  • wake_remote cross-machine: mini → MacBook landed osascript injection into desktop app, hook fired, response posted in room.
  • Smoke-run scripts/install.sh on a clean macOS (deferred — requires fresh Mac).

Known limitations carried over

  • tmux_run allowlist still uses prefix matching; shell-chain bypass via && / ; unfixed (CodexMB review item, deferred to follow-up release).
  • Multi-daemon visibility on CodeWatch app side: configurable URL list shipped as a fallback; primary path is one canonical daemon (the redirect-mini-to-macbook approach we settled on tonight).

🤖 Generated with Claude Code

Petrus Pennanen and others added 11 commits May 1, 2026 12:27
Adds a Model Context Protocol (MCP) server that exposes IAK's
tmux-backed wake / list / run primitives as MCP tools, so any
MCP-aware client (Claude Desktop / Code, Cursor, custom agents) can
drive the agent fleet directly without re-implementing the
nudge / send-keys protocol.

New files:
  * src/mcp-server.mjs   - MCP server (stdio transport).
                           4 tools: wake_ide, list_sessions, wake_all,
                           tmux_run. wake_all is config-aware: pulls
                           sessions from tmux.ide_session +
                           tmux.default_session + any per-adapter
                           session keys.
  * bin/iak-mcp.mjs      - CLI entry point (chmod +x, registered as
                           the `ide-agent-kit-mcp` bin in package.json
                           and as the `npm run mcp` script).

Dependencies:
  * @modelcontextprotocol/sdk@^1.29.0

Verified by JSON-RPC handshake on stdio: initialize succeeds,
tools/list returns the 4 tools, tools/call name=list_sessions
returns the live tmux sessions on this host (6 found in smoke test).

One small implementation note worth flagging:
the tmux list-sessions format uses '|' as the field delimiter
rather than \t. Single-quoted shell strings do not interpret \t,
so tmux would receive literal backslash-t and emit it verbatim
instead of a tab, which broke the .split('\t') parser in early
iteration. '|' is safe for tmux session names (which are
alphanumeric + dash + underscore in IAK's conventions).

Wiring example in README. Drop in your MCP client config:

    {
      "mcpServers": {
        "ide-agent-kit": {
          "command": "node",
          "args": ["/absolute/path/to/ide-agent-kit/bin/iak-mcp.mjs"]
        }
      }
    }

…restart the client, the 4 tools appear in the picker, and you can
wake any IDE in the fleet from any agent that speaks MCP.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ession, tests, version-from-package

Addresses every item in @claudemm's PR #10 review:

* **Security (high) — tmux_run fail-closed.** When `tmux.allow` is missing
  or empty AND `mcp.allow_unrestricted` is not true, `tmux_run` is
  omitted from the tool list entirely (so it cannot be invoked at all).
  The boot log explains the decision: "[iak-mcp] tmux_run: enabled —
  tmux.allow has 5 pattern(s)" or "[iak-mcp] tmux_run: disabled —
  tmux.allow is missing or empty …". New helper decideTmuxRunMode() is
  exported and unit-tested.

* **Fragile session discovery (medium) — explicit mcp.sessions.**
  Replaced the "scan every top-level config key for objects with a
  .session string" heuristic with an explicit `mcp.sessions: [...]`
  config key (preferred) plus the existing tmux.ide_session +
  tmux.default_session fallback. Unrelated keys (`sentry: {session:
  "warn"}`) no longer leak into wake_all targets.

* **Hardcoded version (low).** Server now reads its own version from
  ../package.json at module load instead of hard-coding "0.6.1".
  Tracks future bumps automatically.

* **Missing read_session tool (medium scope).** New tool wraps
  `tmux capture-pane -p -t <session> -S -<lines>` so MCP clients can
  see what an agent printed after a wake_ide. Lines clamped to
  [1, 2000].

* **No tests (medium).** Added test/mcp-server.test.mjs covering:
  - decideTmuxRunMode: missing config, empty allow, populated allow,
    allow_unrestricted with empty allow, allow_unrestricted=false.
  - configuredAgentSessions: empty config, explicit mcp.sessions,
    fallback to tmux.* keys, dedup, anti-fragility (does NOT scan
    unrelated keys), drops empty/non-string entries.
  - End-to-end stdio: server boots, advertises name + real semver
    version, exposes safe tools; with empty allowlist tmux_run is
    OMITTED; with mcp.allow_unrestricted=true tmux_run is INCLUDED.
  All 14 tests pass locally.

* **Config pass-through.** loadConfig() now passes `mcp` through as
  `raw.mcp || {}` (same shape as `openclaw` already does), so MCP
  server-specific config keys round-trip without being dropped.

README updated with the new tool table row, the new fail-closed
behavior, and an explicit "MCP-specific config keys" subsection
documenting `mcp.sessions` and `mcp.allow_unrestricted`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements the Codewatch / GroupMind confirmation flow @Petrus asked
for, on top of the MCP server already in this branch.

Architecture:
  agent --MCP--> request_confirmation(prompt)
              |       \
              |        \--> GroupMind room: posts the prompt with
              |             /approve <id> · /deny <id> quick replies
              |             (uses poller.api_key + mcp.confirmations.room)
              |
              \--> CLAWWATCH_GATE: posts the prompt to CodexMB's
                   PR #8 receiver, which renders an Android interactive
                   notification with Approve / Deny buttons that
                   vibrate the watch.

  user taps Approve on watch (or types /approve <id> in chat)
              |
              v
  Codewatch's notification action POSTs to
    http://<callback_base>/intent/<id>/decision  {decision: "approve"}
              |
              v
  iak-mcp's tiny HTTP server settles the intent, the in-memory
  promise resolves, request_confirmation returns synchronously.

New files:
  * src/confirmations.mjs
      - in-memory intent registry (pending / decided)
      - createIntent + waitForDecision (synchronous-friendly)
      - decideIntent (idempotent for same decision; rejects flip-flops)
      - listIntents
      - startConfirmationsServer (POST /intent/:id/decision, GET /intents)
        with optional bearer auth (constant-time check)
      - announcers: makeGroupmindAnnouncer (HTTPS POST to
        groupmind.one/api/v1/messages), makeCodewatchAnnouncer (POST to
        the CLAWWATCH_GATE proxy)
      - composeAnnouncers (channel fan-out, per-channel error isolation)

  * test/confirmations.test.mjs — 15 tests:
      - createIntent: announces, returns id
      - decideIntent: validates, idempotent, rejects flip-flops
      - waitForDecision: immediate / blocking / timeout paths
      - listIntents: shows transitions
      - createIntent: tolerates announce failures
      - composeAnnouncers: fan-out + per-channel error isolation
      - HTTP: end-to-end POST settles a waiter; rejects bad json /
        unknown id; GET /intents lists; bearer auth gate works

mcp-server.mjs additions:
  * Imports the confirmations module and conditionally starts the HTTP
    server + wires announcers based on mcp.confirmations config.
  * Registers four new tools — request_confirmation, list_intents,
    approve_intent, deny_intent — only if at least one channel is
    configured. Without a channel they're omitted (fail-closed, same
    pattern as tmux_run).
  * Boot log explains which channels are armed:
    "[iak-mcp] confirmations: enabled on http://127.0.0.1:8788
     — channels: groupmind, codewatch"
    or "disabled — set mcp.confirmations.room (+ poller.api_key)
     and/or mcp.confirmations.codewatch_gate_url".

README:
  * New "Confirmation flow" subsection with config keys + the four
    tools + an end-to-end walkthrough mapping the watch tap back
    to the MCP tool's return.

Test suite: 76 / 76 pass (61 existing + 15 new).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…aemon

* src/confirmations.mjs: GET / and /intents.html serve a small mobile-first HTML
  page with Approve / Deny tap targets per pending intent (inlined CSS/JS, no
  external assets, auto-refresh 2s). GroupMind announcer message body now
  includes a 'Tap to decide:' link to the same UI URL.
* bin/iak-mcp-daemon.mjs (new): long-running daemon — starts the HTTP listener
  and a chat-reply poller that watches the configured GroupMind room every 5s
  for '/approve <id>' / '/deny <id>' and routes to the local intent endpoint.
  --demo flag posts a verification intent at boot.

End-to-end verified live: tap the link in chat OR /approve <id> reply both
land at /intent/<id>/decision and settle a waiting request_confirmation call.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
makeGroupmindAnnouncer now includes:
  metadata: { actions: ["Approve","Deny"], intent_id,
              intent_prompt, intent_session }

Companion change in antfarm (PR https://github.com/ThinkOffApp/antfarm/pull) renders inline Approve/Deny buttons on chat messages whose metadata carries both fields. Tap → posts `/approve <id>` as a chat reply → existing chat-reply poller in this daemon catches it and routes to /intent/:id/decision.

End-to-end: agent calls request_confirmation MCP tool → daemon posts to room with metadata → user taps Approve in GroupMind chat → chat reply posted → daemon catches reply → intent settled → MCP tool resolves with {decision: "approve"}.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the missing piece for unattended Claude Code:

- scripts/claudemb-poll.sh        synced with the production version
                                  on the MacBook (DM polling, focus-
                                  preserving wake, cooldown, dual
                                  /tmp file paths). Same script that
                                  has been driving @claudemb's
                                  auto-respond loop in the
                                  thinkoff-development room.
- scripts/claudemb-wake.sh        AppleScript injector. Activates
                                  the Claude desktop app, types the
                                  nudge ("check rooms"), then restores
                                  focus to whatever app was frontmost.
- scripts/check-rooms-hook.sh     UserPromptSubmit hook. Reads
                                  /tmp/iak-new-messages.txt and
                                  prepends to the prompt, then clears.
- docs/auto-wake.md               Full setup + ASCII diagram +
                                  env-var reference + troubleshooting.

Lets @claudemm and any other Claude desktop instance mirror the
auto-wake loop on a fresh box: drop the three scripts, wire the hook,
start the poller in tmux, done.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
scripts/claudecode-stop-resume.sh — Claude Code Stop hook that reads
/tmp/iak-new-messages.txt and exits 2 with content on stderr,
which makes Claude Code resume the turn with the new messages as
additional context. No Accessibility permission needed.

Pairs with the existing osascript wake path: the AppleScript wake
covers from-idle (creates a new turn from nothing); the Stop hook
covers in-flight (catches messages that arrive during an active
turn). Use either or both depending on your macOS Accessibility
state.

Idea + reference impl from @claudemm on the Mac mini.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- src/confirmations.mjs: startConfirmationsServer now accepts an
  optional `announce` callback. New POST /intent endpoint creates a
  pending intent, wires up announcements via that callback, and
  returns {ok, id}. Lets any HTTP caller (Bash gates, external
  scripts, other agents) create confirmations without going through
  stdio MCP.

- bin/iak-mcp-daemon.mjs: builds the announcer map up-front and
  passes it into startConfirmationsServer so POST /intent fires
  GroupMind/Codewatch announcements out of the box.

- src/mcp-server.mjs: request_confirmation now probes for a live
  daemon at startup; when present, forwards intent creation +
  decision polling via HTTP instead of starting an in-process
  HTTP listener (which would conflict with the daemon's port).
  Result: many MCP clients can share one daemon's intent registry.

- test/real-agent-demo.mjs: tiny MCP-SDK client harness that
  spawns iak-mcp-server and calls request_confirmation, useful
  for end-to-end testing.

Unblocks @claudemm's unification plan: a PreToolUse Bash gate on the
mini can now POST /intent + poll for the decision instead of going
through the older watch-gate.py /relay/events path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- src/confirmations.mjs: startConfirmationsServer accepts an optional
  wakeScript path. New POST /wake endpoint runs the script with
  the requested text (default "check rooms") and returns 202. Spawns
  detached so the response returns immediately.

- bin/iak-mcp-daemon.mjs: defaults wakeScript to scripts/claudemb-wake.sh
  in the repo. Override via mcp.confirmations.wake_script.

- src/mcp-server.mjs: new wake_remote MCP tool. Body {gateUrl, text}.
  Forwards to the remote daemon's POST /wake. Lets any agent with the
  IAK MCP registered nudge another agent's desktop app within ~500ms,
  bypassing the 15s room-poll cadence.

Use case: claudemm posts a confirmation that needs claudemb's input.
Their daemon calls wake_remote(gateUrl="http://192.168.50.240:8788")
and claudemb's desktop Claude gets a "check rooms" prompt instantly
instead of waiting up to 15s for the next IAK poller tick.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
curl -fsSL https://raw.githubusercontent.com/ThinkOffApp/ide-agent-kit/main/scripts/install.sh | bash

Idempotent. Verifies prereqs (node/git/tmux via brew), clones to
~/ide-agent-kit, npm installs, writes a starter config (with
required-edit fields highlighted), wires UserPromptSubmit + Stop
hooks into ~/.claude/settings.json, starts the daemon in a tmux
session, prints the LAN URL the user pastes into CodeWatch.

Does NOT generate keys, touch Accessibility (prints System Settings
deep-link), or install Claude Code itself.

Pairs with the in-app CodeWatch setup card (separate commit) so a
user can go from "fresh phone + fresh Mac" to fully working in
about 3 minutes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
See CHANGELOG.md for full notes. Major adds: request_confirmation +
iak-mcp-daemon, POST /intent + POST /wake endpoints, wake_remote MCP
tool for cross-machine nudge, GroupMind metadata.actions for inline
Approve/Deny buttons (antfarm PR #13), Stop-hook auto-resume for the
desktop app, one-shot macOS install.sh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector
Copy link
Copy Markdown

To use Codex here, create an environment for this repo.

@ThinkOffApp
Copy link
Copy Markdown
Owner Author

Superseded — feat/mcp-wake-ide already merged via PR #10 (commit c3cd47d) and v0.7.0 tagged + GitHub release published: https://github.com/ThinkOffApp/ide-agent-kit/releases/tag/v0.7.0. Same content. README + release notes updated post-merge. Thanks @claudemm.

@ThinkOffApp ThinkOffApp closed this May 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant