Summary
The daemon's default backend is a hardcoded literal with no configuration or environment entry point, so an operator whose only installed backend is something other than Claude must pass --provider on every session creation.
src/daemon/providers/registry.ts:167:
const registry = new ProviderRegistry("claude");
src/daemon/models.ts:114-118 documents the coupling:
"The provider id whose model space this catalog describes. Must match the default id the provider registry is built with (createDefaultProviderRegistry → new ProviderRegistry("claude")); DEFAULT_PROVIDER_ID in session-manager re-exports this so there is one source of truth."
Resolution chain for a new session (src/daemon/session.ts:774-775):
const effectiveProviderId =
opts.providerId ?? this.#providersRegistry?.defaultId ?? CLAUDE_PROVIDER_ID;
No configuration entry exists today
- The env-var mapping table (
src/config.ts:1178-1215) has no provider/backend entry. The only related knob is CODEOID_DEFAULT_MODEL (config.ts:1190), which changes the model, not the backend.
- No
defaultProvider / defaultBackend key exists in config.json (no hits).
providers.pi.enabled / providers.pi.command (config.ts:608-616) control whether a backend is registered, not which one is selected by default.
Workarounds and their gaps
codeoid new <name> --provider pi — works per session, but must be repeated every time; this is the case the word "default" is meant to cover.
conductor.provider (config.ts:429-439, defaults to "claude") — covers only the conductor, and moving it off Claude loses the fleet MCP tools. See the comment at config.ts:424-427 and settings/manifest.ts:294: fleet tools are currently mounted only under the claude provider.
- Switching backend mid-session requires the
session.set_provider protocol message (session.ts:934, session-manager.ts:995). The TUI does not expose it — the slash-command table has only /model, described as "Switch the Claude model" (tui/components/SlashHint.tsx:29).
Proposed change
Add a top-level defaultProvider key to RootSchema (src/config.ts) and have createDefaultProviderRegistry honor it:
const registry = new ProviderRegistry(config?.defaultProvider ?? "claude");
Two things to get right alongside it:
- A misconfigured value should fail fast at startup.
ProviderRegistry.resolve() (registry.ts:150-158) deliberately warns and falls back for unknown ids — that behavior is for resume of sessions written by a newer codeoid. A typo in defaultProvider is a different situation and should be a hard startup error, otherwise it silently reverts to claude.
- Update the "Must match" note at
models.ts:114-118. DEFAULT_MODEL_ALIAS = "opus" is Claude-specific. Risk is low in practice — resolveModelIdForProvider (session.ts:776-782) returns null for Claude-only aliases on a non-Claude backend so the provider picks its own default — but the comment should stop asserting a fixed id.
Motivation
pi is already a first-class supported backend with a complete resolution chain (explicit providers.pi.command → system PATH → bundled optionalDependency; providers/pi/resolve.ts:48,59) and is registered whenever providers.pi.enabled !== false (registry.ts:240-273). The same shape applies to codex and gemini-cli. For an operator running only one of these, the current design forces a redundant flag on every session.
Requested as an enhancement rather than a bug — the hardcoding is clearly deliberate in the current code, but it makes a supported-and-common configuration needlessly awkward, and the fix is a small, well-bounded change.
Environment
@highflame/codeoid 0.4.3 (installed via bun)
- Verified against the released package's
src/ (line numbers are for 0.4.3)
Summary
The daemon's default backend is a hardcoded literal with no configuration or environment entry point, so an operator whose only installed backend is something other than Claude must pass
--provideron every session creation.src/daemon/providers/registry.ts:167:src/daemon/models.ts:114-118documents the coupling:Resolution chain for a new session (
src/daemon/session.ts:774-775):No configuration entry exists today
src/config.ts:1178-1215) has no provider/backend entry. The only related knob isCODEOID_DEFAULT_MODEL(config.ts:1190), which changes the model, not the backend.defaultProvider/defaultBackendkey exists inconfig.json(no hits).providers.pi.enabled/providers.pi.command(config.ts:608-616) control whether a backend is registered, not which one is selected by default.Workarounds and their gaps
codeoid new <name> --provider pi— works per session, but must be repeated every time; this is the case the word "default" is meant to cover.conductor.provider(config.ts:429-439, defaults to"claude") — covers only the conductor, and moving it off Claude loses the fleet MCP tools. See the comment atconfig.ts:424-427andsettings/manifest.ts:294: fleet tools are currently mounted only under theclaudeprovider.session.set_providerprotocol message (session.ts:934,session-manager.ts:995). The TUI does not expose it — the slash-command table has only/model, described as "Switch the Claude model" (tui/components/SlashHint.tsx:29).Proposed change
Add a top-level
defaultProviderkey toRootSchema(src/config.ts) and havecreateDefaultProviderRegistryhonor it:Two things to get right alongside it:
ProviderRegistry.resolve()(registry.ts:150-158) deliberately warns and falls back for unknown ids — that behavior is for resume of sessions written by a newer codeoid. A typo indefaultProvideris a different situation and should be a hard startup error, otherwise it silently reverts toclaude.models.ts:114-118.DEFAULT_MODEL_ALIAS = "opus"is Claude-specific. Risk is low in practice —resolveModelIdForProvider(session.ts:776-782) returnsnullfor Claude-only aliases on a non-Claude backend so the provider picks its own default — but the comment should stop asserting a fixed id.Motivation
piis already a first-class supported backend with a complete resolution chain (explicitproviders.pi.command→ systemPATH→ bundled optionalDependency;providers/pi/resolve.ts:48,59) and is registered wheneverproviders.pi.enabled !== false(registry.ts:240-273). The same shape applies tocodexandgemini-cli. For an operator running only one of these, the current design forces a redundant flag on every session.Requested as an enhancement rather than a bug — the hardcoding is clearly deliberate in the current code, but it makes a supported-and-common configuration needlessly awkward, and the fix is a small, well-bounded change.
Environment
@highflame/codeoid0.4.3 (installed via bun)src/(line numbers are for 0.4.3)