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.

Diagram

First-run Onboarding

πŸ“‹ User Request

βš™οΈ First-run Onboarding

βœ… Result

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.

python
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.

Diagram

First-run Onboarding

πŸ“ First Launch

πŸ” Detect Credentials

βš™οΈ Setup Wizard

πŸ€– Verified Agent

βœ… Working Prompt

Onboarding Flow

Diagram

Yes

No

Yes

No

No

Yes

Detected

Nothing detected

fail

pass

πŸš€ praisonai / run / code / chat

Cloud key
configured?

βœ… Run normally

Local endpoint
reachable?

πŸ–₯️ Use local model
print stderr notice β†’ continue

Interactive TTY?

❌ exit 1 with guidance

πŸ§™ Setup Wizard

Provider key
in env?

Confirm: Use Anthropic? [Y/n]

Provider menu

⌨️ Enter key

validate_api_key

πŸ’Ύ Persist to ~/.praisonai/.env

πŸ§ͺ Agent.start(‘Say hello in one sentence’)

βœ… Verified β€” prints reply

Quick Start

  1. Run praisonai without any setup
    bash
    praisonai

    If 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.

  2. 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 (permissions 0600). Legacy ~/.praison/credentials.json is still read as a fallback and migrated automatically on the next write β€” no re-login required.

  3. 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.

  1. Auto-detect a key you already have

    If a *_API_KEY is 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 n to 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 provider ModelCatalogue knows about (Groq, OpenRouter, Mistral, DeepSeek, xAI, …), curated ones first and custom last.

    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.
  2. Validate the key before it persists

    Entered keys run through the same validate_api_key() check as praisonai 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.

  3. 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 doctor to 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.

Diagram
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
    end

Credential detection order

StepWhat is checkedExample
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, Ollamaexport MISTRAL_API_KEY=...
2. Zero-disk env blobPRAISONAI_AUTH_CONTENT β€” a full JSON credential store loaded in memory (CI / containers), preferred over diskexport PRAISONAI_AUTH_CONTENT='{...}'
3. Credential store~/.praisonai/credentials.json written by praisonai setup (also mirrored to ~/.praisonai/.env)praisonai setup
4. LLM resolutionresolve_llm_endpoint_with_credentials() β€” final fallbackStored OpenAI base URL
5. Keyless local-firstpraisonai_code.llm.local_detect.detect_local_model() β€” probes OPENAI_BASE_URL / OLLAMA_HOST / 127.0.0.1:11434 when no cloud key is setAny running Ollama server auto-adopted
6. Setup wizard auto-detectionAny catalogued provider key, offered as pre-selected default when the user is inside the wizardDetected 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.

ScenarioBehaviour
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, TTYPrints 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, headlessAdopts the detected local model + base URL for this run; the run proceeds.
No cloud key, no local endpoint, TTYSetup 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, headlessExit 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:

EntrypointHeadless when…
praisonai runnot sys.stdin.isatty() OR --output json
praisonai code-p / --print OR piped stdin (non-TTY)
praisonai chat--json OR piped stdin (non-TTY)
Bare praisonainot 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 praisonai and interactive praisonai chat (no prompt) run the gate only when the wrapper is available. On a bare praisonai-code install, the gate is skipped and the TUI shows its own hint.
  • Single-prompt chat "…" and every praisonai code invocation 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 $?
1

Keyless + 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.

python
# 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:

bash
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):

OrderSourceNotes
1OPENAI_BASE_URLAny OpenAI-compatible base URL (a trailing /v1 is stripped before the /api/tags probe)
2OLLAMA_HOSTA bare host:port gets an http:// prefix automatically
3http://127.0.0.1:11434Default 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 answeredModel id labelExample server
Ollama /api/tagsollama/<name>ollama/llama3.2:latest
OpenAI-compatible /v1/modelsopenai/<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

yaml
- 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:

yaml
- name: Run PraisonAI agent (local model)
  run: praisonai run "Summarize the changelog"
  env:
    OLLAMA_HOST: http://ollama:11434

Skipping the Prompt

Several ways to avoid the setup prompt:

MethodCommand / Action
Set an env varexport OPENAI_API_KEY=sk-...
Run setup ahead of timepraisonai setup
Have a local Ollama runningollama serve (auto-detected, no explicit flag needed)
Inject a zero-disk store (CI)export PRAISONAI_AUTH_CONTENT='{...}' β€” see below
Answer “No” at the promptType 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:

yaml
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