Configuration Reference

September 10, 2026 · View on GitHub

On first run, Waveloom generates a default config at .waveloom/settings.json. Config file locations (highest priority first):

  1. CLI --settings flag
  2. .waveloom/settings.json (project root)
  3. ~/.waveloom/settings.json (global)

settings.json

Minimal config:

{
  "llm": {
    "api_key": "sk-your-deepseek-key"
  }
}

llm Configuration

FieldDescriptionDefault
api_keyDeepSeek API Key, falls back to LLM_API_KEY env var when empty
providerdeepseek, kimi, glm, or openaideepseek
modelModel namedeepseek-flash
base_urlAPI endpointhttps://api.deepseek.com
timeoutRequest timeout600s
extra_paramsExtra parameters (thinking, reasoning_effort, etc.)Thinking mode on by default
retryRetry policy {"max_retries":3, "initial_backoff":"1s", "max_backoff":"30s", "multiplier":2.0}Default retry policy
sub_modelSub-agent default model (explore subagent uses this model for code search and discovery, ~2x cheaper)Auto-paired (pro → flash)
profilesMulti-provider configuration, keyed by provider name (e.g., "kimi", "glm", "openai"). Each profile may contain api_key, model, sub_model, base_url, extra_params. Used with --provider CLI flag. Provider-independent fields (timeout, retry, headers) are inherited from the top level
{
  "llm": {
    "provider": "deepseek",
    "profiles": {
      "kimi": {
        "api_key": "sk-your-kimi-key",
        "model": "kimi-k2",
        "base_url": "https://api.moonshot.cn/v1"
      },
      "openai": {
        "api_key": "sk-your-openai-key",
        "model": "gpt-5",
        "base_url": "https://api.openai.com/v1"
      },
      "glm": {
        "api_key": "your-glm-key",
        "model": "glm-5.3",
        "sub_model": "glm-5.3-flash",
        "base_url": "https://open.bigmodel.cn/api/coding/paas/v4"
      }
    }
  }
}

permissions Configuration

{
  "permissions": {
    "allow": ["read_file", "web_fetch", "bash(go build *)", "bash(go test *)"],
    "deny":  ["bash(rm -rf /*)"],
    "ask":   ["write_file", "edit_file"]
  }
}

Rule format: ToolName or ToolName(pattern), e.g., bash(ls *) matches all commands starting with ls .

compaction Configuration

FieldDescriptionDefault
tier1_thresholdTier 1 (Snip) trigger threshold0.6 (60%)
tier2_thresholdTier 2 (Prune) trigger threshold0.8 (80%)
tier3_thresholdTier 3 (Summarize) trigger threshold0.95 (95%)
protection_zone_tokensProtection zone token count, supports "8K" / 80008000
context_limit_tokensModel context limit, supports "1M" / 10000001000000

hooks Configuration

The Hook system is compatible with the Claude Code Hooks protocol, injecting external scripts into the tool execution lifecycle. Typical use cases: command rewriting (e.g., RTK token optimization), result processing, event notification.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/rtk-rewrite.sh",
            "timeout": 5000
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "curl -s -X POST 'http://localhost:8080/log' -d @-"
          }
        ]
      }
    ],
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "notify-slack.sh"
          }
        ]
      }
    ]
  }
}

Configuration hierarchy (highest priority first, same-event merge)

  1. .claude/settings.local.json — Local override (do not commit)
  2. .waveloom/settings.json — Waveloom project-level
  3. .claude/settings.json — Claude Code project-level
  4. ~/.waveloom/settings.json — Waveloom user-level
  5. ~/.claude/settings.json — Claude Code user-level

Event types

EventTriggerSync/AsyncCan rewrite
PreToolUseBefore tool executionSyncYes (params)
PostToolUseAfter tool executionSyncYes (result)
NotificationLifecycle events (task start/complete/error)AsyncNo
StopAgent Loop terminationSyncNo

Matcher rules

SyntaxExampleDescription
Empty string""Match all tools
Exact name"Bash"Exact tool name match
Prefix wildcard"Read*"Match tools starting with Read
Multi-pattern"Bash|Read"| delimited, match any

Hook entry fields

FieldTypeRequiredDescription
typestringNo"command" (default)
commandstringYesExecutable script path or shell command
timeoutnumberNoTimeout in milliseconds, default 30000

Hook scripts receive JSON event context via stdin and return JSON results via stdout. Exit code 0 = apply rewrite, 1 = pass through, 2 = block execution. See Claude Code Hooks docs for details.

environment Configuration

The agent auto-detects available toolchains at startup. For tools not in PATH or to pin a specific version, configure via environment.tools. See environment.en.md for details.

lsp LSP Diagnostics Configuration

After every edit / write, LSP diagnostics run automatically. See lsp.en.md.

FieldDescriptionDefault
lsp.serversFile extension → LSP Server config. Key is extension (e.g. ".py"), value is {"command": "...", "args": ["..."]}. User-defined entries override built-in defaults
lsp.idle_timeout_msIdle timeout before server is reaped (ms)300000 (5 min)

Example: adding Python and Java LSP Servers:

{
  "lsp": {
    "servers": {
      ".py": { "command": "pyright-langserver", "args": ["--stdio"] },
      ".java": { "command": "jdtls" }
    }
  }
}

web_search Configuration

The web_search tool defaults to DuckDuckGo — no configuration required. For better result quality, switch to the Brave Search API via an environment variable:

export BRAVE_API_KEY="your-brave-api-key"

Falls back to DuckDuckGo when not set.

Tool Timeout Configuration

FieldDescriptionDefault
tool_timeoutSingle tool execution timeout (Go Duration format, e.g. "10m" / "600s" / "0s", 0 to disable)"5m"

session Configuration

FieldDescriptionDefault
session.dirSession storage directory (relative or absolute path). Priority: settings.json session.dir > WAVELOOM_SESSION_DIR env var > ~/.waveloom/<project>/sessions/~/.waveloom/<project>/sessions/
{
  "session": {
    "dir": ".waveloom/sessions"
  }
}

UI Configuration

FieldDescriptionDefault
themeTheme mode: auto (detect terminal background automatically), dark, light, darkcolorblind, lightcolorblind. Can be changed and persisted at runtime via /theme commandauto
localeUI language: zh-CN (Chinese), en-US (English), auto (detect from LANG env var). Priority: --locale CLI > settings.json > LANGauto
{
  "theme": "dark",
  "locale": "zh-CN"
}

Plan Mode Configuration

FieldDescriptionDefault
plans_directoryPlan file storage directory (relative paths are relative to the settings file directory)~/.waveloom/plans/

sandbox Configuration

FieldDescriptionDefault
enabledEnable the sandbox in TUI mode; auto-activated by --bypass-permissions / one-shot / non-interactive ACP (no need to set true)false
failIfUnavailableRefuse to start when the backend is missing (e.g. bwrap not installed)false
allowUnsandboxedCommandsHint escape (add to excludedCommands) when a sandboxed command failstrue
excludedCommandsEscape hatch list (prefix/exact/wildcard); matching commands run unsandboxed but still pass through Guard[]
envEnv vars injected inside the sandbox (tool-agnostic mechanism); values support path prefixes (~/ home, //// absolute, ./ workspace-relative), anything else is injected verbatim; keys matching the credential-strip list are ignored (strip wins){}
network.modeNetwork policy: off (fully offline) / on (direct); proxy is v2, not implemented. Defaults to on (2025-09 decision: non-interactive entries need networked tools out of the box; exfiltration risk is mitigated by denyRead / credentials.files)on
network.allowedDomainsDomain allowlist (v2 proxy placeholder, not active yet)[]
filesystem.allowWriteExtra writable paths (//abs absolute, ~/ home, ./ or bare name = project root); root and mask-conflicting paths are rejected[]
filesystem.allowReadDeprecated (2026-09): parsed only to warn and ignore; no longer has any effect. Use denyRead / credentials.files instead[]
filesystem.denyReadMasked (unreadable) paths. Nothing is masked by default — configure explicitly (recommended list below)[]
capabilities.keepKernel capabilities re-added after --cap-drop ALL (e.g. net_raw for ping)[]
credentials.filesCredential mask paths (strongly recommended when network is on)[]
credentials.envVarsExtra env vars to strip, layered on built-in globs (*TOKEN* / *_API_KEY etc.)[]
{
  "sandbox": {
    "enabled": false,
    "excludedCommands": ["docker *"],
    "env": {
      "GOPATH": "./.waveloom-gopath",
      "GOMODCACHE": "./.waveloom-gomodcache",
      "GOCACHE": "./.waveloom-gocache",
      "GOPROXY": "https://proxy.golang.org,direct"
    },
    "network": { "mode": "off" },
    "filesystem": { "allowWrite": ["~/.cache"], "denyRead": ["~/.aws"] },
    "credentials": { "files": ["~/.ssh"], "envVars": ["GH_TOKEN"] }
  }
}

Env Injection Inside the Sandbox (env)

sandbox.env is a tool-agnostic mechanism: the listed env vars are injected when commands start inside the sandbox. Its typical use is redirecting build-tool caches into the writable workspace area — under the read-only root, host caches (e.g. ~/go/pkg/mod) are not writable, so go/npm/cargo would fail or degrade with warnings.

  • Value path semantics: ./ → workspace-relative ("./.waveloom-gomodcache"<project root>/.waveloom-gomodcache); ~/ → home; // or / → absolute; anything else (URLs etc.) is injected verbatim (e.g. GOPROXY)
  • Go example: pointing GOPATH / GOMODCACHE / GOCACHE at the workspace makes the first in-sandbox build download dependencies over the network (one-time, cached persistently), after which offline builds work; host builds are unaffected
  • npm/cargo etc.: configure npm_config_cache / CARGO_HOME / PIP_CACHE_DIR the same way
  • Security: keys matching the credential-strip rules (built-in globs *TOKEN* / *_API_KEY etc. or credentials.envVars) are ignored — strip wins, preventing the config from re-injecting stripped secrets into the sandbox

Masking Strategy (2026-09: nothing masked by default)

The sandbox masks no paths by default (~/.ssh, ~/.aws, keychains, etc. are all readable), aligned with Claude Code / Codex. Credential protection is configured explicitly via filesystem.denyRead / credentials.files; when network is on without any mask, a startup warning is emitted ("network can exfiltrate unmasked files; configure masking for stronger protection").

Fixed built-in masks (write-protection / escape prevention, cannot be removed):

PathPurpose
<project root>/.git/hooksPersistent-injection guard (hooks execute on write — escape); Linux: tmpfs overlay, Seatbelt: deny read+write
/var/run/docker.sockEscape prevention (docker can mount host root); macOS also masks ~/.docker/run/docker.sock

Recommended credential masking config (strongly advised when network is on):

{
  "sandbox": {
    "network": { "mode": "on" },
    "filesystem": {
      "denyRead": [
        "~/.waveloom/settings.json", "~/.git-credentials", "~/.config/git/credentials",
        "~/.bashrc", "~/.bash_profile", "~/.profile", "~/.zshrc", "~/.zshenv",
        "~/.npmrc", "~/.netrc", "~/.docker/config.json",
        "~/.config/gh/hosts.yml", "~/.mcp.json", "~/.claude/settings.json",
        "~/.aws", "~/.ssh", "~/.kube/config", "~/.config/gcloud", "~/.gnupg",
        "~/.pgpass", "~/.config/containers/auth.json", "~/.env",
        ".waveloom/settings.json", ".env"
      ]
    },
    "credentials": {
      "files": ["~/.ssh", "~/.aws/credentials"],
      "envVars": ["GH_TOKEN", "NPM_TOKEN", "AWS_ACCESS_KEY_ID"]
    }
  }
}

macOS: additionally consider ~/Library/Keychains, ~/Library/HTTPStorages, ~/Library/Cookies, ~/Library/Application Support/Google/Chrome, .../Firefox, .../Microsoft/Edge (keychains / cookies / browser sessions can be read and exfiltrated when network is on).

Note: env var stripping (built-in globs: *TOKEN* / *_API_KEY / AWS_* / GH_* etc.) is an independent defense that is always active, regardless of path masking config.

CLI Flags

FlagDescriptionDefault
--modelModel namedeepseek-flash
--system-promptCustom system promptBuilt-in prompt
--max-turns NMaximum turns, 0 = unlimited0 (unlimited)
--context-limit 1MContext window size, supports 1M / 200k / raw number1M
--theme auto/dark/lightTheme, auto detects terminal backgroundauto
--locale zh-CN/en-US/autoUI language, auto detects from LANG env varauto
--provider NAMESwitch LLM provider (requires matching profile in profiles)
--log-level levelLog level (error/warn/info/debug)info
--bypass-permissionsone-shot (direct terminal input) / ACP: ASK → ALLOW by default (binary decision), keeping deny rules and high-risk hard blocks; one-shot piped input requires this flag, otherwise write/bash degrade to deny; TUI: enables the binary decision (no more prompt dialogs)Off (default on for one-shot terminal input / ACP)
--sandbox-network off/onSandbox network mode, overrides network.mode in settings.json (on: credential masking recommended)From config (default on)
--no-sandboxDisable the sandbox (one-shot/ACP force it on by default; explicitly disable for eval Docker isolation / CI environments; highest priority)Off (sandbox active)
--tool-timeout DSingle tool execution timeout (Go Duration format, e.g. 10m / 600s / 0s, 0 to disable)5m
--resume IDResume a specific session
--continueResume the most recent session
--settings PATHSpecify config file path.waveloom/settings.json
--versionShow version

Priority: CLI flags > .waveloom/settings.json (project) > ~/.waveloom/settings.json (global)