CLI Configuration

One config, every project: layered, project-aware defaults for the praisonai CLI

The praisonai CLI reads defaults from a layered hierarchy so you can set a model once and have it work everywhere — globally, per project, or per command.

python
from praisonaiagents import Agent

agent = Agent(name="assistant", instructions="Use project defaults from .praisonai/config.yaml.")
agent.start("What model am I using?")

The user sets a default model in config once; every praisonai command in that project picks it up without repeating flags.

Diagram

Configuration Precedence (highest wins)

⚡ CLI flags

🌱 Per-key env vars
PRAISONAI_MODEL, …

📦 Env config
PRAISONAI_CONFIG_CONTENT
or PRAISONAI_CONFIG

📁 Project config
.praisonai/config.yaml

🏠 Global config
~/.praisonai/config.yaml

🏢 Managed defaults

📋 Built-in defaults

Quick Start

  1. Set a default model
    bash
    praisonai config set agent.model gpt-4o-mini
  2. Run any agent
    bash
    praisonai run "Summarise this README"

    The model from config is picked automatically — no --model flag needed.

  3. Inspect what was resolved
    bash
    praisonai config show --sources

When you praisonai run, CLI defaults flow into the agent automatically:

python
from praisonaiagents import Agent

# Model, temperature, and tools come from resolved CLI config
agent = Agent(name="assistant", instructions="Be helpful.")
# praisonai run "..." uses agent.model from ~/.praisonai/config.yaml or project config

How It Works

Diagram
AgentProject configConfigResolverpraisonai CLIUserAgentProject configConfigResolverpraisonai CLIUserpraisonai run “task”resolve_config()walk-up cwd → git root OR $HOME.praisonai/config.yamlmerged ResolvedConfigagent.model, temperature, toolsresponse

Layers are deep-merged. Lists are concatenated. Scalars are overridden by higher layers.

LayerSourcePrecedence
1Built-in defaultsLowest
2Global ~/.praisonai/config.yaml (+ legacy paths)
3Project config (walk-up to git root or $HOME, whichever comes first)
4Environment variables
5CLI flagsHighest

Project vs Global Config

LocationScopeCommit to repo?
~/.praisonai/config.yamlAll projects on this machineNo
./.praisonai/config.yamlThis project (and subdirectories)Yes
./praisonai.yaml / ./praisonai.ymlCanonical project configYes
./praison.yaml / ./praison.ymlLegacy fallback (backward compat, still discovered)Yes
./.praison/config.tomlLegacy TOML (backward compat)Optional †

† When placed directly at $HOME, .praison/config.toml is loaded once as global: (never as project:).

Walk-up discovery searches, at each directory from cwd up to the git root or $HOME (whichever comes first). At $HOME the legacy .praison/config.toml name is skipped — that file is owned by the global loader:

  1. .praisonai/config.yaml
  2. .praisonai/config.yml
  3. praisonai.yaml / praisonai.yml (canonical project-root config, added in PR #3422)
  4. praison.yaml / praison.yml (legacy fallback, discovered for backward compat)
  5. .praison/config.toml (legacy)
yaml
# .praisonai/config.yaml — commit this to your repo
agent:
  model: claude-sonnet-4-6
  temperature: 0.3
  max_tokens: 16000
  tools:
    - search_web
    - read_file
bash
# Anywhere inside the repo (including subdirs):
praisonai run "Find recent benchmarks for retrieval-augmented generation"
# Uses claude-sonnet-4-6 automatically — no --model flag needed

Walk-up Boundaries

Walk-up stops at the nearer of two boundaries: a .git-marked directory or $HOME.

Diagram

Walk-up boundaries (first match wins)

📁 cwd

📁 parent

📁 .git boundary 🛑

🏠 $HOME boundary 🛑

  • The walk stops at the nearer of a .git-marked directory or $HOME.
  • $HOME itself is still searched for project configs, so ~/.praisonai/config.yaml and ~/praisonai.yaml remain discoverable.
  • The legacy .praison/config.toml name is skipped only at $HOME — that file belongs to the global loader and is loaded exactly once as global:.
  • A config placed above $HOME (e.g. /Users/praisonai.yaml in a shared-parent layout) no longer wins, because $HOME is now a hard boundary.
  • If $HOME is unresolvable (Path.home() raises), the walk falls back to filesystem root.
  • The CLI home root (sessions, traces, logs, cache, model-recency) is now the canonical ~/.praisonai/ — the same directory praisonai setup and the SDK use — unless PRAISONAI_HOME overrides it. A legacy ~/.praison/ is read-only when it is the sole directory present.

Choose Your Scope

Diagram

Just this one command

This shell session only

This repo / team-wide

All my projects

Where should this setting live?

CLI flag

Environment variable

Project config
.praisonai/config.yaml

Global config
~/.praisonai/config.yaml


CLI Home Root

The CLI writes everything under one directory — ~/.praisonai/ by default, or wherever PRAISONAI_HOME points. Config, sessions, traces, logs, cache, credentials, .env, and durable state all live together there.

Diagram

Yes

No

Yes

No, but ~/.praison/ exists

Neither

Where does the CLI put my data?

PRAISONAI_HOME set?

🌱 $PRAISONAI_HOME/
config, sessions, traces, logs, cache

~/.praisonai/ exists?

🏠 ~/.praisonai/
canonical default

📁 ~/.praison/ legacy — read-only
first write migrates forward

🆕 ~/.praisonai/ created on first write

Every user-scoped artefact resolves under the same home root:

PathContents
<home>/config.tomlUser CLI config (written by praisonai config set)
<home>/config.yamlUser CLI YAML config (written by praisonai setup / praisonai init --global)
<home>/.envAPI keys (0600)
<home>/credentials.jsonUnified credential store (0600)
<home>/sessions/Session state (JSON)
<home>/traces/Execution traces
<home>/logs/Log files
<home>/cache/Disposable caches (model catalogue, etc.)
<home>/state/Durable state (model recency, DLQs, journals, approvals, update-check)
<home>/skills/User-scope skills (see Skill Manage)

Override with PRAISONAI_HOME

Set PRAISONAI_HOME to re-root every artefact together — config and sessions and traces and logs and cache all move as one.

bash
export PRAISONAI_HOME=/var/lib/praisonai
praisonai config set agent.model gpt-4o-mini
# → writes /var/lib/praisonai/config.toml
# → sessions, traces, logs, cache all now live under /var/lib/praisonai/

Tilde is expanded, so PRAISONAI_HOME=~/mycustom resolves the same as PRAISONAI_HOME=$HOME/mycustom.

python
from praisonaiagents.paths import get_data_dir

# Both the SDK and the CLI resolve the same home root
print(get_data_dir())  # /var/lib/praisonai (or ~/.praisonai by default)

Legacy ~/.praison/ — read-only fallback

If an older install still has ~/.praison/config.toml, the CLI keeps reading it until the first write. Any praisonai config set / praisonai config reset seeds from whatever currently resolves, then writes the merged result to ~/.praisonai/config.toml — migrating legacy values forward without ever mutating the legacy file. The SDK honours the legacy directory the same way (with a deprecation warning); praisonai migrate-data moves everything to the canonical root.


Project data directory (.praisonai/)

Project-local CLI state lives in ./.praisonai/ — the same directory the runtime (praisonaiagents.paths) reads from. Everything below goes through a single pair of helpers in cli/configuration/paths.py, derived from the one constant PROJECT_DATA_DIRNAME (itself praisonaiagents.paths.DEFAULT_DIR_NAME), so a new site cannot drift:

  • get_project_data_path(...) — the canonical write path (<cwd>/.praisonai/<file>).
  • resolve_project_data_path(...) — the read path: returns the canonical file if it exists, else an existing legacy <cwd>/.praison/<file>, else the canonical path.

Files written under ./.praisonai/

These nine (plus one) project-data sites migrated from ./.praison/ (or ~/.praison/) to the canonical ./.praisonai/ in PR #4946. A read-only fallback to .praison/ is preserved so nothing saved earlier is orphaned:

File / directoryFeature
thinking.jsonThinking level (praisonai thinking)
compaction.jsonConversation compaction state
output.jsonOutput-style (praisonai output-style)
file-historyInteractive input history
queue.dbBackground queue database
knowledge/<collection>Knowledge vector-store path (config loader, unified schema, and three retrieval.py sites)
skills checkpraisonai doctor skills check
memory checkpraisonai doctor memory check

Configuration Schema

agent.* defaults

KeyTypeDefaultNotes
agent.modelstrNonee.g. gpt-4o-mini, claude-sonnet-4-6
agent.providerstrNonee.g. openai, anthropic
agent.base_urlstrNoneCustom LLM base URL
agent.toolslist[str][]Default tool names
agent.toolsetstrNoneNamed toolset
agent.default_agentstrNoneDefault agent slug
agent.memorybool or dictNoneEnable memory or config dict
agent.streamboolTrueStream responses
agent.temperaturefloat0.7LLM temperature. Forwarded to every LLM call (PraisonAI PR #4245)
agent.max_tokensint16000LLM token budget

mcp.servers.<name>

KeyTypeDefaultDescription
commandlist[str] or str—Local (stdio) server launch command. List form preferred.
argslist[str][]Extra args appended to command.
envdict[str, str]{}Env vars for the server process. Values containing , are skipped on the command-string path.
enabledbooltrueSet false to declare-but-not-wire a server.
type"remote"—Marks a remote server; skipped by the run command-string path.
urlstr—Remote endpoint; presence implies remote.

permissions.*

KeyTypeDefaultDescription
default"allow" \"deny" \"ask"—Fallback action when no rule matches.
ruleslist[{pattern, action}][]Structured rule list. action must be allow, deny, or ask.
<pattern>"allow" \"deny" \"ask"—Flat shorthand — same shape as --allow/--deny produces.

instructions

Top-level list of extra instruction/context sources loaded alongside the convention-only AGENTS.md / CLAUDE.md auto-discovery. List values concatenate across the config hierarchy (global → user → project), so a project extends rather than replaces the org-wide list.

KeyTypeDefaultDescription
instructionslist[str][]File paths, globs (docs/standards/*.md), ~/env-var paths, or http(s):// URLs. See Instruction Sources for source-type behaviour, the SSRF guard, and merge semantics.
yaml
# .praisonai/config.yaml
instructions:
  - docs/standards/python.md
  - docs/standards/security.md
  - https://example.com/rules.md

Same first-class, layerable status as agent., mcp.servers., and permissions.* — also mirrored by the repeatable praisonai run --instructions <path|glob|url> flag.

Example combining all three sections:

yaml
# .praisonai/config.yaml
agent:
  model: gpt-4o
  temperature: 0.3

mcp:
  servers:
    playwright:
      command: ["npx", "-y", "@playwright/mcp"]

permissions:
  default: ask
  rules:
    - { pattern: "bash:git *", action: allow }
    - { pattern: "bash:rm *",  action: deny }

instructions:
  - docs/standards/python.md
  - https://example.com/rules.md

See Single-Source Config for a full guide to using all three sections together. Other top-level sections (output, traces, session) are also valid — see Config CLI reference.


Validation

Configuration is validated against a published JSON Schema. Unknown keys produce actionable warnings with typo suggestions; opt into strict mode to fail fast.

Diagram

Known keys

Unknown key

Strict mode

📄 .praisonai/config.yaml

🔍 Schema check

✅ Applied

⚠ Warn + suggest

❌ Raise ValueError

ModeEnable viaBehaviour on unknown key
Warn (default)—Logs UserWarning, valid keys still apply
Strict (per-call)--strict-config / ConfigResolver(strict=True)Raises ValueError
Strict (global)PRAISONAI_STRICT_CONFIG=1All resolver calls strict

Typo example:

Unknown config key 'temprature' in .praisonai/config.yaml (section: agent). Did you mean 'temperature'?

The # yaml-language-server: $schema=... line written by praisonai init enables real-time autocomplete and inline errors in VS Code (YAML extension) and other LSP-aware editors against the published schema.


Environment Variables

VariableMaps toNotes
MODEL_NAMEagent.model
OPENAI_MODEL_NAMEagent.model
PRAISONAI_MODELagent.model
PRAISONAI_PROVIDERagent.provider
OPENAI_BASE_URLagent.base_url
OPENAI_API_BASEagent.base_url
PRAISONAI_BASE_URLagent.base_url
PRAISONAI_OUTPUT_FORMAToutput.format
PRAISONAI_COLORoutput.colorbool: true/1/yes
PRAISONAI_VERBOSEoutput.verbosebool
PRAISONAI_QUIEToutput.quietbool
PRAISONAI_TELEMETRYtelemetrybool
PRAISONAI_BACKGROUND_JOB_STOREbackground job durabilityDefault 1 (on). Set to 0 / false to force get_job_manager() to pure in-memory. See Durable Background Jobs

Subcommand Reference

CommandFlagsBehaviour
praisonai config show`–format yaml\json\table, –sources/-s`Prints fully resolved config; with --sources, lists contributing layers
praisonai config validate [FILE]--strict-config, --json, optional FILEValidates schema; warn-by-default, strict opts into raise
praisonai config sourcesnonePrints precedence hierarchy and active layers
praisonai config list`–scope all\user\project`Lists resolved values; verbose shows sources
praisonai config get KEYdotted pathe.g. agent.model
praisonai config set KEY VALUE`–scope user\project`Writes YAML (0600 user, 0644 project)
praisonai config reset`–scope user\project, -y`Deletes corresponding config.yaml
praisonai config path`–scope user\project`Shows config file path and existence
praisonai config env--scope, --validateRegistered env vars and validation
praisonai config doctornoneConfiguration diagnostics
bash
# Verify resolution
praisonai config show --sources
# Shows sources: defaults, project:/path/to/repo/.praisonai/config.yaml, ...

Backward Compatibility

Legacy ~/.praison/config.toml

Loaded once as a global: source by the global loader. RAG and model keys are migrated to the new agent. / rag. schema automatically. Project walk-up never re-discovers it at $HOME, so praisonai config sources shows it exactly once with the global: label.

The legacy file is read-only. praisonai config set / praisonai config reset always write to the canonical ~/.praisonai/config.toml, seeding from whatever currently resolves — so a first write migrates any legacy values forward and the legacy file is never mutated after that. The same applies to the whole legacy directory: sessions, traces, logs, and cache now live under the canonical home too.

Legacy ~/.praisonai/.env

Model and provider keys from .env are merged into the resolved config when no YAML is present.

Project .praison/config.toml

Walk-up discovery still finds legacy TOML project configs in subdirectories (e.g. <subdir>/.praison/config.toml) and migrates them on read. The exception is the file at $HOME itself, which is only ever loaded as global: (see above).


Best Practices

Pin model per project

Commit .praisonai/config.yaml to your repo so teammates get the same defaults.

Keep secrets out of YAML

api_key is never serialised; use env vars or praisonai auth.

Use config sources to debug

When behaviour surprises you, praisonai config sources prints exactly which layer won.

Walk-up means subdirectories inherit

Running praisonai from repo/scripts/ finds repo/.praisonai/config.yaml.


Interpolation & Provenance

Any config value can reference ${VAR}, {env:NAME:-default}, or {file:./relative/path} — see Value Interpolation for the directive table and its security rules.

Run praisonai config provenance to see the winning value of each key and the exact layer/file that supplied it — see provenance.


Related