Path utilities

Shared user-level directory utilities for Klea packages.

Wraps platformdirs.PlatformDirs to provide OS-appropriate paths for cache, data, and config directories (~/.cache/klea/, ~/.local/share/klea/, ~/.config/klea/ on Linux, with equivalents on macOS and Windows).

Consumers pass an app_name so that different packages (klea, nml_mcp) get isolated directories without repeating the boilerplate.

File: klea_utils/paths.py

Copyright 2026 Ankur Sinha Author: Ankur Sinha <sanjay DOT ankur AT gmail DOT com>

klea_utils.paths.CHECKPOINT_DB_NAME = 'checkpoints.db'

Name of the SQLite database that holds LangGraph checkpoints.

klea_utils.paths.ENDPOINT_FILE_NAME = 'klea_agent.endpoint'

port) to.

Type:

Name of the file a running backend writes its endpoint (host

klea_utils.paths.LOCKFILE_NAME = 'klea_agent.lock'

Name of the PID lockfile that enforces one backend per storage root.

klea_utils.paths.LOG_DIR_NAME = 'logs'

Subdirectory of the storage root that holds backend logs.

klea_utils.paths.SESSION_DB_NAME = 'sessions.db'

Name of the SQLite database that holds chat sessions and messages.

klea_utils.paths.STORAGE_APP_NAME = 'klea_agent'

Application name used to derive the default per-user data directory. The klea_agent data directory is the single storage root that owns the checkpoint database, the session database, the backend PID lockfile, the endpoint file and the logs (ADR-0023, amendment “one backend per storage root”).

klea_utils.paths.STORAGE_ROOT_ENV = 'KLEA_AGENT_HOME'

Environment variable that relocates the whole storage root – data and runtime artifacts – so a user can run deliberately independent instances. It is an isolation override, not a concurrency mechanism (ADR-0023).

klea_utils.paths.checkpoint_db_path(root: str | Path | None = None) → Path[source]

Return the LangGraph checkpoint database path inside root.

Parameters:

root – Storage root; resolved via resolve_storage_root() when None

klea_utils.paths.cleanup_dir(path: str | Path) → None[source]

Remove all contents of path but keep the directory itself.

klea_utils.paths.endpoint_file_path(root: str | Path | None = None) → Path[source]

Return the path of the file that advertises a backend’s endpoint.

Parameters:

root – Storage root; resolved via resolve_storage_root() when None

klea_utils.paths.get_cache_dir(dirs: Unix) → Path[source]

Return the OS-appropriate per-user cache directory for dirs.

On Linux: ~/.cache/{app_name}/ On macOS: ~/Library/Caches/{app_name}/ On Windows: C:\Users\<user>\AppData\Local\{app_name}\cache\

klea_utils.paths.get_config_dir(dirs: Unix) → Path[source]

Return the OS-appropriate per-user config directory for dirs.

On Linux: ~/.config/{app_name}/ On macOS: ~/Library/Preferences/{app_name}/ On Windows: C:\Users\<user>\AppData\Roaming\{app_name}\

klea_utils.paths.get_data_dir(dirs: Unix) → Path[source]

Return the OS-appropriate per-user data directory for dirs.

On Linux: ~/.local/share/{app_name}/ On macOS: ~/Library/Application Support/{app_name}/ On Windows: C:\Users\<user>\AppData\Local\{app_name}\

klea_utils.paths.init_dir(path: str | Path) → Path[source]

Create path (and parents) if it doesn’t exist.

Returns:

The same path as a Path for chaining.

klea_utils.paths.lockfile_path(root: str | Path | None = None) → Path[source]

Return the backend PID lockfile path inside root.

Parameters:

root – Storage root; resolved via resolve_storage_root() when None

klea_utils.paths.log_dir_path(root: str | Path | None = None) → Path[source]

Return the log directory inside root.

The directory is only named, never created: callers use init_dir() when they are ready to write logs.

Parameters:

root – Storage root; resolved via resolve_storage_root() when None

klea_utils.paths.resolve_app_config_path(config_file: str, conf_dir: str | Path, cwd: str | Path | None = None) → Path[source]

Locate the application config file, checking the working directory first.

config_file may be an absolute path or a relative name/path. The working directory is searched before conf_dir (the per-app config directory), so a profile dropped in CWD overrides one installed in the config directory.

Parameters:
  • config_file – App config file path or bare filename

  • conf_dir – Config directory searched after the working directory

  • cwd – Working directory to search first (defaults to Path.cwd())

Returns:

The first existing match

Raises:
klea_utils.paths.resolve_storage_root(data_dir: str | Path | None = None, env: Mapping[str, str] | None = None, *, default_root: str | Path | None = None, env_name: str | None = 'KLEA_AGENT_HOME') → Path[source]

Return the effective storage root for a Klea backend.

Precedence, highest first:

  1. data_dir – the --data-dir flag, i.e. an explicit choice

  2. env_name (default STORAGE_ROOT_ENV, KLEA_AGENT_HOME) – an opt-in relocation of the data and runtime artifacts

  3. default_root – the graph’s existing per-app data directory, when given

  4. the platform user data directory for STORAGE_APP_NAME (~/.local/share/klea_agent on Linux)

The resolved root is logged at INFO level together with the source that selected it, so a user can tell which home a running backend uses.

Parameters:
  • data_dir – Value of the --data-dir flag, if given

  • env – Environment mapping to read (defaults to os.environ)

  • default_root – Per-app data directory used when no relocation is configured; preserves a graph’s existing default layout

  • env_name – Environment variable to read, or None to ignore it

Returns:

The resolved storage root, absolute and expanded

klea_utils.paths.session_db_path(root: str | Path | None = None) → Path[source]

Return the chat session/message database path inside root.

Parameters:

root – Storage root; resolved via resolve_storage_root() when None