This is the record of an abcd-managed repository

abcdBetav0.16.2 · 2026-11-06

Development record

abcd-ships-an-openai-compatible-api-oracle-adapter-the-first

specclosedspc-2609221011153746

Summary

The design record for itd-2609081951381895: the OpenAI-compatible API adapter with per-provider allowlists that alone decide which models a provider serves, and the optional oracle.denylist the configuration writes (adr-2609221009491186, superseded by adr-2609300107513982, which retires the bundled vendor denylist under ruling H9 of 2026-09-29).

Scope

  1. Configuration (internal/core/oracle/config.go): the provider blocks, the optional oracle.denylist (abcd bundles no entry), the resolver that validates every role and judgement route at read time and returns the refusal (criteria 1 to 3).
  2. The adapter (internal/adapter/openaiapi): one client over the chat completions protocol, the request rendered from the same brief the host gets, the response validated against the same output contract, the transcript captured (criterion 1).
  3. The credential: by name from the machine configuration or the environment; a name that resolves to nothing is a refusal (criterion 4).
  4. The record: provider, requested and reported model per call in the run record (criterion 5).
  5. The setup (ahoy gap → itd-63's mode): detect no provider block; explain; on yes ask the home (three choices, keychain recommended in prose); write the key by the chosen method (external: store the variable or config name only; abcd: ~/.abcd/credentials.json mode 0600; keychain: the platform keychain under abcd's service name via the security command on macOS and the secret-service API on Linux, the configuration holding the name); write the provider block with the first allowlist; one verification call (criteria 7, 8).
  6. Review: security reviewer on the lane (criterion 9).

Out of scope

  • Provider routing; learned routers; the tier's judgement.

Approach

The adapter implements the same validator/runner interface the host path and the RepoPrompt route (itd-6) implement, so the loop does not know which ran; OpenRouter and a local server differ only in configuration.

Footprint

  • packages: internal/core/oracle, internal/surface/cli, and a new adapter package for the OpenAI-compatible client
  • tests: the resolver's refusals (unlisted, a configured denylist entry, no key) and a listed model of any vendor admitted; the call against a fake server; the record fields

How the criteria are satisfied

Criterion Where
1 the call; unconfigured unchanged scope 2
2 unlisted refused at read scope 1
3 the list alone decides; a configured denylist entry refuses scope 1
4 key by name scope 3
5 the record scope 4
7 ahoy explains and offers scope 5
8 three homes, keychain in prose, nothing in the harness scope 5
9 security review scope 6

Frontmatter

idspc-2609221011153746
typespec
lifecycleclosed

References1

mentions5