XDG Base Directories

Run PraisonAI on servers, containers, and CI with XDG-compliant config/data/state/cache paths

On fresh installs, PraisonAI honours XDG_{CONFIG,DATA,STATE,CACHE}_HOME so config, data, state, and cache can live on different volumes. Existing single-root installs (~/.praisonai/ or PRAISONAI_HOME) keep working unchanged.

Diagram

Directory Classes

โš™๏ธ config
XDG_CONFIG_HOME

๐Ÿค– PraisonAI

๐Ÿ’พ data
XDG_DATA_HOME

๐Ÿงพ state
XDG_STATE_HOME

๐Ÿ—‘๏ธ cache
XDG_CACHE_HOME

Quick Start

  1. Default (existing installs, unchanged)
    python
    from praisonaiagents import Agent
    
    agent = Agent(name="assistant", instructions="Be helpful.")
    agent.start("Hello")
    # Config, data, state, cache all stay under ~/.praisonai/ โ€” nothing to configure.
  2. Split classes onto different volumes
    bash
    export XDG_CONFIG_HOME=/etc/praisonai       # config.yaml, credentials
    export XDG_DATA_HOME=/mnt/persistent/data   # sessions, memory, knowledge, plugins
    export XDG_STATE_HOME=/var/lib/praisonai    # MRU model, logs, spill
    export XDG_CACHE_HOME=/tmp/praisonai-cache  # tmpfs is fine
    
    praisonai run "Summarise this repo"
  3. Explicit single root (PRAISONAI_HOME) still wins
    bash
    export PRAISONAI_HOME=/app/data
    praisonai run "..."   # Every class stays under /app/data โ€” XDG is ignored.

Which directory does what?

Each class has its own purpose, precedence, and helper.

ClassPurposePrecedence (fresh install)XDG fallback defaultHelper
configEditable config, credentials, rulesPRAISONAI_HOME โ†’ existing single root โ†’ $XDG_CONFIG_HOME/praisonai~/.config/praisonaiget_config_dir()
dataSessions, memory, knowledge, pluginsPRAISONAI_HOME โ†’ existing single root โ†’ $XDG_DATA_HOME/praisonai~/.praisonai (branded default; only overridden when XDG_DATA_HOME is explicitly set)get_data_dir()
stateMRU model, logs, session spillPRAISONAI_HOME โ†’ existing single root โ†’ $XDG_STATE_HOME/praisonai~/.local/state/praisonaiget_state_dir()
cacheDisposable caches, transient indexesPRAISONAI_HOME โ†’ existing single root โ†’ $XDG_CACHE_HOME/praisonai~/.cache/praisonaiget_cache_dir()

How It Works

The single-root decision runs once, then per-class XDG dirs apply on a fresh install.

Diagram

PRAISONAI_HOME set

~/.praisonai/ exists

Neither: fresh install

Which root
applies?

Explicit single root
every class under it

Existing single root
every class under ~/.praisonai/

Per-class XDG dirs
config / data / state / cache

Behaviour notes:

  • Back-compat is preserved. If ~/.praisonai/ (or ~/.praison/) already exists, or PRAISONAI_HOME is set, every class stays under that single root.
  • The single-root decision is snapshotted once per process. If PraisonAI later creates ~/.praisonai/ mid-run for data, config/state/cache do not retroactively move onto it.
  • Relative XDG paths are ignored, per spec. XDG_CONFIG_HOME=relative/path falls back to ~/.config/praisonai.
  • get_session_spill_dir() now lives under <state>/state/session_spill/ โ€” no longer under ~/.praisonai/state/.
  • get_config_path() now returns <config>/config.yaml โ€” no longer <data>/config.yaml.
  • Split state ends. MRU model recency now writes under the canonical state home, so ~/.praison and ~/.praisonai no longer disagree.

Configuration Options

VariableTypeDefaultDescription
PRAISONAI_HOMEabsolute pathunsetExplicit single root. Wins over everything else; every class stays under it.
XDG_CONFIG_HOMEabsolute path~/.configWhere get_config_dir() resolves on fresh installs.
XDG_DATA_HOMEabsolute path~/.praisonai (branded default)Where get_data_dir() resolves on fresh installs.
XDG_STATE_HOMEabsolute path~/.local/stateWhere get_state_dir() resolves on fresh installs.
XDG_CACHE_HOMEabsolute path~/.cacheWhere get_cache_dir() resolves on fresh installs.

Python API

python
from praisonaiagents.paths import (
    get_config_dir,   # NEW โ€” editable config, credentials, rules
    get_data_dir,     # sessions, memory, knowledge, plugins  (XDG-aware)
    get_state_dir,    # NEW โ€” MRU model, logs, spill
    get_cache_dir,    # disposable caches                       (XDG-aware)
    get_all_paths,    # dict now includes "config_dir" and "state_dir"
)

Common Patterns

Kubernetes

Mount a ConfigMap at $XDG_CONFIG_HOME, a PVC at $XDG_DATA_HOME, and an emptyDir at $XDG_CACHE_HOME.

bash
export XDG_CONFIG_HOME=/config     # ConfigMap (read-only)
export XDG_DATA_HOME=/data         # PersistentVolumeClaim
export XDG_CACHE_HOME=/cache       # emptyDir

systemd service

Set the directory directives and let systemd populate the XDG vars.

ini
[Service]
ConfigurationDirectory=praisonai
StateDirectory=praisonai
CacheDirectory=praisonai

CI runners

Point state and cache at the workspace so logs and caches don’t leak into $HOME.

bash
export XDG_STATE_HOME="$CI_WORKSPACE/state"
export XDG_CACHE_HOME="$CI_WORKSPACE/cache"

Existing install

No action needed; ~/.praisonai/ continues to hold every class.

bash
praisonai run "Nothing to configure"

Best Practices

๐Ÿ—‚๏ธ Separate volumes by class

Back up $XDG_CONFIG_HOME/praisonai (small, precious); put $XDG_CACHE_HOME/praisonai on tmpfs (disposable); size $XDG_DATA_HOME/praisonai for session/memory growth.

๐Ÿงญ Use PRAISONAI_HOME when you want one directory

It short-circuits XDG entirely and keeps every class under one root.

๐Ÿงพ Check the resolved paths

Run praisonai paths show โ€” the output now includes config_dir and state_dir.

๐Ÿšซ Don't use relative XDG paths

Per spec they’re ignored and the default applies.


Related