Skip to content
Back to skills

Batuta Routing

ASecurity

Default cost/complexity routing table for the batuta conductor. Read at bootstrap as a starting point, validated against the live provider catalog, then stored as the per-workspace loop configuration; the stored workspace override is authoritative afterwards.

  • 2,785 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 3, 2026
ai-agentsrust

Works with

  • cli

Security analysis

A100/100

Scanned September 3, 2026

npx -y skills add compozy/compozy --skill batuta-routing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Batuta Routing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Batuta Routing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/compozy-batuta-routing/badge)](https://www.skillsdirectory.com/skills/compozy-batuta-routing)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: batuta-routing
description: Default cost/complexity routing table for the batuta conductor. Read at bootstrap as a starting point, validated against the live provider catalog, then stored as the per-workspace loop configuration; the stored workspace override is authoritative afterwards.
---

# Batuta Routing Table

Batuta's core opinion: route every task to the cheapest executor that can
handle it. Lanes use the `complexity` vocabulary that `cy-create-tasks`
writes into task frontmatter (`low`, `medium`, `high`, `critical`) — the
same vocabulary `runtime_rules[].match.complexity` matches on.

## Lane semantics (the durable opinion)

| Lane       | Intent                                | Selection rule                                             |
| ---------- | ------------------------------------- | ---------------------------------------------------------- |
| `low`      | Contained change, well-trodden paths  | Cheapest coding-capable model in the catalog               |
| `medium`   | New interfaces, moderate coordination | Mid-tier coding model; raise reasoning before raising cost |
| `high`     | New subsystem, heavy reasoning        | Strong coding model, premium tier acceptable               |
| `critical` | Cross-cutting, high regression risk   | The operator's most trusted frontier model                 |

## How batuta derives the concrete table (never copy an example)

1. `compozy__provider_models_list` (with costs) is the ONLY source of
   concrete provider/model IDs — it reflects the CLIs actually installed
   and the models actually discovered on this machine. A provider absent
   from the catalog is not installed; never route to it.
2. Map each lane's selection rule onto the catalog using the cost fields
   (`input_per_million` / `output_per_million`) as evidence.
3. Model enablement is account-side and invisible to the daemon — present
   the derived table (with costs) to the operator for confirmation before
   storing; ask what their accounts enable when in doubt.

### Example only — derived on one machine on 2026-08-11, DO NOT reuse

On that machine the derivation produced: `low → codex/gpt-5.6-luna`,
`medium → codex/gpt-5.6-terra@high`, `high → codex/gpt-5.6-sol`,
`critical → claude/claude-opus-4-8`. Your catalog will differ; derive, do
not copy.

## Canonical rule shape

This is the exact JSON SHAPE batuta writes with `compozy__loop_configure`
(stored per-workspace override for `implement-tasks`) after deriving the
values from the catalog — the model/provider strings below are the same
dated example as above and MUST be replaced by the derived ones. The stored
override is what `run-loop` children resolve at execution — batuta never
sends per-run rules on dispatch, because per-run rules freeze into the run
and are not inherited by `run-loop` children anyway. Rule matching
precedence inside the stored layer: `id > type > complexity`.

```json runtime_rules
[
  { "match": { "complexity": "low" }, "runtime": { "provider": "codex", "model": "gpt-5.6-luna" } },
  {
    "match": { "complexity": "medium" },
    "runtime": { "provider": "codex", "model": "gpt-5.6-terra", "reasoning": "high" }
  },
  { "match": { "complexity": "high" }, "runtime": { "provider": "codex", "model": "gpt-5.6-sol" } },
  {
    "match": { "complexity": "critical" },
    "runtime": { "provider": "claude", "model": "claude-opus-4-8" }
  }
]
```

## Provider quirks

- Some providers multiplex upstreams and require the model field to carry a
  prefix — e.g. `opencode` only binds `opencode/kimi-k2.5`, never bare
  `kimi-k2.5`. The catalog's exact `model_id` is authoritative; copy it
  verbatim into the rule.
- A model can exist in the catalog and still be disabled for the operator's
  account at the provider (invisible to the daemon). When a lane fails its
  bind with zero tokens, ask the operator what their account enables.

## Escalation and reclassification

- Repeated failure in a lane: write a surgical `id` rule one lane up into
  the STORED override (`compozy__loop_configure` on `implement-tasks`, e.g.
  `{"match":{"id":"task_NN"},"runtime":{...}}` prepended to the rules), then
  re-dispatch `batuta-deliver`. `id` beats `complexity`; remove the rule
  after the task lands.
- Operator reclassification in conversation ("use luna for this one")
  becomes the same stored `id` rule before the next dispatch.
- The daemon persists `resolved_runtime` with per-field provenance on every
  generation — routing decisions are auditable via `compozy__loop_status`,
  never narrated.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…