# claw-forge configuration — generated by `claw-forge init`
# Edit providers below, then copy .env.example → .env and fill in your keys.

model_aliases:
  opus:   ${MODEL_OPUS:-claude-opus-4-6}
  sonnet: ${MODEL_SONNET:-claude-sonnet-5}
  haiku:  ${MODEL_HAIKU:-claude-haiku-4-6}
  fast:   ${MODEL_FAST:-claude-haiku-4-6}

pool:
  # Provider routing strategy when more than one provider is configured
  # in ``providers:`` below.  Pick one of:
  #   quality_ranked  — (default) rank enabled providers by measured
  #                     gate-pass rate, folded from this project's own
  #                     ``state.db`` attempt history, best first.  A
  #                     provider below ``pool.quality_min_attempts``
  #                     (default 5) gated attempts is UNRANKED — unknown,
  #                     not bad — and every unranked provider sits below
  #                     every ranked one, ordered by ``priority:`` and then
  #                     list order among themselves.  Among RANKED
  #                     providers, an exact rate tie prefers the warm
  #                     provider (the one routing last selected, whose
  #                     provider-scoped prompt cache is usually still hot),
  #                     then lower ``priority:`` value, then list order —
  #                     warmth is not consulted in the unranked tail.  A
  #                     fresh project with no measured history yet has
  #                     every provider unranked, so it routes exactly like
  #                     ``priority``.
  #   priority        — always prefer the highest-priority provider
  #                     (lowest ``priority:`` integer wins); only fall
  #                     through when its CircuitBreaker opens.  Use when
  #                     one provider is clearly preferable (cheaper,
  #                     faster, or your "primary") and others are
  #                     standby fallbacks.  Providers that share a
  #                     ``priority:`` keep config-file order, and that
  #                     order never rotates — equal priority means "same
  #                     tier", not "spread load across these".  Use
  #                     round_robin or weighted_random for that.
  #   round_robin     — rotate through enabled providers in order; each
  #                     request advances a cursor by one.  Best when
  #                     providers have similar latency / cost profiles
  #                     (e.g. several proxy keys for the same upstream);
  #                     evens out load and bypasses circuit-open providers
  #                     automatically.  No quality term at all, so a
  #                     heterogeneous pool gets spread work uniformly
  #                     regardless of which provider is actually good.
  #   weighted_random — random order weighted by each provider's
  #                     ``weight:`` field (higher wins; see the commented
  #                     example below).  Use for stochastic load
  #                     balancing without strict round-robin order.
  #                     NOT ``priority:``, which is inverted (lower wins)
  #                     and is ignored by this strategy.  ``weight:``
  #                     defaults to 1.0, so leaving every provider at the
  #                     default is uniform random — fine on purpose, but
  #                     it is not weighted routing.
  #
  #   Retired: least_cost and least_latency optimized cost and latency —
  #   axes this project ranks below quality — against quality itself.
  #   Either value in an old config still runs: it is routed through the
  #   same shim that resolves this default, onto quality_ranked, with one
  #   WARNING naming the retired value and its replacement.  It is never
  #   silently honored and never crashes an unattended upgrade.
  strategy: quality_ranked
  # May a bare ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN in your shell or
  # .env bypass this pool?  Before 1.14.2 it always did — silently, so a
  # carefully configured pool ran every agent on one credential and
  # rotation never happened.  Pick one of:
  #   fallback — (default) the pool wins whenever it holds at least one
  #              enabled provider; a shell credential is used only when
  #              the pool has none.  A single-key setup with no providers
  #              configured still works, and a real pool is never bypassed.
  #              Note a pool whose providers have all tripped their
  #              circuit breakers is *exhausted*, not empty: that still
  #              drains rather than falling back.
  #   prefer   — the pre-1.14.2 behaviour: a shell credential short-
  #              circuits the pool.  Use only to deliberately pin every
  #              agent to one credential.
  #   ignore   — never read a shell credential on the dispatch path, so a
  #              misconfigured pool fails loudly instead of quietly
  #              running on your personal key.
  env_credential: fallback
  # CircuitBreaker tuning — opens a provider's breaker after this many
  # consecutive failures (rate-limit, network error, 5xx).  Once open,
  # the router skips this provider until ``recovery_timeout`` elapses.
  failure_threshold: 5
  # Per-request retry attempts before falling through to the next
  # provider in the rotation.  Total fallback attempts across the pool
  # = max_retries × len(providers).
  max_retries: 3
  # Seconds to wait before re-probing a provider whose CircuitBreaker
  # opened.  Lower this for chatty debugging; raise it for flaky
  # upstreams that need longer to recover.
  recovery_timeout: 60

providers:
  # Claude OAuth — run `claude setup-token` once, paste token into .env
  claude-oauth:
    type: anthropic_oauth
    oauth_token: ${ANTHROPIC_OAUTH_TOKEN}   # from `claude setup-token`
    priority: 1
    enabled: true

  # Direct Anthropic API key (set enabled: true and add ANTHROPIC_API_KEY to .env)
  anthropic-direct:
    type: anthropic
    api_key: ${ANTHROPIC_API_KEY}
    priority: 2
    enabled: false

  # Anthropic-compatible proxy (optional)
  # anthropic-proxy:
  #   type: anthropic_compat
  #   api_key: ${PROXY_API_KEY}
  #   base_url: ${PROXY_BASE_URL}
  #   model: ${PROXY_MODEL}
  #   priority: 3     # lower wins — read by `strategy: priority`
  #   weight: 5.0     # higher wins — read by `strategy: weighted_random`
  #   enabled: true

  # Local Ollama (optional, free)
  # local-ollama:
  #   type: ollama
  #   base_url: http://localhost:11434
  #   model: qwen2.5:32b
  #   priority: 10
  #   enabled: true

# ── Orchestrator ─────────────────────────────────────────────────────────
orchestrator:
  # Exit non-zero when the run ends with pending tasks dropped as
  #     unsatisfiable (their dependency failed, or its squash was abandoned
  #     at the merge-retry cap).  Those tasks did NOT run and are NOT
  #     counted as failed, so by default the run prints the drop and still
  #     exits 0 — which a `claw-forge run && ...` script cannot distinguish
  #     from convergence.  Turn this on if you script around the exit code.
  #     Note `agent.assembly_gate.fail_run` is the other failing exit path.
  fail_run_on_stranded_tasks: false

agent:
  default_model: ${MODEL_DEFAULT:-claude-sonnet-5}
  plan_model: null  # separate model for planning phase (e.g. claude-opus-4-6)
  max_tokens: 8192
  max_concurrent_agents: 5
  # Fast test entry point (optional). When set, every agent is taught the
  # two-speed test loop: iterate with THIS command (seconds, targeted), run
  # the full suite at most once before declaring done. Point it at a make
  # target or script that runs a targeted subset without multi-minute
  # worker/bootstrap overhead. Measured motivation: tasks dominated by
  # dozens of repeated in-task full-suite passes at minutes each.
  # fast_test_command: "make test-fast"
  # Task-level acceptance gating: after an agent reports a task complete, run
  # the project's test command in its worktree; a non-zero exit blocks
  # completion (the task flips to `failed` and the retry loop re-runs the agent
  # with the failures in its resume preamble). "Done" then means verified, not
  # just claimed. Auto-skips when no test command is detected (greenfield).
  #
  # OFF by default (2026-10-06): a full-suite gate costs minutes and gigabytes
  # of RAM per task, concurrent suites can OOM a small box, and on a red
  # baseline the gate mostly records FORGIVEN — verification theater at full
  # price. Enable it once the project's suite is green, bounded, in
  # claw-forge.local.yaml:
  #
  #   agent:
  #     acceptance_gate:
  #       enabled: true
  #       scope: package       # narrows turbo/pnpm monorepo gates to the
  #                            # packages a task touches; falls back to the
  #                            # full suite everywhere else
  #       max_concurrent: 1    # gates run suites one at a time — two
  #                            # concurrent full suites can OOM a small box
  #
  #   OPTIONAL, deliberately not part of the recipe above — a deliberate
  #   second step, not a peer of the keys you just copied:
  #
  #       reuse_agent_run: true
  #
  #   skips the gate's duplicate suite run when the agent's LAST command
  #   was exactly the gate command and the harness watched it pass on an
  #   unchanged tree.  It trades gate EXECUTION for harness-OBSERVED
  #   evidence: the agent's shell is persistent, so an earlier PATH
  #   export, cd, or tool shim can make the identical command string mean
  #   something else, invisibly.  Reused passes record the distinct
  #   verdict ``PASSED:agent_run`` (`claw-forge status` labels them
  #   "passed (agent's own run reused)") — enable this only after you
  #   have watched a few of those hold up in your project.
  #
  # (The run summary suggests this block when it sees merged-but-unverified
  # work beside a detectable test suite.)
  acceptance_gate:
    enabled: false
    # ``scope: full`` (default) runs the whole suite in the task's worktree.
    #     ``scope: package`` narrows a shape="plugin" task's gate to the
    #     workspace packages its touches_files actually cover (turbo / pnpm
    #     workspaces only).  On a large monorepo the full suite runs for every
    #     task — hodago: ~4,587 tests x 300+ tasks — and any inherited or flaky
    #     failure anywhere can fail unrelated work.  Narrowing trades
    #     cross-package regression coverage for throughput, so it is opt-in;
    #     it falls back to the full suite whenever the footprint cannot be
    #     mapped onto packages confidently.
    #     Narrowing ADDS package filters to the gate command — it never
    #     substitutes a different one, so the command must ITSELF be a turbo
    #     or pnpm invocation.  Auto-detection yields ``npm test`` for any
    #     repo with a package.json, and whether that root script delegates to
    #     turbo is not knowable, so it is left un-narrowed: set ``command``
    #     below to e.g. ``npx turbo run test`` to opt a monorepo in.
    scope: full
    # command: ""        # override; empty -> auto-detect (pytest/npm/cargo/go)
    # timeout: 600       # seconds before the test run is killed (exit 124)
  # Run-boundary assembly verification.  Every other gate runs inside a
  # worktree, which cannot see integration — integration is the property that
  # exists only BETWEEN tasks.  This one runs on target_branch after every
  # task has merged and checks that declared <layout> seams actually reference
  # the plugin roots that were built.
  assembly_gate:
    enabled: true
    # ``fail_run: true`` makes `claw-forge run` exit non-zero when the gate
    #     fails.  This is the FIRST failing exit path on `run` — set false if
    #     you script `claw-forge run && ...` and are not ready for it.
    fail_run: true
    # Integration tasks created per failing gate before giving up.  1 by
    # design: the repair agent runs exclusively, with full write permission,
    # against a finding naming the file and the exact symbols missing from it.
    repair_attempts: 1
    # End-of-run reachability audit: the run's own diff is scanned for new
    #     top-level public symbols that no other tracked file references —
    #     the "71/71 green, product dead" shape where a component or DI seam
    #     lands fully tested and wired to nothing.  Advisory warnings only;
    #     never fails a run.  Set false to silence it.
    reachability: true
    # Optional boot probe — stronger evidence, needs project knowledge.
    #     Seam population proves the wiring was WRITTEN; the boot probe proves
    #     it RUNS, which is the tier that catches a seam whose only mention of
    #     its components is a "// TODO: mount ..." comment.  Runs only when
    #     ``build`` or ``liveness`` is set.  ``start`` is spawned in its own
    #     session and killed afterwards, so a server never outlives the probe.
    #     ``liveness`` is retried until it exits 0 or ``timeout`` elapses — a
    #     server is not ready the instant it is spawned.
    # build: ""          # e.g. "uv sync --all-packages"
    # start: ""          # e.g. "uv run uvicorn app.main:app --port 8099"
    # liveness: ""       # an http(s):// URL to fetch, or a command exiting 0.
    #                    #   URL:     http://127.0.0.1:8099/health
    #                    #   command: test -S /tmp/app.sock
    #                    # Any non-5xx status counts as alive — a 404 on the
    #                    # probe path still proves the server is up and routing.
    # timeout: 300       # seconds for the build, and for liveness to come up
  # Edit tool mode for agent file operations.
  # ``hashline`` (default): content-addressed line tagging — fewer
  # ambiguous-match edit failures on long files; auto-raises the
  # dispatcher's failure-retry threshold by 3 (e.g. 5 → 8).
  # ``str_replace``: legacy exact-text matching.  Override per-run with
  # ``claw-forge run --edit-mode <mode>``.
  edit_mode: hashline    # hashline | str_replace
  # Per-agent isolation mode — defends against the agent writing files
  # outside its assigned worktree (the v0.8.14/15 leak class).  See
  # CLAUDE.md → "Worktree-Leakage Defenses" for the full layered design.
  #
  # ``sandbox`` (default, v0.8.18 → v0.8.21): OS-level filesystem jail
  #     per agent process.
  #     - macOS: wraps the ``claude`` CLI in ``sandbox-exec`` so writes
  #       outside the worktree return ``EACCES``.
  #     - Linux (v0.8.21+): wraps the ``claude`` CLI in ``bwrap``
  #       (bubblewrap) so writes outside the worktree fail at
  #       ``open(2)``.  Requires ``bwrap`` on PATH.
  #     - Other OSes (Windows, BSD): falls back to the behavioural-only
  #       stack (Layers 1–3 + snapshot-rollback) with a logged warning.
  #
  # ``container`` (v0.8.19): per-agent Docker/Podman container with the
  #     worktree mounted at ``/workspace`` and the parent project absent
  #     from the container's filesystem namespace.  Strongest isolation
  #     — escapes return ``ENOENT`` rather than ``EACCES``.  Opt-in
  #     because it requires a container runtime + an operator-built
  #     image (Dockerfile template in docs/container-isolation.md) +
  #     adds ~1–3s per-task startup latency.  Right for security-
  #     sensitive deployments, untrusted prompts, multi-tenant hosts,
  #     and CI pipelines.  Set ``agent.container.image`` when using
  #     this mode; see docs/container-isolation.md for full config.
  #
  # ``process`` (deprecated alias for ``sandbox``, kept for backward
  #     compat with v0.8.18 → v0.8.20 configs).
  isolation: sandbox     # sandbox | container | process (alias)
  # container:
  #   runtime: auto              # docker | podman | auto
  #   image: my-claw-forge-agent
  #   pull_if_missing: false     # opt-in to auto-pull from registry
  #   extra_mounts: []
  #   extra_env: []

  # Supply-chain hardening (v0.8.33).  Two defaults-on knobs that defend
  # against the package-manager blast radius the OS sandbox alone doesn't
  # cover.  Both default ``true``; set to ``false`` to opt out per-project.
  #
  # ``npm_ignore_scripts: true`` injects ``npm_config_ignore_scripts=true``
  #     + ``YARN_ENABLE_SCRIPTS=false`` into the agent's environment so
  #     ``npm install`` / ``pnpm install`` / ``yarn install`` skip
  #     ``postinstall`` hooks — the dominant npm-supply-chain vector
  #     (compromised package runs code as the npm child process the moment
  #     it's installed, bypassing every static Bash hook).  Disable only
  #     if a project legitimately depends on install-time side effects
  #     (e.g. native module compilation that runs in postinstall).
  npm_ignore_scripts: true
  # ``dynamic_file_claims: true`` claims a write target that falls OUTSIDE the
  #     task's declared ``touches_files`` at the moment of the write.
  #     Dispatch-time file-claims only cover the *declared* footprint, but
  #     measured conformance is ~3% — agents routinely edit undeclared shared
  #     files (package.json, a barrel index.ts, tsconfig.base.json), which take
  #     no lock and only collide later as a merge conflict that discards a
  #     whole agent run.  A write is denied ONLY when another *running* task
  #     already holds that file; every other outcome (state service
  #     unreachable, unexpected status) fails open, so claim enforcement never
  #     becomes a liveness gate.  Set false to restore pre-0.8.115 behaviour.
  dynamic_file_claims: true
  # Infrastructure-scoped failures (missing toolchain, dead credential,
  # sandbox unavailable) do not spend the agent retry budget — no retry
  # fixes a broken box.  They get this separate, smaller budget instead;
  # at the cap the task fails for real with its scope preserved.
  # 0 disables infra re-pending (every infra failure is terminal).
  infra_retry_attempts: 2
  # Agent-scoped failures (the agent gave up, or the acceptance gate went
  # red) re-pend under this budget — the ONLY retry channel they have.
  # A failed task is dispatched again in a later wave, and its previous
  # error_message is fed back to the agent in the retry preamble, so the
  # second attempt starts by reading its own failure.  At the cap the task
  # fails for real, annotated with the attempt count.
  # 0 disables agent re-pending (every agent failure is terminal on its
  # first attempt — the pre-1.8.1 behaviour).
  agent_retry_attempts: 2
  # A third, unrelated budget: how many times to re-invoke a task handler
  # that *raises* — a crash in the harness or the SDK, not a task that
  # failed — with 1s/2s/4s… back-off.  A task whose agent merely failed
  # returns rather than raises, so it is never retried by this; that is
  # what agent_retry_attempts above is for.  YOLO mode overrides this to 5.
  exception_retry_attempts: 3
  # ``sandbox.home_protection: true`` extends the OS sandbox-exec / bwrap
  #     profile with deny rules for credential stores (~/.ssh, ~/.aws,
  #     ~/.gnupg, ~/.config/gh, ~/.docker, ~/.kube), shell rc files
  #     (.bashrc, .zshrc, .profile, .gitconfig, .netrc), package-manager
  #     caches (~/.npm, ~/.cache, ~/.yarn), package-manager global
  #     config (pnpm's ~/.config/pnpm, ~/Library/Preferences/pnpm), and
  #     macOS / Linux persistence dirs (~/Library/LaunchAgents,
  #     /etc/cron.d, /etc/systemd/system).  Reads are still allowed;
  #     only writes are blocked.  No-op in container mode (the
  #     container's filesystem namespace already excludes ``$HOME``).
  # ``sandbox.tmp_protection`` extends the OS sandbox to the shared temp
  #     roots (/tmp, /var/tmp).  Agents' temp traffic is already redirected
  #     into <worktree>/.claw-forge/tmp via TMPDIR, but hardcoded /tmp paths
  #     bypass an env var.  ``auto`` (default): on for Linux bwrap — each
  #     agent gets a private, ephemeral tmpfs /tmp, so nothing breaks and
  #     nothing leaks; off for macOS sandbox-exec, whose only tool is a
  #     write-deny that would break /tmp unix sockets (e.g. postgres's
  #     default socket dir).  Set ``true``/``false`` to override per project.
  # ``uv_cache_dir`` (opt-in): one shared uv package cache for the whole
  #     project instead of the per-worktree default.  A relative value
  #     resolves against the PROJECT ROOT (never the cwd); the sandbox
  #     grants exactly this one directory as an extra write surface, and
  #     ``init`` pre-gitignores the conventional ``.uv-cache/`` spot.
  #     Trade-off: faster installs across worktrees vs a shared mutable
  #     cache every agent can write (poisoning blast radius spans tasks).
  # uv_cache_dir: .uv-cache
  sandbox:
    home_protection: true
    tmp_protection: auto
    # ``sandbox.fence_to_touches_files: false`` (opt-in).  When true, a
    #     shape="plugin" task's OS sandbox is narrowed from the whole
    #     worktree down to the directories its touches_files declare (plus
    #     the .claw-forge scratch dir).  An agent writing outside its
    #     declared footprint then fails with EACCES instead of silently
    #     editing a shared file.  Requires plugins to register via
    #     auto-discovery (validator Gap 11 flags shared-file edits).  Core
    #     and unannotated tasks are unaffected.  Default false until the
    #     false-positive rate is established.
    fence_to_touches_files: false

  # ── Network isolation (opt-in, v0.8.33 scaffold) ──────────────────────
  # Reserved for a future network-egress allowlist that would replace the
  # default-open network behavior with a strict allowlist.  Useful for
  # paranoid deployments where you want to stop a compromised package or
  # malicious agent action from exfiltrating data over arbitrary HTTP(S)
  # targets.  Composes with ``isolation: sandbox``; container mode users
  # achieve the same effect via ``docker run --network none`` + explicit
  # ``extra_mounts``.  Uncomment to opt in once implemented:
  #
  # network_isolation:
  #   mode: allowlist            # off | allowlist
  #   allowed_hosts:
  #     - api.anthropic.com      # Claude API — always needed
  #     - registry.npmjs.org     # if you use npm
  #     - pypi.org               # if you use pip
  #     - github.com             # if your agent clones repos
  #     - api.github.com         # if your agent uses gh CLI
  #   # Note: DNS still works freely; only outbound TCP connect()s are
  #   # restricted.  Enable ``isolation: container`` for stronger guarantees.

skills:
  - pyright
  - typescript-lsp
  - rust-analyzer
  - systematic-debug
  - git-workflow

state:
  # database_url: sqlite+aiosqlite:///path/to/state.db  # (default)
  host: "0.0.0.0"
  port: 8420
  # Self-reclaim for an orphaned state service.  The service is started
  # detached so Ctrl+C on a run never reaches it, and the run's own reap is
  # skipped while a Kanban client is connected — so without this an open
  # browser tab at Ctrl+C time leaks a service that outlives its run and
  # keeps serving pre-upgrade code.  It exits only when the owning run is
  # gone, no dispatcher has heartbeated, no client is watching, and it has
  # served no request for this long.  0 disables.
  idle_exit_seconds: 1800

git:
  enabled: true
  merge_strategy: auto    # auto | manual
  branch_prefix: feat
  target_branch: main
  commit_on_plugin_boundary: true
  # Smart-mode startup cleanup: walk .claw-forge/worktrees/ at startup and
  # preserve/salvage/remove per task state in the DB.  See docs/commands.md
  # for the full decision matrix.  ``smart`` (default) prevents stale
  # worktrees from accumulating across runs; ``manual`` falls back to the
  # legacy ``orphans_reset > 0`` gate that only fires after an interrupted
  # run.  Smart mode is a no-op when ``merge_strategy: manual``.
  cleanup_orphan_worktrees: smart     # smart | manual

  # Gitignored-but-required files copied from the project root into every
  #     fresh worktree.  A worktree contains only the files git TRACKS, and it
  #     cannot fetch the rest itself — the agent's file sandbox jails reads to
  #     its own worktree, so the parent project's ``.env`` is unreadable, not
  #     merely absent.  Dependencies are handled automatically; this is for
  #     everything else: ``.env``, a dev certificate, a seeded fixture DB.
  #     Empty by default — claw-forge does not guess about secrets.
  #     Each file is copied only after ``git check-ignore`` proves the worktree
  #     ignores it.  Anything committable is SKIPPED with a warning, because
  #     auto-checkpoint's ``git add -A`` would otherwise commit it to the
  #     feature branch and squash-merge it into your target branch.
  # worktree_seed_files:
  #   - .env
  #   - certs/dev.pem
  # When smart-mode salvage hits a real merge conflict, drafts
  # CONFLICT_PROPOSAL.md inside the preserved worktree via claude_agent_sdk.
  # Advisory only — never lands on main; the user reviews and applies.
  # On by default — conflicts are rare, and when they happen having a
  # ready-to-review proposal beats reasoning from scratch.  Costs one
  # agent call per conflict.  Set to false to disable if you'd rather
  # resolve conflicts by hand or don't want the API spend.
  llm_conflict_proposals: true        # set to false to disable the advisor
  # After every successful squash-merge, push <target_branch> to its remote.
  # Set to true to use 'origin' (default) or to a remote name string like
  # "upstream" for forks.  No-op merges and missing remotes are silent
  # skips; push failures are warnings, never fail the task.  Off by default.
  push_after_merge: false
  # Ecosystem-aware auto-resolution of merge conflicts on *shared* files that
  # parallel agents edit as side-effects but don't declare in touches_files —
  # dependency manifests (pyproject.toml, package.json, Cargo.toml, …),
  # lockfiles (uv.lock, package-lock.json, pnpm-lock.yaml, bun.lock, …), and
  # env templates (.env.example).  During a catch-up merge these conflicts are
  # resolved mechanically (union / strict-validated union / lockfile regen)
  # instead of failing the task or burning an agent retry.  Whole-set gated and
  # best-effort: a conflict on any *unregistered* file (real source code) is
  # left untouched for the agent, and any failure falls back to today's
  # behavior.  See docs/superpowers/specs/
  # 2026-06-10-shared-file-conflict-resolution-design.md.
  shared_file_resolution:
    enabled: true      # set false to disable mechanical resolution entirely
  # At ``claw-forge run`` startup, ensure the main worktree is clean
  # (everything committed to HEAD) before any agent worktree branches off.
  # ``smart`` (default, autonomous): archive untracked files to
  # .claw-forge/orphans/ with PROVENANCE.json, stash dirty-tracked state
  # with a marker message — both reversible, no human in the loop.
  # ``abort`` (fail-fast): refuse to start whenever any uncommitted state
  # exists.  ``ignore`` (legacy): handler doesn't run.
  handle_uncommitted_at_startup: smart   # ignore | smart | abort

# Training-trace capture (ON by default for fresh `claw-forge init`).
# claw-forge records every agent message during `claw-forge run` into the
# state.db events table for export-and-fine-tune workflows.
#
# Anthropic's Usage Policies prohibit using Claude outputs to develop models
# that compete with Anthropic's services.  This feature is intended for
# personal/internal distillation on your own code.  Set both flags to false
# to disable recording.  See docs/training/unsloth-recipe.md for the
# export → train → eval flow.
training_traces:
  enabled: true
  acknowledged_terms: true
  redaction:
    secrets: true                 # scrub well-known token / API-key patterns
    usernames: true               # /Users/<you>/ → /Users/<USER>/
    paths: false                  # full path anonymization (signal-destroying; off)
    custom_patterns: []
  retention:
    # 0 = forever; else prune agent_message events older than N days.
    keep_days: 0
    on_state_service_startup: true

update:
  # Best-effort, 24h-throttled check against PyPI for a newer claw-forge
  # release.  Prints a one-line notice (never blocks, never installs
  # anything) when one is available; upgrade explicitly with:
  #   claw-forge upgrade
  # Turn it off with any one of:
  #   check_enabled: false          (this project)
  #   CLAW_FORGE_NO_UPDATE_CHECK=1
  # CI environments are always excluded.
  check_enabled: true

telemetry:
  # Anonymous, structural-only usage telemetry — ON BY DEFAULT.
  # You are automatically opted in; see PRIVACY.md for the usage agreement
  # and exactly what is (and is never) collected.  No free text ever leaves
  # your machine: no project names, paths, source, prompts, or IPs.
  # Turn it off with any one of:
  #   claw-forge telemetry disable   (permanent, this install)
  #   enabled: false                 (add the key below, this project)
  #   DO_NOT_TRACK=1  or  CLAW_FORGE_TELEMETRY=0
  # CI environments are always excluded.
  # See exactly what would be sent:  claw-forge telemetry preview
  # Booleans accept a quoted / ${ENV}-substituted string too (e.g.
  # enabled: "${TELEMETRY_ENABLED}") — true/1/yes/on and false/0/no/off are
  # both recognised, case-insensitively.
  sink: webhook                  # none | hosted | otlp | webhook
  # Leave blank to use the project's hosted collector
  # (https://telemetry.claw-forge.net).  Set your own URL to self-host.
  # This key decides *where*, never *whether* — to stop collection use one of
  # the opt-outs listed above, or `sink: none`.
  endpoint: ""
  include_economics: true        # token + provider counters
  flush_on_exit: true
  # Second-tier consent: also transmits normalised feature-category labels
  # as raw strings, to improve the domain classifier.  Off by default —
  # category labels occasionally carry client or product names.
  include_category_labels: false

# diagnostics:
#   invariants:
#     # Record internal-consistency violations to the log instead of ignoring
#     # them.  Never fatal: a violation is a diagnostic, not a liveness gate.
#     enabled: false
