Skip to content

minimax-ai/cli-agent-bridge

v0.1.0MIT

Delegate coding tasks from MiniMax Code to locally installed coding CLIs (Claude Code, Codex, Kimi Code, ZCode, DSH) through a dependency-free stdio MCP server with git-diff review.

CLI Agent Bridge

The problem

MiniMax Code users who also run Claude Code, Codex, Kimi Code, ZCode, or DSH want to keep MiniMax Code as the single orchestrator while handing well-scoped implementation work to those CLIs. Without a bridge, delegation means copying prompts between terminals and pasting results back, with no record of what the worker changed.

What this Plugin does

This Plugin ships one dependency-free stdio MCP server and one Skill. MiniMax Code calls the three MCP tools to drive headless sessions of the other coding CLIs inside the same git repository:

  • list_backends: report which coding CLIs are installed and available on this machine.
  • workspace_status: git status, diff stat, and changed files before delegating work.
  • delegate_task: run a self-contained task with a chosen backend CLI and return its exit code, output tail, stderr tail, and the before/after git snapshots (staged, unstaged, untracked, and committed deltas) the worker produced. Runs against the same workspace are serialized across independent bridge processes; dirty trees are refused unless allowDirty=true; cancellation and timeout terminate the complete worker process tree before the lock is released.

The Skill teaches MiniMax Code when and how to delegate, and to review the returned diff before reporting completion.

Try it

Use the cli-agent-bridge skill, then delegate the login-form refactor in this repository to codex.

Expected result: MiniMax Code checks workspace_status, confirms the tree is clean, runs delegate_task with backend=codex and a self-contained task, then reviews the returned git status, diff stat, changed files, and output tail before continuing.

Use cli-agent-bridge to have claude and kimi implement the same small feature independently,
then compare the two diffs. Create two independent clones first.

Expected result: the orchestrator creates two clones at the same starting commit, delegates the same task to backend=claude in the first and backend=kimi in the second, then compares the two diffs reported to the user. Linked worktrees share refs and therefore queue behind the same repository lock; use separate clones when the comparison must run in parallel.

Requirements

  • Node.js 20 or newer to run the MCP server (the server has no npm dependencies).
  • git available on PATH; the target workspace must be a git repository.
  • Production delegation and workspace inspection are supported on Windows, where delegated workers and potentially extensible Git helpers run inside a kill-on-close Job Object. End-to-end verified with Claude Code 2.1.226 and Kimi Code 0.30.0. Linux, macOS, and BSD fail closed before backend configuration, workspace access, Git resolution, or executable probing: this dependency-free server cannot prove lifecycle containment after an arbitrary local worker asks a host service to launch a process outside its original process tree.
  • Each backend CLI must be installed, on PATH, and signed in with your own account before use:
BackendCLIStatusHeadless form used
claudeClaude Codeverified end-to-end (2.1.226)claude -p --output-format text --permission-mode acceptEdits
codexOpenAI Codex CLIdocumented non-interactive formcodex exec --
kimiKimi Codeheadless invocation verified (0.30.0)kimi -p

The claude template passes --permission-mode acceptEdits so the headless worker can edit files in the workspace without an interactive approval prompt; other permission levels can be selected by editing backends.json. The kimi prompt mode (-p) accepts no permission flags on current versions, so the worker runs with kimi's own non-interactive defaults.

Experimental backends ship with a documented template and a note in list_backends:

BackendCLIStatusHeadless form used
zcodeZCodeexperimentalzcode -p (desktop builds have no verified headless mode)
dshDeepSeek Harnessexperimentaldsh --profile headless (requires a headless profile)

ZCode desktop builds have no verified headless CLI; point the command field at your own CLI if your ZCode distribution provides one. The dsh template uses its documented headless profile (dsh --profile headless), which must exist under DSH_HOME/profiles. Edit backends.json (or set the CLI_AGENT_BRIDGE_BACKENDS environment variable to a custom file) to adjust command, args, or binary paths.

On Windows, the contained launcher recognizes the fixed format generated by npm for standard .cmd shims and starts their real Node entry directly. This preserves empty, multiline, Unicode, quoted, and metacharacter-containing task arguments without a cmd.exe reinterpretation. PowerShell .ps1 backends use a UTF-8 JSON runner. An argument-bearing non-standard .cmd/.bat wrapper fails closed; point command at its underlying real executable in backends.json.

Data and network

  • This Plugin makes no network calls of its own and stores no credentials, tokens, or session logs. Per-user temporary lock records contain only process identity; if termination cannot be confirmed, a quarantine marker containing the workspace path/backend/error persists until an operator explicitly approves recovery as described below.
  • delegate_task passes the task text to the backend CLI you choose, which runs with your own local authentication and may contact that vendor or service for the requested work.
  • The task text and workspace files are processed by the chosen backend provider. Never include credentials, private endpoints, or personal data in a task.
  • The server returns bounded command-output tails and Git snapshots to its MCP client; nothing is transmitted elsewhere by the server itself.
  • Workers run with the permission level baked into their template (claude: acceptEdits, which auto-approves workspace file edits but still gates other tool classes) or with that CLI's own non-interactive defaults. Review the returned diff before accepting the work.

Customizing backends

backends.json maps each backend to a command template. The placeholders and are substituted at run time. To use a differently named binary (for example a zcode wrapper), change the command field. resumeSessionId is honored only for backends whose resumeArgs is set. The bridge does not discover or parse session IDs from CLI output; pass resumeSessionId only when you already obtained a valid ID from that backend outside this Plugin.

Limitations

  • MiniMax Code Agent Plugins 1.0 does not expose hooks, so context metering and automatic orchestration switches from the upstream subagent-mcp design are out of scope here; the Skill plays that role instead.
  • The bridge delegates tasks; it does not merge code, commit, or push. The user reviews every diff.
  • Delegations and status snapshots targeting the same Git common directory are serialized even when callers name a subdirectory, different path casing, symlink, or linked worktree, and even when separate MCP clients launched separate bridge server processes. Use separate clean clones for parallel comparison runs. The cross-process lock is an owner blob referenced by an atomic Git-ref compare-and-swap in a private bare repository at <git-common-dir>/cli-agent-bridge-lock-store.git. Keeping coordination refs out of the target repository prevents git push --mirror from publishing host/process/token metadata. The private store publishes its persistent UUID through an exclusive ordinary-file compatibility anchor and the same-value UUID blob behind a create-only Git-ref CAS, without requiring hard-link support. The bridge keeps a common-directory handle open through release. Renaming the repository therefore cannot create a second lock domain or strand the original holder on its obsolete pathname, while deleting and recreating a repository cannot inherit the old lock identity. A stale idle lock is reclaimed only when its same-host owner is positively confirmed dead; owner records include the bridge process start identity so a reused PID cannot pin the queue. The host identity also includes the OS user, so another user cannot interpret a user-scoped quarantine marker as cleared. Malformed, foreign-user/host, starting, running, or uncertain records fail closed. A crashed bridge can interrupt the durable state transition that follows worker cleanup, so inspect the recorded process identity before clearing its coordination ref.
  • Linked worktrees share refs and therefore intentionally share one repository lock. The repositoryConcurrency field remains as a fail-safe disclosure if an older bridge instance or an external writer updates bridge history during a snapshot, but current bridge instances do not run linked-worktree delegations concurrently.
  • Locking leaves the target repository refs, worktree, and index unchanged, but it requires writable metadata in the private bare lock store. Its initialization inherits the enclosing repository's core.sharedRepository mode for group/multi-user repositories. Each acquisition writes an owner blob and temporarily updates a coordination ref there. Before returning an acquired lease, it also publishes a unique activity-object ID. Snapshots compare activity IDs rather than clocks from different hosts, and any extant foreign lease ref (including idle, pending, malformed, or quarantined state) remains a conservative attribution-overlap signal. Each normal release schedules Git's safe automatic maintenance for superseded state. A failed release first leaves an exact-owner recovery record in the shared store, so another bridge process can finish cleanup after the transient failure clears. For these reasons workspace_status is not marked read-only in its MCP annotations even though the snapshot itself does not edit worktree files.
  • Cancellation and timeout confirm that the delegated process tree has exited before releasing the workspace mutex. On the supported Windows production path, a kill-on-close Job Object is the kernel lifecycle boundary; the bridge does not substitute PID ancestry polling or inherited environment markers on unsupported platforms. Repository discovery and read-only snapshots resolve Git before entering the workspace and explicitly disable repository hooks, fsmonitor, pagers, external diff drivers, text conversion, and detached automatic maintenance. Worktree status and unstaged diff commands are additionally process-contained because Git may still invoke repository-configured clean filters while reading working-tree content. Coordination-store Git commands use the same hook-free configuration, while operations that create the store or a temporary tree remain process-contained. If termination cannot be confirmed, the bridge writes a shared quarantine marker after first moving its lease into a non-reclaimable quarantine-pending state, then advances the lease into the recoverable quarantined state, and every bridge process refuses further delegation until an operator checks for leftovers and deliberately renames the reported quarantinePath to quarantinePath.recovery-approved. That durable, incident-bound rename authorizes the next delegation to reclaim the quarantined lease; simple marker absence (for example, OS temporary-file cleanup) never authorizes recovery. If the bridge crashes mid-run, a lease recording a running worker still cannot be reclaimed automatically (descendant liveness cannot be proven), and an abrupt crash may leave no quarantine marker. Locate and inspect the retained lease explicitly: first run git rev-parse --path-format=absolute --git-common-dir, append cli-agent-bridge-lock-store.git to obtain <lock-store>, then run git --git-dir=<lock-store> for-each-ref --format="%(refname) %(objectname)" refs/cli-agent-bridge/workspace-locks/ and git --git-dir=<lock-store> cat-file blob <object-id>. The JSON owner record contains the server/worker state and PIDs. Only after checking those processes and escaped descendants are gone, clear the listed ref with git --git-dir=<lock-store> update-ref -d <lock-ref>. The quarantine marker itself lives under the repository's private cli-agent-bridge-lock-store.git/cli-agent-bridge-quarantines directory. This makes repository access, rather than a predictable shared temporary path, the collaboration boundary for manual recovery (including repositories shared deliberately by multiple users). New markers are atomically claimed directories, so publication does not depend on hard-link support and the reported path is renamed the same way during recovery.
  • Cancelling a workspace_status request interrupts its queued lock wait or Git snapshot and returns a cancelled tool result instead of performing a stale snapshot later.
  • timeoutMs is an overall deadline that includes workspace lock acquisition, preflight Git checks, the worker, and post-run snapshots. Safe process-tree termination can extend beyond that deadline by the documented kill grace period.
  • Snapshots include all Git refs as well as HEAD, so a worker that commits on a new branch and returns to the original branch still reports the created ref and commit. Commits are attributed to the worker only when they are not reachable from any pre-delegation ref, so checking out an existing divergent branch is reported as a HEAD move with no new commits, and refs pointing at non-commit objects (for example a blob tag) are reported without failing the delegation. A commit reached through multiple moved refs is counted and logged once with all contributing labels; ref namespaces alone never prove that a commit came from outside the worker. Git exposes only the final, overwritable FETCH_HEAD and no complete cross-version per-fetch tip log. A private, per-delegation Trace2 event stream therefore detects completed fetch/pull attempts in the canonical workspace, including nonzero fetches that may have updated only some destinations; when one occurred, the response keeps the worktree/ref snapshot but marks commit attribution unavailable instead of guessing which commits were worker-created. The trace is user-private, bounded, consumed after worker cleanup, and removed before the response. Runs without fetch/pull batch commit-tip classification, and each changed target uses one boundary graph walk, so repositories with thousands of refs do not spawn one Git process per baseline. Any bounded Git capture that truncates is rejected as an unreliable snapshot; backend output truncation is disclosed.
  • zcode and dsh backends are experimental: ZCode desktop builds have no verified headless CLI, and dsh needs a headless profile present under DSH_HOME/profiles.
  • Custom wrapper shims that re-bind dashed flags can misreport a backend as unavailable; point the backend command at the real executable to bypass the wrapper.
  • The stdio transport accepts newline-delimited JSON-RPC with a 1,000,000-character per-line limit. An unterminated or complete line beyond that bound is rejected and closes the dispatch gate through the same awaited cleanup path as host disconnect.

Verification

Run the dependency-free fake-backend suites from the repository root:

node --test plugins/Hylouis233/cli-agent-bridge/test/server.test.mjs
node --test plugins/Hylouis233/cli-agent-bridge/tests/server.test.mjs
node --test plugins/Hylouis233/cli-agent-bridge/tests/workspace-lock.test.mjs

They cover the full MCP flow plus in-process and cross-process canonical worktree locking, stale owner compare-and-swap, live-owner non-steal, quarantined-lease recovery after an explicit operator approval rename, interruptible lease state updates, shared quarantine markers, queued and discovery-phase cancellation (including list_backends probes), overall deadlines, cancel/timeout Windows Job Object termination, internal fail-closed process-tree state-machine fixtures, PID-reuse identity checks before signaling, unusual Git pathnames (including a trailing-space worktree root), JSON-RPC id typing and bounded lines, unborn HEAD and non-HEAD ref changes, checkout-only HEAD moves, single-count attribution for commits on the checked-out branch, fork-point diff baselines for new branches, non-commit refs, fetched-history exclusion, repository-wide serialization and failed-release recovery between linked worktrees, capture truncation, and Codex prompt delimiters on Windows and POSIX.

License

MIT. See LICENSE. Upstream credits: see NOTICE.