Tutorial: Dynamic Model Discovery, Probing & Role Assignment β
This field manual walks you through using wb-flow model to discover credentialed AI models, verify reachability and credit balances via live probing (--probe), and configure 3-tier fallback chains across execution roles (Planner, Validator, Worker, Mechanical).
βοΈ Model Orchestration Pipeline Architecture β
wb-flow model uses a multi-stage flow to discover, validate, and persist your AI execution contract:
π 1. Executing the Prober & Interactive Picker β
To probe your catalog and launch the interactive picker, combine the three universal flags:
wb-flow model --pick --probe --all| Flag | Role / Purpose |
|---|---|
--pick (-i) | Opens the interactive terminal user interface. |
--probe | Dispatches real inference calls to test provider API reachability and balance. |
--all (-a) | Pre-probes the entire curated catalog in models.json. Reachable models are grouped by role; unreachable ones are hidden. |
--all=raw | Streams every result as probed, including β failures β the pre-1.0.2 output. |
--all=<provider> | Narrows the probe to one provider (anthropic, openai, antigravity, opencode, β¦) β saves time and credits. |
--all=<role> | Narrows the probe to one role (planner, validator, worker, mechanical). |
All
--allforms work with or without--pick.wb-flow model --probe --all=anthropicin a script behaves exactly like the interactive path: same catalog-authoritative routing (anthropic/*probes via theclaudeCLI,openai/*viacodexβ not opencode) and the same filtering. Only--all=rawstreams; every other form groups by role and hides unreachable models.
π°οΈ 2. Reading Live Probe Results β
When probing starts, wb-flow reads API credentials from your system environment and local .env files, making live HTTP test requests to each vendor endpoint:
π Using custom models catalog: /home/wissemb11/Allprojects/wb-labs/.wb/models.json
π°οΈ Pre-probing all catalog model(s) to verify reachability & balanceβ¦
β anthropic/claude-opus-5 β π§ Lead Architect & Planner β (Insufficient balance)
β openai/gpt-5.6-sol β π§ Lead Architect & Planner β (Insufficient balance)
β
openrouter/qwen/qwen-2.5-coder-32b-instruct β π» Great Coder Worker
β
opencode-go/deepseek-v4-pro β π§ Big Planner & Deep Thinker
β
gemini-3.6-flash-high β β‘ Fast Mechanical Worker
β Probed catalog: 4 of 54 models verified reachable with sufficient balance.Probe Status Key β
- β Reachable: The API key is valid and the account has active credits.
- β Insufficient balance: API key is authenticated, but the provider billing account lacks credits/balance to run inference.
- β Model not found: Model slug is deprecated or unsupported by the target provider CLI.
π³ 3. Step 0: Active Provider Subscription Selection β
Once probing finishes, you enter Step 0, where you select your active subscriptions:
Step 0 β Select your active provider subscriptions
(Use β/β to move, Space to toggle rank, 'a' to select/deselect all, Enter to confirm)
β― [1] β π³ π anthropic [claude-pro]
[2] β π³ π openai [chatgpt]
β― π³ π openrouter [openrouter]
[3] β π³ π opencode-go [opencode-go]
[4] β π³ π antigravity [google-one]
β― π³ π github-copilot [github-copilot]
chain: anthropic || openai || opencode-go || antigravity
β Enabled subscriptions: anthropic, openai, opencode-go, antigravityControls: β
Up / Down Arrows: Navigate provider subscriptions.Space: Toggle enable/disable subscription.Enter: Confirm enabled providers and advance to Role Selection.
π² 4. The Model Tree Picker & Role Qualification Badges β
In Step 1, you configure the 3-tier fallback chain for each execution role:
π Mechanical β select model chain in priority order
(Use β/β to move, Space to toggle rank, 'a' to select/deselect all, Enter to confirm)
β― [4] β π anthropic [claude-pro]
β― βββ β π anthropic/claude-opus-5 β π§ Lead Architect & Planner (Insufficient balance)
β― βββ β π anthropic/claude-haiku-4-5-20251001 β β‘ Fast Mechanical Worker (Insufficient balance)
[3] β π openai [chatgpt]
β― βββ β π openai/gpt-5.6-sol β π§ Lead Architect & Planner (Insufficient balance)
β― βββ β π openai/gpt-5.5 β π» Great Coder Worker (Insufficient balance)
[1] β π opencode-go [opencode-go]
β― βββ β
π opencode-go/deepseek-v4-pro β π§ Big Planner & Deep Thinker
β― βββ β π opencode-go/kimi-k3 β π¨ Heavy Worker (Insufficient balance)
[2] β π antigravity [google-one]
β― βββ β
π gemini-3.6-flash-high β β‘ Fast Mechanical Worker
β― βββ β
π claude-opus-4-6-thinking β π§ Big Planner & Deep Thinker
chain: opencode-go (auto) || antigravity (auto) || openai (auto) || anthropic (auto)Model Role Qualification Badges β
wb-flow automatically analyzes each model's benchmark capability and tags it with a role badge:
- π§ Lead Architect & Planner: Complex reasoning & architecture (
claude-opus-5,gemini-3.1-pro,gpt-5.6-sol). - π» Great Coder Worker: High-speed implementation & coding (
claude-sonnet-5,qwen-2.5-coder-32b,gpt-5.5). - β‘ Fast Mechanical Worker: Low-latency lightweight execution (
claude-haiku-4.5,gemini-3.6-flash-high). - π¨ Heavy Worker: Massively parallel long-context processing (
deepseek-v4-pro,kimi-k3). - π‘ General Worker: General fallback routing pools (
github-copilot/auto).
π 5. How Fallback Chains (||) Work at Runtime β
When wb-flow wave dispatches background tasks, it wraps commands in .wb/bin/wbRun. If a primary provider encounters a rate limit or API outage, execution seamlessly fails over to the secondary and tertiary models in the chain:
Shell Chain Example: β
.wb/bin/wbRun agy --model claude-opus-5 -p "<prompt>" || \
.wb/bin/wbRun agy --model gemini-3.6-flash-high -p "<prompt>" || \
.wb/bin/wbRun opencode run -m opencode-go/deepseek-v4-pro "<prompt>"π‘ Best Practice: Always select models from different billing providers (e.g. Anthropic + Google + OpenCode) for your fallback chain. Three models under a single subscription represent a single point of failure!
What --probe --all pre-selects for you β
When a probe has run, the models it proved reachable become the pre-checked default chain for each role in Step 1. Detection alone only proves a credential exists; the probe proves the model answered, so its result outranks the detected roster.
Two rules shape the defaults:
- One tier per model.
gemini-3.6-flash-high,-mediumand-loware one model at three service tiers, so only-highis pre-checked β a chain of three tiers of the same model is one point of failure wearing three hats. Different releases are kept:gemini-3.6-flash-highandgemini-3.5-flash-highare separate models and both remain eligible. The other tiers stay visible in the tree, just unchecked, so you can still select them deliberately. - More than one billing pool. Each link is drawn from a different subscription where one is available, which is the entire point of a fallback chain: a rate-limit window or a lapsed card takes out one pool, not the ladder.
Never pre-checked: anything the probe marked β unreachable, anything marked β οΈ substituted (it answered as a different model β putting it in a chain guarantees a dispatch that silently runs something else), and anything outside the subscriptions you enabled in Step 0.
You are always free to override β Space toggles rank, and the order you check is the order the chain dispatches.
WARNING
wb-flow model --show and wb-flow wave can report different rosters. For any question about what a wave will dispatch, trust wb-flow wave <plan.md> --wave=<L> --list β not model --show.
They resolve the roster file differently:
| Searches | Picks | |
|---|---|---|
model --show | the current directory only (.wb/commands/ β commands/ β ~/.wb-flow/ β shipped seed) | the first file that exists |
wave | the package root, the repo root and ~/.wb-flow/ | the most recently written file |
So running model --show from inside a sub-package that carries its own older .wb/commands/model_recommendations.md reports that stale file, while the wave dispatches from the fresher roster wb-flow model --pick wrote at the repo root. Observed 2026-08-14 β the two named completely different planner chains.
wave --list prints π Roster in effect: with the resolved file path and the full chain per role, precisely so this is visible rather than silent. It is read-only and dispatches nothing.
wb-flow wave <plan.md> --wave=A --list # authoritative for wave dispatch
wb-flow model --show # the roster in THIS directory; may differThe divergence is known and not yet unified: model --show shares its resolver with the write path used by --pick, so changing it would move where your roster is saved. Until that is settled deliberately, the two commands answer two different questions β "what is configured here" versus "what will this wave actually run".
ποΈ The three model files β and editing them by hand β
wb-flow keeps model configuration in three files. Two are yours to edit; the third is generated.
| File | What it is | Ships? | Hand-editable |
|---|---|---|---|
models.json | The catalog β which models exist and which provider/pool serves each | β
a skeleton ships at templates/models.json β providers only, no models | generated by --sync-catalog, hand-editable |
selected.json | Your picks β the ordered roster per role, written by --pick | β generated, never shipped | β yes |
commands/model_recommendations.md | The dispatch roster β what --wave actually reads | seed only | β yes |
models.json β the catalog β
It ships empty on purpose. The skeleton names which providers exist and which CLI reaches each; the model lists are filled from your machine. A catalog copied from someone else's install is worse than none: an unreachable model does not fail at install, it fails much later as a wave cell dying at Gate 1 with
Model not found.
Filling it β --sync-catalog and --add β
wb-flow model --sync-catalog # refresh every provider already in the catalog
wb-flow model --sync-catalog --dry-run # see the diff, write nothing
wb-flow model --add=zen,codex,grok # fill specific providers (aliases accepted)
wb-flow model --remove=openrouter # drop oneA real run prints what changed:
π Catalog sync β /home/you/.wb/models.json
| Verdict | Count |
|---|---|
| add | 50 |
| keep | 18 |
| retire | 15 |
| refused | 5 |
| reported | 6 |
**retire:** anthropic/claude-sonnet-4-6, openai/gpt-5.3-codex, gemini-3.6-flash-medium, β¦
**refused:** anthropic/claude-sonnet-5 (named by the live roster β pass --force)
**reported:** deepseek, google, groq, llama, nvidia, ollama
βΉοΈ Credentialed but not in your catalog β add explicitly if you want them:
wb-flow model --add=nvidia
β οΈ openai: codex models is interactive-only β use --add codex --from-pickerFour things that table is telling you:
retiremarks, it does not delete. A model missing from one enumeration is more often a CLI hiccup than a real removal, so the entry stays with aretireddate.--prunedeletes for real.refusedis a guard. A slug your live roster still dispatches to is never removed without--forceβ deleting one breaks routing at the next wave, hours after the sync that caused it.reportedis not an error. Holding a credential is not the same as wanting work sent there. Those providers are named, never auto-added;--add=<name>is the consent.--addis per-provider transactional.--add=zen,codexfills Zen, reports that codex cannot enumerate itself, and exits 0. One provider failing does not abort the others;--strictchanges that.
Codex β the provider that cannot enumerate itself β
codex models exists but is interactive-only, so paste its own picker instead:
codex models # copy the list it prints
wb-flow model --add codex --from-picker # paste on stdin, then Ctrl-D
# or: wb-flow model --add codex --from-file=picker.txtEach model is stamped verified: true and checkedAt: <date>, and detect() prefers that over the built-in seed from then on. --add codex --probe is the alternative and costs real API calls, so it never runs under a plain --sync-catalog.
The shipped default is copied to ~/.wb/models.json on wb-flow init (only if absent, so your edits are never overwritten). Resolution order, first hit wins:
$WB_MODELS_FILE β ./.wb/models.json β ~/.wb/models.json β ~/.config/wb-flow/models.jsonAdd a provider or model by editing it directly:
{
"providers": [
{
"provider": "anthropic", // β decides the CLI: anthropic β claude
"pool": "claude-pro", // β billing pool, shown in the picker
"models": ["anthropic/claude-opus-5", "Claude (auto)"]
}
]
}The provider field is what routes the model, not its name. claude-opus-4-6-thinking is Anthropic-branded but listed under antigravity, so it dispatches through agy and bills against google-one. Put a model under the wrong provider and it will be probed β and dispatched β through the wrong CLI. A provider not in the routing table falls back to opencode.
selected.json β your roster β
Written by wb-flow model --pick, next to the roster it generates. Order is priority order:
{
"updatedAt": "2026-08-13T15:39:40.161Z",
"roster": {
"planner": ["Codex (auto)", "gemini-3.1-pro-high", "gemini-3.6-flash-high"],
"validator": ["Codex (auto)", "gemini-3.1-pro-high"],
"worker": ["Codex (auto)", "gemini-3.1-pro-high"],
"mechanical": ["Antigravity (auto)"]
}
}Edit it to reorder or swap models without re-running the picker. selected.json is a record of your choice; model_recommendations.md is what the dispatcher reads β so if you hand-edit one, edit the other to match, or re-run wb-flow model --pick to regenerate both.
Which roster --wave uses β
Every role dispatches its chain left to right with bash ||, so model1 || model2 || model3 means try model1; if it fails to run, try model2. Each link routes through its own CLI, so one chain routinely spans several:
.wb/bin/wbRun codex exec -m gpt-5.6-terra β¦ \
|| .wb/bin/wbRun agy --model gemini-3.1-pro-high β¦ \
|| .wb/bin/wbRun opencode run -m opencode-go/deepseek-v4-pro β¦Precedence, highest first:
-M/--modelon the invocation β delegates that one run- A plan's own
> **Active Model Roster for this Plan:**header - The most recently written
model_recommendations.mdacross the package root, repo root and~/.wb-flow/ - Built-in defaults
Point 3 is freshness, not position β deliberately. --pick writes into the current directory's.wb/, so a scope carrying an older roster of its own used to shadow the picks you had just made, and --wave would dispatch to models you had not chosen. Within a single root the order is still fixed: .wb/commands/ (your install) outranks templates/commands/ (the neutral shipped seed).
Verify what a plan will actually dispatch before committing to a wave:
wb-flow wave <plan.md> --wave=A --list