Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
161d73b
Test provider routing, review ownership, and native state boundaries
greenpolo Sep 23, 2026
34ffc9a
Preserve admitted native workers and accept isolated worktree starts
greenpolo Sep 23, 2026
c89dc8e
Resolve provider worker models through one Agent type per provider
greenpolo Sep 23, 2026
b50fd97
Display native harness actions in their owning Claude transcripts
greenpolo Sep 23, 2026
9927aa2
Separate native context from turn consumption and repair receipt rend…
greenpolo Sep 23, 2026
de3e4e1
Type-check Claude Mods against generated engine declarations
greenpolo Sep 23, 2026
2c43977
Merge branch 'feat/native-rows-and-red-test' into integrate/refactor
greenpolo Sep 26, 2026
ca0b459
Prove real Claude launcher and Mods tool loops without provider crede…
greenpolo Sep 26, 2026
05a6e4a
Standardize isolated TypeScript E2E scenarios and prove OpenAI tool r…
greenpolo Sep 26, 2026
f37dedf
Prove bounded streams and native worker replay with extensible E2E dr…
greenpolo Sep 26, 2026
cfefe20
Run E2E scenarios against a pinned Claude Code on three platforms
greenpolo Sep 26, 2026
482427a
Prove launcher lifecycle and direct-provider session continuity end t…
greenpolo Sep 26, 2026
8ccfded
Prove provider switching, worker isolation, model routing, and errors…
greenpolo Sep 26, 2026
934ee57
Expose native usage regressions and prepare isolated live credentials
greenpolo Sep 26, 2026
118905b
Bound E2E routing coverage and discover registered provider workers
greenpolo Sep 26, 2026
814768d
Assert unsupported Grok context tags fail without native dispatch
greenpolo Sep 26, 2026
eb4281d
Prove native worker lifecycle, durable replay, and compaction end to end
greenpolo Sep 26, 2026
5a751b1
Prove permission effects and interactive approvals through the E2E ha…
greenpolo Sep 26, 2026
d2416bf
Merge branch 'e2e-slice-2' into test/e2e
greenpolo Sep 26, 2026
2a76eed
Merge branch 'e2e-slice-3' into test/e2e
greenpolo Sep 26, 2026
dd0a00e
Merge branch 'e2e-slice-4' into test/e2e
greenpolo Sep 26, 2026
c85ca8b
Merge branch 'e2e-slice-5' into test/e2e
greenpolo Sep 26, 2026
d435fe3
Wait for native worker completion before SendMessage resume in E2E sc…
greenpolo Sep 26, 2026
639f8e6
Merge branch 'test/e2e' into integrate/refactor
greenpolo Sep 26, 2026
3045ada
Merge branch 'test/e2e' into integrate/refactor
greenpolo Sep 26, 2026
42da1ba
Resolve E2E worker types from Claude's advertised registrations
greenpolo Sep 26, 2026
b2a2c10
Merge branch 'test/e2e' into integrate/refactor
greenpolo Sep 26, 2026
b85abfe
Accept the native-rows display-row refusal in the forged-row E2E check
greenpolo Sep 26, 2026
8d692c5
Gate the native worker resume E2E scenarios on the refactor
greenpolo Sep 26, 2026
2997a35
Run the E2E native fakes the way Windows runs real native CLIs
greenpolo Sep 26, 2026
35ec89b
Merge branch 'test/e2e' into integrate/refactor
greenpolo Sep 26, 2026
23cfae8
Check token accounting end to end and fix live-tier E2E variants
greenpolo Sep 26, 2026
2831f1c
Merge branch 'test/e2e' into integrate/refactor
greenpolo Sep 26, 2026
2ff9c30
Check live native worker runs by completion, not scripted final text
greenpolo Sep 26, 2026
57bf23f
Merge branch 'test/e2e' into integrate/refactor
greenpolo Sep 26, 2026
8f31f7f
Check token accounting and the context gauge against live providers
greenpolo Sep 26, 2026
8b6a93c
Drop Zen models that no longer serve requests
greenpolo Sep 26, 2026
cde9be9
Merge branch 'test/e2e' into integrate/refactor
greenpolo Sep 26, 2026
2bbe786
Keep Claude's native 1M context window behind the gateway
greenpolo Sep 27, 2026
f4cc21f
Enforce plan mode in OpenAI automatic review
greenpolo Sep 27, 2026
0fe4bd4
Allow only read-only Antigravity tools in plan mode
greenpolo Sep 27, 2026
2e8143d
Keep plan mode binding across workers and mid-turn changes
greenpolo Sep 27, 2026
9f13604
Stop claiming a first-party base URL for the 1M window
greenpolo Sep 27, 2026
88cdfb9
Answer Claude's server-side auto-mode checks for non-Claude replies
greenpolo Sep 28, 2026
2bf8e5b
Defer tool definitions the way Claude Code does natively
greenpolo Sep 28, 2026
a512ec3
Prepare 0.3.0
greenpolo Sep 28, 2026
b6aa8e0
Keep empty arguments when launching cmd shims on Windows
greenpolo Sep 28, 2026
75d5d86
Make E2E deadlines and macOS workspace paths deterministic
greenpolo Sep 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,43 @@
},
"metadata": {
"description": "Choose the model providers to use inside Claude Code.",
"version": "0.2.1"
"version": "0.3.0"
},
"plugins": [
{
"name": "multi-core",
"source": "./",
"version": "0.2.1",
"version": "0.3.0",
"description": "Shared Multi gateway, setup, status and reversible Claude startup integration."
},
{
"name": "multi-openai",
"source": "./plugins/multi-openai",
"version": "0.2.1",
"version": "0.3.0",
"description": "ChatGPT models through Codex login"
},
{
"name": "multi-cursor",
"source": "./plugins/multi-cursor",
"version": "0.2.1",
"version": "0.3.0",
"description": "Official Cursor SDK coding harness"
},
{
"name": "multi-zen",
"source": "./plugins/multi-zen",
"version": "0.2.1",
"version": "0.3.0",
"description": "OpenCode Zen direct API models"
},
{
"name": "multi-antigravity",
"source": "./plugins/multi-antigravity",
"version": "0.2.1",
"version": "0.3.0",
"description": "Official Antigravity CLI harness"
},
{
"name": "multi-grok",
"source": "./plugins/multi-grok",
"version": "0.2.1",
"version": "0.3.0",
"description": "Official Grok Build CLI harness"
}
]
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.2.1",
"version": "0.3.0",
"author": {
"name": "greenpolo",
"url": "https://github.com/greenpolo"
Expand Down
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,27 @@ jobs:
name: node-reports-${{ matrix.os }}
path: report.*.json
if-no-files-found: ignore

e2e:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 20
env:
# Pinned so an engine release can't change results without a commit here.
CLAUDE_CODE_VERSION: 2.1.283
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
- run: npm ci
- run: npm install --global --no-audit --no-fund "@anthropic-ai/claude-code@$CLAUDE_CODE_VERSION"
shell: bash
# The package's native binary is always named claude.exe; point at it
# directly rather than at the npm shim, which is a .cmd file on Windows.
- run: echo "MULTI_E2E_CLAUDE=$(npm root --global)/@anthropic-ai/claude-code/bin/claude.exe" >> "$GITHUB_ENV"
shell: bash
- run: npm run test:e2e
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ report.*.json

# Local Claude agent worktrees are independent checkouts, not source inputs.
/.claude/worktrees/

# Claude Code function-hook declarations, written per build by `/plugin-types`;
# `npm run typecheck:mod` reads them. Regenerate after an update, never edit.
/.claude/types/
11 changes: 6 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ Claude Code function-hook UI and extensibility rules live in
| `plugins/multi-core/src/gateway/messages.ts`, `fetch.ts`, `tools.ts` | Shared protocol, outbound fetch, and tool aliases. |
| `plugins/multi-core/src/gateway/executable.ts`, `process-tree.ts` | Resolves executables and manages child processes. |
| `plugins/multi-core/src/gateway/atomic-write.ts`, `state-lock.ts` | Protects files and serializes native state. |
| `plugins/multi-core/src/gateway/cursor-settings.ts`, `mode-hook.ts`, `agent-definitions.ts` | Admits settings and maps prompt and worker permissions. |
| `plugins/multi-core/src/gateway/cursor-settings.ts`, `mode-hook.ts`, `agent-definitions.ts`, `worker-catalog.ts` | Admits settings, maps prompt and worker permissions, and resolves the Agent tool's `model` against each provider's worker catalog. |
| `plugins/multi-core/src/gateway/approval.ts`, `permission-hook.ts` | Approval protocol and capability checks. |
| `plugins/multi-core/src/gateway/mod-*.ts`, `tool-observer.ts` | Claude Mods control-plane routes, compaction, policy, and progress observation. |
| `plugins/multi-core/src/gateway/mod-*.ts`, `display-rows.ts`, `tool-observer.ts` | Claude Mods control-plane routes, compaction, policy, native action display rows, and tool observation. |
| `plugins/multi-core/src/gateway/harness-*.ts` | Session store, exchange registry, response builder, completion, and notices shared by Cursor, Antigravity, and Grok; CLI process runner and text prompt preparation shared by Antigravity and Grok. |
| `plugins/multi-core/src/account.ts`, `setup.ts`, `install/` | Accounts, bootstrap, plugin discovery, and installation. |
| `plugins/multi-openai/src/` | Codex authentication, models, Responses translation, instructions, and reviewer. |
Expand Down Expand Up @@ -70,9 +70,10 @@ Run `npm run check`. It checks the generated banner, Biome lint, Knip, strict
type checking, and offline tests. `npm test` runs `tsc --noEmit` and the unit
test suite. Use Node 24.12 or newer and avoid `DEP0190` warnings.

For Claude Mods hook or surface changes, also run `npm run test:mod`. It runs
`claude plugin test` with the installed Claude executable, without provider
inference. It is separate from `npm run check` and the current CI matrix.
For Claude Mods hook or surface changes, also run `npm run test:mod`. It type-checks
the hooks against `.claude/types` (write them with `/plugin-types` first; they are
gitignored) and runs `claude plugin test` with the installed Claude executable,
without provider inference. It is separate from `npm run check` and the current CI matrix.

| Command | Check | Login needed |
| --- | --- | --- |
Expand Down
55 changes: 42 additions & 13 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ usage. Provider setup and limits are documented in [docs/installation.md](docs/i
## Overview

The plugin puts external models and coding harnesses inside one Claude Code
session. The launcher registers provider models and named workers. The Node
gateway routes requests, preserves Claude passthrough, and coordinates sessions.
session. The launcher registers provider models and one Agent-tool worker type
per provider. The Node gateway routes requests, preserves Claude passthrough,
and coordinates sessions.
Claude Mods provide the in-engine control plane for model rows, worker rows,
permission state, progress, and compaction. [The local Mods reference](docs/claude-mods.md)
is required reading for changes to Claude Code UI or extensibility. Provider adapters own their model
Expand All @@ -32,9 +33,27 @@ Claude Code session (/model, workers, prompts)

Claude Code sends Anthropic Messages traffic and provider requests to the gateway.
The gateway passes Anthropic traffic through and translates direct-provider
requests. `/model` exposes provider model and effort rows. Named workers expose
explicit provider choices. Each run reports a visible lifecycle: row, elapsed
time, streamed progress, completion, failure, and cancellation.
requests. `/model` exposes provider model and effort rows. Each connected
provider's Agent-tool worker type runs that provider's picker rows; the Agent
tool's `model` parameter picks which. Each run reports a visible lifecycle: row,
elapsed time, streamed progress, completion, failure, and cancellation.

## Worker types

The Agent tool offers exactly one type per signed-in or enabled provider:
`multi-openai`, `multi-zen`, `multi-cursor`, `multi-antigravity`, and
`multi-grok`. A type's models are exactly that provider's rows in the session's
`/model` picker, so `--models`, `MULTI_MODELS`, and the provider-specific
`_EXTRA_MODELS`/`_MODELS` environment variables bound them. The Agent tool's
`model` parameter names a model as a short id (`composer-2.5`, `gpt-6-luna`) or
the full `multi/<provider>/<id>`; a Multi mod hook takes it out before Claude's
Agent schema check and resolves it against the catalog at spawn, rewriting the
spawn to the full id. An unknown id, another provider's model, a Claude alias,
or an effort-suffixed name (`gpt-6-luna-high`) refuses the spawn, naming the
provider's available models. Omitting `model` runs the provider default.
Effort is never part of a type or model name: OpenAI and Zen workers carry one
provider-wide default effort, while Cursor, Antigravity, and Grok workers apply
the session's `/effort`, validated by the provider.

## Execution contracts per provider

Expand All @@ -54,17 +73,24 @@ review stays with the originating OpenAI account. Zen never borrows Codex
review. Missing GPT review fails explicitly.

Cursor, Antigravity and Grok are harness integrations. Their SDK or CLI executes
tools, keeps native state, and applies provider authentication. Claude displays external
actions and progress; it never replays those actions as executable Claude tool
calls. Cursor supports Auto, Plan, and Bypass. Antigravity uses its native CLI
tools, keeps native state, and applies provider authentication. Each finished native
action becomes a display row in the harness's own reply: a tool_use block named after
the native tool (`mcp__multi-core__run_command`) with the native parameters and a
gateway-issued token, answered by the Multi mod with the native output, so the row
sits in the transcript of the `/model` session or worker that ran it. Display tools
are never model tools: the gateway strips them from every provider's tools and
history, the mod defers them and refuses any call without an issued token, and the
gateway answers the engine's follow-up request with the reply's remaining text
without a native run. Nothing is replayed or re-executed. Cursor supports Auto, Plan, and Bypass. Antigravity uses its native CLI
with Claude policy enforcement at the prompt boundary. Grok carries the same
policy in its own run arguments, and each announced toolset is checked against
it because an unknown removal is accepted and ignored by that CLI.

All three harnesses share their session store, in-flight exchange registry,
response builder, durable completion, and notices from
response builder, durable completion, notices, and the transcript action summary from
`plugins/multi-core/src/gateway/harness-*.ts`. Grok and Antigravity additionally
share native process execution and text prompt preparation; Cursor retains its
share native process execution, text prompt preparation, and the native action
tracker (Cursor uses it too) that turns native actions into display rows; Cursor retains its
SDK and image-aware prompt format. Each provider still owns
its own event grammar, CLI argument construction, usage accounting, and (for
Cursor) SDK agent lifecycle. The shared layer owns turn leases, lock lifetime,
Expand Down Expand Up @@ -119,6 +145,9 @@ the saved response, the harness emits a notice and continues on its native recor
it does not require a matching prompt hash or unique response anchor. Native state
is never rewound. Compaction summarizes authenticated context while preserving the
native record. Cache reuse and usage accounting remain provider-owned.
The shared response builder reports a harness turn's last model call, its live
context, in the standard usage fields and the turn's consumption in `multi_usage`
([docs/claude-mods.md](docs/claude-mods.md)); each adapter supplies both.

`HarnessSessionStore` (`gateway/harness-session.ts`) owns the loading gate,
record validation, and lock lifetime. Persisted `saved` fields are separate from
Expand Down Expand Up @@ -146,9 +175,9 @@ Handles with an in-flight billed usage query are not evicted. A detached SDK
record's `running` status is not a live ownership claim: the existing interrupted
continuation notice remains the fallback when no terminal result can be recovered.

Replay validation is provider-parameterized: Cursor's replies may carry the
display-only `tool_use` blocks a Claude Mods row produces, while Grok and
Antigravity stay text-only. `gateway/conversation.ts` normalizes Messages content
Replay validation is provider-parameterized: new replies from every harness are
text-only, and Cursor still accepts the display-only `tool_use` blocks that the
retired pseudo-MCP rows wrote into records before 0.2.2, so those records replay. `gateway/conversation.ts` normalizes Messages content
and media for Cursor and OpenAI without coupling Cursor to OpenAI request
construction; provider-specific reasoning decoding stays with OpenAI.

Expand Down
Loading
Loading