First-run Onboarding
Auto-detects missing credentials and routes new users into the setup wizard
PraisonAI leads you to a verified, working agent in as few keystrokes as possible β auto-detecting any provider key you already have or a locally-running model (e.g. Ollama) reachable on the machine, validating the one you enter, and smoke-testing before it hands back the prompt.
praisonai --init is now safe to run before setup β if no provider is configured it prints provider guidance and exits cleanly rather than throwing a stack trace. Either order works for onboarding.
from praisonaiagents import Agent
agent = Agent(name="onboarding-agent", instructions="Guide new users through setup.")
agent.start("Walk me through setting up PraisonAI for the first time.")The user launches PraisonAI without API keys; the CLI uses a reachable local model if one is running, otherwise offers the setup wizard instead of failing on the first model call.
All four LLM-bound entrypoints β praisonai (bare), praisonai run, praisonai code, and praisonai chat β route their first-run check through the same shared helper, so a keyless newcomer is offered the wizard (or a clean hint) from any first command.
Onboarding Flow
Quick Start
- Run praisonai without any setup
bash praisonaiIf no cloud credentials are configured and no local model is reachable, you’ll see:
No API key configured. Would you like to run the setup wizard now? [Y/n]:Type
Y(or press Enter) to launch the setup wizard. - Complete setup once
The setup wizard asks for your provider and API key, then stores the credential securely:
bash praisonai setup # Choose from a catalogue-driven menu: OpenAI, Anthropic, Google, Ollama, Groq, # OpenRouter, Mistral, DeepSeek, xAI, β¦ (curated first, Custom last) # Enter your API key when prompted (a "Get your key" hint prints first)Credentials are stored in
~/.praisonai/credentials.json(permissions0600). Legacy~/.praison/credentials.jsonis still read as a fallback and migrated automatically on the next write β no re-login required. - Re-run β no prompts after the first time
bash praisonai "What is 2+2?" # Runs immediately β no credential prompt
Wizard flow (post-#2680)
The wizard moves through three stages: auto-detect, validate, and smoke-test.
- Auto-detect a key you already have
If a
*_API_KEYis already exported, the first prompt is a confirmation β not a numeric menu:Detected ANTHROPIC_API_KEY in your environment. Use Anthropic (claude-sonnet-4-20250514)? [Y/n]:Answer
nto fall through to the full provider menu. The pre-selection surface is no longer four keys β the wizard auto-detects any catalogued credential env var (the full 14-row table), including Together (TOGETHER_API_KEY/TOGETHERAI_API_KEY) and Fireworks (FIREWORKS_API_KEY/FIREWORKS_AI_API_KEY) aliases. The provider menu only appears when no key is detected, and is catalogue-driven β it lists every providerModelCatalogueknows about (Groq, OpenRouter, Mistral, DeepSeek, xAI, β¦), curated ones first andcustomlast.Just having a catalogued key set is enough β no wizard, no
--model:Mistral
python # Only MISTRAL_API_KEY set in the environment β no wizard, no --model needed. from praisonaiagents import Agent agent = Agent(name="assistant", instructions="Answer briefly.") agent.start("Say hello in one line.") # Uses mistral/mistral-large-latest automatically.DeepSeek
python # Only DEEPSEEK_API_KEY set in the environment. from praisonaiagents import Agent agent = Agent(name="assistant", instructions="Answer briefly.") agent.start("Say hello in one line.") # Uses deepseek/deepseek-chat automatically.Fireworks
python # Only FIREWORKS_AI_API_KEY set β the alias is honoured. from praisonaiagents import Agent agent = Agent(name="assistant", instructions="Answer briefly.") agent.start("Say hello in one line.") # Uses fireworks_ai/accounts/fireworks/models/llama-v3p3-70b-instruct automatically. - Validate the key before it persists
Entered keys run through the same
validate_api_key()check aspraisonai auth login. A bad key re-prompts instead of silently writing a broken credential:2. Enter your OpenAI API key: Enter API key (hidden): Invalid API key for OpenAI: OpenAI keys start with "sk-" Try again? [Y/n]: y Enter API key (hidden):After up to three attempts the wizard proceeds with the last entry so you’re never stuck in a loop.
- Smoke-test before handing back the prompt
After the config is written, the wizard runs one live call and prints the reply:
Verifying your setup... β Verified β your agent is working! Hello! How can I help you today?A failed smoke test is a warning, not an error β your config is already saved, so you can run
praisonai doctorto diagnose the key or model.
How It Works
praisonai (bare), praisonai run, praisonai code, and praisonai chat all perform the same credential check before doing any work β each one delegates to the shared ensure_configured_or_onboard() helper.
Shared onboarding helper
Every entrypoint funnels its first-run check through one choke point, ensure_configured_or_onboard(*, model, interactive) in praisonai_code/llm/credentials.py. It returns the model unchanged when already configured, adopts a reachable local endpoint (with a one-line stderr notice) when keyless and no explicit model is set, exits 1 with Run: praisonai setup when keyless and headless, and offers the setup wizard when keyless in an interactive TTY. Because all four commands share it, onboarding behaviour is identical no matter which command a newcomer types first.
sequenceDiagram
participant User
participant CLI
participant CredCheck as Credential Check
participant Store as CredentialStore
participant Detector as Local Detector
participant Wizard as Setup Wizard
participant LLM
User->>CLI: praisonai run "hello"
CLI->>CredCheck: is_configured()?
CredCheck->>CredCheck: Check env vars
CredCheck->>Store: Check ~/.praisonai/credentials.json
Store-->>CredCheck: Not found
CredCheck-->>CLI: False
CLI->>Detector: detect_local_model()
alt Local endpoint reachable
Detector-->>CLI: LocalModel(ollama/llama3.2, base_url)
CLI->>User: stderr: "No cloud key found; using local model ollama/llama3.2 β¦"
CLI->>LLM: run against local base URL
LLM-->>User: response
else No local endpoint β is TTY?
Detector-->>CLI: None
alt TTY β interactive
CLI->>User: "No API key configured. Run setup wizard? [Y/n]"
User->>CLI: Y
CLI->>Wizard: praisonai setup
Wizard-->>CLI: Credentials stored
Wizard->>LLM: Agent.start("Say hello in one sentence")
LLM-->>Wizard: reply
Wizard->>User: prints reply + β
Verified
CLI->>User: Continues with run
else non-TTY / --quiet / --output json
CLI->>User: stderr: "No API key configured. Run: praisonai setup"
CLI->>CLI: exit 1
end
endCredential detection order
| Step | What is checked | Example |
|---|---|---|
| 1. Env vars (fast path) | Any catalogued provider key from PROVIDER_ENV_CATALOGUE β OpenAI, Anthropic, Google/Gemini, Groq, Cohere, OpenRouter, Mistral, DeepSeek, xAI, Together, Perplexity, Fireworks, Ollama | export MISTRAL_API_KEY=... |
| 2. Zero-disk env blob | PRAISONAI_AUTH_CONTENT β a full JSON credential store loaded in memory (CI / containers), preferred over disk | export PRAISONAI_AUTH_CONTENT='{...}' |
| 3. Credential store | ~/.praisonai/credentials.json written by praisonai setup (also mirrored to ~/.praisonai/.env) | praisonai setup |
| 4. LLM resolution | resolve_llm_endpoint_with_credentials() β final fallback | Stored OpenAI base URL |
| 5. Keyless local-first | praisonai_code.llm.local_detect.detect_local_model() β probes OPENAI_BASE_URL / OLLAMA_HOST / 127.0.0.1:11434 when no cloud key is set | Any running Ollama server auto-adopted |
| 6. Setup wizard auto-detection | Any catalogued provider key, offered as pre-selected default when the user is inside the wizard | Detected on wizard entry, not first Agent.start() |
When no cloud key is present, PraisonAI adopts a reachable local endpoint before offering the wizard β the first praisonai run "..." works against a running Ollama on localhost:11434 with zero setup. See Keyless local-first fallback and Local Models.
Behaviour by Mode
This table applies to all four entrypoints (praisonai, run, code, chat) β they share the same ensure_configured_or_onboard() gate.
| Scenario | Behaviour |
|---|---|
| Cloud key present (env var or stored credential) | Cloud key wins β local detection never overrides. No extra prompts, no added latency. |
| No cloud key, local endpoint reachable, TTY | Prints No cloud key found; using local model <name>. Run \praisonai setup\ to add a hosted provider. on stderr and continues into the TUI / the run. |
| No cloud key, local endpoint reachable, headless | Adopts the detected local model + base URL for this run; the run proceeds. |
| No cloud key, no local endpoint, TTY | Setup wizard is offered as a non-blocking suggestion (Would you like to run the setup wizard now? [Y/n]). |
| No cloud key, no local endpoint, headless | Exit 1 with: No API key configured. Run: praisonai setup β¦ (a running local endpoint such as Ollama would be used automatically). |
Headless triggers per entrypoint
“Headless” (interactive=False) is decided per command β this is what “non-TTY” means for each:
| Entrypoint | Headless when⦠|
|---|---|
praisonai run | not sys.stdin.isatty() OR --output json |
praisonai code | -p / --print OR piped stdin (non-TTY) |
praisonai chat | --json OR piped stdin (non-TTY) |
Bare praisonai | not sys.stdin.isatty() OR --quiet |
Standalone pip install praisonai-code (no wrapper)
Two entrypoints skip the gate when the wrapper isn’t installed so the resident TUI can surface its own actionable install hint (pip install praisonai[tui]) instead of a raw “No API key configured” exit:
- Bare
praisonaiand interactivepraisonai chat(no prompt) run the gate only when the wrapper is available. On a barepraisonai-codeinstall, the gate is skipped and the TUI shows its own hint. - Single-prompt
chat "β¦"and everypraisonai codeinvocation always run the gate β no wrapper is needed to dispatch a single turn.
First command is praisonai code
A brand-new user whose first-ever command is praisonai code "add a test for foo" now lands in onboarding instead of a raw provider error.
Interactive TTY
$ praisonai code "add a test for foo"
No API key configured.
Would you like to run the setup wizard now? [Y/n]: Y
π PraisonAI Setup Wizard
Choose your LLM provider: 1
Enter API key (hidden): ****
Verifying your setup...
β
Verified β your agent is working!
[code assistant starts]Headless (-p)
$ praisonai code -p "add a test for foo" --output json
Error: No API key configured. Run: praisonai setup
or set environment variables like OPENAI_API_KEY
(a running local endpoint such as Ollama would be used automatically)
$ echo $?
1Keyless + local Ollama
$ praisonai code "add a test for foo"
No cloud key found; using local model ollama/llama3.2. Run `praisonai setup` to add a hosted provider.
[code assistant starts against local Ollama]The equivalent trio for praisonai chat uses --json for the headless line. See Chat β First-run credential gate and Code β First-run credential gate.
Keyless local-first (Ollama & OpenAI-compatible)
With a model already running locally, PraisonAI works before you configure any cloud key.
# Have Ollama running: `ollama serve` and `ollama pull llama3.2`
# Then just:
from praisonaiagents import Agent
agent = Agent(
name="assistant",
instructions="You are a helpful assistant.",
)
agent.start("Say hi")
# The CLI/wrapper detects the local endpoint. No API key set,
# no `model=` argument, no OPENAI_BASE_URL export needed.The same convenience applies straight from the terminal:
ollama serve
ollama pull llama3.2
praisonai "Summarise this repo"
# stderr: No cloud key found; using local model ollama/llama3.2. Run `praisonai setup` to add a hosted provider.Endpoint precedence
The detector resolves the endpoint to probe in this order, then hits Ollama’s native /api/tags first (falling back to the OpenAI-compatible /v1/models):
| Order | Source | Notes |
|---|---|---|
| 1 | OPENAI_BASE_URL | Any OpenAI-compatible base URL (a trailing /v1 is stripped before the /api/tags probe) |
| 2 | OLLAMA_HOST | A bare host:port gets an http:// prefix automatically |
| 3 | http://127.0.0.1:11434 | Default Ollama endpoint when neither variable is set |
Model id labels
The detected model id carries a provider prefix so it routes to the right path:
| Probe that answered | Model id label | Example server |
|---|---|---|
Ollama /api/tags | ollama/<name> | ollama/llama3.2:latest |
OpenAI-compatible /v1/models | openai/<id> | llama.cpp Β· LM Studio Β· vLLM |
See also Keyless Local-First Run for the full deep-dive.
CI / Scripting
In non-interactive environments with no credentials and no reachable local endpoint, PraisonAI exits with code 1 and writes to stderr:
No API key configured. Run: praisonai setup
(a running local endpoint such as Ollama would be used automatically)The second line is a reminder that a reachable local endpoint (Ollama or any OpenAI-compatible server) is adopted automatically β see Keyless Local-First Run.
Non-interactive detection: not sys.stdin.isatty() or --output json mode.
GitHub Actions example
- name: Run PraisonAI agent
run: praisonai run "Summarize the changelog"
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}Setting any of the detected cloud provider env vars silences the check completely β no code changes needed.
Keyless CI with an in-cluster Ollama sidecar
A CI runner that ships an Ollama sidecar can run keylessly by pointing OLLAMA_HOST at it β no cloud secret required:
- name: Run PraisonAI agent (local model)
run: praisonai run "Summarize the changelog"
env:
OLLAMA_HOST: http://ollama:11434Skipping the Prompt
Several ways to avoid the setup prompt:
| Method | Command / Action |
|---|---|
| Set an env var | export OPENAI_API_KEY=sk-... |
| Run setup ahead of time | praisonai setup |
| Have a local Ollama running | ollama serve (auto-detected, no explicit flag needed) |
| Inject a zero-disk store (CI) | export PRAISONAI_AUTH_CONTENT='{...}' β see below |
| Answer “No” at the prompt | Type n β exits 0 with a hint to run praisonai setup |
| Run headless keyless (fail-fast) | code -p / --print, or chat --json β exits 1 with Run: praisonai setup (not “skipping” β this is how headless behaves on a keyless run) |
Default model on first run
If you run a command like praisonai chat without --model on first use, PraisonAI picks a default that matches the provider credential it finds in your environment β Anthropic key β Claude, Gemini key β Gemini Flash, etc. The picker now selects a provider-appropriate model for Mistral, DeepSeek, xAI, Together, Perplexity, and Fireworks too (see the full 14-row table). When no cloud key is present, resolve_default_model() prefers a reachable local model (e.g. ollama/llama3.2) before falling back to the terminal default (gpt-4o-mini). A cloud-key provider always wins over the local model. See Default Model Resolution for the full ladder.
Run praisonai config provenance run.model any time to see which rung the resolver picked and why β see config provenance.
Best Practices
In CI, set credentials before invoking
Set OPENAI_API_KEY (or the provider key for your model) as a repository secret, then reference it in your workflow env block. This is the recommended approach β no credential files in your repo, no interactive prompts:
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}Prefer stored credentials over env vars for shared machines
On shared developer machines, stored credentials (praisonai setup) are scoped to the user’s home directory and avoid environment variable leakage between sessions. Run praisonai setup config --show to verify what is stored.
Test your setup with a quick prompt before piping through automation
Run praisonai run "ping" manually before wiring the command into a pipeline or CI job. A successful response confirms credentials are configured and the model is reachable.
Skip the smoke test in CI
The smoke test is convenient locally but wastes a token round-trip in CI. Skip it with --no-verify on both setup and setup wizard.
Related
Interactive wizard for configuring LLM provider credentials
Run CommandRun agents from files or prompts
Code CommandCode assistant β first-run credential gate
Chat CommandChat mode β first-run credential gate
Keyless Local-First RunZero-config runs against a local Ollama or OpenAI-compatible model