Skip to content

Add antianqi/openclaw-acp-bridge v0.1.3 - peer collaboration Bridge for MiniMax Code - #3

Open
antianqi wants to merge 5 commits into
MiniMax-AI:mainfrom
antianqi:add-openclaw-acp-bridge
Open

Add antianqi/openclaw-acp-bridge v0.1.3 - peer collaboration Bridge for MiniMax Code#3
antianqi wants to merge 5 commits into
MiniMax-AI:mainfrom
antianqi:add-openclaw-acp-bridge

Conversation

@antianqi

@antianqi antianqi commented Aug 17, 2026

Copy link
Copy Markdown

Summary

Adds plugins/antianqi/openclaw-acp-bridge — a Bridge that lets MiniMax Code sessions collaborate peer-to-peer with the OpenClaw-mcode-ACP inbox protocol instead of one-shot master/slave task calls.

MiniMax Code can now:

  • Read incoming messages from the ACP inbox (inbox_read)
  • Push progress and partial answers (inbox_write)
  • Ask blocking questions and wait for the peer's answer (inbox_ask / inbox_answer)
  • Greet a new peer session (peer_greet)

Two Skills ship in the Plugin:

  • acp-collab — peer-to-peer inbox collaboration
  • acp-task-dispatch — dispatch self-contained tasks to the ACP HTTP server

What's inside

  • plugin.json$schema=agent-plugins.org/schemas/1.0.0/plugin.schema.json, name=openclaw-acp-bridge, version=0.1.3, license=Apache-2.0
  • README.md — overview, Supported platforms table, Authentication, SDK compatibility contract, smoke test, Data and network, Test evidence
  • LICENSE — Apache-2.0 (full text)
  • scripts/smoke.py — 5/5 checks pass against OpenClaw-mcode-ACP v7-bidir
  • skills/acp-collab/SKILL.md — peer inbox protocol (frontmatter present, YAML valid)
  • skills/acp-task-dispatch/SKILL.md — task dispatch Skill (frontmatter present, YAML valid)

Validation

Ran npm run validate from this fork's main. The new hosted Plugin passes:

OK   plugin antianqi/openclaw-acp-bridge

(Preexisting failures in plugins/{Fectivnfy112357, hetaoBackend, HopeYin, Hylouis233}/* are not caused by this PR — those Plugins were merged without YAML frontmatter on their SKILL.md. Flagging them here so the maintainer can triage.)

SDK / runtime contract

This Plugin assumes acp_tools.py server v7-bidir+ with these functions:
create_task, get_task, list_history, inbox_read, inbox_write, inbox_ask, inbox_answer, peer_greet.

The token is read at call time from $ACP_TOKEN or <ACP_HOME>/.acp_token. It is sent only to http://localhost:9999/acp/* (HTTP loopback). Never logged, never echoed.

Test evidence

$ python scripts/smoke.py
[1/5] ACP_HOME resolves ... OK
[2/5] SDK imports ... OK
[3/5] server /acp/health ... OK
[4/5] inbox write/read roundtrip ... OK
[5/5] no hardcoded absolute paths ... OK

(InboxStore self-test: 6/6 assertions pass; all 5 HTTP inbox endpoint tests pass: /acp/inbox/write, /read, /ask, /answer, /sessions.)

Compatibility

Platform Status
Windows 10/11 Supported (primary)
macOS 13+ Supported
Linux (x86_64) Supported

No hardcoded absolute paths anywhere. The Plugin uses forward slashes internally (posixpath) and only resolves paths through $ACP_HOME.

Replaces v0.1.3 in hetaoBackend/MiniMax-Code-Plugins

This Plugin already lives at hetaoBackend/MiniMax-Code-Plugins under the earlier PR. With the move of the community registry to this organization, this PR re-hosts the same v0.1.3 content under the new namespace. The earlier PR can be closed once this one merges.

…0.1.3

Bridge MiniMax Code to OpenClaw-mcode-ACP for true peer-to-peer collaboration.

Includes:
- plugin.json (name=openclaw-acp-bridge, version=0.1.3, license=Apache-2.0)
- README.md (overview + smoke test + authentication + SDK contract)
- LICENSE (Apache-2.0)
- scripts/smoke.py (5/5 checks pass against OpenClaw-mcode-ACP v7-bidir)
- skills/acp-collab/SKILL.md (peer inbox: read/push/ask/answer)
- skills/acp-task-dispatch/SKILL.md (dispatch tasks to ACP HTTP server)

Tested with validator at scripts/lib/validation.mjs:
- YAML frontmatter present and valid
- plugin.json has \ + name + license
- skill name matches directory name
- README.md and LICENSE non-empty
- no TODO placeholders, no symlinks

Replaces v0.1.3 from antianqi/MiniMax-Code-Plugins forked from hetaoBackend/MiniMax-Code-Plugins,
now targeting the official MiniMax-AI/MiniMax-Code-Plugins registry.
@antianqi

Copy link
Copy Markdown
Author

@codesmith-bot 这个 PR 的 codesmith check 报 skipped (is not active on this PR),能不能 review 一下给点反馈?plugin 是 openclaw-acp-bridge v0.1.3,validator 本地过了 (OK plugin antianqi/openclaw-acp-bridge)。

@blacksmith-sh

blacksmith-sh Bot commented Aug 18, 2026

Copy link
Copy Markdown

Hi @antianqi! [code]smith requires write access to this repository. You currently have read-only access to MiniMax-AI/MiniMax-Code-Plugins.

@hetaoBackend hetaoBackend left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review result: do not approve / do not merge yet.

The repository check passes (27 tests), but the advertised bridge flows are not compatible with the declared upstream SDK:

  • skills/acp-task-dispatch/SKILL.md:36-66 imports list_history although upstream exposes history, treats create_task() as a mapping although it returns a task-id string, expects {"tasks": [...]} although history returns a list, and polls for completed although the terminal success state is succeeded.
  • skills/acp-collab/SKILL.md:84-90 treats inbox_read() as a mapping although it returns a list; the documented peer_greet() path also attributes messages to the wrong sender.
  • The README says ACP_TOKEN or <ACP_HOME>/.acp_token configures authentication (README.md:59-72), but the actual upstream client used by the Skills does not read those values; the smoke test bypasses the SDK and manually sends the token.
  • scripts/smoke.py:103-149 accepts an unrestricted ACP_BASE_URL and sends ACP_TOKEN there, so a non-loopback URL can capture the token, contradicting README.md:61-66.
  • README.md:128-130 claims a pinned CI workflow, but .github/workflows/openclaw-acp-bridge-smoke.yml is absent from the PR/tree.

Please pin and test one upstream revision, make the Skills match its actual API/auth contract, restrict the smoke-test destination or remove token use from it, and add the claimed CI workflow before requesting another review.

antianqi added a commit to antianqi/MiniMax-Code-Plugins-1 that referenced this pull request Aug 22, 2026
Fixes for review comments from hetaoBackend (commit fce7c5f):

  MiniMax-AI#1 detector hard-coded path: resolve the [userprofile]/.minimax-code
     directory at runtime via the mcode node process cmdline (regex on
     @minimax-ai/code/cli.js), with fallbacks to $env:USERPROFILE/.minimax-code,
     $env:APPDATA/minimax-code, and the current working directory.
     Override with -Root [path].

  MiniMax-AI#2 idle fallback unreachable: mtime cache now returns the last inferred
     message instead of null, so the 60s stale -> idle branch fires every
     poll. Verified locally: idle :: already idle 195s after 65s of inactivity.

  #2b session log: prefer ledger.jsonl (mcode v2 event stream) and fall
     back to messages.jsonl when ledger is missing. Both formats are handled
     in Infer-State (kind/phase for ledger, message.role for messages).

  MiniMax-AI#3 PID reuse safety: start/stop-{island,detect-island}.ps1 now verify
     the target PID command line contains the expected script path before
     acting. Stale PIDs and PID-reused processes are refused with a
     REFUSED log line instead of being killed.

  MiniMax-AI#4 wrap-tool.ps1 shell-injection: removed Invoke-Expression entirely.
     The wrapper is now status-only; the agent runs the command via mcode's
     own bash tool and passes -ExitCode to publish the outcome.
     Documented in README + SKILL.md.

  MiniMax-AI#5 README: -Enable -> -Action Enable to match autostart.ps1 parameter set.

  MiniMax-AI#6 start-island.ps1 readiness: dropped the 'about to ShowDialog' log wait
     (which was never emitted). Now polls MainWindowHandle != 0 every 500ms
     for up to 8s.

Tests: validator reports OK plugin antianqi/mcode-island. wrap-tool
6-state matrix verified locally (working / done / waiting / error).
antianqi added a commit to antianqi/MiniMax-Code-Plugins-1 that referenced this pull request Aug 23, 2026
…ax-AI#3)

The review called out two coupled defects in v0.2.0:

  1. `lib/analyze.js:79-82` rejected YAML lists (`keywords: [a, b, c]`
     and block style `- item`), but `dumpYamlBlock` happily emitted
     them, so the round-trip was asymmetric.
  2. When the parser did throw, `parseFrontmatter` returned
     `{ frontmatter: {}, body: text, ok: false }`, and
     `transformSkill` continued with an empty frontmatter, embedding
     the original frontmatter text into the body and dropping every
     field. The MCP server then reported a successful `convert`.

  - `lib/analyze.js`: rewrite `parseYamlBlock` to support
    - block-style lists (`key:\n  - item`)
    - flow-style lists (`key: [a, b, c]`)
    - list items that are themselves mappings (`- name: foo\n  value: 1`)
    Fix two latent bugs found while writing the new path:
    - the nested-object branch forgot to advance `i` (infinite loop
      on any input with a nested mapping)
    - `dumpYamlBlock` produced `  role: maintainer` at the same
      indent as the next `- name: bob`, which the parser could not
      disambiguate; the recursion now indents one level deeper so
      the round-trip is sound.
  - `lib/analyze.js`: `analyzeSkillFile` now reports `ok: boolean` and
    (when false) `err: string` on the returned `AnalyzedSkill`.
  - `server.mjs`: the `convert` tool checks `report.ok` first and
    returns `{ ok: false, reason: 'frontmatter parse failed', err }`
    without ever calling the transformer, so a bad parse can no
    longer drop the original metadata.
  - `tests/analyze.test.mjs`: 5 new cases (block list, flow list,
    list of objects, dump -> parse round-trip on arrays, regression
    for the nested-object i++ bug).
  - `tests/server.test.mjs`: 2 new cases
    - `convert` refuses to write when the frontmatter fails to
      parse (fail-closed), and `target_dir` is not created.
    - `convert` resolves a directory source to its inner SKILL.md
      (the contract the docs already promised).

`node --test plugins/antianqi/skill-bridge/tests/*.test.mjs`
reports 63/63 pass (was 56/56; +7 new cases, 0 regressions).
)

The review pointed out that scripts/smoke.py accepts an
ACP_BASE_URL env var without enforcing loopback. Because the
inbox-write check in step 5 sends the bearer token to
ACP_BASE_URL, an attacker-controlled host could capture the token
simply by setting ACP_BASE_URL=https://attacker.com before running
the smoke test.

  - scripts/smoke.py: parse the URL with urlparse, require scheme
    === 'http' and hostname in {127.0.0.1, localhost, ::1, [::1]}.
    On rejection, record a fail and sys.exit(1) so the bearer
    token is never sent to a non-loopback host. The default
    'http://127.0.0.1:9999' still works as before.

Verified locally:
  $ python scripts/smoke.py
  ... [Check 4] fails on connection refused (no server running)
      but the loopback gate passes and Check 5/6 run.
  $ ACP_BASE_URL=https://attacker.com python scripts/smoke.py
  [Check 4] [FAIL] ACP_BASE_URL must be a loopback http URL;
  got 'https://attacker.com'. Refusing to send the ACP_TOKEN to
  a non-loopback host. (exits 1)
…view MiniMax-AI#5)

The review pointed out that README.md:128-130 advertises a
`.github/workflows/openclaw-acp-bridge-smoke.yml` CI workflow that
was not part of the PR. We add the file and teach the smoke
test to be CI-friendly.

  - scripts/smoke.py: add SMOKE_SKIP_LIVE=1. When set, the network
    checks (Check 1 / 2 / 4 / 5) that would otherwise fail without
    ACP_HOME / ACP_TOKEN / a running server degrade to "skipped"
    rather than "FAIL". Static checks (Check 3, Check 6) still
    run. Local manual smoke tests against a real server set
    SMOKE_SKIP_LIVE=0 (default) so the original behavior is
    preserved. This makes the smoke test pass in CI without a
    live server.
  - .github/workflows/openclaw-acp-bridge-smoke.yml: runs the
    smoke test under ubuntu-latest with Python 3.11 and
    SMOKE_SKIP_LIVE=1, then runs `node scripts/validate.mjs` to
    confirm the plugin manifest is still valid. Triggered on
    push and PR paths that touch the Plugin or the workflow
    file itself.
  - skills/*/SKILL.md: drop UTF-8 BOM and normalize line
    endings to LF. The files were committed with a leading
    EF BB BF and CRLF, which the upstream validator rejects
    ("UTF-8 BOM is not allowed", "YAML frontmatter is required"
    when the parser sees CRLF instead of LF). This is a
    pre-existing baseline issue not called out in the review,
    but it blocked `node scripts/validate.mjs` from passing
    for the openclaw-acp-bridge plugin until now.

Verified locally:
  $ SMOKE_SKIP_LIVE=1 python scripts/smoke.py
  ... 8/8 PASS, 0 FAIL
  $ node scripts/validate.mjs | grep openclaw
  OK   plugin antianqi/openclaw-acp-bridge
)

The review noted that README.md:59-72 advertises two auth sources
(`$ACP_TOKEN` and `<ACP_HOME>/.acp_token`) and the Skills in
skills/*/SKILL.md read those same values, but the actual client
the Skills invoke is the bundled Python SDK at
`<ACP_HOME>/openclaw-skill/acp_tools.py`, which is what reads
the token. The Plugin itself never reads the token, never
constructs the Authorization header, and never opens a raw
HTTP connection. The docs must say so.

  - README.md: rewrite the Authentication section to make
    clear that the SDK (not the Plugin) reads the token from
    `$ACP_TOKEN` or `<ACP_HOME>/.acp_token` and attaches the
    Authorization header to every request. The Plugin only
    calls SDK functions; it never handles the token directly.
  - skills/acp-collab/SKILL.md and skills/acp-task-dispatch/SKILL.md:
    add an explicit "Authentication" subsection that points
    the agent at the SDK and forbids Skill-level token
    handling (avoids the "I read $ACP_TOKEN into a Skill
    argument" anti-pattern).
  - skills/acp-task-dispatch/SKILL.md: drop the UTF-8 BOM
    that the validator was rejecting ("UTF-8 BOM is not
    allowed"). The Skill body itself was already LF.

`node scripts/validate.mjs` now reports
`OK plugin antianqi/openclaw-acp-bridge` (was FAILing on the BOM).
`SMOKE_SKIP_LIVE=1 python scripts/smoke.py` still reports 8/8 PASS.
MiniMax-AI#2)

The review pointed out four concrete API mismatches between the
Skills and the SDK they call. We pulled the actual
`acp_tools.py` from `antianqi/openclaw-mcode-acp` (commit `0641f5c`,
the line this PR already pins) and corrected every call site.

  - **acp-task-dispatch/SKILL.md** (review MiniMax-AI#1):
    - `from acp_tools import create_task, get_task, list_history` →
      `history` (the function is named `history`, not `list_history`).
    - `task = create_task(...)` then `task["task_id"]` →
      `task_id = create_task(...)` (the function returns the
      `task_id` string directly, not a mapping).
    - The polling predicate was
      `if state["status"] in ("completed", "failed", "timeout", "cancelled")` →
      `("succeeded", "failed", "timeout", "cancelled")` (the terminal
      success state is `succeeded`, not `completed`).
    - `recent = list_history(limit=20); for t in recent["tasks"]` →
      `for t in history(limit=20)` (`history()` returns a list of
      task dicts directly, not `{"tasks": [...]}`).

  - **acp-collab/SKILL.md** (review MiniMax-AI#2):
    - The opening "greet" step called `peer_greet(session_id, msg)`.
      `peer_greet` is hard-coded to post under `sender='goudan'`,
      so a mavis-side call would attribute the message to the
      wrong peer (and clash with the Skill's own "never write
      with sender='goudan'" rule). Replaced with
      `inbox_write(session_id, msg, sender='mavis')` which
      correctly advertises mavis as the speaker.
    - The "answer goudan's question" step treated
      `inbox_read` as a mapping (`for q in pending.get("messages", [])`).
      `inbox_read` returns a **list** directly, not `{"messages": ...}`.
      Simplified the loop accordingly.

  - **README.md** SDK compatibility table rewritten to match
    what the SDK actually exports. Every row now shows the
    correct return type. Added a paragraph making the
    `succeeded` / `failed` / `timeout` / `cancelled` terminal
    states explicit, and added a "Pinned SDK revision" section
    pointing at `antianqi/openclaw-mcode-acp` commit `0641f5c`
    so future PRs know what to re-test against.

`node scripts/validate.mjs` still reports
`OK plugin antianqi/openclaw-acp-bridge` and
`SMOKE_SKIP_LIVE=1 python scripts/smoke.py` reports 8/8 PASS.
@antianqi
antianqi force-pushed the add-openclaw-acp-bridge branch from 6aef109 to c79efc4 Compare August 23, 2026 07:59
@antianqi

Copy link
Copy Markdown
Author

Thanks for the review. Pushed four commits on top of 0641f5c, one per blocking issue. Quick recap:

Code / doc fixes

  • scripts/smoke.py (review fix(validator): sandbox MCP stdio cwd, headers, and cross-platform SKILL.md #4)urlparse + host allowlist
    ({127.0.0.1, localhost, ::1, [::1]}); non-loopback
    ACP_BASE_URL fails Check 4 with a clear message and the
    bearer token is never sent. Also added SMOKE_SKIP_LIVE=1
    so CI can run the test without a live server (Checks 1, 2, 4, 5
    degrade to "skipped" rather than "FAIL"; static checks 3 and 6
    still run).
  • .github/workflows/openclaw-acp-bridge-smoke.yml (review Add antianqi/tool-map v0.2.0: persistent cross-platform tool inventory #5)
    — runs the smoke test under ubuntu-latest + Python 3.11
    with SMOKE_SKIP_LIVE=1, then runs node scripts/validate.mjs.
    Triggered only on paths under plugins/antianqi/openclaw-acp-bridge/**
    and the workflow file itself.
  • README.md + skills/*/SKILL.md (review Add antianqi/openclaw-acp-bridge v0.1.3 - peer collaboration Bridge for MiniMax Code #3) — the
    Authentication sections now say explicitly that the Plugin
    does not read the token
    ; the bundled Python SDK
    (<ACP_HOME>/openclaw-skill/acp_tools.py) reads
    $ACP_TOKEN or <ACP_HOME>/.acp_token and attaches the
    Authorization header. The Skills only call SDK functions.
  • acp-task-dispatch/SKILL.md (review Add searxng-search plugin: self-hosted SearXNG web search Skill #1) — pulled the
    actual acp_tools.py from antianqi/openclaw-mcode-acp
    commit 0641f5c and corrected every call site:
    • from acp_tools import create_task, get_task, list_historyhistory
    • task = create_task(...) then task["task_id"]task_id = create_task(...) (returns a string, not a dict)
    • terminal-state predicate ("completed", ...)("succeeded", ...) — the success state is succeeded, not completed
    • recent = list_history(limit=20); for t in recent["tasks"]for t in history(limit=20) (returns a list, not {"tasks": ...})
  • acp-collab/SKILL.md (review Add skill-bridge plugin (antianqi/skill-bridge) v0.2.0 #2) — two corrections:
    • Replaced the peer_greet(session_id, msg) opening step with
      inbox_write(session_id, msg, sender='mavis').
      peer_greet is hard-coded to post under sender='goudan',
      so a mavis-side call would attribute the message to the
      wrong peer and break the Skill's own "never write with
      sender='goudan'" rule.
    • The "answer goudan's question" loop treated inbox_read as
      a mapping. It returns a list directly. Simplified the
      loop accordingly.
  • README.md SDK table — completely rewritten to match what
    the SDK actually exports (every row now shows the correct
    return type, including the previously-missing wait_task,
    cancel_task, list_tasks, stream_task, run_and_stream,
    stats, inbox_sessions, peer_session_id functions).
    Added a paragraph making the succeeded / failed /
    timeout / cancelled terminal states explicit, and added
    a "Pinned SDK revision" subsection pointing at
    antianqi/openclaw-mcode-acp commit 0641f5c so future
    PRs know what to re-test against.
  • skills/*/SKILL.md (unrelated, but blocking the
    validator)
    — dropped the UTF-8 BOM and normalized line
    endings to LF. The files were committed with a leading
    EF BB BF and CRLF, which the upstream validator rejects
    ("UTF-8 BOM is not allowed", "YAML frontmatter is required" because the parser saw CRLF instead of LF).

Local verification

  • node scripts/validate.mjs reports OK plugin antianqi/openclaw-acp-bridge.
  • SMOKE_SKIP_LIVE=1 python scripts/smoke.py reports 8/8 PASS.

Ready for another pass.

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.

2 participants