feat(cli): add docker agent setup wizard, offered when no model is usable (phase 3 of #3442)#3499
Merged
Conversation
…urce Write-side counterparts of the read-side secret providers, for the setup wizard: macOS Keychain (security -i, value over stdin, never in argv), pass (insert -e -f, value over stdin), and an env file at ~/.config/cagent/.env (0600, atomic write, upsert preserving other lines). The config env file becomes a default secret source (config-env-file, between run-secrets and credential-helper) so stored keys resolve on every run without flags and show up in docker agent doctor. A missing file is skipped; a malformed one logs a warning instead of blocking the chain, unlike an explicit --env-from-file which stays fatal.
Same pull as the run path (skip when the model exists locally, recover once from a corrupted partial download) but without the interactive confirmation, for callers that already obtained consent such as the setup wizard.
…able Phase 3 of #3442. docker agent setup walks either path interactively: pick a cloud provider, paste its API key (hidden input) and choose where to store it (Keychain, pass, or the docker agent env file), or check Docker Model Runner and pull a local model. Ends with a ready-to-copy docker agent run line. When an interactive run finds no usable model (auto selection fell through, DMR not installed, or missing model credentials), the failure is printed and the wizard offered, decline-able; on success the run is retried once. Non-TTY and --exec runs are unchanged, and DOCKER_AGENT_NO_SETUP=1 / CAGENT_NO_SETUP=1 suppress the offer for scripted terminals. Declining returns a one-line error instead of repeating the full failure text. The no-usable-model errors (AutoModelFallbackError, RequiredEnvError, the first_available variant, doctor's issue line) now name docker agent setup so non-interactive failures point at the same fix.
dgageot
approved these changes
Jul 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 3 of #3442: a guided path from "no API key" to a working model. Complements Phase 1 (#3452, actionable errors) and Phase 2 (#3489,
docker agent doctor). Phase 4 (docs tutorial) stays a follow-up.What it does
Issue expectations vs implementation
term.ReadPassworddmr.ListModels(doctor) and a newdmr.Pull(run-path pull minus the second confirmation)docker agent runline--model provider/modelvariant and adoctorpointerdocker agentor an interactive run finds no usable model (TTY only, decline-able)AutoModelFallbackError,dmr.ErrNotInstalled,RequiredEnvErrorwith missing model credentials, and thefirst_availablevariant; retries the run once after a successful setupOpen questions from the issue, resolved here
setupstores keys by default (keychain on macOS, pass on Linux, fallback~/.config/cagent/.env?)passwhen installed, env file always last (plain text, labeled as such). For the env file to be useful it becomes a default secret source (config-env-file, betweenrun-secretsandcredential-helper): read on every run, reported bydoctor. Missing file skipped; malformed file logs a warning instead of blocking the chain (an implicit file must not lock every command out, unlike an explicit--env-from-file, which stays fatal per Phase 1)setupon first run before the tour, or only on failure?Sample session
Implementation notes
pkg/environment/store.go:SecretStoreinterface + Keychain (security -i, command over stdin so the value never reaches argv,-Uupdates the item on re-runs), pass (insert -e -f, value over stdin), env file (0600, atomic write, upsert preserving comments and unrelated lines). Store names match the source names so the wizard and the doctor never diverge (asserted by a test).cmd/root/setup.go: the command and the wizard behind test seams (scripted answers, fake stores, fake DMR); a failed store re-offers the locations without re-asking the key; EOF/Ctrl+C cancel cleanly.AutoModelFallbackError,RequiredEnvError,first_availablevariant, doctor issue line) now namedocker agent setup, so non-TTY failures point at the same fix as the interactive offer.setup; secrets guide gains theconfig-env-filesource (table, section, precedence).Validation
go build ./...go testoncmd/...,pkg/environment,pkg/config,pkg/model/provider/dmr,pkg/cliTestURLSource_Read_RejectsLocalAddressesandTestLoadExamplesfail onmaintoo in this sandboxed network)golangci-lint runon touched packagesgo run ./lint .docker agentandrun(decline: concise error, exit 1; accept: wizard, retry, TUI starts),DOCKER_AGENT_NO_SETUP=1suppression, non-TTYsetuperrors with exit 1