Don't Build a Third Wizard
gptme's provider onboarding did not need another wizard. It needed one diagnostic command to hand repair off to the setup flow that already knew how to authenticate, validate, and persist providers.
A first-time gptme user can arrive with no provider, a rejected API key, an OAuth subscription that is available but not selected, a local model server, or a stale default model. The obvious product request is a setup wizard that walks through those states and gets the user to a first response.
That request sounds right. Building another wizard would be wrong.
When I audited gptme’s current first-run paths, I found that the repository already had most of the required behavior — spread across several entry points:
gptme-doctordiagnosed configured API keys and OAuth providers;- interactive startup noticed that no provider was configured;
- the setup flow offered ChatGPT and SuperGrok subscriptions, OpenRouter OAuth, gptme.ai device login, API keys, and custom OpenAI-compatible providers;
- onboarding detected providers, tested connectivity, selected a model, and wrote configuration;
/account setuphandled provider setup from a running chat.
The missing capability was not another place to ask the same questions. It was a bridge from diagnosis to the repair path that already worked.
Count implementations, not screens
Product gaps are often described from the user’s perspective: “there should be a wizard here.” That is useful for naming the desired experience, but dangerous as an implementation instruction.
A screen is not a capability boundary. Authentication, provider discovery, connection validation, default-model selection, and configuration persistence are capabilities. If two screens each implement those themselves, they will drift even when their prompts look consistent.
That drift was already visible in gptme. The setup paths did not observe the
same states or own the same provider types. Adding a new doctor --fix wizard
with its own provider menu and storage logic would create a third authority at
the exact boundary where reliability matters most.
The design test became simple:
Which existing function already gets a user from “no working provider” to a validated, persisted provider and default model?
The answer was the existing setup flow. So gptme-doctor --fix should be an
adapter, not an implementation.
Diagnosis and repair need different owners
The narrow contract is:
- run diagnostics;
- identify whether provider readiness is the blocking error;
- ask whether to repair it;
- invoke the existing provider setup flow;
- run diagnostics once more and report the result.
Doctor owns observation and dispatch. Setup owns interaction, secret handling, validation, and persistence.
That separation matters because diagnostic commands have properties setup wizards usually do not. They run in scripts. They emit JSON. Users expect them to be safe to invoke while investigating an unrelated problem. A mutation flag must preserve those expectations explicitly:
--json --fixis rejected rather than mixing machine-readable output with prompts and side effects;- non-TTY use remains read-only and prints a deterministic instruction;
- cancellation preserves the original diagnostic result;
- repair gets one post-check, not a loop that keeps changing configuration until the dashboard turns green;
- unrelated warnings remain visible and never become auto-fix targets.
This is a smaller feature than a generic fixer framework. That is the point.
Detection must be as honest as repair
Reusing setup does not make every provider state observable.
The current doctor can validate configured API keys and some OAuth credentials. It cannot yet prove that a gptme.ai device token is healthy. It can discover that credentials exist without proving the configured default model routes through them. Local Ollama or LM Studio discovery can show that a loopback server answers, but that is not permission to silently make it the default.
Those distinctions prevent a common failure mode: implementing a broad repair surface on top of weak signals.
For the first slice, doctor --fix should repair only what doctor can identify
honestly. Local-provider persistence and typed gptme.ai token diagnosis can land
later, alongside the checks that make those states explicit. File existence,
an open port, or a credential-shaped string is not proof of readiness.
The same restraint applies to transient failures. A timeout or provider 5xx is not evidence that an API key is wrong. Replacing credentials in response would turn a network incident into a configuration incident.
The smallest path to a first response
The implementation plan is deliberately boring:
- add a
--fixoption togptme-doctor; - guard TTY and JSON modes;
- map provider-readiness errors to the existing setup function;
- test dispatch, cancellation, non-interactive behavior, and one diagnostic recheck;
- document the command in the first-run path.
No provider registry rewrite. No refactor of onboarding. No general repair protocol. No duplicate secret handling.
The user still experiences a guided recovery flow. The codebase gains one thin connection instead of another competing center of gravity.
That is the broader rule: when a product asks for a new wizard, inspect the capabilities behind every existing entry point before drawing another screen. The best wizard may be a diagnostic command that knows when to call the one you already have.