feat: kyora council — summon other model families over MCP - #8
Merged
Conversation
MCP server exposing council_convene (sync + async), council_ask, council_task (read or write), council_result, and council_status, backed by the review engine table so every member runs as its vendor's own CLI on the user's subscription. Seating is quota-aware: highest remaining quota first, never an engine that is cooling down or spent. Adds an optional PostToolUse hook that watches the agent with a cheap model and nudges it to consult the council at high-stakes moments — keyword pre-filter, rate-limited classification and nudges, silent on every failure path so it can never block work. Engines gain write-capable invocations for delegated tasks; the review package now exports its engine, usage, and extract modules. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CQy3ZJ5MyUxo4qjZwA93Na
Owner
Author
|
Added the plain subagent shape plus model/effort control:
Two bugs this surfaced, both fixed:
Verified live: codex chat with |
eliahilse
added a commit
that referenced
this pull request
Jul 31, 2026
Follow-up to #8 — these commits were pushed to `feat/council` after it squash-merged, so main has the council without them. ## Plain subagents, not just councils - **`agent_spawn`** — delegate to another model family *without naming one*: the least-spent capable family is chosen automatically (`prefer` is a hint, ignored when that family has no quota). Read-only by default, `write: true` for edits, `background: true` for a job id. This is the subagent shape — hand it work, get a worker from another lineage on a separate subscription. - **`agent_fanout`** — several *different* tasks in parallel, one per family, so independent workstreams spread across subscriptions instead of draining one. Assignment is pure and unit-tested: pinned-first, one family each, reuse only once families run out, and a task pinned to an unavailable family is reported rather than silently rerouted. The split is now clean: `council_*` gathers opinions on one question, `agent_*` does work. ## Model and effort control - **`council_models`** lists which families are summonable and the models/efforts each accepts. - **`model` and `effort`** on every delegation tool, applied per engine as real flags (codex `-m` + `-c model_reasoning_effort`, grok `-m` + `--reasoning-effort`, claude `--model`) or the model env var for endpoint-routed families. A caller-supplied effort replaces the engine's built-in flag rather than duplicating it. ## Two bugs this surfaced 1. **Council asks were broken on codex.** They inherited the review path's `--output-schema` and passed it an empty schema, so every codex consultation 400'd — present in the merged #8. Added a **chat mode** so free-form answers use unconstrained invocations. 2. **The codex model list was invented.** My first pass shipped plausible-looking ids the account rejected outright. It now reads the model from the user's own `~/.codex/config.toml` (here `gpt-5.6-sol`), and other families list only ids actually run in testing. Models pass straight through to the vendor CLI, so newer ids work before this package knows them — the list is a hint, not a gate. ## Verification - codex chat at `effort: low` answers correctly in 10s (was a hard 400 before the fix) - glm honors `model: glm-5.2` through the env route - all 9 tools register over stdio; 11 council tests + 34 review tests green, types clean 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01CQy3ZJ5MyUxo4qjZwA93Na Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.
Your agent is one lineage with one set of blind spots. This gives it a way to ask the others — mid-work, on the subscriptions you already pay for.
The MCP server
council_convenecouncil_convene_asynccouncil_resultwhile you keep workingcouncil_askcouncil_taskwrite: truepermits file editscouncil_resultcouncil_statusBacked by the same engine table as
kyora-review, so every member is its vendor's own CLI under your own login. Seating is quota-aware — highest remaining quota first, never an engine that's cooling down or spent, andsizecaps a council so one question doesn't drain every subscription. The prompts push members to disagree rather than defer, and the summary tells the caller to treat disagreement as the signal rather than averaging votes.Engines gained write-capable invocations for delegation (codex
workspace-write, claude/kimi/glm/qwen with edit tools restored but CI suites and destructive git still denied). The review package now exports./engines,./usage,./extract,./types.The high-stakes watcher
Optional
PostToolUsehook: a cheap model reads the transcript tail and the pending action, and when it judges the moment genuinely consequential — schema migration, auth change, force push, irreversible op — it injects a note nudging the agent to consult the council before committing.Built to be cheap and quiet, since a noisy or expensive watcher is one you'd turn off: a keyword/size pre-filter runs in-process so most tool calls never reach a model, classification is rate-limited (2m default), nudges harder (15m default), and every failure path exits silently so it can never block or break the agent. Model is any OpenAI-compatible endpoint — defaults to
glm-4.5-airorqwen3.6-plusdepending on which key is present.Verification
Follow-ups (not in this PR)
🤖 Generated with Claude Code
https://claude.ai/code/session_01CQy3ZJ5MyUxo4qjZwA93Na