Skip to content

feat: interactive provider wizard (/setup, claw setup, Ctrl+P)#2810

Open
TheArchitectit wants to merge 18 commits into
ultraworkers:mainfrom
TheArchitectit:feat/provider-wizard
Open

feat: interactive provider wizard (/setup, claw setup, Ctrl+P)#2810
TheArchitectit wants to merge 18 commits into
ultraworkers:mainfrom
TheArchitectit:feat/provider-wizard

Conversation

@TheArchitectit
Copy link
Copy Markdown

@TheArchitectit TheArchitectit commented Apr 26, 2026

Summary

Adds an interactive provider wizard so users can configure their AI provider, API key, base URL, and model without manually editing config files or setting environment variables. Settings persist across sessions in ~/.claw/settings.json.

Three ways to access the wizard:

  • claw setup — CLI subcommand
  • /setup — slash command inside the REPL
  • Ctrl+P — hotkey inside the REPL (inserts [Provider Swap] prompt, press Enter to confirm)

Problem this solves

No way to configure providers without environment variables

Before: the only way to set your provider, API key, base URL, or model was via environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY, OPENAI_BASE_URL, etc.) or manually editing a settings file. There was no guided setup — users had to read docs, figure out which env vars to set, and hope they got the names right. Switching providers mid-session required exiting, setting new env vars, and restarting.

Fix: The interactive wizard walks users through provider selection, API key entry, base URL (for OpenAI-compat), and model name — all with prompts and validation. Settings persist in ~/.claw/settings.json, so they survive across sessions. Ctrl+P enables in-session provider hot-swap without restarting.

No persistent auth — re-enter credentials every session

Before: API keys entered as environment variables are lost when the terminal closes. There was no way to save them persistently without editing shell profiles. Users who don't use .env files or shell rc files had to export keys every time.

Fix: The wizard saves all settings (including API key) to ~/.claw/settings.json with 0o600 permissions. Auth resolution follows a three-tier priority: env var > .env file > stored config. Environment variables always win, so power users aren't blocked.

Model written under wrong JSON key

Before: save_user_provider_settings() wrote model nested under the provider object in settings.json, but the config reader expected it at the top level. This meant the model selection from the wizard was silently ignored on next startup.

Fix: model is now written at the top level of settings.json alongside the provider block, matching what the config reader expects.

How it works

Three-tier auth resolution

read_env_or_config() checks in order:

  1. Environment variable (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.)
  2. .env file in the current directory
  3. Stored config from ~/.claw/settings.json

How Ctrl+P works

Rustyline cannot chain commands or show popup menus. The implementation:

  1. Ctrl+P inserts invisible sentinel character \x01
  2. The Highlighter replaces it with a cyan [Provider Swap] label so the user sees feedback
  3. User presses Enter → read_line() returns ReadOutcome::ProviderSwap
  4. The REPL loop calls run_setup_wizard(), then hot-swaps the model and reprints the connection line

Persistence

Settings are stored in ~/.claw/settings.json:

{
  "provider": {
    "kind": "xai",
    "apiKey": "xai-...",
    "baseUrl": "https://api.x.ai/v1"
  },
  "model": "grok-4"
}

File is created with 0o600 permissions. All provider fields are optional — only set values are written.

Files changed

File What changed
runtime/src/config.rs RuntimeProviderConfig struct, save_user_provider_settings(), clear_user_provider_settings(), I/O helpers. Model written at top level, not nested under provider.
runtime/src/config_validate.rs provider top-level field + PROVIDER_FIELDS constant (kind, apiKey, baseUrl, model) for validation
api/src/providers/mod.rs provider_config_value(), read_env_or_config() (3-tier fallback), stored_provider_kind(), updated detect_provider_kind()
api/src/providers/anthropic.rs read_env_non_empty()read_env_or_config()
api/src/providers/openai_compat.rs Same change as anthropic.rs
commands/src/lib.rs SlashCommand::Setup variant, spec, validation
rusty-claude-cli/src/setup_wizard.rs New file (~226 lines). Interactive wizard: provider selection, API key, base URL, model prompts
rusty-claude-cli/src/input.rs ReadOutcome::ProviderSwap variant, Ctrl+P → sentinel char + [Provider Swap] highlight, Enter to confirm
rusty-claude-cli/src/main.rs CliAction::Setup, /setup REPL handler with model hot-swap, Ctrl+P→wizard dispatch

Test plan

  • cargo test --workspace — all tests pass
  • cargo clippy --workspace --all-targets -- -D warnings — clean
  • claw setup — wizard runs interactively, saves to ~/.claw/settings.json
  • /setup in REPL — wizard runs, model hot-swaps, connection line reprints
  • Ctrl+P in REPL — shows [Provider Swap], Enter launches wizard
  • Start REPL without env vars but with stored config — auth works from stored config
  • Start REPL with env vars AND stored config — env vars take priority
  • Non-interactive terminal — claw setup errors with clear message
  • model field read correctly from top level of settings.json on startup

💘 Generated with Crush

@TheArchitectit TheArchitectit marked this pull request as draft April 26, 2026 21:24
@TheArchitectit TheArchitectit marked this pull request as ready for review April 26, 2026 22:38
code-yeongyu added a commit to code-yeongyu/claw-code-1 that referenced this pull request Apr 28, 2026
code-yeongyu added a commit to code-yeongyu/claw-code-1 that referenced this pull request Apr 28, 2026
code-yeongyu added a commit to code-yeongyu/claw-code-1 that referenced this pull request Apr 28, 2026
code-yeongyu added a commit to code-yeongyu/claw-code-1 that referenced this pull request Apr 29, 2026
itwizardo pushed a commit to itwizardo/hackcode that referenced this pull request Apr 30, 2026
TheArchitectit and others added 17 commits May 10, 2026 21:27
When the model API returns a context_window_blocked error (because the request
exceeds the model's context window), the CLI now automatically:

1. Compact the session (remove old messages to free up space)
2. Retry the original request with the compacted session
3. Report results to the user

This eliminates the need for users to manually run /compact when they
hit context limits - the recovery happens automatically.

## Technical Details

- Detection: Looks for 'context_window' or 'Context window' in error message
- Uses runtime::compact_session() to aggressively compact (max_estimated_tokens=0)
- Creates new runtime with compacted session and retries the turn
- Reports compaction results and final status to user

## Testing

Tested successfully with a request that exceeded model's context:
- Auto-compact triggered: 'Messages removed 19, Messages kept 5'
- Successfully retried and completed after compaction
…rl+P

Adds an interactive setup wizard that lets users configure their provider,
API key, base URL, and model without setting environment variables.
Configuration is persisted to ~/.claw/settings.json (with 0600 permissions).

New features:
- `claw setup` CLI subcommand runs the wizard from the terminal
- `/setup` slash command runs the wizard inside the REPL (hot-swaps model)
- Ctrl+P hotkey in the REPL triggers /setup for in-session provider swap
- Stored provider config used as fallback when env vars are absent
- Three-tier auth resolution: env var > .env file > stored config
- RuntimeProviderConfig struct and validation in settings schema

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Ctrl+P now inserts a sentinel char (\x01) that the highlighter renders
as a cyan "[Provider Swap]" prompt. User presses Enter to confirm and
launch the setup wizard. Returns ReadOutcome::ProviderSwap so the REPL
loop can hot-swap the model and reprint the connection line.

Also fixes clippy warnings: merged duplicate match arms in
provider_config_value, doc_markdown on ProviderKind, map_unwrap_or
idioms in setup_wizard.rs, and pre-existing clippy issues in main.rs
and commands/lib.rs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Previously /resume latest only searched the current workspace's
fingerprinted session directory. If you started claw from a different
directory, it found zero sessions even though sessions existed
elsewhere on disk.

Changes:
- Add global_sessions_root() pointing to ~/.claw/sessions/
- Add scan_global_sessions() to scan all workspace namespaces
- Modify latest_session() to fall back to global scan when no
  workspace-local sessions are found
- Add load_session_loose() that skips workspace validation for
  alias references (latest/last/recent) so cross-workspace resume
  works while still enforcing workspace check for explicit IDs
- Wire load_session_loose() into CLI's load_session_reference()
- Add provider field to config validation schema (needed because
  user's settings.json already has the provider key)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous implementation only scanned ~/.claw/sessions/ for the
global fallback, but sessions are actually stored in the project-local
<cwd>/.claw/sessions/<fingerprint>/ by SessionStore::from_cwd().
Now scans both the global root and the project-local parent directory
(checking all fingerprint subdirs) so /resume latest finds sessions
regardless of where they're stored.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Previously /resume latest returned the most recently created session,
which was always the empty one just created on startup. Now it skips
sessions with 0 messages and excludes the current session ID, so it
finds the previous session with actual conversation history.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ider

The setup wizard wrote `model` inside the `provider` object, but
`parse_optional_model` reads it from the top level. This caused the
model setting to be silently ignored after `claw setup`.

Also clean up the top-level `model` key when clearing provider settings.
claw setup now asks for a subagentModel (smaller/cheaper model for
Agent subtasks) after the main model prompt. The value is written to
~/.claw/settings.json as subagentModel.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Some OpenAI-compatible providers (e.g., GLM-5) omit the `id` field in
streaming and non-streaming responses. Adding #[serde(default)] allows
the parser to accept these responses instead of failing with
"missing field `id`".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds scripts/install.sh that builds the release binary and links it
to ~/.local/bin/claw. Run after code changes to update the CLI.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When a provider returns HTML (e.g., error page, wrong endpoint) instead
of JSON in an SSE stream, provide a clear error message instead of
hanging or failing with a cryptic parse error.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When a provider returns a JSON error (e.g., {"error":{"message":"..."}})
without SSE framing (no "data:" prefix), the SSE parser was silently
ignoring it and hanging. Now detects and surfaces these errors.

Also handles HTML responses that lack SSE framing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Some providers (GLM, DeepSeek) emit reasoning tokens in `reasoning_content`
or nested `thinking.content` fields instead of `content`. Added support
for these fields so reasoning models work correctly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The final streaming chunk from some providers contains only finish_reason
and usage, with no delta field. Made it optional to prevent parse errors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When preserve_recent_messages == 0, raw_keep_from equals messages.len(),
causing index out of bounds when accessing session.messages[k].

Added k >= session.messages.len() check to prevent panic.

Reason: Compaction with preserve_recent_messages=0 triggered OOB access
when checking for tool-use/tool-result pair preservation at boundary.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@TheArchitectit TheArchitectit force-pushed the feat/provider-wizard branch from 5e728d7 to 9f58553 Compare May 10, 2026 21:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant