Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
"email": "hi@okis.dev"
},
"description": "Multi-model orchestration marketplace for Claude Code.",
"version": "0.0.37",
"version": "0.0.38",
"plugins": [
{
"name": "grok",
"source": "./plugins/grok",
"displayName": "Grok Companion",
"description": "Local Grok CLI delegation: task, review, resumable history, best-of-n tournaments, background jobs, stats, and setup health checks.",
"version": "0.0.37",
"version": "0.0.38",
"author": {
"name": "Harry Yep"
},
Expand All @@ -34,7 +34,7 @@
"source": "./plugins/codex",
"displayName": "Codex Companion",
"description": "First party local Codex CLI delegation for tasks, reviews, resumable threads, and durable background jobs.",
"version": "0.0.37",
"version": "0.0.38",
"author": {
"name": "Harry Yep"
},
Expand All @@ -55,7 +55,7 @@
"source": "./plugins/fusion",
"displayName": "Fusion Orchestrator",
"description": "Multi-model orchestration: tier agents, routing rules, blind panel, ultra fleet, model config, and drift doctor.",
"version": "0.0.37",
"version": "0.0.38",
"author": {
"name": "Harry Yep"
},
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# changelog

## 0.0.38

- Fable and Opus 5 are peer orchestrators: the routing preamble drops the Opus as fallback framing (switching is lateral; posture, gates, fleet defaults, and delegation never condition on which of the two is active), the readme reframes `best[1m]` floating as lateral within the top tier, and doctor treats a deliberate Opus 5 session as healthy instead of a fallback to recover
- the stop hook's in flight advisory closes a cross process staleness window: candidate records are fresh read and filtered through the existing terminal collected predicates immediately before signing and emission (`reverifyInFlightRecords`), so an overlapping stop pass can no longer announce a task as still in flight after its notification driven terminal flip landed
- `/fusion:stats` direct arguments gain a second closed family: value free report and maintenance requests (`--json`, `--audit`, `--all`, `--prune-dead`, each at most once) pass without the raw-args transport; the settlement family, the rejection message, and the transport requirement for `--session` and all free text are unchanged, and the skill carve-out wording now matches the predicate verbatim

## 0.0.37

- settlement and telemetry become more discriminating: batched settlement validates every pair before writing, reports per pair rejection reasons, and `/fusion:stats` adds lane drift, per SKU trends, narrow wave watch, and an acceptance epoch cutoff; the worker lifecycle adds a parent context advisory, package type and brief byte capture, recalibrated trivial worker budgets, and token observations, while the inline guard gains tail allowance and softens zero dispatches
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Requested by prompts (the orchestrator follows the installed instructions; not r

## Model roles

Roles bind to alias tiers, not to specific models, so a same tier release (Sonnet 5 under `sonnet`, a future Opus) needs zero configuration, and `best[1m]` floats the orchestrator to future Fable releases or degrades it to the latest Opus when Fable is unavailable. The one deliberate exception is `fusion:trivial-worker`, pinned to the full ID `claude-haiku-4-5` for machines where ANTHROPIC_DEFAULT_HAIKU_MODEL remaps the haiku alias; bump it by hand when a newer cheap tier ships. It is a fallback for trivial work when no eligible peer lane remains, or when Claude-only tools or privacy are required, not the default for single file tasks. Peer engine defaults live in each CLI's config (`~/.grok/config.toml`, `~/.codex/config.toml`); `/fusion:config` reads and changes them interactively. Alias semantics are Claude Code behavior as observed on 2.1.x, and nothing here sets your main model for you: pick it yourself, for example `/model best`. `/fusion:doctor` audits all of this.
Roles bind to alias tiers, not to specific models, so a same tier release (Sonnet 5 under `sonnet`, a new Opus generation) needs zero configuration, and `best[1m]` floats the orchestrator to future Fable releases or to the latest Opus when Fable is unavailable; since Opus 5 the two are the same top tier, so that float is lateral rather than a degradation. The one deliberate exception is `fusion:trivial-worker`, pinned to the full ID `claude-haiku-4-5` for machines where ANTHROPIC_DEFAULT_HAIKU_MODEL remaps the haiku alias; bump it by hand when a newer cheap tier ships. It is a fallback for trivial work when no eligible peer lane remains, or when Claude-only tools or privacy are required, not the default for single file tasks. Peer engine defaults live in each CLI's config (`~/.grok/config.toml`, `~/.codex/config.toml`); `/fusion:config` reads and changes them interactively. Alias semantics are Claude Code behavior as observed on 2.1.x, and nothing here sets your main model for you: pick it yourself, for example `/model best`. `/fusion:doctor` audits all of this.

## Benchmark

Expand Down
2 changes: 1 addition & 1 deletion plugins/codex/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "codex",
"displayName": "Codex Companion",
"version": "0.0.37",
"version": "0.0.38",
"description": "First party local Codex CLI delegation for tasks, reviews, resumable threads, and durable background jobs.",
"author": {
"name": "Harry Yep"
Expand Down
2 changes: 1 addition & 1 deletion plugins/fusion/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "fusion",
"displayName": "Fusion Orchestrator",
"version": "0.0.37",
"version": "0.0.38",
"description": "Multi-model orchestration: tier agents, routing rules, blind panel, ultra fleet, model config, and drift doctor.",
"author": {
"name": "Harry Yep"
Expand Down
1 change: 1 addition & 0 deletions plugins/fusion/rules-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"35136a84eefb3d1debe84fecfa0d667ffbfd782efaff5f6bd2bd99ac2994b6dc",
"44432f9aba3bed7d5029ecc38b8cf36100261fa045eb238b3df777d038ac0c00",
"4960b1b6ffe5091429d7d78cfb38fee625325adc91c1f7821e6389c198894b56",
"50693459c23a833b0012025399bb6d666740a749d856f5466654bdc03c0fbf67",
"5c1dbef35d32e6ad194af7c514ad38786c9485dd2c25edd09946b2e8cb76c6b4",
"5e4b52c0304ee1906203d2551e9bea77a8d8c480ac41306fe85c2057b6ca4f06",
"6d2e66c19ec296ffe2e3fce9705c0b68f9656c76aad0510877b5c6344e8a0655",
Expand Down
2 changes: 1 addition & 1 deletion plugins/fusion/rules/orchestration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This policy governs the main session. If the Agent tool is not available to you, you are a delegate: ignore this file and follow your own agent instructions. Each companion plugin owns its engine runtime details; this policy owns only cross-engine orchestration and collection invariants.

The policy is model agnostic. If the session falls back from Fable to Opus, keep orchestrating under the same rules and consider /model best to restore the strongest available orchestrator. Opus holds no standing routing seat and serves only as the fallback orchestrator when Fable is unavailable.
The policy is model agnostic. Fable and Opus 5 are peer orchestrators of the same top tier: either may hold the main session as a deliberate choice, switching between them is lateral (latency, fast mode availability, and quota mix are the deciders), and no posture, gate, fleet default, delegation rule, or verification requirement in this policy conditions on which of the two is active. Orchestrating on Opus 5 is never a degraded mode and never a reason to narrow functionality. Older Opus generations sit below this tier; a session that falls below it keeps orchestrating under the same rules and considers /model best to restore a top tier orchestrator. Neither orchestrator model gains a standing worker or advisory routing seat from being the session model; those seats stay as explicitly assigned (fusion:deep-reasoner on Fable, fusion:fast-worker on Sonnet, fusion:trivial-worker on Haiku).

## Output invariant

Expand Down
7 changes: 6 additions & 1 deletion plugins/fusion/scripts/fusion-stats.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2579,6 +2579,11 @@ function isStrictDirectRecordArguments(argv) {
}
}

function isStrictDirectReportOrMaintenanceArguments(argv) {
const flags = new Set(["--json", "--audit", "--all", "--prune-dead"]);
return argv.length > 0 && argv.every((token) => flags.delete(token));
}

function writeRecordConfirmation({ kind, engine = null, jobId = null, worker = null, queued = false, asJson, stdout }) {
if (asJson) {
stdout.write(`${JSON.stringify(kind === "engine" ? { kind, engine, jobId, acceptance: worker?.acceptance } : { kind, taskId: worker.taskId, acceptance: queued ? worker.pendingVerdict?.acceptance : worker.acceptance, ...(queued ? { queued: true } : {}) })}\n`);
Expand Down Expand Up @@ -2768,7 +2773,7 @@ function runCli(argv = process.argv.slice(2)) {
consumeRawArgsTransport(argv[2]);
return;
}
if (isStrictDirectRecordArguments(argv)) {
if (isStrictDirectRecordArguments(argv) || isStrictDirectReportOrMaintenanceArguments(argv)) {
if (argv.some((token, index) => token === "--record" && parseRecordPair(argv[index + 1]).verdict === "rejected")) {
process.stderr.write("Rejected verdicts require --reason through the raw-args transport. For batch settlements, use --reason-for <id> <text> for each rejected pair.\n");
process.exitCode = 1;
Expand Down
14 changes: 12 additions & 2 deletions plugins/fusion/scripts/worker-lifecycle.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1805,6 +1805,12 @@ function inFlightAdvisorySignature(records) {
.join(",");
}

export function reverifyInFlightRecords(records, tasks, env = process.env) {
return records
.map((record) => readWorkerRecord(record.taskId, env))
.filter((record) => record && !terminalCollectedRecord(record) && !terminalTransportObserved(record, runtimeTaskForRecord(record, tasks)));
}

function claimStopAdvisory(sessionId, kind, signature, env) {
let claimed = false;
updateWorkerSessionState(sessionId, env, (current) => {
Expand Down Expand Up @@ -1926,9 +1932,13 @@ function handleStop(input, env) {
return;
}
if (inFlight.length > 0) {
const signature = inFlightAdvisorySignature(currentRecords);
const verifiedInFlight = reverifyInFlightRecords(inFlight, tasks, env);
if (verifiedInFlight.length === 0) {
return;
}
const signature = inFlightAdvisorySignature(verifiedInFlight);
if (!input.stop_hook_active && claimStopAdvisory(input.session_id, "in-flight", signature, env)) {
writeOutput(hookOutput("Stop", `Fusion task${inFlight.length === 1 ? "" : "s"} ${inFlight.map((record) => record.taskId).join(", ")} ${inFlight.length === 1 ? "is" : "are"} still in flight. Collection is armed and will be required after terminal notification.`));
writeOutput(hookOutput("Stop", `Fusion task${verifiedInFlight.length === 1 ? "" : "s"} ${verifiedInFlight.map((record) => record.taskId).join(", ")} ${verifiedInFlight.length === 1 ? "is" : "are"} still in flight. Collection is armed and will be required after terminal notification.`));
}
return;
}
Expand Down
2 changes: 1 addition & 1 deletion plugins/fusion/skills/doctor/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Checks to perform:
4. List ~/.claude/agents/ if it exists. A file whose name matches a plugin agent (deep-reasoner, fast-worker, trivial-worker) registers as a duplicate agent alongside the fusion: namespaced one and confuses auto delegation; flag it as a stale leftover to delete unless the user says it is a deliberate local override.
5. Compare the template hash of ~/.claude/rules/orchestration.md against the template hash of ${CLAUDE_PLUGIN_ROOT}/rules/orchestration.md, using the same normalization as rules-sync: replace everything between the `<!-- fusion:model-table:start -->` and `<!-- fusion:model-table:end -->` sentinel lines with the fixed normalized marker before computing SHA-256. Prefer `node --input-type=module` with `hashRulesTemplate` exported by `${CLAUDE_PLUGIN_ROOT}/scripts/lib/rules-template.mjs`; a sed or similar comparison that strips only the sentinel region is also acceptable. Missing live rules or a mismatched template hash means the static routing policy is stale; point at /fusion:setup to install or update it. A user selected live model table may differ from the scored canonical table and is healthy when the template hashes match.
6. Remind the user of the role model: the main Claude session is the only control plane and final judge. Claude workers are native specialists rather than an independent model family, Codex owns ordinary implementation and default deep external review, and Grok keeps the protected `burst`, `independence`, `live-web`, and `large-context` roles. The orchestrator, deep reasoning, mechanical, and trivial Claude tiers are roles bound to alias tiers, not to specific models, so same tier releases (for example Sonnet 5 under the sonnet alias) adopt their role with no configuration change. Only a genuinely new tier above or between the existing rungs requires a decision.
7. Note the recovery moves: if the main session fell back from Fable (safety classifier or availability), /model best restores the strongest available orchestrator. Peer engine models are owned by their own CLIs (~/.grok/config.toml, ~/.codex/config.toml); this setup never pins them.
7. Note the recovery moves: a main session on Opus 5 by deliberate choice is a healthy top tier configuration, not a fallback. If the session dropped below the top tier (safety classifier or availability), /model best restores the strongest available orchestrator. Peer engine models are owned by their own CLIs (~/.grok/config.toml, ~/.codex/config.toml); this setup never pins them.
8. Point at /codex:setup and /grok:setup for peer runtime health checks beyond config defaults; peer config defaults themselves are covered in the next step.
9. Peer engine defaults: extract the model related keys from ~/.grok/config.toml and the model and model_reasoning_effort keys from ~/.codex/config.toml (never read or print the full files; they sit next to credentials; use a scoped rg query rather than Read on those two files). Report each peer's configured default and flag grok drift when the grok CLI default is absent from the capability table or when that table's recorded lane or scores disagree with the default shown by the CLI. Run `node "${CLAUDE_PLUGIN_ROOT}/scripts/fusion-config.mjs" audit` and report its Codex listing section as one checklist item. It reads only ~/.codex/models_cache.json (or FUSION_CODEX_MODELS_CACHE) and never refreshes it or invokes the Codex binary. Flag the configured-but-absent IDs and unconfigured gpt-* newcomers it reports, including the listing mtime. Treat `listing unavailable` as a warning without aborting the doctor run. /fusion:config is the write path for changing these scores; this audit never changes model-routing.json. When the capability table has no scored models at all, recommend /fusion:config propose so routing stops relying on the qualitative lane descriptions alone.
10. Audit the installed Codex surface against the foreground invariant. Glob `~/.claude/plugins/cache/claude-code-fusion/codex/*/commands/` and `~/.claude/plugins/cache/claude-code-fusion/codex/*/agents/`, then inspect the task, rescue, review, adversarial-review, and codex-rescue instructions. Task and review calls must stay foreground regardless of complexity, expected duration, review size, or model unless the incoming user request explicitly supplied `--background`; the rescue agent's companion Bash call must use the 10 minute tool timeout. A package that cannot fit the cap must be split or routed elsewhere. Fusion orchestration gives every detached job it creates one same turn collection attempt capped at 540000ms; a timeout must remain explicitly uncollected with the job id and result command. Direct Codex slash command instructions inspect through status and collect through result; Fusion's monitor is notification only. Confirm that task and rescue expose opt in `--web`, require `--write --network` for sandbox network access, and leave both settings disabled when absent. Flag any instruction that can detach implicitly or accepts a foreground receipt as a result.
Expand Down
Loading
Loading