> ## Documentation Index
> Fetch the complete documentation index at: https://docs.clawker.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

> Reference for .clawker.yaml project configuration

Every Clawker project has a `.clawker.yaml` file in the project root. Create one with:

```bash theme={"dark"}
clawker project init
```

## How Configuration Works

Clawker uses a layered configuration system that discovers, loads, and merges YAML files from multiple locations. Understanding this system is key to using Clawker effectively -- especially in monorepos, shared environments, or when you want per-directory overrides.

### Discovery and Merge

When you run any Clawker command, the configuration engine:

1. **Walk-up discovery** -- Starting from your current working directory, walks up the directory tree to the registered project root, probing for config files at each level.
2. **Explicit paths** -- Checks the user config directory (`~/.config/clawker/`) for additional config files.
3. **Defaults** -- Applies built-in defaults as the lowest-priority base layer.

Files found closer to CWD have **higher priority** than files found further up the tree. This means a `.clawker.yaml` in a subdirectory overrides values from the one at the project root.

**Merge rules:**

* **Scalars** (strings, numbers, booleans): closest-to-CWD wins.
* **Maps** (objects): recursively merged -- keys from higher-priority files override, but unmentioned keys from lower-priority files are preserved.
* **Slices** (arrays): replaced entirely by higher-priority files, unless the field is tagged for union merge (e.g., firewall `add_domains`).

### File Placement

At each directory level during walk-up, the engine checks two placement styles:

| Style                 | Path                    | When                                 |
| --------------------- | ----------------------- | ------------------------------------ |
| **Directory form**    | `.clawker/clawker.yaml` | When a `.clawker/` directory exists  |
| **Flat dotfile form** | `.clawker.yaml`         | When no `.clawker/` directory exists |

The directory form takes precedence. Both `.yaml` and `.yml` extensions are accepted.

<Note>
  Walk-up discovery is **bounded** -- it never walks past the registered project root and never reaches `~/.config/clawker/`. Home-level configs are loaded separately via the explicit path mechanism.
</Note>

### Local Overrides

Clawker also discovers `clawker.local.yaml` (or `.clawker.local.yaml` / `.clawker/clawker.local.yaml`) files alongside the main config. These are intended for machine-specific or developer-specific settings that shouldn't be committed to version control.

At each directory level, both `clawker.yaml` and `clawker.local.yaml` are discovered. The local file merges at the same priority level but is loaded after the main file, so its values win.

```
.clawker.yaml              # Committed to git
.clawker.local.yaml        # In .gitignore -- personal overrides
```

### Precedence (Highest to Lowest)

```
1. .clawker.yaml in CWD (or .clawker/clawker.yaml)
2. .clawker.local.yaml in CWD
3. .clawker.yaml in parent directory
4. .clawker.local.yaml in parent directory
5. ... (continues up to project root)
6. .clawker.yaml at project root
7. .clawker.local.yaml at project root
8. ~/.config/clawker/clawker.yaml (user-level overrides)
9. Built-in defaults
```

### Project Registration

Walk-up discovery requires your project to be **registered** in the project registry. This is how Clawker knows where to stop walking up:

```bash theme={"dark"}
# Register during project init
clawker project init

# Or register an existing project
clawker project register
```

If CWD is not within a registered project, walk-up is skipped entirely and only the user config directory and defaults are used.

#### Project name normalization

When you register a project, Clawker derives the slug from your directory name. Mixed case becomes lowercase, spaces become hyphens, and the slug is used downstream for Docker container/volume names and the cert SAN identity. If the directory name produces a slug you don't like — or your directory name contains characters Docker won't accept — set the top-level `name` field in your `.clawker.yaml` to take over:

```yaml theme={"dark"}
name: my-app
```

The override applies at every command run (it's read from the project config, not the registry). The hierarchy is: positional/CLI flag > `.clawker.yaml::name` > directory-derived slug.

The registry is `registry.yaml` under clawker's data directory — `$XDG_DATA_HOME/clawker` (with `$XDG_DATA_HOME` itself defaulting to `~/.local/share` per the XDG Base Directory spec), or `$CLAWKER_DATA_DIR` when set — and maps project names to filesystem paths (managed via `clawker project` commands):

```yaml theme={"dark"}
projects:
  - name: "my-app"
    root: "/Users/dev/my-app"
    worktrees:
      feature-auth:
        path: "/Users/dev/.local/share/clawker/worktrees/my-app-auth-a1b2c3d4e5f6"
        branch: "feature/auth"
```

### Monorepo Support

The layered merge system enables monorepo workflows. Place a shared `.clawker.yaml` at the repo root with common settings, then add per-service overrides in subdirectories:

```
monorepo/
├── .clawker.yaml           # Shared: base image, firewall rules, common packages
├── services/
│   ├── api/
│   │   └── .clawker.yaml   # Override: add Python packages, different image
│   └── web/
│       └── .clawker.yaml   # Override: add Node packages, different env vars
```

To create a subdir config, run `clawker init` from inside the subdirectory. It detects that you're inside an existing project and skips project registration — going straight to preset selection and config file creation. The resulting file layers on top of the root config.

```bash theme={"dark"}
cd services/api
clawker init          # Interactive: pick a preset, customize
clawker init --yes    # Non-interactive: Bare preset defaults
```

When you run `clawker run` from `services/api/`, the engine merges:

1. `services/api/.clawker.yaml` (highest priority)
2. `.clawker.yaml` at repo root
3. `~/.config/clawker/clawker.yaml` (if exists)
4. Built-in defaults

Only the fields you specify in the subdirectory config are overridden. Everything else inherits from the parent.

### Writes

When Clawker writes configuration changes (e.g., via `clawker project init`), each field is routed back to the file it originally came from (provenance tracking). New fields that didn't come from any file are written to the highest-priority discovered file. All writes are atomic (temp file + fsync + rename) with advisory file locking for cross-process safety.

## Project Configuration Schema

The complete `.clawker.yaml` schema with all fields and nested object structures. Descriptions are shown as comments.

```yaml theme={"dark"}
# Override the project slug derived from the directory name (set this when the directory name isn't a good clawker identifier — e.g. dots, spaces, unicode)
name: <string>  # default: n/a | required: false
build:
  # Starting Docker image (e.g. node:20-slim, python:3.12); clawker layers tools on top
  image: <string>  # default: n/a | required: false
  # Use your own Dockerfile instead of clawker's generated one; ignores image, packages, and instructions
  dockerfile: <string>  # default: n/a | required: false
  # System packages (apt/apk) needed by your project that aren't in the base image
  packages:  # default: ripgrep | required: false
    - <string>
  # Directory to use as Docker build context when using a custom Dockerfile (relative to project root)
  context: <string>  # default: n/a | required: false
  instructions:
    # Bake config files or credentials into the image (e.g. .npmrc, SSH config)
    copy:
      # File or directory to copy from your project
      - src: <string>  # default: n/a | required: false
        # Where to place it inside the container
        dest: <string>  # default: n/a | required: false
        # Set file ownership (e.g. claude:claude)
        chown: <string>  # default: n/a | required: false
        # Set file permissions (e.g. 0644)
        chmod: <string>  # default: n/a | required: false
    # Environment variables baked into the image; use agent.env for runtime-only vars
    env:  # default: n/a | required: false
      <key>: <value>
    # Custom Docker labels for image metadata or tooling integration
    labels:  # default: n/a | required: false
      <key>: <value>
    # Build-time variables resolved during docker build (ARG); not available at runtime
    args:
      # Build argument name (referenced as $NAME in Dockerfile instructions)
      - name: <string>  # default: n/a | required: false
        # Value used when not overridden by --build-arg at build time
        default: <string>  # default: n/a | required: false
    # Setup commands that run as the container user (e.g. npm install -g, pip install)
    user_run:  # default: n/a | required: false
      - <string>
    # Setup commands that need root privileges (e.g. system config, additional repos)
    root_run:  # default: n/a | required: false
      - <string>
  inject:
    # Add Dockerfile instructions while root with only the base image — e.g. apt sources, proxy config, or CA certs that package installation depends on
    after_from:  # default: n/a | required: false
      - <string>
    # Add Dockerfile instructions while root with system packages available — e.g. compile native libraries or install tools that need those packages
    after_packages:  # default: n/a | required: false
      - <string>
    # Add Dockerfile instructions while root with the claude user created — e.g. set up directories, fix permissions, or configure services
    after_user_setup:  # default: n/a | required: false
      - <string>
    # Add Dockerfile instructions as the claude user — e.g. install dotfiles, configure your shell, or set up user-level tools
    after_user_switch:  # default: n/a | required: false
      - <string>
    # Add Dockerfile instructions as the claude user with Claude Code available — e.g. add MCP servers, install plugins, or extensions
    after_claude_install:  # default: n/a | required: false
      - <string>
    # Add Dockerfile instructions at the very end — e.g. final environment tweaks or cleanup that must happen after everything else
    before_entrypoint:  # default: n/a | required: false
      - <string>
agent:
  # Load environment variables from .env-style files (e.g. .env.local)
  env_file:  # default: n/a | required: false
    - <string>
  # Pass specific host env vars into the container (e.g. AWS_PROFILE, GITHUB_TOKEN)
  from_env:  # default: n/a | required: false
    - <string>
  # Set container env vars directly; use from_env to forward host values instead
  env:  # default: n/a | required: false
    <key>: <value>
  # Editor for git commits and interactive editing inside the container
  editor: <string>  # default: n/a | required: false
  # Visual editor ($VISUAL) for the container
  visual: <string>  # default: n/a | required: false
  claude_code:
    config:
      # How to initialize Claude Code config: copy syncs host settings/plugins, fresh starts clean
      strategy: <string>  # default: copy | required: false
    # Let the container use your host Claude Code credentials so you don't have to re-authenticate. The credential will be copied in at creation and persisted in the container's volume, but the container will refresh its tokens independently. If new containers keep starting unauthenticated, log in on the host to rotate the refresh token seed.
    use_host_auth: <boolean>  # default: true | required: false
    # Bind mount host ~/.claude/projects/ into the container so auto-memory and sessions are shared across container runs and instances
    mount_projects: <boolean>  # default: true | required: false
  # Share files between host and container via ~/.clawker-share (read-only in container)
  enable_shared_dir: <boolean>  # default: false | required: false
  # Shell commands to run after container starts but before Claude Code launches (e.g. install MCP servers). Useful for seeding claude code config or running setup steps that require the container environment to be up. Runs only one time after container creation in the workdir with env vars loaded.
  post_init: <string>  # default: n/a | required: false
  # Shell commands run on every container start, in the workdir, right before the CMD (default: claude) runs (e.g. npm install)
  pre_run: <string>  # default: n/a | required: false
workspace:
  # bind mounts your project live (edits sync); snapshot copies it (isolated, disposable)
  default_mode: <string>  # default: bind | required: true
security:
  firewall:
    # Shorthand: domains the container can reach over HTTPS (converted to https+port-443 rules)
    add_domains:  # default: n/a | required: false
      - <string>
    # Full egress rules with protocol, port, and path control
    rules:
      # Domain or IP the container needs to reach (e.g. api.github.com, registry.npmjs.org)
      - dst: <string>  # default: n/a | required: false
        # L7 protocol: https (TLS-MITM, default), http (plaintext HCM), ws/wss (websocket over http/https), ssh, tcp, udp, or any opaque L7 name for TCP pass-through
        proto: <string>  # default: n/a | required: false
        # Destination port: a single port (443) or an inclusive range (9000-9100); empty = protocol default
        port: <string>  # default: n/a | required: false
        # Allow or deny traffic to this destination (default: allow)
        action: <string>  # default: n/a | required: false
        # Fine-grained path filtering (only applies to http/https/ws/wss)
        path_rules:  # default: n/a | required: false
          # URL path to match: a literal prefix starting with / (e.g. /v1/api), or — when prefixed with ~ — an RE2 regex matched full-string for exact/anchored matching (e.g. ~/repos/(a|b)/?)
          - path: <string>  # default: n/a | required: false
            # Whether to allow or deny requests matching this path
            action: <string>  # default: n/a | required: false
            # HTTP methods this path rule applies to (e.g. GET, HEAD); empty = all methods. Only meaningful for http/https/ws/wss.
            methods:  # default: n/a | required: false
              - <string>
        # What to do with HTTP paths that don't match any path rule (allow or deny)
        path_default: <string>  # default: n/a | required: false
        # Accept a self-signed/untrusted upstream TLS cert for this destination (default: false). Use only for trusted local-dev endpoints.
        insecure_skip_tls_verify: <boolean>  # default: n/a | required: false
  # Mount the host Docker socket (DooD, not DinD) — lets the container manage sibling containers but is a security risk
  docker_socket: <boolean>  # default: false | required: true
  # Extra Linux capabilities for the agent container. Empty by default — the eBPF firewall is attached from outside, so no in-container caps are needed. Add e.g. SYS_PTRACE only if your workflow requires it.
  cap_add:  # default: n/a | required: false
    - <string>
  # Run a proxy for browser-based auth flows and credential forwarding from the host
  enable_host_proxy: <boolean>  # default: true | required: false
  git_credentials:
    # Let git clone/push use your host HTTPS credentials (via host proxy)
    forward_https: <boolean>  # default: true | required: false
    # Let git use your host SSH keys for cloning and pushing
    forward_ssh: <boolean>  # default: true | required: false
    # Let git sign commits using your host GPG keys
    forward_gpg: <boolean>  # default: true | required: false
    # Sync your host .gitconfig (aliases, user.name, user.email) into the container
    copy_git_config: <boolean>  # default: true | required: false
# Command aliases expanded before execution; the value is appended to 'clawker' and supports $1..$N placeholders; merged across all config layers
aliases:  # default: go=run --rm -it --agent $1 @ --dangerously-skip-permissions,wt=run --rm -it --agent $1 --worktree $2 @ --dangerously-skip-permissions | required: false
  <key>: <value>

```

## Project Configuration Reference

The following tables are auto-generated from the schema struct tags in `internal/config/schema.go`. Each section corresponds to a top-level key in `.clawker.yaml`.

### name

| Field  | Type   | Default | Description                                                                                                                                               |
| ------ | ------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | —       | Override the project slug derived from the directory name (set this when the directory name isn't a good clawker identifier — e.g. dots, spaces, unicode) |

### build

| Field        | Type        | Default   | Description                                                                                           |
| ------------ | ----------- | --------- | ----------------------------------------------------------------------------------------------------- |
| `image`      | string      | —         | Starting Docker image (e.g. node:20-slim, python:3.12); clawker layers tools on top                   |
| `dockerfile` | string      | —         | Use your own Dockerfile instead of clawker's generated one; ignores image, packages, and instructions |
| `packages`   | string list | `ripgrep` | System packages (apt/apk) needed by your project that aren't in the base image                        |
| `context`    | string      | —         | Directory to use as Docker build context when using a custom Dockerfile (relative to project root)    |

#### instructions

| Field      | Type          | Default | Description                                                                       |
| ---------- | ------------- | ------- | --------------------------------------------------------------------------------- |
| `copy`     | object list   | —       | Bake config files or credentials into the image (e.g. .npmrc, SSH config)         |
| `env`      | key-value map | —       | Environment variables baked into the image; use agent.env for runtime-only vars   |
| `labels`   | key-value map | —       | Custom Docker labels for image metadata or tooling integration                    |
| `args`     | object list   | —       | Build-time variables resolved during docker build (ARG); not available at runtime |
| `user_run` | string list   | —       | Setup commands that run as the container user (e.g. npm install -g, pip install)  |
| `root_run` | string list   | —       | Setup commands that need root privileges (e.g. system config, additional repos)   |

#### inject

| Field                  | Type        | Default | Description                                                                                                                                        |
| ---------------------- | ----------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `after_from`           | string list | —       | Add Dockerfile instructions while root with only the base image — e.g. apt sources, proxy config, or CA certs that package installation depends on |
| `after_packages`       | string list | —       | Add Dockerfile instructions while root with system packages available — e.g. compile native libraries or install tools that need those packages    |
| `after_user_setup`     | string list | —       | Add Dockerfile instructions while root with the claude user created — e.g. set up directories, fix permissions, or configure services              |
| `after_user_switch`    | string list | —       | Add Dockerfile instructions as the claude user — e.g. install dotfiles, configure your shell, or set up user-level tools                           |
| `after_claude_install` | string list | —       | Add Dockerfile instructions as the claude user with Claude Code available — e.g. add MCP servers, install plugins, or extensions                   |
| `before_entrypoint`    | string list | —       | Add Dockerfile instructions at the very end — e.g. final environment tweaks or cleanup that must happen after everything else                      |

### agent

| Field               | Type          | Default | Description                                                                                                                                                                                                                                                                                             |
| ------------------- | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `env_file`          | string list   | —       | Load environment variables from .env-style files (e.g. .env.local)                                                                                                                                                                                                                                      |
| `from_env`          | string list   | —       | Pass specific host env vars into the container (e.g. AWS\_PROFILE, GITHUB\_TOKEN)                                                                                                                                                                                                                       |
| `env`               | key-value map | —       | Set container env vars directly; use from\_env to forward host values instead                                                                                                                                                                                                                           |
| `editor`            | string        | —       | Editor for git commits and interactive editing inside the container                                                                                                                                                                                                                                     |
| `visual`            | string        | —       | Visual editor (\$VISUAL) for the container                                                                                                                                                                                                                                                              |
| `enable_shared_dir` | boolean       | `false` | Share files between host and container via \~/.clawker-share (read-only in container)                                                                                                                                                                                                                   |
| `post_init`         | string        | —       | Shell commands to run after container starts but before Claude Code launches (e.g. install MCP servers). Useful for seeding claude code config or running setup steps that require the container environment to be up. Runs only one time after container creation in the workdir with env vars loaded. |
| `pre_run`           | string        | —       | Shell commands run on every container start, in the workdir, right before the CMD (default: claude) runs (e.g. npm install)                                                                                                                                                                             |

#### claude\_code

| Field            | Type    | Default | Description                                                                                                                                                                                                                                                                                                                                        |
| ---------------- | ------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `strategy`       | string  | `copy`  | How to initialize Claude Code config: copy syncs host settings/plugins, fresh starts clean                                                                                                                                                                                                                                                         |
| `use_host_auth`  | boolean | `true`  | Let the container use your host Claude Code credentials so you don't have to re-authenticate. The credential will be copied in at creation and persisted in the container's volume, but the container will refresh its tokens independently. If new containers keep starting unauthenticated, log in on the host to rotate the refresh token seed. |
| `mount_projects` | boolean | `true`  | Bind mount host \~/.claude/projects/ into the container so auto-memory and sessions are shared across container runs and instances                                                                                                                                                                                                                 |

### workspace

| Field          | Type   | Default | Description                                                                                          |
| -------------- | ------ | ------- | ---------------------------------------------------------------------------------------------------- |
| `default_mode` | string | `bind`  | bind mounts your project live (edits sync); snapshot copies it (isolated, disposable) **(required)** |

### security

| Field               | Type        | Default | Description                                                                                                                                                                                                  |
| ------------------- | ----------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `docker_socket`     | boolean     | `false` | Mount the host Docker socket (DooD, not DinD) — lets the container manage sibling containers but is a security risk **(required)**                                                                           |
| `cap_add`           | string list | —       | Extra Linux capabilities for the agent container. Empty by default — the eBPF firewall is attached from outside, so no in-container caps are needed. Add e.g. SYS\_PTRACE only if your workflow requires it. |
| `enable_host_proxy` | boolean     | `true`  | Run a proxy for browser-based auth flows and credential forwarding from the host                                                                                                                             |

#### firewall

| Field         | Type        | Default | Description                                                                               |
| ------------- | ----------- | ------- | ----------------------------------------------------------------------------------------- |
| `add_domains` | string list | —       | Shorthand: domains the container can reach over HTTPS (converted to https+port-443 rules) |
| `rules`       | object list | —       | Full egress rules with protocol, port, and path control                                   |

#### git\_credentials

| Field             | Type    | Default | Description                                                                   |
| ----------------- | ------- | ------- | ----------------------------------------------------------------------------- |
| `forward_https`   | boolean | `true`  | Let git clone/push use your host HTTPS credentials (via host proxy)           |
| `forward_ssh`     | boolean | `true`  | Let git use your host SSH keys for cloning and pushing                        |
| `forward_gpg`     | boolean | `true`  | Let git sign commits using your host GPG keys                                 |
| `copy_git_config` | boolean | `true`  | Sync your host .gitconfig (aliases, user.name, user.email) into the container |

### aliases

| Field     | Type          | Default                                                                                                                                 | Description                                                                                                                                     |
| --------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `aliases` | key-value map | `go=run --rm -it --agent $1 @ --dangerously-skip-permissions,wt=run --rm -it --agent $1 --worktree $2 @ --dangerously-skip-permissions` | Command aliases expanded before execution; the value is appended to 'clawker' and supports $1..$N placeholders; merged across all config layers |

## Interactive Editing

Instead of editing YAML by hand, you can use Clawker's built-in interactive editor:

```bash theme={"dark"}
# Edit project configuration (.clawker.yaml)
clawker project edit

# Edit user settings (settings.yaml)
clawker settings edit
```

The editor opens a TUI with your configuration fields grouped into tabs. You can browse fields, see their current values and defaults, edit them inline, and save. When you save a field, you choose which config layer to write it to — for example, saving to a local override file instead of the committed project config. The editor also shows which file each value comes from, so you can see exactly how the layered merge is working.

## User Settings Schema

The complete `settings.yaml` schema.

```yaml theme={"dark"}
logging:
  # Write structured logs to disk for debugging and diagnostics
  file_enabled: <boolean>  # default: true | required: false
  # Rotate the log file when it exceeds this size
  max_size_mb: <integer>  # default: 50 | required: false
  # Delete rotated logs older than this
  max_age_days: <integer>  # default: 7 | required: false
  # Number of rotated log files to keep
  max_backups: <integer>  # default: 3 | required: false
  # Gzip rotated logs to save disk space
  compress: <boolean>  # default: true | required: false
  otel:
    # Send logs to the OTEL collector for OpenSearch visibility (requires monitoring stack running)
    enabled: <boolean>  # default: false | required: false
    # Give up on an export batch after this long
    timeout_seconds: <integer>  # default: 5 | required: false
    # Buffer this many log records before dropping (increase if you see gaps)
    max_queue_size: <integer>  # default: 2048 | required: false
    # How often to flush buffered logs to the collector
    export_interval_seconds: <integer>  # default: 5 | required: false
monitoring:
  # Host port for the OTEL HTTP receiver
  otel_collector_port: <integer>  # default: 4318 | required: false
  # Hostname for reaching the collector from the host
  otel_collector_host: <string>  # default: localhost | required: false
  # Host port for the OTEL gRPC receiver
  otel_grpc_port: <integer>  # default: 4317 | required: false
  # Port the OTel collector listens on for infra service logs (CP, Envoy, CoreDNS)
  otel_infra_port: <integer>  # default: 4319 | required: false
  # Host port for the OpenSearch REST API (logs + traces backend)
  opensearch_port: <integer>  # default: 9200 | required: false
  # Host port for the OpenSearch Dashboards UI
  opensearch_dashboards_port: <integer>  # default: 5601 | required: false
  # JVM -Xms/-Xmx for the OpenSearch node; raise on memory-hungry workloads
  opensearch_heap_mb: <integer>  # default: 512 | required: false
  # Host port for the Prometheus UI and its native OTLP receiver (agent metrics flow through the OTEL collector, not here; this port is only used by direct OTLP pushers)
  prometheus_port: <integer>  # default: 9090 | required: false
  # In-network port the otel-collector exposes its Prometheus scrape endpoint on (Prometheus scrapes the collector over clawker-net for collector + agent metrics; not host-published — no localhost binding, no host port-conflict check needed)
  prometheus_metrics_port: <integer>  # default: 8889 | required: false
  telemetry:
    # HTTP path on Prometheus' native OTLP receiver — available for direct OTLP/HTTP pushers that want to bypass the collector
    prometheus_otlp_path: <string>  # default: /api/v1/otlp/v1/metrics | required: false
    # How often Claude exports metrics (lower = more granular, higher = less overhead)
    metric_export_interval_ms: <integer>  # default: 10000 | required: false
    # How often Claude exports logs (lower = more real-time, higher = less overhead)
    logs_export_interval_ms: <integer>  # default: 5000 | required: false
    # Capture full tool call inputs/outputs in telemetry (verbose but useful for debugging)
    log_tool_details: <boolean>  # default: true | required: false
    # Capture user prompts in telemetry (disable for privacy)
    log_user_prompts: <boolean>  # default: true | required: false
    # Tag telemetry with your Anthropic account ID (useful for multi-user setups)
    include_account_uuid: <boolean>  # default: true | required: false
    # Tag telemetry with session ID to correlate events across a single run
    include_session_id: <boolean>  # default: true | required: false
host_proxy:
  manager:
    # Local port the host proxy listens on (change if 18374 conflicts)
    port: <integer>  # default: 18374 | required: false
  daemon:
    # Local port the proxy daemon binds to
    port: <integer>  # default: 18374 | required: false
    # How often to check if containers still need the proxy
    poll_interval: <duration>  # default: 30s | required: false
    # How long to keep the proxy alive after the last container stops
    grace_period: <duration>  # default: 60s | required: false
    # Restart the proxy daemon after this many consecutive failures
    max_consecutive_errs: <integer>  # default: 10 | required: false
firewall:
  # Master switch for the Envoy firewall; when off, containers have unrestricted network access
  enable: <boolean>  # default: true | required: true
control_plane:
  # gRPC admin API port (CLI ↔ CP)
  admin_port: <integer>  # default: 7443 | required: false
  # Plain HTTP /healthz readiness endpoint
  health_port: <integer>  # default: 7080 | required: false
  # Hydra OAuth2 token endpoint (HTTPS)
  hydra_public_port: <integer>  # default: 4444 | required: false
  # Hydra admin API for introspection and client registration (HTTPS, container-internal)
  hydra_admin_port: <integer>  # default: 4445 | required: false
  # Oathkeeper HTTP auth proxy for future webui (HTTPS)
  oathkeeper_port: <integer>  # default: 4456 | required: false
  # Oathkeeper management API (HTTPS, container-internal)
  oathkeeper_api_port: <integer>  # default: 4457 | required: false
  # Kratos identity public API (HTTPS, container-internal)
  kratos_public_port: <integer>  # default: 4433 | required: false
  # Kratos identity admin API (HTTPS, container-internal)
  kratos_admin_port: <integer>  # default: 4434 | required: false
  # In-container gRPC port for clawkerd agent connections (mTLS, clawker-net only)
  agent_port: <integer>  # default: 7444 | required: false
docker:
  # Host path to the Docker daemon socket
  socket: <string>  # default: /var/run/docker.sock | required: false

```

## User Settings Reference

Global settings live at `~/.config/clawker/settings.yaml`. The following tables are auto-generated from the schema struct tags.

### logging

| Field          | Type    | Default | Description                                                 |
| -------------- | ------- | ------- | ----------------------------------------------------------- |
| `file_enabled` | boolean | `true`  | Write structured logs to disk for debugging and diagnostics |
| `max_size_mb`  | integer | `50`    | Rotate the log file when it exceeds this size               |
| `max_age_days` | integer | `7`     | Delete rotated logs older than this                         |
| `max_backups`  | integer | `3`     | Number of rotated log files to keep                         |
| `compress`     | boolean | `true`  | Gzip rotated logs to save disk space                        |

#### otel

| Field                     | Type    | Default | Description                                                                                   |
| ------------------------- | ------- | ------- | --------------------------------------------------------------------------------------------- |
| `enabled`                 | boolean | `false` | Send logs to the OTEL collector for OpenSearch visibility (requires monitoring stack running) |
| `timeout_seconds`         | integer | `5`     | Give up on an export batch after this long                                                    |
| `max_queue_size`          | integer | `2048`  | Buffer this many log records before dropping (increase if you see gaps)                       |
| `export_interval_seconds` | integer | `5`     | How often to flush buffered logs to the collector                                             |

### monitoring

| Field                        | Type    | Default     | Description                                                                                                                                                                                                                                   |
| ---------------------------- | ------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `otel_collector_port`        | integer | `4318`      | Host port for the OTEL HTTP receiver                                                                                                                                                                                                          |
| `otel_collector_host`        | string  | `localhost` | Hostname for reaching the collector from the host                                                                                                                                                                                             |
| `otel_grpc_port`             | integer | `4317`      | Host port for the OTEL gRPC receiver                                                                                                                                                                                                          |
| `otel_infra_port`            | integer | `4319`      | Port the OTel collector listens on for infra service logs (CP, Envoy, CoreDNS)                                                                                                                                                                |
| `opensearch_port`            | integer | `9200`      | Host port for the OpenSearch REST API (logs + traces backend)                                                                                                                                                                                 |
| `opensearch_dashboards_port` | integer | `5601`      | Host port for the OpenSearch Dashboards UI                                                                                                                                                                                                    |
| `opensearch_heap_mb`         | integer | `512`       | JVM -Xms/-Xmx for the OpenSearch node; raise on memory-hungry workloads                                                                                                                                                                       |
| `prometheus_port`            | integer | `9090`      | Host port for the Prometheus UI and its native OTLP receiver (agent metrics flow through the OTEL collector, not here; this port is only used by direct OTLP pushers)                                                                         |
| `prometheus_metrics_port`    | integer | `8889`      | In-network port the otel-collector exposes its Prometheus scrape endpoint on (Prometheus scrapes the collector over clawker-net for collector + agent metrics; not host-published — no localhost binding, no host port-conflict check needed) |

#### telemetry

| Field                       | Type    | Default                   | Description                                                                                                              |
| --------------------------- | ------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `prometheus_otlp_path`      | string  | `/api/v1/otlp/v1/metrics` | HTTP path on Prometheus' native OTLP receiver — available for direct OTLP/HTTP pushers that want to bypass the collector |
| `metric_export_interval_ms` | integer | `10000`                   | How often Claude exports metrics (lower = more granular, higher = less overhead)                                         |
| `logs_export_interval_ms`   | integer | `5000`                    | How often Claude exports logs (lower = more real-time, higher = less overhead)                                           |
| `log_tool_details`          | boolean | `true`                    | Capture full tool call inputs/outputs in telemetry (verbose but useful for debugging)                                    |
| `log_user_prompts`          | boolean | `true`                    | Capture user prompts in telemetry (disable for privacy)                                                                  |
| `include_account_uuid`      | boolean | `true`                    | Tag telemetry with your Anthropic account ID (useful for multi-user setups)                                              |
| `include_session_id`        | boolean | `true`                    | Tag telemetry with session ID to correlate events across a single run                                                    |

### host\_proxy

#### manager

| Field  | Type    | Default | Description                                                      |
| ------ | ------- | ------- | ---------------------------------------------------------------- |
| `port` | integer | `18374` | Local port the host proxy listens on (change if 18374 conflicts) |

#### daemon

| Field                  | Type     | Default | Description                                                     |
| ---------------------- | -------- | ------- | --------------------------------------------------------------- |
| `port`                 | integer  | `18374` | Local port the proxy daemon binds to                            |
| `poll_interval`        | duration | `30s`   | How often to check if containers still need the proxy           |
| `grace_period`         | duration | `60s`   | How long to keep the proxy alive after the last container stops |
| `max_consecutive_errs` | integer  | `10`    | Restart the proxy daemon after this many consecutive failures   |

### firewall

| Field    | Type    | Default | Description                                                                                                |
| -------- | ------- | ------- | ---------------------------------------------------------------------------------------------------------- |
| `enable` | boolean | `true`  | Master switch for the Envoy firewall; when off, containers have unrestricted network access **(required)** |

### control\_plane

| Field                 | Type    | Default | Description                                                                           |
| --------------------- | ------- | ------- | ------------------------------------------------------------------------------------- |
| `admin_port`          | integer | `7443`  | gRPC admin API port (CLI ↔ CP)                                                        |
| `health_port`         | integer | `7080`  | Plain HTTP /healthz readiness endpoint                                                |
| `hydra_public_port`   | integer | `4444`  | Hydra OAuth2 token endpoint (HTTPS)                                                   |
| `hydra_admin_port`    | integer | `4445`  | Hydra admin API for introspection and client registration (HTTPS, container-internal) |
| `oathkeeper_port`     | integer | `4456`  | Oathkeeper HTTP auth proxy for future webui (HTTPS)                                   |
| `oathkeeper_api_port` | integer | `4457`  | Oathkeeper management API (HTTPS, container-internal)                                 |
| `kratos_public_port`  | integer | `4433`  | Kratos identity public API (HTTPS, container-internal)                                |
| `kratos_admin_port`   | integer | `4434`  | Kratos identity admin API (HTTPS, container-internal)                                 |
| `agent_port`          | integer | `7444`  | In-container gRPC port for clawkerd agent connections (mTLS, clawker-net only)        |

### docker

| Field    | Type   | Default                | Description                           |
| -------- | ------ | ---------------------- | ------------------------------------- |
| `socket` | string | `/var/run/docker.sock` | Host path to the Docker daemon socket |

You can also place a `clawker.yaml` in `~/.config/clawker/` to set user-level project config defaults. This file is merged as the lowest-priority project config layer (just above built-in defaults), so any project-level `.clawker.yaml` overrides it.

## Command Aliases

The `aliases` key in the project config defines command shortcuts that are expanded before execution, merged across every config layer like any other project config key:

```yaml theme={"dark"}
aliases:
  go: run --rm -it --agent $1 @ --dangerously-skip-permissions
  lg: logs $1 --tail $2
```

Manage them with the `clawker alias` command group (`set`, `list`, `export`, `delete`). See the [Command Aliases](/aliases) guide for expansion semantics, shipped defaults, team sharing, and the full rules.

## Directory Structure

Clawker follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/latest/). Files are organized across three directories:

| Directory | Location                   | Contents                                                       |
| --------- | -------------------------- | -------------------------------------------------------------- |
| Config    | `$XDG_CONFIG_HOME/clawker` | `settings.yaml`, `clawker.yaml` (user-level project overrides) |
| Data      | `$XDG_DATA_HOME/clawker`   | `registry.yaml`, worktree directories, `.clawker-share`        |
| State     | `$XDG_STATE_HOME/clawker`  | Log files, PID files, update cache                             |

These follow the XDG base directories, which themselves default to `~/.config`, `~/.local/share`, and `~/.local/state` when the `XDG_*_HOME` vars are unset — so on a typical machine the directories land at `~/.config/clawker`, `~/.local/share/clawker`, and `~/.local/state/clawker`. To point clawker somewhere else without touching your XDG vars, set `CLAWKER_CONFIG_DIR`, `CLAWKER_DATA_DIR`, or `CLAWKER_STATE_DIR` — each takes precedence over its `XDG_*_HOME` counterpart. (On Windows, `%AppData%` / `%LOCALAPPDATA%` stand in for the unset XDG defaults.)
