Caveman Configuration Resolution Order: How Default Modes Are Determined

Caveman resolves its default mode through a four-tier priority chain: environment variables override repo-local configs, which override user-level configs, with a built-in fallback to "full" mode.

The JuliusBrussee/caveman project implements a deterministic configuration system that determines which operation mode (off, lite, full, ultra, etc.) the tool uses at startup. Understanding the Caveman configuration resolution order is essential for managing different behaviors across local development, CI/CD pipelines, and personal workstations.

The Four-Tier Resolution Hierarchy

1. Environment Variable (Highest Priority)

Caveman checks the CAVEMAN_DEFAULT_MODE environment variable first. If set to a valid mode—such as off, lite, full, or ultra—this value wins outright regardless of any configuration files present.

2. Repository-Local Configuration

If no environment variable is set, Caveman searches for repo-local settings by walking up the directory tree from the current working directory. It looks for .caveman/config.json or .caveman.json in each directory until reaching the filesystem root. The first file found containing a valid defaultMode field determines the behavior.

3. User-Level Configuration File

When neither environment variables nor repo-local configs are present, Caveman checks per-user defaults. On Unix-like systems, it reads $XDG_CONFIG_HOME/caveman/config.json (or ~/.config/caveman/config.json if XDG_CONFIG_HOME is unset). On Windows, it checks %APPDATA%\caveman\config.json.

4. Built-in Fallback Default

If all preceding sources fail to yield a valid mode, Caveman defaults to "full" mode as the safe baseline.

Core Implementation in src/hooks/caveman-config.js

The resolution logic is implemented in src/hooks/caveman-config.js, specifically within the getDefaultMode() function. This module also defines VALID_MODES to ensure only accepted strings are recognized:

function getDefaultMode() {
  // 1️⃣ env var
  const envMode = process.env.CAVEMAN_DEFAULT_MODE;
  if (envMode && VALID_MODES.includes(envMode.toLowerCase())) {
    return envMode.toLowerCase();
  }

  // 2️⃣ repo‑local config
  const repoConfigPath = findRepoConfigPath(process.cwd());
  if (repoConfigPath) {
    const repoMode = readModeFromConfigFile(repoConfigPath);
    if (repoMode) return repoMode;
  }

  // 3️⃣ user config
  const userMode = readModeFromConfigFile(getConfigPath());
  if (userMode) return userMode;

  // 4️⃣ fallback
  return 'full';
}

The helper functions findRepoConfigPath() and readModeFromConfigFile() handle the directory traversal and JSON parsing, while getConfigPath() determines the appropriate user-level directory based on platform conventions. The test suite in tests/test_repo_local_config.js verifies this hierarchy, ensuring that environment variables correctly override file-based configurations.

Practical Configuration Examples

Override with Environment Variable

Set the mode for a single invocation without modifying any files:

CAVEMAN_DEFAULT_MODE=lite caveman run

Project-Specific Defaults

Create .caveman/config.json in your project root to ensure all team members use the same mode:

{
  "defaultMode": "commit"
}

Running caveman from anywhere inside the project directory tree will start in commit mode unless overridden by the environment variable.

Personal Defaults

Configure your user-level file at ~/.config/caveman/config.json (Linux/macOS) or %APPDATA%\caveman\config.json (Windows):

{
  "defaultMode": "review"
}

Fallback Behavior

Without any configuration, Caveman automatically uses "full" mode:

caveman status  # Executes in "full" mode

Summary

  • Environment variables take precedence: CAVEMAN_DEFAULT_MODE overrides all other sources.
  • Repo-local configs are priority two: Files named .caveman/config.json or .caveman.json in the project hierarchy apply next.
  • User-level configs provide personal defaults: Located in XDG config directories or Windows AppData.
  • Safe fallback: The built-in default is "full" mode when no other configuration exists.
  • Source location: The getDefaultMode() function in src/hooks/caveman-config.js implements this hierarchy.

Frequently Asked Questions

What is the Caveman configuration resolution order?

Caveman resolves configuration through a strict four-level hierarchy: environment variables (CAVEMAN_DEFAULT_MODE) are checked first, followed by repository-local config files (.caveman/config.json or .caveman.json), then user-level config files (~/.config/caveman/config.json or %APPDATA%\caveman\config.json), and finally falls back to the built-in default of "full" mode.

Where does Caveman look for repository-local configuration?

Caveman searches for .caveman/config.json or .caveman.json starting from the current working directory and walking upward through parent directories until reaching the filesystem root. The first valid file encountered in this traversal determines the configuration.

How do I set a system-wide default mode for Caveman?

Set the CAVEMAN_DEFAULT_MODE environment variable in your shell profile or system environment settings. Alternatively, create a user-level config file at ~/.config/caveman/config.json on Unix systems or %APPDATA%\caveman\config.json on Windows to apply defaults across all projects that lack repo-specific configurations.

What happens if I specify an invalid mode in my config file?

Invalid mode values are ignored during the resolution process. If a config file contains an invalid defaultMode, Caveman continues to the next level in the hierarchy. If no valid mode is found throughout the entire chain, the tool defaults to "full" mode.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →