Development record
Every external credential abcd holds is named in configuration and kept in one store the person chose; never the harness, never the repository
Context
The first adapter to need a secret (the OpenAI-compatible API adapter, for
OpenRouter) was given a one-time walkthrough at ahoy with three homes for
the key: a setup outside abcd, abcd-only on the machine, or the platform
keychain. The site setup needs a hosting credential; a transcript cloud hook
and a forge token are foreseeable. The product thinker observed on
2026-09-22 that the walkthrough is a pattern for every credential, and the
record's rule is one canonical primitive: a generic-smelling thing is built
once in its home and extended, never copied.
Decision
We will hold every external credential through one credential store.
- A name in configuration, never a value. Configuration names a credential; the value lives in the store. Nothing under the repository and nothing in the harness's settings ever carries a value.
- Three homes, the person's choice, made once per credential at an
ahoywalkthrough that first explains what the credential unlocks and what works without it (itd-63's mode): a setup accessible outside abcd (an existing tool's configuration or a named environment variable; the store holds the pointer), abcd-only on the machine (the user-level~/.abcd/store, owner-only permissions), or the platform keychain (macOS Keychain; the secret service on Linux). The keychain is named as the recommendation in the walkthrough's prose and never as a marked option. - One reader. Every adapter resolves a credential through the store's one function by name; an adapter that reads a secret any other way is a defect. A name that resolves to nothing is a refusal naming the walkthrough, never a silent unauthenticated call.
- Scanned before it can be written. The store's write path runs the secret scanner on any file it touches, and a value that would land in a tracked path is refused.
Alternatives Considered
- Each adapter its own walkthrough and file. Rejected: three copies of one thing within a month, each a place to audit and each a place to leak.
- The harness's own secret handling. Rejected: abcd is host-agnostic, the harness's settings are the one place the product thinker asked to keep secrets out of, and a harness file is often synced or committed.
- Keychain only. Rejected: some people will not want it, and Linux has no single equivalent everywhere; the choice is theirs.
Consequences
- itd-2609221017023290 builds the store and the walkthrough; the API adapter (itd-2609081951381895) and the site setup (itd-2609061543533170) read through it, and their own walkthrough criteria are met by calling it.
- A future hook to an external service adds a name and an explanation, not a store.
- The brief's adapters chapter gains the invariant beside adr-2609221009491186.
Frontmatter
| id | adr-2609221017021499 |
|---|---|
| type | adr |
| status | accepted |
| date | 2026-09-22 |
.abcd/development/decisions/adrs/2609221017021499-every-external-credential-abcd-holds-is.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 hostrelated
- itd-63The Amateur Coder Is Told What Is Being Installed And Why, Not Just Asked To Run A Commandrelated
- itd-2609061543533170One verb takes a managed repository's site from the checkout to a live addressrelated
- itd-2609081951381895abcd ships an OpenAI-compatible API adapter, and a provider serves only the models it listsrelated
- itd-2609221017023290abcd keeps every external credential the same wayrelated
mentions5
- dcn-26092200000000012026-09-22 — Model routing, after an independent research pass (product thinker, at an interactive interview). Jev (TypeSafe AI, on OpenRouter) is a typed-decision model, not a router: it fits abcd's closed-option judgements and nothing generative. Rulings: a provider adapter serves only the models it lists under a vendor denylist no listing overrides, everything else on the host (adr-2609221009491186); the OpenAI-compatible API adapter is planned with OpenRouter as configuration, a one-time walkthrough at ahoy and the key kept out of the harness (itd-2609081951381895); a decision adapter for the typed judgements runs in shadow as an abcd lab and a research note is the evidence a ruling turns a judgement type on with (itd-2609221009495079); escalation inside a lane is a rule on a failed fix round, recorded on the model tier (itd-2609170822093401); model per role, the pick and consistency are not routing and stand as ruled; itd-17's learned router is superseded. Every external credential abcd holds goes through one store with three homes the person chooses (adr-2609221017021499, itd-2609221017023290); the API adapter and the site setup read through it. The research is filed as research/notes/2026-09-22-jev-and-model-routing-sota.md.
- dcn-26110415501266392026-11-04 — The product thinker's rulings on the per-key budget draft itd-2611011230226453, at its planning interview. The API key a session names is a named credential, resolved through the credential store by name from whichever of its homes the person chose (adr-2609221017021499); the keychain is the suggested home, never a required one, so a machine without a keychain tool is offered the key route like any other, and the draft is reworded to say so. Spend never passing a cap admits the exceptions the record names: a response larger than any launch cost recorded on the key before it, a launch whose cost cannot be read, several launches sharing one key at once, and the same key used by abcd on a second machine; an overrun abcd can see is recorded against the key and named in the run's record, and the provider's own console limit is the outer stop past every one of them. On that ruling adr-2611011231015519 is accepted, and its refinement of decisions 17 and 34 of itd-2610161733316518 is no longer advisory. The key route and the subscription route compose by one rule: a key at its cap pauses or moves to a second key the person named and never falls to a subscription, a subscription at its usage mark never opens a route the person has not named, and both out at once is a wait, never a third route. The key reaches the harness by a channel the agent's own shell cannot read, proved to work with the harness first, and that proof is the plan's first step; this binds how the key is handed over and not what an agent spends through the harness, which the caps bound.
- iss-2609290825240166itd-2609221017023290 ac-3 promises that the store's write path runs the scanner and refuses a write that would land in a tracked path, and adr-2609221017021499 ruling 4 says the scanner runs on any file the write path touches; the delivered store scans the index (~/.abcd/credential-homes.json) alone, writes ~/.abcd/credentials.json, the file that holds the value, unscanned by construction (internal/core/credential/credential.go SetMachine), and refuses only the abcd home's value write inside a git working tree while the index is still written there (internal/core/credential/store.go Set, ruled at review in 278e266d8 and stated on commands/ahoy.md). The invariant the intent guards, no value in a tracked path or the harness's settings, holds and is tested; the record's wording does not match what ships, and a scan of the value file is unsatisfiable, since a real key is exactly what the scanner flags. The ADR and the intent should say the index is what is scanned and the value write is what is refused, or a ruling should say why the wording stands. Fidelity audit verdict: ac-3 MET_WITH_CONCERNS.
- itd-2611011230226453Agents abcd starts on your API key stay within the budget you set
- spc-2609221017544877abcd-keeps-every-external-credential-the-same-way-one