"Defines the yellow-plugins.local.md per-project config file schema. Use when authoring commands that should accept per-project overrides for review pipeline behavior, reviewer set narrowing, depth controls, or focus-area filtering."
Install
npx skillscat add kinginyellows/yellow-plugins/local-config Install via the SkillsCat registry.
yellow-plugins.local.md — per-project configuration
yellow-plugins.local.md is an optional per-project config file that
lets a project override defaults for yellow-plugins commands. Place it at
the repo root (next to CLAUDE.md). The file uses YAML frontmatter for
structured settings and an optional markdown body for human-readable
notes.
What It Does
- Provides a single, discoverable location for per-project overrides to
yellow-plugins command behavior. - Doubles as the rollback escape hatch for the Wave 2 review-pipeline
rewrite — projects experiencing high false-positive review noise can
setreview_pipeline: legacyand the pre-Wave-2 adaptive selection is
used instead. - Supports optional
reviewer_set.{include,exclude}for narrowing or
expanding the persona dispatch table without forking commands.
When to Use
- A project wants to skip specific reviewer personas
(reviewer_set.exclude: [adversarial-reviewer]) - A project wants to force the legacy pipeline during the Wave 2
dogfooding period (review_pipeline: legacy) - A project wants to narrow review focus to specific areas
(focus_areas: [security, correctness]) - A project wants a custom
review_depthregardless of diff size
(review_depth: largeto always invokeadversarial-reviewer)
When the file is absent, all commands use their built-in defaults.
The file is purely additive — no command behavior depends on its
existence.
Usage
File location and shape
<repo-root>/yellow-plugins.local.mdFrontmatter-only is the typical shape; a markdown body is optional and
used only by humans (commands ignore the body).
Schema
---
# review:pr / review:all behavior overrides (Wave 2 keys)
review_pipeline: persona | legacy # default: persona (Wave 2 default)
review_depth: small | medium | large # default: auto-detect from diff size
focus_areas: [security, correctness, ...] # default: all areas
reviewer_set:
include: [<agent-name>, ...] # additional agents to spawn beyond defaults
exclude: [<agent-name>, ...] # agents to skip
reviewer_selection: off | shadow | jev # default: off (review:pr only; jev = shadow for now)
reviewer_selection_private_repos: [<owner/repo | owner/*>, ...] # user-level file only; default: empty
# Wave 3 keys (documented; consumer adoption tracked per-key below)
stack: [ts, py, rust, go] # default: auto-detect from repo
agent_native_focus: true | false # default: false
confidence_threshold: 0..100 # default: 75
resolve_pr:
cluster_line_distance: 10 # default: 10 (positive integer)
cluster_cap: 20 # default: 20 (positive integer)
verify_command: "pnpm test" # default: unset (no verification)
verify_unattended: false # default: false (opt in for --non-interactive)
verify_timeout_seconds: 540 # default: 540 (integer 1–540)
repass_wait_seconds: 120 # default: 120 (integer 0–480; 0 disables)
repass_max_passes: 5 # default: 5 (integer 1–10)
resolve_human_threads: evidence # evidence | never | all
---Consumer adoption status (Wave 3 keys): the keys are valid frontmatter
today and parsers do not warn on them, but the commands that act on them
land in separate Wave 3 PRs:
| Key | Acted on by | Status |
|---|---|---|
stack |
polyglot-reviewer, review:pr Step 4 dispatch |
Pending W3 polyglot scoping. Until then: documented but ignored. |
agent_native_focus |
review:pr Step 4 dispatch (forces W3.5 reviewers) |
Pending W3.5 (agent-native-reviewers branch). Until then: documented but ignored. |
confidence_threshold |
review:pr aggregation gate, audit-synthesizer |
Pending W3.13b (yellow-debt-confidence-calibration branch). Until then: documented but ignored. |
resolve_pr.cluster_line_distance |
review:resolve Step 3d cluster threshold |
Acted on by review:resolve (W3.3). Invalid values (non-integer, ≤ 0) emit a warning to stderr and fall back to the default 10. |
resolve_pr.cluster_cap, verify_command, verify_unattended, verify_timeout_seconds, repass_wait_seconds, repass_max_passes, resolve_human_threads |
review:resolve Steps 4–8 |
Acted on by review:resolve. See the field reference for defaults and fallbacks. |
Authors may set Wave 3 keys today without breaking Wave 2 consumers — the
graceful-degradation rule (unknown keys emit a warning but do not abort)
means the file remains valid forward-and-backward.
Field reference
| Field | Type | Default | Effect |
|---|---|---|---|
review_pipeline |
persona | legacy |
persona |
legacy falls back to pre-Wave-2 adaptive selection (no learnings pre-pass, no confidence rubric, no new personas). Use as escape hatch only. |
review_depth |
small | medium | large |
auto | Forces a depth tier regardless of computed diff size. large always invokes adversarial-reviewer; small skips it even on large diffs. |
focus_areas |
array of strings | empty (= all) | Narrows reviewer set to those whose category matches one of the listed areas. Recognized areas: security, correctness, reliability, performance, maintainability, project-compliance, project-standards, architecture, testing, documentation, types, adversarial. Always-on personas (project-compliance-reviewer, correctness-reviewer, maintainability-reviewer, project-standards-reviewer) survive the filter regardless of focus_areas — filtering them out would defeat the always-on contract. |
reviewer_set.include |
array of agent names | empty | Additive — agents are spawned even if their conditional triggers don't fire. This is also the only way to reach thermonuclear-reviewer (yellow-review): an opt-in structural-quality persona that appears in neither dispatch table, so it runs only when named here. Two silent drops apply to include, both visible in the precedence pseudo-code under "Reading the config from a command". First, review_pipeline: legacy branches before overrides are read at all, so include has no effect there. Second, focus_areas filters the merged set afterwards, and thermonuclear-reviewer is not always-on (its category is maintainability), so an included thermonuclear-reviewer survives only when focus_areas is unset or lists maintainability. Neither drop emits a diagnostic. |
reviewer_set.exclude |
array of agent names | empty | Subtractive — agents are skipped even if always-on or their triggers fire. Applied after include. |
reviewer_selection |
off | shadow | jev |
off |
/review:pr only. shadow logs, per review, the conditional personas the table's exact rules pick, the set the orchestrator picked, and the set TypeSafe's Jev would pick from one request on the redacted diff, to <git-common-dir>/yellow-review/jev-persona/ (yellow-review references/review-pr/persona-shadow.md). It never changes which reviewers run. jev behaves as shadow until per-persona switching ships. The Jev call needs TYPESAFE_API_KEY and sends diff text to a third party only for public repositories or those in reviewer_selection_private_repos (docs/security.md "Persona selection shadow log"). The only key with a user-level fallback: when the repo file leaves it unset, ${CLAUDE_CONFIG_DIR:-$HOME/.claude}/yellow-plugins.local.md is read, so one line there enables it for every repository. |
reviewer_selection_private_repos |
array of owner/repo or owner/* |
empty | Private repositories that may send their redacted diff to Jev under reviewer_selection: shadow; owner/* covers every repository of that owner (case-insensitive). Read only from the user-level ${CLAUDE_CONFIG_DIR:-$HOME/.claude}/yellow-plugins.local.md; a value in a repository's file is ignored, because /review:pr reads config from the checked-out PR head, where a contributor could add an opt-in. A repository whose visibility cannot be read counts as private. |
stack |
array of ts | py | rust | go |
auto-detect | Forces language-specific reviewer behavior. When set, polyglot-reviewer (when triggered) scopes to listed languages and skips non-matching files. Auto-detect uses repo root signals: package.json → ts, pyproject.toml/requirements.txt → py, Cargo.toml → rust, go.mod → go. Multi-stack repos may set this explicitly to scope review to a subset. Acted on by W3-pending consumers (see status table). |
agent_native_focus |
boolean | false |
When true, always invokes the W3.5 agent-native reviewer triplet (cli-readiness-reviewer, agent-cli-readiness-reviewer, agent-native-reviewer) regardless of whether the diff touches plugins/*/agents/, plugins/*/skills/, or plugins/*/commands/. Useful for repos that author Claude Code plugins but house plugin code outside the standard plugins/ layout. Acted on by W3.5 (pending). |
confidence_threshold |
integer 0–100 | 75 |
Override the Wave 2 confidence aggregation gate used by review:pr and audit-synthesizer. Values below 75 surface more findings (more false positives, fewer missed issues); values above 75 suppress more (fewer false positives, more missed issues). Set above 100 to suppress all findings (effectively a dry-run). Acted on by W3.13b (pending). |
resolve_pr.cluster_cap |
positive integer | 20 |
Maximum resolver clusters review:resolve --non-interactive dispatches (Step 4). Extra clusters are reported as blocking not attempted (cluster cap). Invalid values warn and use 20. |
resolve_pr.verify_command |
string | unset | Shell command review:resolve runs from the repo root before committing resolver fixes (Step 6). On failure it attempts to save a patch under the git common dir, reverts the resolver files and holds fixed threads open; a patch the credential screen flags or cannot screen is withheld. Interactive runs show it with git diff --stat and ask first. Unset means no verification. The command runs test and script files the resolvers may just have edited from untrusted review comments, with your credentials. |
resolve_pr.verify_unattended |
boolean | false |
Lets --non-interactive runs (/review:sweep, /review:resolve-stack) execute verify_command. When false, unattended runs behave as if verify_command were unset: nothing runs and threads resolve normally. When true, verify still does not run if yellow-plugins.local.md is tracked by git (verify skipped (tracked config)) or the fixes touch runner files — code or config a verify command, package manager or git hook would execute, such as package.json, lockfiles, .npmrc, Makefile, conftest.py, pyproject.toml or anything under the repo-root scripts/ or any .husky/ (full list in yellow-review's references/resolve/dispositions.md) — (verify skipped (runner files changed)); in both cases fixed threads are held open. Keep this file untracked and ignored: add yellow-plugins.local.md to .git/info/exclude (or a global or repo .gitignore), because an untracked file that is not ignored shows as ?? yellow-plugins.local.md and stops /review:resolve at its clean-tree check. The runner gate refuses only a deny list of known entry points (manifests, lockfiles, hooks, root scripts/, test setup files), so the command can still execute any source file the test suite imports: opt in only for repositories whose review comments you trust. |
resolve_pr.verify_timeout_seconds |
integer 1–540 | 540 |
Timeout for verify_command; the command is killed 10 s after it. Capped so the run fits Claude Code's 600 s Bash tool limit. Invalid or larger values warn and use the default or cap. |
resolve_pr.repass_wait_seconds |
integer 0–480 | 120 |
How long each review:resolve Step 8 poll waits (fetching every 20 s) for new threads after a successful push before the next re-pass. 0 disables the re-pass. Capped so the poll fits the Bash tool limit. Out-of-range or non-integer values warn and use 120. |
resolve_pr.repass_max_passes |
integer 1–10 | 5 |
Most re-passes review:resolve Step 8 runs after the first pass. The loop also ends sooner: no new thread within the wait, a pass that did not push, a re-pass whose new threads are all P2 or lower, or a new thread on a line this run already fixed. A non-integer warns and uses 5; a value outside 1–10 warns and is clamped to the nearer bound. repass_wait_seconds: 0 still disables the re-pass. |
resolve_pr.resolve_human_threads |
evidence | never | all |
evidence |
Which human-reviewer threads review:resolve may resolve. evidence: resolve fixed (verified push) and addressed (verified pointer); oos and disagree reply and stay open. Dropped non-actionable threads are also resolved, except under never. never: reply only and never resolve. all: same as bot threads. A thread counts as a bot thread only when every comment you did not write is from a Bot account (and all its comments were fetched); one human reply makes it human. Other values warn and use evidence. |
resolve_pr.cluster_line_distance |
positive integer | 10 |
Cluster threshold for review:resolve Step 3d. Adjacent threads on the same file with line distance ≤ this value merge into a single resolver task (transitive merge). Larger values cluster more aggressively (fewer resolvers, broader edits per agent); smaller values keep clusters tighter. Invalid values (non-integer, ≤ 0) emit a warning to stderr and fall back to the default. |
Example: tighten review for a security-critical project
---
review_pipeline: persona
review_depth: large
focus_areas: [security, correctness, reliability]
reviewer_set:
include: [security-reviewer, adversarial-reviewer]
exclude: [comment-analyzer, type-design-analyzer]
---Example: rollback escape hatch during Wave 2 dogfooding
---
review_pipeline: legacy
---
# Notes for humans (commands ignore this body)
We hit unexpected false-positive noise from `correctness-reviewer` on
2026-04-29; reverting to legacy pipeline until upstream lands a fix.
Re-enable persona pipeline by removing `review_pipeline: legacy` (or
flipping it to `persona`).Reading the config from a command
Commands that honor this config (today: review:pr, review:all,review:resolve) read the file from the project root and merge values with
their built-in defaults. review:resolve reads only the resolve_pr.* keys;review:resolve-stack and review:sweep do not read the file themselves but
run review:resolve per PR, so those keys apply to them too.review:sweep-all also reads resolve_pr.repass_wait_seconds andresolve_pr.repass_max_passes itself, to print the worst-case re-pass wait
before it starts. The merge precedence is:
- Command argument overrides (e.g., explicit flags) — highest
yellow-plugins.local.mdfrontmatter- Command built-in defaults — lowest
Pseudo-code:
config = load_yaml_frontmatter("yellow-plugins.local.md")
review_pipeline = config.review_pipeline ?? "persona"
review_depth = command_arg.depth ?? config.review_depth ?? auto_detect()
# Precedence step 1: review_pipeline branches BEFORE any reviewer override is
# read. The legacy path dispatches its own fixed persona list and consults
# neither reviewer_set nor focus_areas — see
# plugins/yellow-review/references/review-pr/legacy-fallback.md.
if review_pipeline == "legacy":
use_legacy_dispatch(LEGACY_FIXED_PERSONA_LIST)
return
# Precedence step 2 (persona path only): merge reviewer overrides.
focus_areas = config.focus_areas ?? [] # empty = no filter
include = config.reviewer_set.include ?? []
exclude = config.reviewer_set.exclude ?? []
# After computing the default reviewer set per Step 4 of review-pr.md:
reviewer_set = (defaults ∪ include) \ exclude
# Precedence step 3: focus_areas filters the merged set, so an included agent
# is still dropped when its category is not listed.
if focus_areas:
# Always-on personas survive the filter regardless of focus_areas; filtering
# them would defeat the always-on contract documented in
# plugins/yellow-review/commands/review/review-pr.md Step 4.
always_on = {project-compliance-reviewer, correctness-reviewer,
maintainability-reviewer, project-standards-reviewer}
reviewer_set = always_on ∪ filter_by_category(reviewer_set \ always_on, focus_areas)
use_persona_dispatch(reviewer_set)Validation
- Unknown top-level keys → emit a warning to stderr but do not abort.
Forward-compatibility matters more than strictness for an optional
config. - Unknown reviewer names in
reviewer_set.include→ emit a warning naming
the unrecognized name. The graceful-degradation guard inreview:pr
Step 4 handles missing agents at dispatch time anyway. - Mutually exclusive entries (same name in both
includeandexclude)
→excludewins; emit a warning naming the conflicting agent. review_pipelinevalues other thanpersona/legacy→ fall back topersonaand emit a warning.stackentries other thants/py/rust/go→ drop the
unknown entry, emit a warning naming it. An empty array after dropping
unknowns falls back to auto-detection.agent_native_focusnon-boolean values → fall back tofalseand
emit a warning. Common mistake: quoting the value ("true") — YAML
parses that as a string, not a boolean.confidence_thresholdoutside0..100→ clamp to the range and emit
a warning. Non-integer values fall back to the default (75).resolve_pr.*keys with an invalid type or range → emit a warning naming
the key and fall back to its default (see the field reference). An emptyverify_commandcounts as unset.review:resolvereads these keys once
before any agent runs and ignores later edits to the file.
Example: TypeScript-focused plugin repo with strict gating
---
review_pipeline: persona
review_depth: large
focus_areas: [security, correctness, project-compliance]
stack: [ts]
agent_native_focus: true
confidence_threshold: 60
---Effect, once Wave 3 consumers land: polyglot-reviewer scopes to
TypeScript only, the W3.5 agent-native reviewer triplet is always
invoked, and the confidence gate fires earlier (60 vs. default 75) so
borderline findings surface for human review.
Migration
Projects that previously relied on hard-coded defaults need no migration —
the absence of yellow-plugins.local.md keeps existing behavior. The
file is opt-in.
Related
RESEARCH/upstream-snapshots/e5b397c9d1883354f03e338dd00f98be3da39f9f/confidence-rubric.md— the
confidence rubric that the persona pipeline uses for aggregation.plugins/yellow-review/commands/review/review-pr.md— primary consumer
of the config keys defined here.plugins/yellow-review/commands/review/review-all.md— secondary
consumer; its inline pipeline references the same overrides.plugins/yellow-review/skills/pr-review-workflow/SKILL.md— selection
rules and severity definitions.