Skip to content

Add a Provider or Model ​

Version: wb-flow 1.0.7

A model name in models.json is not enough. A usable model has three parts: a stable catalog ID, a billing/rate-limit pool, and a CLI adapter that can run it headlessly. If any one is missing, the orchestrator cannot safely delegate a wave cell to it.

This guide has two paths:

Your changePathWhat changes
Add or refresh models for an already supported providerCLI catalog pathYour active models.json and roster only
Add a provider with a new or dedicated CLIManual provider pathwb-flow 1.0.7 source, tests, shipped catalog seed, and provider documentation

wb-flow model deliberately cannot invent a new CLI adapter. Discovering a credential is not permission to spend against it, and an unknown adapter might send a namespaced ID to the wrong binary. Complete Path B once for a new provider; after that, operators can use Path A for its models.

The provider contract ​

Collect this information before changing anything. Do not infer model IDs from a subscription name.

FieldExampleWhy it is required
Provider keyacmecloudStable key in models.json and the dispatch registry
Pool keyacme-team-planA billing and rate-limit boundary used to build independent fallbacks
Native CLIacmeThe executable launched by a delegated cell
Canonical model slugacmecloud/acme-coder-v2The catalog and roster identity
CLI model argumentacme-coder-v2Many vendor CLIs require the bare ID, not the catalog slug
Headless commandacme run --model acme-coder-v2 --prompt "…"The exact command wb-flow must generate
Authentication and regionvendor login/profile/base URLPrevents a valid CLI from using the wrong account or endpoint
Listing capabilityacme models list, or “not enumerable”Determines whether catalog sync can discover models automatically
Permission and stdin behaviornon-interactive flag, /dev/null needPrevents a delegated wave from blocking for approval or input

Never put API keys, cookies, or account IDs in models.json, a roster, a plan, or a generated wave script. Authenticate the vendor CLI using its normal secure login/profile mechanism.

Path A: CLI catalog path ​

Use this when the provider's dispatch adapter already ships with wb-flow 1.0.7. It is the normal way to pick up a new model release without changing package source.

1. Confirm the local CLI and account ​

Run the vendor's own non-writing, one-prompt command first. It must prove the exact model and account that the orchestrator will use:

bash
<vendor-cli> --version
<vendor-cli> <headless-model-and-prompt-flags> "Reply exactly: MODEL_OK"

Record the model's actual catalog slug and pool. A successful interactive chat is not enough: delegated wave cells are non-interactive processes.

2. Preview catalog changes ​

--sync-catalog enumerates only providers already present in the catalog. It does not make a credentialed provider active merely because a CLI reports it.

bash
wb-flow model --sync-catalog --dry-run
wb-flow model --add=<supported-provider> --dry-run

Use --add to scope the refresh to one registered provider. Review additions, retirement marks, and the reported billing pool before removing --dry-run:

bash
wb-flow model --add=<supported-provider>

For a provider whose CLI cannot list models, use its documented picker/import route instead of guessing. For example, wb-flow supports importing a reviewed picker transcript with --from-picker or --from-file; only use that with model IDs copied from the vendor CLI.

3. Prove reachability, then assign roles ​

Catalogued means “known”; it does not mean “your plan can run it.” Probes make real provider calls.

bash
wb-flow model --probe --all=<supported-provider>
wb-flow model --set worker=<provider>/<model-id>
wb-flow model --set mechanical=<provider>/<model-id>
wb-flow wave <plan.md> --wave=A --list

Use --list before dispatching work. It shows the exact roster file and generated lane, without spending a model call. Keep a Validator fallback in a different pool from the Worker that edited the files.

Path B: manual provider integration ​

Use this for a new provider, especially when it brings its own CLI. This is a source change to wb-flow 1.0.7, not an end-user catalog command.

1. Validate the vendor CLI outside wb-flow ​

Verify the command shape from a clean terminal:

bash
<vendor-cli> --version
<vendor-cli> --help
<vendor-cli> <non-interactive-flags> <model-flag> <bare-model-id> <prompt-flag> "Reply exactly: MODEL_OK"

Test both approval modes if the CLI supports a sandboxed mode. Confirm whether it reads stdin even when it receives a prompt: a CLI that does must be redirected from /dev/null in generated scripts.

2. Define the shipped catalog seed ​

Add the provider group to core/templates/models.json:

json
{
  "provider": "acmecloud",
  "pool": "acme-team-plan",
  "cli": "acme",
  "models": ["acmecloud/acme-coder-v2"]
}

The namespaced slug is wb-flow's stable identity. The adapter decides whether the vendor CLI receives that full slug or only acme-coder-v2. The template is the seed for new installs; an existing user catalog is resolved from WB_MODELS_FILE, .wb/models.json, ~/.wb/models.json, or ~/.config/wb-flow/models.json.

3. Add the dispatch adapter ​

Update core/bin/cli_registry.js, the single source of truth shared by model probing and wave dispatch:

  1. Add acmecloud: 'acme' to PROVIDER_CLI.
  2. Add an acme entry to CLI_SPEC with its executable, non-interactive argument builder, prompt form, permission behavior, and stdinNull requirement.
  3. Add acme to BARE_MODEL_CLIS if the vendor accepts only bare model IDs.
  4. Set slashCommands: false unless the CLI really expands /wbWork-style commands. For a false value, wb-flow embeds the command template in the generated prompt.

Do not rely on the fallback-to-OpenCode behavior for a dedicated CLI. It is appropriate only when OpenCode itself is the provider's supported execution lane.

3a. Implement the command syntax explicitly ​

models.json records what a model is. cli_registry.js records how to invoke it. wb-flow never guesses a vendor's flag order, approval mode, prompt form, or whether the CLI accepts a bare model ID. Copy this shape and replace every placeholder only after verifying it against the installed vendor CLI:

js
// 1. In PROVIDER_CLI: provider key from models.json → CLI_SPEC key.
const PROVIDER_CLI = {
  // existing providers …
  acmecloud: 'acme',
};

// 2. In CLI_SPEC: the exact headless invocation contract.
const CLI_SPEC = {
  // existing CLI specifications …
  acme: {
    bin: 'acme',
    slashCommands: false, // functional: false makes wb-flow inline the /wb* template
    inlineTemplate: true, // optional explanatory metadata; do not rely on it for behavior
    stdinNull: true,      // set only when the CLI would otherwise consume script stdin
    argv: function (model, prompt, opts) {
      const a = [];
      if (model) a.push('--model', model);

      // Replace with the verified flags. A sandboxed route must never retain a
      // non-sandbox permission bypass by accident.
      if (opts && opts.sandbox) {
        a.push('--sandbox', '--approval-mode=auto');
      } else {
        a.push('--approval-mode=yolo');
      }

      if (prompt != null) a.push(prompt); // positional prompt in this example
      return a;
    },
  },
};

// 3. Add the CLI here only when it accepts a bare model ID.
const BARE_MODEL_CLIS = new Set([
  'claude', 'codex', 'agy', 'gemini', 'copilot', 'grok', 'acme',
]);

With a catalog ID of acmecloud/acme-coder-v2, this adapter receives model === 'acme-coder-v2' because acme is in BARE_MODEL_CLIS. Leave it out of that set when the CLI expects the full namespaced slug instead.

The generated Worker command is then conceptually:

bash
acme --model acme-coder-v2 --approval-mode=yolo \
  "Read <wb-flow command template> and execute the procedure described there. Arguments: …" \
  < /dev/null

The health-check command and the delegated-task command are intentionally different. A probe can use --approval-mode=plan --max-tool-calls=0 because it only asks for text. A Worker must be allowed to read and edit scoped files, so it needs the provider's reviewed non-interactive execution mode instead. Do not put --max-tool-calls=0 into the production adapter.

Qwen Code adapter — shipped in wb-flow 1.0.7 ​

Qwen Code 0.24.4 exposes qwen, -m/--model, a positional prompt, --sandbox, and --approval-mode. wb-flow 1.0.7 registers qwencloud → qwen with this adapter:

js
// PROVIDER_CLI
qwencloud: 'qwen',

// CLI_SPEC
qwen: {
  bin: 'qwen',
  slashCommands: false,
  inlineTemplate: true,
  stdinNull: true,
  argv: function (model, prompt, opts) {
    const a = [];
    if (model) a.push('-m', model);
    if (opts && opts.probe) a.push('--approval-mode=plan', '--max-tool-calls=0');
    else if (opts && opts.sandbox) a.push('--sandbox', '--approval-mode=auto');
    else a.push('--approval-mode=yolo');
    if (prompt != null) a.push(prompt);
    return a;
  },
},

// BARE_MODEL_CLIS
// add 'qwen' to the Set initializer

Qwen Cloud ships with reviewed seed IDs under the alibaba-token-plan pool. Qwen has no stable non-interactive model-list command, so wb-flow model --sync-catalog preserves those IDs rather than inventing a list. Confirm the IDs your account serves with a real, no-tool probe before using one in a roster:

bash
# Required once after upgrading an existing catalog created before Qwen support.
wb-flow model --add=qwencloud

# Makes real, no-tool provider calls; only keep models your Token Plan answers with.
wb-flow model --probe --all=qwencloud

4. Teach catalog discovery what is true ​

Update core/bin/model.js and core/bin/catalog_sync.js:

  • detect the installed CLI and its authenticated state;
  • enumerate models only when the CLI has a stable, non-interactive list command;
  • otherwise mark the provider non-enumerable and require explicit reviewed IDs or a safe picker import;
  • add the pool to ranking when it is a supported subscription pool;
  • add role-pattern preferences only when their behavior is deliberate, not merely because a model name contains a familiar word.

Never invent an enumeration command. A stale curated list is safer when paired with a real probe; an invented list creates a catalog that fails only after a wave has started.

5. Document the integration ​

Add the provider's authentication prerequisites, region/profile requirements, exact verified command shapes, canonical IDs, and known limitations to core/templates/commands/model_reference_manual.md. The page you are reading explains the generic contract; that reference manual is where users find provider-specific operational commands.

6. Test the adapter before publishing ​

At minimum, extend core/test/model_routing.js to prove that:

  • acmecloud/acme-coder-v2 resolves to acme, never opencode;
  • the generated argument vector uses the expected bare or namespaced ID;
  • headless permission and stdin handling are present;
  • sandbox behavior does not silently enable a bypass flag;
  • the provider pool is preserved for fallback and cross-provider validation.

Then run the package test suite and preview the actual generated wave command:

bash
cd deployement/packages/wb-flow/next/core
npm test
wb-flow wave <plan.md> --wave=A --print

Read the generated command before a live wave. The essential check is that it launches the intended binary with the intended model ID and inline template behavior.

Example: applying the contract to Qwen Cloud ​

Qwen Cloud demonstrates the completed manual-provider path: wb-flow 1.0.7 now has the dedicated qwencloud → qwen adapter, a tested bare-model argument shape, the alibaba-token-plan pool, and a non-enumerable catalog policy. Your Token Plan still determines which seeded IDs are entitled, so probe the selected model before assigning it to a production roster.

Annex — providers registered in wb-flow 1.0.7 ​

This table reflects core/bin/cli_registry.js, which is the dispatch authority. The cli field in a catalog group is descriptive; a route is selected through PROVIDER_CLI and built by CLI_SPEC.

Provider keyAdapter / executableModel argument/wb* command expansion
anthropicclaudebare model IDyes
openaicodexbare model IDno — template is inlined
xaigrokbare model IDyes
antigravityagybare model IDno — template is inlined
googlegeminibare model IDno — template is inlined
github-copilotcopilotbare model IDno — template is inlined
openrouteropencodefull namespaced slugyes
opencode-goopencodefull namespaced slugyes
opencode-zenopencodefull namespaced slugyes
qwencloudqwenbare model IDno — template is inlined

qwencloud is non-enumerable by design: a Qwen model is not added merely because a subscription exists. The local qwen CLI must be authenticated, and the selected model must pass a real probe.

Release checklist ​

  • [ ] Vendor CLI command succeeds non-interactively with the target account and model.
  • [ ] Provider, pool, canonical slug, and CLI model argument are recorded.
  • [ ] models.json seed and provider manual are updated.
  • [ ] cli_registry.js resolves the provider to the intended binary.
  • [ ] Discovery is implemented or explicitly marked non-enumerable.
  • [ ] Routing, pool, permission, and stdin behavior have regression tests.
  • [ ] npm test passes and wb-flow wave --print shows the intended invocation.
  • [ ] A model probe succeeds before the provider enters a production roster.

← Concepts Hub · Model Fallback Chains · Model Picker Tutorial