# .red/config.yaml — per-project plugin settings (consumed by /afk and friends)
# Uncomment any line to override the default.

# Plugin activation gate (ADR 0067). RedSkills hooks are installed globally on
# every agent but stay fully inert in any directory whose `.red/config.yaml`
# does NOT set `plugins.<name>.enabled: true`. /red-setup writes this
# block; it is the only authorized creator of `.red/`. Strict opt-in: a block
# without `enabled: true` is OFF.
plugins:
  dev:
    enabled: true                 # the engineering stack (/afk, /triage, /retake, …)
  #   trunk: main                 # canonical location: plugins.dev.trunk.
  #                               # The Trunk (ADR 0083): the focal branch agent work
  #                               # bases on and lands to when no lock/pin names one
  #                               # (precedence lock > pin > trunk). Always consumed
  #                               # as fresh-fetched origin/<trunk>, never the local
  #                               # branch. Set e.g. develop or workspace/<user>.
  #   lock:
  #     primary-branch: true      # branch-lock compatibility/base-pinning flag
  #                               # (Section H of /red-setup sets this)
  #     branch: my-branch         # static base lock: AFK bases/merges here (ADR 0031);
  #                               # the runtime /branch-lock overrides it per session
  #   dispatch:
  #     engine_floor: warn        # what a SUPERSEDED engine costs a dispatch.
  #                               # At dispatch time the engine that would run is
  #                               # compared against the published dist-tag:
  #                               # `warn` (default) dispatches loudly naming both
  #                               # versions, `refuse` is a hard stop that mints
  #                               # nothing, `off` silences the check. An
  #                               # unreachable registry always degrades to a
  #                               # warning — offline dispatch must not die.
  #   triage:
  #     external_pr_surface:
  #       enabled: false          # default OFF. When true, /triage may list/read
  #                               # external PRs as request data. It still treats
  #                               # PR bodies/diffs as untrusted and never checks
  #                               # out, builds, tests, or executes PR code.
  #   afk:
  #     standing:                 # optional persistent project drain
  #       runner: codex           # one of redcode, claude-code, codex, pi,
  #                               # opencode — the child ACP Agent a Worker runs
  #       target: 4               # both leaves are required; a half-written block
  #                               # stays inert. MCP startup registers the block,
  #                               # and the daemon keeps recoverable intent while
  #                               # queued work remains
  #     standing_orders:          # durable maintainer directives (#4141)
  #       enabled: false          # opt OUT only. When left alone, `.red/
  #                               # STANDING-ORDERS.md` (if it exists) is read at
  #                               # every handoff composition and emitted verbatim
  #                               # as the handoff's <standing-orders> section, so
  #                               # an instruction given once survives every
  #                               # respawn. An absent file emits nothing.
  #     setup:                    # required repository-owned dependency setup
  #       - LEFTHOOK=0 pnpm install --frozen-lockfile
  #                               # /red-setup detects the package/hook managers,
  #                               # confirms exact commands, and writes them here.
  #                               # AFK runs declared commands verbatim; the
  #                               # engine never substitutes a package manager.
  #     validation:               # operator-declared Validation moments (ADR 0135)
  #       preflight: false        # experimental: preview exact post_done commands
  #                               # before DONE; default off, gate still enforces
  #       subsecond_failures_are_branch_fault: false
  #                               # Set true only when the declared suite can
  #                               # legitimately fail in under one second.
  #       iteration:              # light checks named in the inner-agent handoff
  #         - pnpm test
  #       post_done:              # runs after DONE against the branch fork point
  #         - pnpm typecheck
  #         - pnpm lint
  #       landing: []             # before push/PR/queue; [] is declared empty
  #                               # Omit a moment to skip it loudly. /red-setup
  #                               # discovers package-manifest scripts, proposes
  #                               # this block, and writes only after confirmation.
  #                               # The merge queue is the CI-side final Validation moment.
  #     implementer:
  #       skills: dev:tdd, dev:diagnose
  #       runner_startup_baseline_ms: 840
  #                               # Optional exact worker skill allowlist. Entries
  #                               # are `plugin:skill`, comma-separated. It replaces
  #                               # the trimmed implementer default (so it can widen
  #                               # or narrow it) but never bypasses the ADR 0067
  #                               # `plugins.<name>.enabled: true` activation gate.
  #                               # baseline_ms is an optional historical
  #                               # unprojected invocation-to-first-event sample.
  #   review:
  #     appraisal_floor: off      # `off` records the 0-1 Appraisal only. Set a
  #                               # 0-1 floor to make lower scores consume the
  #                               # review's reserved Re-seed round and park on
  #                               # exhaustion through the validation path.
  # memory:
  #   enabled: true               # then run /memory:init to pick a storage mode
  # brain:
  #   enabled: true               # the agentic command-center context

# Release standard (ADR 0139). /red-setup detects the workspace's Version
# surfaces, proposes this entire block, and writes it only after operator
# confirmation. The release engine re-derives npm/Cargo workspace members and
# refuses drift from this declared contract while naming the orphan package.
# release:
#   scheme: semver                 # `semver` (default) or calver `YYYY.M.MICRO`
#   trigger: version-pr            # `version-pr` (default) or `auto`
#   prerelease: true               # default false; true enables RC graduation
#   execution: pinned              # pinned npx (default) or `vendored` bundle
#   version_surfaces:              # non-empty, one product version for the workspace
#     - path: package.json
#       format: npm                # `npm`, `cargo`, or `text`
#     - path: packages/cli/package.json
#       format: npm
#     - path: Cargo.toml
#       format: cargo
#     - path: VERSION.txt
#       format: text
#   sync_command: node scripts/sync-release-carriers.mjs
#                                 # optional repo-owned propagation for exotic carriers;
#                                 # receives the next version as RED_RELEASE_VERSION

# rsp hook activation and retention (ADR 0095 amended by ADR 0098). /red-setup
# provisions `.red/state/red-skills.rdb`; the hook remains inert unless this
# explicit flag is true.
rsp:
  enabled: true
  ttlDays: 7
  ephemeralTtlHours: 6
  byteBudget: 67108864            # 64 MiB

# Required host binaries (ADR 0097). /red-setup installs these through their
# checksum-verified upstream installers and records the exact pin here so
# /red-doctor can red-flag absence or version drift. tq is required for
# TOON/TOONL inspection; there is no jq fallback lane.
host_binaries:
  tq:
    version: 0.26.2

# Built-in dev shell guard: once plugins.dev.enabled is true, agent-created
# worktrees must live under a registered .red/tmp/ lane, and branch-changing
# commands in the primary checkout are blocked. Create task branches with:
#   git worktree add .red/tmp/worktrees/manual/<slug> -b <branch> origin/main
#
# Command guard policy. The installed Claude Code, Codex, and opencode hooks are
# thin proxies: they read this repo-owned policy at runtime and stay inert unless
# plugins.dev.enabled is true. These rules are additional to the built-in
# registered .red/tmp worktree boundary above. Uncomment only rules this repo actually wants.
# command_guard:
#   global:                       # applies in main sessions and runtime worktrees
#     - "rm -Rf /*"
#     - "git stash"
#   main:                         # primary interactive session scope, not branch name
#     - "git rebase"
#     - "git checkout -b"
#   worktree:                     # /afk and /go worktrees under .red/tmp/
#     - "git clean"

# afk:
#   default_runner: claude        # fallback runner when no explicit signal
#   worktree_launches_pull_request: true   # landing MODE, decoupled from the lock
#                                 # (ADR 0030 amended, #842). true (default) → land
#                                 # via an admin-merged PR into the resolved base;
#                                 # false → direct merge into that base (offline,
#                                 # no PR). The branch-lock only resolves the target
#                                 # base (lock > pin > main, ADR 0031), NOT the mode.
#                                 # How a PR merges stays governed by `afk.merge.*`.
#                                 # NOTE: default true means a locked repo now gets
#                                 # an admin-PR to the lock branch; set false to keep
#                                 # the old offline/direct-promotion flow.
#   routes:                       # optional task-class runner + pair (flag/env/project_start pins win)
#     validate:
#       runner: codex             # omitted tier → default_runner
#       model: gpt-5.6-sol        # omitted value → selected runner's tier table
#       effort: high
#     simple:
#       runner: codex
#     complex:
#       runner: claude
#     think:
#       runner: claude
#   models:                       # suggested fallback table for every supported runner
#     claude:
#       validate:
#         model: claude-opus-5
#         effort: high
#       simple:
#         model: claude-opus-5
#         effort: high
#       complex:
#         model: claude-opus-5
#         effort: high
#       think:
#         model: claude-opus-5
#         effort: high
#     codex:
#       validate:
#         model: gpt-5.6-sol
#         effort: high
#       simple:
#         model: gpt-5.6-sol
#         effort: high
#       complex:
#         model: gpt-5.6-sol
#         effort: high
#       think:
#         model: gpt-5.6-sol
#         effort: high
#     hermes:                     # explicit: never silently inherits Claude's table
#       base:
#         model: claude-opus-5
#         effort: high
#     opencode:                   # proposed current OpenRouter ids; OpenCode syntax is provider/model
#       validate:
#         model: openrouter/anthropic/claude-haiku-4.5
#         effort: low
#       simple:
#         model: openrouter/anthropic/claude-sonnet-5
#         effort: high
#       complex:
#         model: openrouter/anthropic/claude-opus-5
#         effort: high
#       think:
#         model: openrouter/anthropic/claude-opus-5
#         effort: high
#     claude-minimax:             # MiniMax-M3 rejects high/thinking; runtime accepts low only
#       base:
#         model: MiniMax-M3
#         effort: low             # honest provider constraint, not a quality compromise
#   fleet:
#     target: 2                   # default supervisor worker target
#     scope:                      # cgroup isolation for the fleet (#2697)
#       enabled: true             # Linux + systemd `--user`: run the supervisor in a
#                                 # transient `red-fleet-<name>.scope` so a memory-pressure
#                                 # kill hits the fleet, not the terminal that launched it.
#                                 # `false` (or `RED_AFK_FLEET_SCOPE=off`) launches unscoped
#                                 # — the launcher warns, it never skips silently.
#       memory_high: 70%          # the scope's `MemoryHigh` throttle; any systemd memory
#                                 # value ("70%", "6G"). Empty sets no property.
#   release:                      # bundle release channel (ADR 0058)
#     channel: canary             # `stable` (default = today's version-pinned
#                                 # release) or `canary` (npm dist-tag pointer to
#                                 # an already-published stable package version).
#                                 # The launcher reads this or the
#                                 # `RED_SKILLS_CHANNEL` env var (env wins); absent
#                                 # config keeps tracking stable. Canary promotion
#                                 # moves the npm dist-tag (scripts/afk-promote-channel.sh),
#                                 # gated on the proof-by-drain telemetry.
#   output_shaping:
#     terse_steering: false       # default OFF. When true, even-numbered issues
#                                 # get a phrasing-only terse steering block;
#                                 # odd-numbered issues are the holdout. The arm
#                                 # is stamped next to heartbeat output-token
#                                 # counters and reported by `afk-output-shaping`.
#   test:
#     quarantine:                 # config-declared flaky-test quarantine lane (issue #1035).
#                                 # Each entry excludes a known-flaky test file from the
#                                 # scoped gate run and emits a visible "quarantined" sidecar
#                                 # record — exclusions are NEVER silent (repo norm). An entry
#                                 # without an issue ref fails the gate loudly. /red-doctor warns
#                                 # when a referenced issue is closed (managed debt, not
#                                 # permanent forgetting).
#                                 # Pattern is a repo-relative file path passed to vitest
#                                 # --exclude (relative to the scope dir at run time).
#                                 # Named entries e0, e1, e2 … are read in order until the
#                                 # first gap.
#       e0:
#         pattern: apps/plugin-dev/tests/supervisor.test.ts
#         issue: "https://github.com/reddb-io/red-skills/issues/1063"
#         since: "2026-07-02"
#         reason: "OOM under AFK fleet=2 concurrent load (exit 137 / SIGKILL)"
#       e1:
#         pattern: apps/plugin-brain/tests/dashboard.test.ts
#         issue: "https://github.com/reddb-io/red-skills/issues/1064"
#         since: "2026-07-02"
#         reason: "tsx spawn timeout under concurrent AFK load (40 s ceiling)"
#   hooks:
#     defaults:
#       cargo: true               # ship cargo isolation on Rust projects
#       gradle: true              # ship gradle isolation when GRADLE_USER_HOME_BASE is set
#   trust-gate:                   # "executable issue" trust gate (#621, ADR 0085)
#     allowlist: alice,bob        # comma/space-separated GitHub logins. An issue is
#                                 # executable only when its AUTHOR is in this list AND
#                                 # `ready-for-agent` was applied by a listed actor
#                                 # (read from the issue timeline, not the label set).
#                                 # ABSENT/empty (the default) → PERMISSIVE: the gate
#                                 # never fires and every ready-for-agent issue is
#                                 # claimable, exactly as today. Setting it switches the
#                                 # repo to STRICT mode; a ready-for-agent applied by a
#                                 # non-listed actor is skipped at claim and may be
#                                 # stripped by a sweep with an audit comment.
