feat: Pi-Extension für Crew-Routing und Quota-Balance - #1
Merged
Conversation
Installierbares pi-package mit crew_route/crew_balance/crew_apply_dispatch, datengetriebenem Knowledge-Pack (Claude/Codex/Cursor/Grok), quota-axi-Balance und Dry-Run-Writes nach FM_HOME/config/crew-dispatch.json.
Ohne Checks hing der no-mistakes-CI-Schritt endlos; PR braucht mindestens einen grünen Workflow.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Build the firstmate-crew-knowledge MVP: installable Pi coding-agent extension (npm package, keyword pi-package) integrating with Firstmate for model/harness routing and balanced multi-provider quota across Cursor, Grok (xAI), Claude, ChatGPT/Codex. Complements fm-spawn --harness/--model/--effort, config/crew-dispatch.json, quota-array-dispatch, quota-axi --json; does not fork fleet control plane. Goals: (1) classify tasks (trivial_fix, standard_ship, hard_multi_file, research_web_live, scout_audit) and recommend {harness,model,effort}; (2) live quota-axi balance preferring headroom/runway, avoid exhausted when alternatives exist, never invent credentials; (3) tools crew_route/crew_balance/crew_apply_dispatch, emit Firstmate-schema crew-dispatch.json, spawn flags + rationale, FM_HOME writes dry-run default only under config; (4) data-driven knowledge pack; (5) optional mid-session assist that lists/searches authenticated Pi session models and recommends primary switch target without pi-model-switch or crew pane hijack. Tech: pi.extensions index.ts, TypeBox, quota-axi via child_process, degraded offline heuristic, MIT, German docs + short English README, fixture unit tests. Out of scope: Firstmate core bin/AGENTS changes, auto-spawn, billing automation, perfect fairness under missing quota. Also add GitHub Actions CI running npm test so PR checks can go green (repo previously had zero workflows and CI monitor hung).
What Changed
pi-package) mit den Toolscrew_route,crew_balance,crew_apply_dispatchundcrew_suggest_primarysowie dem Slash-Command/crew-route: klassifiziert Tasks, empfiehlt--harness/--model/--effortund schlägt optional ein Primary-Modell vor, ohne zu spawnen oder Modelle zu wechseln.knowledge/plus Live-Balance überquota-axi --json(Headroom/Runway, erschöpfte Provider meiden); fehlt quota-axi, gilt labeled Degraded mit Offline-Heuristik.crew_apply_dispatcherzeugt Firstmate-crew-dispatch.json(Default dry-run, Writes nur unter$FM_HOME/config).npm testaus; Fixture-Unit-Tests decken Scorer, Quota, Dispatch, FM-Home und Primary-Suggest ab.Risk Assessment
Testing
Ran the package’s focused Node test suite, then exercised the real Pi extension tools and public routing/balance/dispatch APIs end-to-end: all five task classes produced
--harness/--model/--effortflags, exhausted Claude lost to Codex, livequota-axi --jsonwas consumed without inventing credentials, default apply-dispatch stayed dry-run while an explicit write landed only under FM_HOME/config, and the CI workflow model runs npm test on Node 22. No screenshot or rendered HTML was captured because this change has no browser/Electron/CSS surface; the user-facing product is Pi tool text and JSON, saved as transcripts.Evidence: All five task classes → spawn flags (balanced fixture)
trivial_fix → --harness codex --model gpt-5.5 --effort low standard_ship → --harness codex --model gpt-5.5 --effort medium hard_multi_file → --harness codex --model gpt-5.5 --effort high research_web_live → --harness grok --model latest --effort medium scout_audit → --harness codex --model gpt-5.5 --effort mediumEvidence: crew_route avoids exhausted Claude (hard_multi_file)
Evidence: crew_balance ranks exhausted Claude last
Evidence: Live quota-axi crew_balance (no invented credentials)
Evidence: Live quota-axi --json snapshot
Evidence: Generated Firstmate-schema crew-dispatch.json
Evidence: Explicit FM_HOME/config write of crew-dispatch.json
Evidence: crew_apply_dispatch dry-run transcript
Evidence: crew_suggest_primary advisory (no switch)
Evidence: Real Pi tool crew_route output
Evidence: Real Pi tool crew_apply_dispatch dry-run
Evidence: Mock Pi extension registration and tool calls
Source: Mock Pi extension registration and tool calls (local file:
/tmp/no-mistakes-evidence/01KZWZX6EYEXG8C1AFMG5TRSP2/mock-pi-extension.json)Evidence: CI workflow semantic model
Evidence: Degraded offline heuristic route
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 4 issues found → auto-fixed (2) ✅
src/quota.ts:101- summarizeProvider skips stale effectiveAvailability/runway (the intended invariant: do not route from stale raw percentages) but still sets exhausted=true from raw windows when every numeric percentRemaining is <= 0. Reachable path: quota-axi returns stale=true, semantics unused, windows all at 0 → exhausted=true → rankCandidates applies penalty=exhausted_while_alternatives_exist (-80) and steers crew_route/crew_balance/crew_suggest_primary away from a recovered provider. Gate the window-exhaustion fallback on !stale at the same boundary as the effectiveRemaining skip (line 72).src/dispatch.ts:172- applyDispatch(merge=true) catch-all treats every failure like a missing file and continues with generated JSON. If config/crew-dispatch.json exists but is invalid JSON, or parses without a rules array (mergeDispatch does existing.rules.map), dryRun=false then overwrites the captain file. Distinguish ENOENT from parse/shape errors; if the file exists but cannot be merged, refuse the write and surface the error.src/quota.ts:45- Missing-binary detection uses /ENOENT|not found|spawn/i on the error message. Node timeout/access failures are spawnSync … ETIMEDOUT/EACCES, so a 20s hang or permission error is reported as “quota-axi not found on PATH”. Classify missing via error.code === "ENOENT" (or equivalent) and keep other failures as quota-axi failed.src/quota.ts:23- readLiveQuota uses execFileSync with a 20s timeout. crew_route, crew_balance, and crew_suggest_primary therefore block the Pi event loop for the whole quota-axi run and ignore the tool AbortSignal (execute either omits signal or binds it as _signal). Switch to async execFile/spawn, honor signal, and keep the existing degraded-on-failure behavior.🔧 Fix: Stale-Quota, Merge-Schutz und AbortSignal korrigiert
1 warning still open:
src/quota.ts:127- readLiveQuota treats AbortSignal cancellation as a successful degraded quota-axi failure (early return at line 127 and catch at line 154). Reachable path: Pi aborts crew_route/crew_balance/crew_suggest_primary → exec is skipped or rejects with ABORT_ERR → degraded result → execute still runs routeTask/balance/suggestPrimary and returns a full offline recommendation. Abort is not a quota-axi outage; rethrow ABORT_ERR/AbortError (and throw on already-aborted at entry) so Pi records cancellation instead of feeding an offline answer after the user cancelled.🔧 Fix: Quota-Abbruch als Cancellation statt Degraded behandeln
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
npm test(node built-in runner,tests/*.test.ts)quota-axi --jsonlive snapshotnode --experimental-strip-types /tmp/no-mistakes-evidence/01KZWZX6EYEXG8C1AFMG5TRSP2/e2e-tools.ts— classify/route/balance/dispatch/suggest against fixtures plus live quotanode --experimental-strip-types /tmp/no-mistakes-evidence/01KZWZX6EYEXG8C1AFMG5TRSP2/mock-pi-extension.ts— loadindex.ts, callcrew_route/crew_balance/crew_apply_dispatch/crew_suggest_primary, slash/crew-routePython semantic parse of.github/workflows/ci.yml(push/PR, setup-node 22,npm test)Python semantic parse ofpackage.json(pi-packagekeyword,pi.extensions, MIT)validateDispatchagainst generatedcrew-dispatch.jsonand Firstmatedocs/examples/crew-dispatch.jsonCI-likenpm install --no-fund --no-audit typebox(peer resolution) thennpm test; worktree cleaned afterward✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.