Hierarchical Configuration

Project-aware JSON config discovery for the praisonai CLI — walk-up from subdirectories, stop at the git boundary

The praisonai CLI reads .praison.json from your project — and finds it automatically even when you run the CLI from a deep subdirectory.

Diagram

Hierarchical Configuration

📋 User Request

⚙️ Hierarchical Configuration

✅ Result

python
from praisonaiagents import Agent

agent = Agent(name="assistant", instructions="Be helpful.")
agent.start("Summarise the README")

The user runs the agent from any subdirectory; hierarchical config supplies merged settings.

Diagram

Hierarchical Configuration

📝 CLI in Subdir

🔍 Walk-up Discovery

⚙️ Merge Configs

🤖 Agent

✅ Merged Settings

Precedence

Diagram

Hierarchical Config (highest wins)

📁 Project
.praison.json / praison.json
walk-up to git root

🏠 User
~/.config/praison/praison.json

🌐 Global
/etc/praison/praison.json

Quick Start

  1. Drop .praison.json in your project root
    json
    {
      "model": "gpt-4o-mini",
      "temperature": 0.3
    }
  2. Use an agent from anywhere inside the repo
    python
    from praisonaiagents import Agent
    
    agent = Agent(name="assistant", instructions="Be helpful.")
    agent.start("Summarise the README")

    The CLI discovers .praison.json automatically — no extra setup needed, even if you’re nested deep inside repo/src/deep/pkg/.

  3. Verify what got merged
    python
    from praisonai.cli.features.config_hierarchy import load_config
    
    print(load_config())

How Walk-up Works

Diagram
repo/ (.git here)_find_project_configcwd: repo/src/deep/pkgrepo/ (.git here)_find_project_configcwd: repo/src/deep/pkgstart searchcheck pkg/.praison.json — misscheck deep/.praison.json — misscheck src/.praison.json — misscheck repo/.praison.json — HITnearest config winsrepo/.praison.json
  • Starts at project_dir (defaults to os.getcwd()).
  • At every level, checks .praison.json then praison.json (in that precedence order).
  • Stops at a directory containing .git — config never leaks across project boundaries.
  • When no .git is ever found, caps the walk at 10 ancestor levels to avoid accidentally picking up unrelated configs.
  • Nearest config wins — the first hit is returned.

Choose Your Mode

Diagram

Default — find config anywhere in this repo

Restrict to the literal current dir

Test fixture / explicit override

How should project config be discovered?

walk_up=True
(default)

walk_up=False

HierarchicalConfig(project_dir=’…’)

Default walk-up (recommended):

python
from praisonai.cli.features.config_hierarchy import HierarchicalConfig

config = HierarchicalConfig()
settings = config.load()

Disable walk-up (cwd only):

python
config = HierarchicalConfig(walk_up=False)
settings = config.load()

Explicit starting directory:

python
config = HierarchicalConfig(project_dir="/path/to/project")
settings = config.load()

Walk-up Boundaries

Diagram

Walk-up boundaries

📁 cwd

📁 parent

📁 .git boundary 🛑

📁 no .git, depth cap = 10 🛑

The walk stops when it hits either:

  • A directory containing .git (inclusive — the git-root itself is still checked for configs).
  • 10 ancestor levels without finding any .git marker.

Configuration File Precedence

LayerPathNotes
Project (hidden).praison.json (walk-up from cwd)Checked first at each level
Project (visible)praison.json (walk-up from cwd)Fallback at each level
User~/.config/praison/praison.json—
Global/etc/praison/praison.json—

Configuration Schema

Top-level keys supported in .praison.json:

KeyTypeDescription
modelstringLLM model name (e.g. "gpt-4o")
temperaturenumberSampling temperature (0–2). Forwarded to every LLM call (PraisonAI PR #4245)
max_tokensintegerMax tokens per response
providersobjectProvider-specific settings (api_key, base_url)
mcpobjectMCP server configuration
permissionsobjectTool and path allowlists
lspobjectLanguage server protocol settings
outputobjectOutput mode and color settings
attributionobjectGit commit attribution style

Example .praison.json:

json
{
  "model": "gpt-4o",
  "temperature": 0.7,
  "permissions": {
    "allowed_tools": ["read_file", "write_file"],
    "allowed_paths": ["./src", "./tests"]
  },
  "output": {
    "mode": "compact",
    "color": true
  }
}

Common Patterns

Monorepo with per-package overrides:

Place a root .praison.json with your default model, then add a packages/frontend/.praison.json for package-specific overrides:

json
// packages/frontend/.praison.json
{
  "model": "gpt-4o",
  "temperature": 0.1
}

Running praisonai run "..." from inside packages/frontend/ picks up the nearest config automatically.

Pin model and permissions for the whole repo:

A single .praison.json at the repo root applies to every subdirectory:

json
{
  "model": "gpt-4o-mini",
  "permissions": {
    "allowed_tools": ["read_file"],
    "allowed_paths": ["./src"]
  }
}

Test fixture isolation:

python
from praisonai.cli.features.config_hierarchy import HierarchicalConfig

def test_my_feature(tmp_path):
    config = HierarchicalConfig(project_dir=str(tmp_path), walk_up=False)
    settings = config.load()

Constructor Parameters

ParamTypeDefaultDescription
project_dirstros.getcwd()Starting directory for project-config discovery.
user_configstr~/.config/praison/praison.jsonPath to the user-level config file.
global_configstr/etc/praison/praison.jsonPath to the global config file.
walk_upboolTrueWhen True, walk parent dirs to the git root (capped at 10 levels without a .git). When False, only check project_dir.

Best Practices

Commit .praison.json to your repo

Every teammate gets the same model and permissions automatically — no manual setup, no environment drift.

Use the hidden filename for project defaults

.praison.json (hidden) is for project-default state checked in to version control. Reserve praison.json (visible) for local human-editable overrides you want to keep out of git.

Keep secrets out of project config

Provider api_key values in .praison.json get committed to git. Store credentials in environment variables or a secrets manager instead.

Disable walk-up in tests

Pass walk_up=False (or set an explicit project_dir to an isolated tmp_path) so tests do not inherit ancestor .praison.json files and become order-dependent or environment-sensitive.

Trust the git-root boundary

Running the CLI from a subdir of an unrelated parent repo will not pull in that parent’s config. The .git marker is the safety boundary.


Related