You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Init-wizard arc closer (#94 PR 2 of 2 / #323) shipped 2026-06-02 with three templates and the Add-to-it recovery merge. Discovered during dogfood discussion: the wizard is implicitly Claude-first, but the framework underneath has been provider-agnostic since #87.
What's true today
Credential pre-flight is hardcoded to Anthropic.atomic_agents/init/wizard.py:134_api_key_preflight() calls _llm._get_key(env_vars=ANTHROPIC_ENV_VARS, keychain_name=\"atomic-agents-anthropic\", config_key=\"anthropic\"). ANTHROPIC_ENV_VARS is fixed at (\"ATOMIC_AGENTS_ANTHROPIC_KEY\", \"ANTHROPIC_API_KEY\") in atomic_agents/init/constants.py:331. The error path at constants.py:351-353 instructs the operator to export ANTHROPIC_API_KEY=sk-ant-....
Template model defaults are hardcoded to Claude. All three shipped templates ship with Claude models in model.md:
Opt-in test call is provider-neutral but credential is not._test_call routes through _llm.call which uses find_backend_for_model(model, preferred_provider=...). So once model.md points at a non-Claude model, the test call uses the right backend automatically — but the pre-flight blocks the operator before they get there.
What's true underneath
The framework is provider-agnostic.atomic_agents/_llm.py registers three reference LLM backends at import time: Anthropic, OpenAI, Moonshot (per CLAUDE.md status block + #87). find_backend_for_model(\"gpt-5\", preferred_provider=\"openai\") routes correctly. model.md's optional provider: field disambiguates when multiple registered backends could plausibly own a model string.
Per-provider _get_key helpers already exist._llm.py:171-188 defines _get_anthropic_key, _get_openai_key, _get_moonshot_key thin wrappers around the same _get_key(env_vars, keychain_name, config_key) primitive that wizard pre-flight uses. The plumbing is there; the wizard just doesn't ask which one to call.
The workaround today
OpenAI-only operator path:
Use --from-template advisor (skips pre-flight per amended spec/35 MUST 7 carve-out).
Open <agent>/model.md, replace Claude model strings with OpenAI ones, add provider: openai.
export OPENAI_API_KEY=....
atomic-agents doctor --agent <name> to verify.
Discoverable but graceless. It's the half-day-deploy friction the wizard was supposed to eliminate, just shifted to non-Claude users.
Proposed fix
Three design surfaces, none mutually exclusive:
A. Env-var autodetect (recommended primary, lowest friction). Before pre-flight runs, scan for ANTHROPIC_API_KEY / ATOMIC_AGENTS_ANTHROPIC_KEY, OPENAI_API_KEY / ATOMIC_AGENTS_OPENAI_KEY, MOONSHOT_API_KEY / ATOMIC_AGENTS_MOONSHOT_KEY. If exactly one is set: use that provider, render templates with that provider's default model defaults, pre-flight against that provider's _get_key helper. If multiple are set: fall back to provider question (C below). If zero are set: error message lists all three options.
B. --provider <anthropic|openai|moonshot> flag. Explicit override for the non-interactive path. Composes with --from-template: atomic-agents init my-agent --from-template advisor --provider openai. Skips autodetect; uses the flagged provider's defaults + key check. CLI-friendly for CI / scripted workflows.
C. Provider question Q0 in the interactive Q&A. If autodetect found multiple keys OR autodetect was skipped, ask the operator which provider before any other question. Show one-line plain-English descriptions: "Anthropic (Claude) / OpenAI (GPT) / Moonshot (Kimi)". Selected answer drives pre-flight + template rendering.
Template rendering with per-provider defaults. The 3 existing templates stay; their model.md becomes a string.Template with \\${default_model} / \\${fallback_model} / \\${provider} variables. The wizard supplies provider-specific defaults at render time:
OpenAI: gpt-5 / gpt-5-mini (advisor + researcher), gpt-5-mini / gpt-5-nano (writer) — exact model strings TBD at impl time based on current OpenAI catalog
Moonshot: moonshot-v1-128k / moonshot-v1-32k or whatever the current Moonshot catalog supports
The model defaults per-provider should be declared as a single constant table in constants.py so the cost guardrails (daily_cap_usd / monthly_cap_usd) can also vary per provider where unit cost differs significantly (e.g. opus-4-7 vs gpt-5 pricing).
Spec/35 amendment. MUST 7's API-key pre-flight wording becomes provider-aware ("matching the configured provider" not "Anthropic"). New MUST documenting provider-selection precedence (--provider flag > env-var autodetect > Q0 question > error).
Acceptance
atomic-agents init my-agent --from-template advisor --provider openai scaffolds an OpenAI-shaped advisor with one command and no model.md editing.
OPENAI_API_KEY=... atomic-agents init my-agent (no --provider flag) autodetects and scaffolds an OpenAI-shaped agent.
Multi-provider failover within a single agent (Sonnet primary + GPT-5 fallback in same model.md) — possible today via model.md if both provider keys are set, but not a wizard concern.
Provider-specific persona advice ("OpenAI models tend to be more verbose; consider shorter SOUL.md") — speculative until we actually observe persona drift across providers.
Effort estimate
Anthropic-only baseline: shipped.
Add autodetect + --provider flag + per-provider template constants + 3 smoke tests + spec/35 MUST 7 amendment: ~1 day of CC time with 2-3 adversarial rounds, similar shape to PR 2 of arc.
Q0 question is optional extension if autodetect resolves the common case cleanly.
Surfaced after
Init-wizard arc closer (#94 PR 2 of 2 / #323) shipped 2026-06-02 with three templates and the Add-to-it recovery merge. Discovered during dogfood discussion: the wizard is implicitly Claude-first, but the framework underneath has been provider-agnostic since #87.
What's true today
Credential pre-flight is hardcoded to Anthropic.
atomic_agents/init/wizard.py:134_api_key_preflight()calls_llm._get_key(env_vars=ANTHROPIC_ENV_VARS, keychain_name=\"atomic-agents-anthropic\", config_key=\"anthropic\").ANTHROPIC_ENV_VARSis fixed at(\"ATOMIC_AGENTS_ANTHROPIC_KEY\", \"ANTHROPIC_API_KEY\")inatomic_agents/init/constants.py:331. The error path atconstants.py:351-353instructs the operator toexport ANTHROPIC_API_KEY=sk-ant-....Template model defaults are hardcoded to Claude. All three shipped templates ship with Claude models in
model.md:advisor:claude-opus-4-7primary +claude-sonnet-4-6fallbackresearcher:claude-opus-4-7primary +claude-sonnet-4-6fallbackwriter:claude-sonnet-4-6primary +claude-haiku-4-5fallbackOpt-in test call is provider-neutral but credential is not.
_test_callroutes through_llm.callwhich usesfind_backend_for_model(model, preferred_provider=...). So oncemodel.mdpoints at a non-Claude model, the test call uses the right backend automatically — but the pre-flight blocks the operator before they get there.What's true underneath
The framework is provider-agnostic.
atomic_agents/_llm.pyregisters three reference LLM backends at import time: Anthropic, OpenAI, Moonshot (per CLAUDE.md status block + #87).find_backend_for_model(\"gpt-5\", preferred_provider=\"openai\")routes correctly.model.md's optionalprovider:field disambiguates when multiple registered backends could plausibly own a model string.Per-provider
_get_keyhelpers already exist._llm.py:171-188defines_get_anthropic_key,_get_openai_key,_get_moonshot_keythin wrappers around the same_get_key(env_vars, keychain_name, config_key)primitive that wizard pre-flight uses. The plumbing is there; the wizard just doesn't ask which one to call.The workaround today
OpenAI-only operator path:
--from-template advisor(skips pre-flight per amended spec/35 MUST 7 carve-out).<agent>/model.md, replace Claude model strings with OpenAI ones, addprovider: openai.export OPENAI_API_KEY=....atomic-agents doctor --agent <name>to verify.Discoverable but graceless. It's the half-day-deploy friction the wizard was supposed to eliminate, just shifted to non-Claude users.
Proposed fix
Three design surfaces, none mutually exclusive:
A. Env-var autodetect (recommended primary, lowest friction). Before pre-flight runs, scan for
ANTHROPIC_API_KEY/ATOMIC_AGENTS_ANTHROPIC_KEY,OPENAI_API_KEY/ATOMIC_AGENTS_OPENAI_KEY,MOONSHOT_API_KEY/ATOMIC_AGENTS_MOONSHOT_KEY. If exactly one is set: use that provider, render templates with that provider's default model defaults, pre-flight against that provider's_get_keyhelper. If multiple are set: fall back to provider question (C below). If zero are set: error message lists all three options.B.
--provider <anthropic|openai|moonshot>flag. Explicit override for the non-interactive path. Composes with--from-template:atomic-agents init my-agent --from-template advisor --provider openai. Skips autodetect; uses the flagged provider's defaults + key check. CLI-friendly for CI / scripted workflows.C. Provider question Q0 in the interactive Q&A. If autodetect found multiple keys OR autodetect was skipped, ask the operator which provider before any other question. Show one-line plain-English descriptions: "Anthropic (Claude) / OpenAI (GPT) / Moonshot (Kimi)". Selected answer drives pre-flight + template rendering.
Template rendering with per-provider defaults. The 3 existing templates stay; their
model.mdbecomes astring.Templatewith\\${default_model}/\\${fallback_model}/\\${provider}variables. The wizard supplies provider-specific defaults at render time:The model defaults per-provider should be declared as a single constant table in
constants.pyso the cost guardrails (daily_cap_usd/monthly_cap_usd) can also vary per provider where unit cost differs significantly (e.g. opus-4-7 vs gpt-5 pricing).Spec/35 amendment. MUST 7's API-key pre-flight wording becomes provider-aware ("matching the configured provider" not "Anthropic"). New MUST documenting provider-selection precedence (
--providerflag > env-var autodetect > Q0 question > error).Acceptance
atomic-agents init my-agent --from-template advisor --provider openaiscaffolds an OpenAI-shaped advisor with one command and nomodel.mdediting.OPENAI_API_KEY=... atomic-agents init my-agent(no--providerflag) autodetects and scaffolds an OpenAI-shaped agent.ANTHROPIC_API_KEY=... OPENAI_API_KEY=... atomic-agents init my-agenttriggers Q0 provider question.test_smoke_from_template_openai,test_smoke_from_template_moonshot,test_smoke_env_var_autodetect_when_single_key_set.Why this is higher leverage than other wizard follow-ups
--ai-assist): ai-assist polishes an existing flow for Claude users; this enables non-Claude users to use the wizard at all.Scope discipline
Out of scope for this issue:
model.md) — possible today viamodel.mdif both provider keys are set, but not a wizard concern.Effort estimate
--providerflag + per-provider template constants + 3 smoke tests + spec/35 MUST 7 amendment: ~1 day of CC time with 2-3 adversarial rounds, similar shape to PR 2 of arc.