Skip to content

design: provider naming & ownership convention — mark fleet-built providers (dt- proposal), rename map #1823

Open

Description

@dezren39

Provider naming & ownership convention — design (Drew directive 2026-11-06)

Drew: "any other alignments for the providers as a whole. if there's a cleaner structure like direct/ or leading _ or _.provider or something. if we know it's ours then we don't need to say direct."

This issue is the design home for the provider-id convention. It broadens #1817 (claude-code → claude-direct) — no renames are executed here; Drew rules on the convention first, then the rename map below is applied as one coordinated pass.

Principle

A provider id should say whose it is. "-direct" describes a mechanism (wire emulation); if the id itself marks fleet ownership, the mechanism suffix is noise. Official upstream ids are never renamed.

Inventory (verified 2026-11-06: fork packages/ai/src/providers/ + fleet config developing-today/code .opencode/opencode.jsonc)

OURS — fleet-built, fork source (header comments state the direct-provider pattern verbatim):

Config id (runtime) Source id (ProviderID.make) Package Notes
claude-code claude-code providers/claude-code.ts wire emulation of the Claude Code CLI (anomalyco#6117)
antigravity-direct antigravity providers/antigravity.ts config id ≠ source id — the split this convention ends
vibe-direct vibe providers/vibe.ts config id ≠ source id, same split
commandcode commandcode providers/commandcode.ts quota registry spells it command-code — second split
meta (native pkg) meta providers/meta.ts ⚠️ config id meta currently binds @ai-sdk/openai → api.meta.ai instead — which "meta" is canonical must be settled before any rename (see map)

OURS — fleet-configured doors (no fork code; official SDK packages + our config):

Config id Binding Notes
muse-direct @ai-sdk/openai → local muse-proxy 127.0.0.1:18747 fleet-created id; fronts a local proxy (infra fate tracked by the decommission pass, not this issue)
opendesign @ai-sdk/openai-compatible → amr-link.open-design.ai names a third-party service
cline-pass @ai-sdk/openai-compatible names a third-party service

OFFICIAL — upstream, used as-is, ids untouchable: the rest of packages/ai/src/providers/ (anthropic, openai, mistral, deepseek, google, groq, openrouter, xai, zai, … 45 source ids total). Fleet-used today include openai, mistral, deepseek; groq/openrouter are defined but disabled. A separate audit (running in parallel) verifies no fleet edits live inside official provider files and that no used provider spawns a binary.

RETIRED ids (definitions retained, disabled, per the switchboard rule): antigravity-ls, antigravity-agy. Plus catalog tombstones in disabled_providers (google, google-vertex, cloudflare-ai-gateway, cloudflare-workers-ai, github-copilot) whose definitions are deleted but whose entries must stay.

Quota-layer ids (packages/ai/src/quota/providers/): antigravity, claude (serves provider claude-code), cline-pass, codex (the OpenAI plan pool), command-code, deepseek, groq, meta, mistral, opencode-go, opendesign, openrouter, turso. Two of these already disagree with their provider ids (claude, command-code) — the convention pass should unify them via the alias mechanism, not leave a third naming layer.

Constraints (why most shapes fail)

  • The provider id is the first segment of every leaf string provider/model in routes, sessions, and config. An id containing / is mechanically impossible — the parser splits on the first slash. This kills the direct/ namespace shape outright.
  • Ids are keys in: config provider blocks, disabled_providers, route leaves, session_message/route_health rows, the quota registry (ids + aliases), the pm-stack quota gatherer, logs and dashboards. A rename is a coordinated config + registry change; historical DB rows keep the old id (they are history, not pointers).
  • Id grammar in the wild is lowercase words + dashes (zai-coding-plan). Any marker must survive JSON keys, URLs, shell, and SQL unchanged.

Candidate evaluation

Shape Example Verdict
Slash namespace direct/claude Impossible — slash is the leaf separator
Mechanism prefix direct-claude Says "direct", not "ours" — the thing Drew wants to drop
Leading underscore _claude Legal, sorts first, clearly non-catalog; but reads as private/internal in most ecosystems and looks like a temporary hack in logs/URLs
.provider suffix claude.provider Dots already occur in model ids (claude-haiku-5.5), so leaf strings get harder to eyeball; and it says "is a provider" (everything here is), not "ours"
_. compound _.claude Stacks both oddities; same private connotation
Ownership prefix dt- dt-claude Recommended. Short, dash-grammar native, unmistakably ours (developing-today), collision with any future upstream id is essentially impossible, the whole family sorts/groups together everywhere ids are listed

Fallback if Drew prefers plain English over the org mark: ours- (same mechanics, one syllable longer, slightly more generic if configs are ever shared).

Rename map (under the recommended dt- convention)

Current Proposed Touches
claude-code dt-claude source id, config block, 4+ leaves, quota id claude becomes an alias of dt-claude
antigravity-direct / antigravity dt-antigravity config + source ids converge; leaves; quota id follows
vibe-direct / vibe dt-vibe config + source converge; mistral-plan membership
commandcode dt-commandcode source + config; quota command-code becomes alias — spelling split closed
meta (native pkg) dt-meta ⚠️ sequence AFTER deciding canonical "meta": today config meta = SDK door to api.meta.ai while the native package is unused by that block. Rename must not silently rebind the config door
muse-direct dt-muse config id only (door definition unchanged)
opendesign, cline-pass unchanged (proposal) fleet-configured but they name third-party services, like openrouter; mark them only if Drew wants every fleet-config id badged
antigravity-ls, antigravity-agy unchanged retired + disabled; renaming dead definitions is churn with zero runtime effect
all official ids unchanged by the principle above

Migration notes

  1. Order: fork first (source ProviderID.make + quota registry, keeping old ids as quota aliases for continuity), then the code-repo config (provider blocks, disabled_providers, every route leaf), then deploy + server restart, verified via GET /api/provider.
  2. The config file's deployed copies must stay byte-identical through the change (single repo edit + normal deploy; regenerate the runtime overlay as part of the same pass — the overlay staleness bit us on 2026-11-06).
  3. Historical session_message / route_health rows keep old ids; dashboards should treat the rename map as the join key for pre/post comparisons.
  4. Docs/comments that narrate the old ids get a dated rename note, not a rewrite of history.
  5. One PR per repo, merge commits only; the whole map lands atomically enough that no route ever names a non-existent provider (config and fork deploy together, or config ships with both ids defined for one release window if sequencing demands it).

Related workstreams (not this issue)

  • Audit: fleet edits inside official provider files (report + follow-ups).
  • Audit: binary-required providers among those the fleet uses (wire-only doctrine check).
  • Proxy-infra decommission: the retired proxy lineage (bin/*-proxy.mjs family, :18749/:18751 units) across opencode / openchamber / code.

Drew rules on: (a) dt- vs ours- vs another marker; (b) whether fleet-configured service doors (opendesign, cline-pass) get badged; (c) canonical "meta" before its rename line is scheduled.

Acceptance criteria

  • A single provider naming & ownership convention is recorded as decided on this issue (the marker scheme for fleet-built providers, and the rule that official upstream ids are never renamed).
  • A complete rename map (config id, source id, package) for every fleet-built provider is attached to this issue before any rename executes.
  • Renames, when executed, land as one coordinated pass across the fork and the fleet config in developing-today/code, with a compat/migration note for stored route-health and session rows keyed by old ids.

Activity

  1. dezren39 commented on Nov 6, 2026

    @dezren39
    Author

    Addendum — pools-first routing shapes the rename's blast radius (Drew, 2026-11-06 04:00 CST)

    Drew's routing principle, stated alongside this design: nearly all usage goes through POOLS (plan routes); direct provider/model seats are the exception, used only where exactly one specific provider+model is deliberately wanted.

    What that changes for this design — nothing about the convention itself, but the migration notes should be read with this sizing:

    • Pool definitions are the primary reference sites for custom provider ids. Most occurrences of our custom ids live inside plan-route definitions (e.g. haiku-plan / sonnet-plan / opus-plan lead seats naming claude-code/*, mistral-plan's membership naming vibe-direct, the antigravity seats inside sonnet-plan/opus-plan/gemini-flash-plan/argon-plan), plus the provider blocks themselves and disabled_providers. Session traffic names the pool, not the provider — so a provider rename touches the pool layer almost exclusively.
    • Direct seats are rare and deliberate — each one is a specific choice someone made, so the migration pass should enumerate them individually (not bulk-rewrite them) and re-confirm each still wants that exact provider+model under its new id.
    • Rename sequencing consequence: pools keep working through the rename as long as pool membership and provider blocks flip in the same deploy; the risk surface is the small set of direct seats and the quota aliases, not the bulk of traffic.

    (A separate lane owns the route→model#effort map and the pools-first audit; this note only records the principle's implication for the rename map.)

  2. added
    kind/designA design proposal (design-architect): multi-step, phased, decision-bearing
    source/humanFiled directly by a human
    priority/normalOrdinary priority (the default)
    effort/lLarge: multi-day or open-ended; expect staged check-ins
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Nov 6, 2026
  3. dezren39 commented on Nov 6, 2026

    @dezren39
    Author

    Intake review

    🤖 Fleet monitor intake (repo-fleet-monitor), 2026-11-06.

  4. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 6, 2026
  5. dezren39 commented on Nov 6, 2026

    @dezren39
    Author

    🤖 Agent note · triaged — design is complete and current; blocked on Drew's ruling (escalated)

    • Agent: repo-queue-worker-shift-opencode lane A (opencode-a)
    • Task: task 11116 (triage)
    • Verified fresh (2026-11-06): issue OPEN, labels kind/design, source/human, priority/normal — no hard-stop labels. The body's inventory and rename map are the verified starting point (fleet monitor intake, 2026-11-06, concurs: still live, no renames executed). Both comments read: Drew's 04:00 CST addendum settles the pools-first sizing of the rename's blast radius, but does not rule on the three convention questions below — so this triage escalates rather than routes a fix.
    • What Drew is being asked to decide (substance, per the issue body):
      1. Marker scheme for fleet-built provider ids: dt- prefix (recommended — short, dash-native, unmistakably ours, near-zero collision risk; e.g. claude-code → dt-claude) vs ours- (plain-English fallback, same mechanics) vs another marker. Slash namespaces are mechanically impossible (the id is the first segment of every provider/model leaf string); leading _ reads as private/hacky; .provider says "is a provider", not "ours".
      2. Badge the fleet-configured service doors? opendesign and cline-pass are our config ids but name third-party services (like openrouter). Proposal in the body: leave them unchanged; Drew rules whether every fleet-config id gets badged instead.
      3. Canonical "meta" must be settled before the meta rename line is scheduled: today config meta binds the @ai-sdk/openai door to api.meta.ai, while the native fork package meta is a different thing. Renaming before this is decided risks silently rebinding the config door.
    • On a ruling: the rename map in the body executes as one coordinated pass (fork source ids + quota aliases first, then the developing-today/code config — provider blocks, disabled_providers, route leaves — then deploy + verify via GET /api/provider); a follow-up implementation task gets enqueued from this issue at that point. Until then the task is blocked on the ruling, not on any engineering unknown.
  6. added
    status/blockedBlocked on something named in the issue/PR
    user/escalatedMuse reviewed it; the decision is genuinely the user's — escalated with Muse's read attached
    and removed
    queue/claimedA queue worker has claimed the task for this item
    work/assignedAn agent holds this item via the queue (claimed task)
    on Nov 6, 2026
  7. dezren39 commented on Nov 6, 2026

    @dezren39
    Author

    Alignment record update — muse-direct (2026-11-06)

    The muse-direct row of the provider alignment audit is resolved:

    • Before: provider id muse-direct was an @ai-sdk/openai config block aimed at a loopback proxy (muse-proxy, :18747) that performed the Meta key exchange and Responses translation out-of-process — a proxy wearing a "direct" name.
    • After: muse-direct is a native fork provider package (@opencode/ai/providers/muse-direct, fork PR muse-direct: native Meta wire provider (#1825) #1872) speaking the Meta Responses wire in-process, performing the /muse-code/key minted-key exchange itself from ~/.config/muse/auth.json. No proxy hop, no subprocess, no placeholder key, no config baseURL/apiKey. muse-proxy is stopped, disabled (unit not-found), its port is dead, and its repo definition is removed (code PR feat: Add kotlin lsp integration anomalyco/opencode#6601).
    • Ids unchanged: provider muse-direct, models muse-spark-1.3-contributor / muse-wonder-1.0-contributor; the two pinpoint seats (speed head / workhorse-primary leaf on spark#xhigh, summit on wonder#xhigh) never moved. Pool discipline intact: meta remains the only PAYG door under its own id; muse stays disabled.
    • Wire-only doctrine: muse-direct now satisfies it — HTTPS + the account's own credential file only, in line with the verified wire-only set (claude-code, commandcode, openai, mistral, deepseek, groq, openrouter, opendesign, cline-pass, opencode-go.*). Remaining doctrine exceptions from the audit are the antigravity-direct and vibe-direct items tracked on audit follow-up: antigravity + vibe credential paths spawn secret-tool; antigravity refresh requires the agy binary #1825.
    • Full evidence (design, scratch capture, production probes verbatim, quota verification, death certificate) is on audit follow-up: antigravity + vibe credential paths spawn secret-tool; antigravity refresh requires the agy binary #1825.
  8. dezren39 commented on Nov 7, 2026

    @dezren39
    Author

    Rulings recorded — Drew, 2026-11-07 07:43 + 07:45 CST

    1. Ownership marker = a leading underscore. Not dt-, not ours-.
    2. The Q2 distinction is rejected. Third-party service ≠ third-party provider. What matters is who built the provider code.
    3. The rule is mechanical — no forced choices: if we custom-made the provider, it gets the leading underscore; if it came from the upstream repo, it doesn't.
    4. Display strip (07:45 addendum): the underscore is a config/source-level ownership marker only. Display surfaces — the pm-stack interface, quota reports, dashboards, status surfaces — strip the leading underscore when presenting provider names. The canonical provider id keeps it.

    Classification — verified from source (git history/authorship in this fork, 2026-11-07)

    Custom-built in this fork (adding commit author): claude-code (Drewry Pope, 2026-11-05), antigravity (Drewry Pope, 2026-11-02), vibe (developing-today[bot], 2026-11-04), commandcode (Drewry Pope, 2026-11-05), muse-direct (Drewry Pope, 2026-11-06; a native source provider since #1872, not config-only).

    Upstream: everything else in packages/ai/src/providers/, including meta — providers/meta.ts was added by upstream PR anomalyco#47826 ("feat(ai): add Meta provider", Aiden Cline, 2026-09-07) and every later commit on it is by upstream authors; zero fleet commits. This corrects this issue's inventory, which listed meta as fleet-built. Per the mechanical rule, meta gets NO underscore. Flagged for Drew: if the intent was that the fork's Meta door specifically is ours, the fleet-built Meta provider is muse-direct → _muse; the upstream meta provider stays meta.

    Config-only doors (no fork provider source; they bind upstream SDK packages @ai-sdk/openai[-compatible]): opendesign, cline-pass — provider implementation is upstream → no underscore, unchanged. (Same outcome the proposal reached, for the rule's reason: it's about who built the provider, not whose service sits behind it.)

    Rename map (executed as one coordinated pass)

    Provider Config id Source id Quota id → New id
    Claude Code wire emulation claude-code claude-code claude _claude
    Antigravity wire emulation antigravity-direct antigravity antigravity _antigravity (config+source converge)
    Mistral Vibe wire emulation vibe-direct vibe — _vibe (converge)
    Command Code wire emulation commandcode commandcode command-code _commandcode (spelling split closed)
    Muse native provider muse-direct muse-direct — _muse
    Meta (upstream provider) meta meta meta unchanged — upstream
    opendesign, cline-pass unchanged — (upstream SDK) unchanged unchanged
    antigravity-ls, antigravity-agy retired/disabled — — unchanged (retired)
    all official upstream ids unchanged unchanged unchanged unchanged

    Notes:

    • Old ids survive as quota aliases (history continuity); historical session/route-health rows keep old ids — the map above is the join key.
    • Module file names (providers/claude-code.ts, @opencode/ai/providers/claude-code) are internal module paths, not provider ids — unchanged.
    • Pool ids in pm-stack follow config provider ids per the 2026-11-03 pool-naming rule: commandcode → _commandcode, antigravity-direct.gemini → _antigravity.gemini, antigravity-direct.claude-gpt → _antigravity.claude-gpt — each starts a new snapshot series; pre-rename series stay unrewritten.
    • Display strip lands in pm-stack aggregator/src/provider-display.ts (the dashboard display-name function) and the fork quota CLI's human header; JSON/machine surfaces keep the canonical id.
    • Supersedes the claude-direct name in Rename custom provider claude-code -> claude-direct (naming alignment, later) #1817 (the underscore convention replaces the -direct scheme).

    Execution: fork PR + code-repo PR (config + pm-stack), merge commits only, no deploy outside the normal path.

  9. added a commit that references this issue on Nov 7, 2026
  10. dezren39 commented on Nov 7, 2026

    @dezren39
    Author

    Execution record — 2026-11-07

    Renames executed per the ruling comment above:

    Not renamed: meta — upstream provider code (anomalyco/opencode anomalyco#47826); flagged in the ruling comment for Drew's confirmation. opendesign / cline-pass — config doors over upstream SDK packages, unchanged per the rule.

    Tracked follow-ups (not in either PR):

    1. The runtime overlay regenerates from the renamed config on the normal deploy; no deploy/restart was performed in this pass. Post-deploy verification: GET /api/provider shows the underscored ids; opencode quota resolves old spellings via aliases.
    2. Agent/cron report surfaces that quote provider ids verbatim (e.g. hourly quota reports) should strip the leading underscore when presenting, per the 07:45 addendum — the dashboard (provider-display.ts) and the fork quota CLI header already do.
    3. Historical session/route-health rows keep the old ids; the rename map in the ruling comment is the join key.
  11. added a commit that references this issue on Nov 7, 2026
  12. dezren39 commented on Nov 8, 2026

    @dezren39
    Author

    🤖 Agent note · triaged

  13. removed
    status/blockedBlocked on something named in the issue/PR
    user/escalatedMuse reviewed it; the decision is genuinely the user's — escalated with Muse's read attached
    on Nov 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    effort/lLarge: multi-day or open-ended; expect staged check-inskind/designA design proposal (design-architect): multi-step, phased, decision-bearingmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)source/humanFiled directly by a humantask/triageQueue packet kind: verify, reproduce, and route this item

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions