Features: the central models allow-list

Dai Ha
2026-09-10 09:11:04 +07:00
parent 5e0ddbc05a
commit 6d8a2d2cb4
+50
@@ -4852,3 +4852,53 @@ read them before designing one.
worker exhaustion starts quarantining the lead's seat too. Arm them together, or not at all.
fleetd #395.
## A central allow-list of the models the fleet may use
**What.** A top-level `models:` block names every model id the fleet is allowed to run. Once it is
non-empty, a `profiles:` entry naming a model that is not on the list **refuses to start**, and
refuses a reload too.
```yaml
models:
allow:
- model: claude-sonnet-5
- model: openai/gpt-5.6-terra
- model: gx/deepseek-v4-flash
```
`model:` is one flat, opaque string namespace. A bare Claude id and a provider-prefixed opencode id
both fit unchanged, because the check is exact string equality — it never parses a provider prefix
and never branches on `kind:`.
**The knob.** `models.allow`. Absent or empty keeps the old behaviour, where no model was ever
checked, so this ships inert until an operator writes the block.
**Why it exists.** Before this there was no single place that said which models the fleet may use.
Each profile named one, and a typo or a withdrawn model id reached the backend adapter as a
free-form string. On an opencode profile that has a specific bad outcome, already recorded here:
a withdrawn model name makes opencode fall back to a **paid** model silently. An allow-list turns
that class of mistake into a refusal at load, which is the cheapest place to find it.
**Why it is operator-owned and not checked against a vendor catalogue.** For an opencode profile
fleetd *synthesizes* the provider from the `provider/model` selector plus `baseUrl`
(`OpenCodeLauncher:562-583`). So a perfectly valid fleetd model id can appear in no published
catalogue — `gx/deepseek-v4-flash` on this fleet is exactly that, absent from models.dev and
correct. Any attempt to validate the list against a vendor catalogue would reject working
configurations. The list is the source of truth; nothing else can be.
**Gotchas.**
- **Adding a profile means adding its model in the same edit.** Otherwise the daemon will not
start. That is the intended trade: the failure is loud and immediate rather than silent and later.
- **`models:` is deferred, not hot.** A reload validates the new block — so a bad edit is refused
and the running config is kept — but a good edit is reported as needing a restart. Edit-then-reload
is a half-change. Restart with `scripts/redeploy-fleetd.sh`.
- **The list is a name gate, not a capability check.** It says the operator permits this id. It does
not say the backend serves it, that the credential may use it, or that the id is spelled the way
the provider spells it. A model on the list can still fail at spawn.
- **Cross-check the two lists rather than trusting either.** `grep -E '^\s+model:' fleetd.yaml |
awk '{print $2}' | sort -u` against the `allow:` entries. If they differ, the daemon refuses to
boot — which is the point, but it is better to know before a restart than during one.
fleetd #398.