Development record
A provider adapter's allowlist alone decides which models it serves, and abcd bundles no vendor denylist
Context
adr-2609221009491186 (2026-09-22) made every provider adapter default-deny by
model. Its decision 2 put a bundled vendor denylist above the per-provider
allowlist: anthropic/* at minimum, refusing a listed model whatever the
allowlist said, extendable by the repository and the machine and never
shortened below the bundled set. The shipped resolver in
internal/core/oracle carried that list, refused a listed model it matched
at read, at the setup and at the call, and discarded an answer whose reported
model it matched.
On 2026-09-29 the product thinker answered ruling AA(a), on which spellings
the anthropic/* prefix should chase, with "I think we need an allow list
rather than trying to catch a deny list": the allowlist is the control. The
technical facilitator then ruled H9 the same day: the bundled denylist is
retired, the allowlist alone decides, and ruling Y (whether a person may
remove a bundled entry on their machine) closes as moot, since no bundled
entry remains to remove. Whether oracle.denylist survives as an optional
extension the configuration writes was left to the implementing lane: keep
it only if it costs nothing.
Ruling H10 of 2026-09-29 settles how a change like this is recorded: an ADR whose decision text is now false is superseded, not edited in place. This record is that successor. It changes decision 2 only; decisions 1, 3, 4 and 5 and the consequence added on 2026-09-29 stand as adr-2609221009491186 stated them, and are carried here so the record in force states the whole decision, as adr-2609292012006845 did for adr-2609212115255771.
Decision
We will keep every provider adapter default-deny by model, with the provider's allowlist alone deciding which models it serves. Decisions 1, 3, 4 and 5 are adr-2609221009491186's, carried forward word for word; decision 2 is revised.
- An allowlist per provider. Each provider block in the configuration lists the model identifiers it may serve. A role or a judgement configured for a model not on its provider's list is refused when the configuration is read, before any call is made, naming the list.
- No bundled vendor denylist; the allowlist alone decides. abcd ships no
denylist of vendor prefixes, so a model a provider lists is served
whichever vendor made it, and a model it does not list is refused by
decision 1.
oracle.denyliststays as an optional extension the configuration writes, in the repository's.abcd/config.jsonor the machine's~/.abcd/config.json: an entry refuses a model it matches even when a provider lists it, at the read, at the setup and when a provider reports answering with it, and the layers are a union, so neither removes the other's entries. With no entry written the list is empty. - Everything else runs on the host. A model that is neither listed nor the host's own is not a route; the host and the person's subscription are where frontier models run.
- The key is named, never stored. The adapter reads its credential from the machine's configuration or the environment by name; nothing about a key enters the repository.
- The run record names the route. Every call through an adapter records the provider, the model identifier asked for and the model the provider reports, so a substitution by the aggregator is visible.
Alternatives Considered
- Keep the bundled
anthropic/*denylist as a backstop. Rejected by ruling H9: the product thinker's answer to AA(a) makes the allowlist the control, and a prefix list is the thing that answer declined to chase. The prefix never caughtopenrouter/anthropic/...,anthropic.claude-...or a bareclaude-...spelling, so it read as a guarantee it did not give. - Drop
oracle.denylistaltogether, refusing any configuration that still names it. Rejected: the setting already existed, and with the bundled list gone it keeps working with no added code, so ruling H9's condition (keep it only if it costs nothing) is met. Dropping it would add a refusal and take away the person's way to rule a vendor out across every provider at once. - Amend adr-2609221009491186's decision 2 in place. Rejected by ruling H10: an accepted ADR whose decision text is false is superseded.
- Supersede decision 2 alone, leaving the other four in force in the old
record. Rejected: the record has no partial supersession, and a record
marked superseded whose other decisions still bind reads as retired to a
reader following
superseded_by. Carrying decisions 1, 3, 4 and 5 forward word for word keeps one record in force.
Consequences
- itd-2609081951381895's criterion 3 and its spec read the allowlist alone:
a listed model of any vendor is admitted, an unlisted one is refused naming
the list, and an
oracle.denylistentry the configuration writes refuses a listed model naming the entry. The intent's Audit Notes name ruling H9 and the criterion's old wording (iss-2609300110451242). - A person who wants a frontier model through an aggregator lists it in the
provider block on their machine, deliberately, and the run record shows
it. A person who wants a vendor kept off every provider writes its prefix
in
oracle.denylist. - An aggregator that answers a listed model's request with another model is
visible in the run record (decision 5); it is refused only when an
oracle.denylistentry names the reported model. abcd ahoy --providersreports theoracle.denylistentries written, or that none is written; it names no bundled entry.- The brief's adapters and configuration chapters state the allowlist-alone invariant.
- Consequence carried from adr-2609221009491186 (added there 2026-09-29): a
route to a provider that holds a key is the machine's alone. Decision 4
keeps the key's value out of the repository; the product thinker's ruling
AA(b) of 2026-09-29 keeps the repository from spending it too. Only a route
the person set up on their own machine may use their paid key, so a role or
a judgement type the repository's configuration points at a provider whose
block names a key is refused when the configuration is read, naming
~/.abcd/config.jsonas where to set it. A repository's route to a provider that holds no key (a local server) and a--routethe person types are unaffected. The allowlist, and anyoracle.denylistentry, still apply to every route that is admitted.
Amendment — 2026-10-02: a repository's route to an unlisted model is skipped, not refused
Decision 1 refuses a role or a judgement type configured for a model not on its
provider's list when the configuration is read. The technical facilitator's
ruling CD3 of 2026-10-02 narrows the refusal for one layer: a route in a
repository's .abcd/config.json naming a model that a configured provider
holding no key does not list is skipped with a diagnostic naming the file, the
route and the list, and the machine's route to the name, if any, applies in its
place, so a checkout's configuration never takes the commands that read it
down. The model is still never asked for: the route is not loaded. The
machine's own route to an unlisted model is refused as decision 1 says, a model
an oracle.denylist entry matches is refused from any layer, and a
repository's route to a provider that holds a key is skipped before that
provider's list is consulted, so the list is never read on a repository's
behalf. adr-25's amendment of the same date records the ruling beside CD4.
Frontmatter
| id | adr-2609300107513982 |
|---|---|
| type | adr |
| status | accepted |
| date | 2026-09-30 |
.abcd/development/decisions/adrs/2609300107513982-a-provider-adapter-s-allowlist-alone.md
open on GitHub ↗ · commit history ↗
References6
- adr-25The LLM is host-delegated by default; oracles are opt-in adaptersrelated
- adr-2609221009491186A provider adapter serves only the models it lists, under a vendor denylist no listing overrides; everything else runs on the hostsupersedes
- itd-6RepoPrompt over MCP is one opt-in reviewer route, beside the host's own agentsrelated
- itd-2609081951381895abcd ships an OpenAI-compatible API adapter, and a provider serves only the models it listsrelated
- itd-2609170822093401abcd proposes the model each agent deserves, and facilitates it where it canrelated
- itd-2609221009495079abcd's typed judgements can run through a decision adapter, measured in a lab before it decides anythingrelated
Referenced by2
- adr-2609221009491186A provider adapter serves only the models it lists, under a vendor denylist no listing overrides; everything else runs on the hostrelated
- itd-2609301918174237A remote provider takes a file-reading agent only as a fixed, blanked, capped bundlerelated
mentions7
- adr-2609212115255771Phases and milestones are retired: sequencing is dependencies rendered as status, the checkpoint is the derived release
- adr-2609292012006845Now, Next and Later list an intent in a lane under Now only; phases stay retired
- dcn-26093000000000062026-09-30 — The technical facilitator's ruling H9 of 2026-09-29 is applied (recorded by lane denyRetire of autonomous run A; the answer is kept verbatim in the local-tier file `.abcd/.work.local/scratch/reports/rulings-answered-2609-29-b.md`, dated 2026-09-29, and restated here because that file is not committed): the bundled `anthropic/*` vendor denylist is retired and a provider's allowlist alone decides which models it serves. adr-2609300107513982 supersedes adr-2609221009491186, revising its decision 2 and carrying decisions 1, 3, 4 and 5 forward word for word; itd-2609081951381895's criterion 3 and spc-2609221011153746 are amended to the allowlist-alone reading, with the old wording in the intent's Audit Notes (iss-2609300110451242). This answers the follow-up the 2026-09-29 entry above left to the technical facilitator under AA(a), whether the bundled entry stays as a backstop: it does not. Ruling Y (added 2026-09-26, from lane apiadapter: may a person remove a bundled entry on their own machine) closes as moot, since no bundled entry remains to remove. The detail H9 left to the lane, whether `oracle.denylist` survives as an optional repository or machine extension, is decided as keep: the setting already existed in both layers, and removing the bundled list leaves it working with no added code, which is the ruling's condition.
- iss-2609300110451242Ruling H9 of 2026-09-29 retires the bundled anthropic/* vendor denylist, which changes the reading of itd-2609081951381895 acceptance criterion 3 (a listed model whose prefix matches the vendor denylist is refused at read, and no allowlist entry overrides it) and of adr-2609221009491186 decision 2: with no bundled list the provider's allowlist alone decides, so a listed model of any vendor is served, and only an oracle.denylist entry the repository or the machine writes refuses a listed model
- itd-2610161733316518One task done across a model matrix, re-runnably
- spc-2609221011153746abcd-ships-an-openai-compatible-api-oracle-adapter-the-first
- spc-2609221533057881abcd-runs-a-delegated-agent-through-a-command-line-model-run