feat(model-router): wave 3-A — first-use route confirmation, decision memory, project exceptions
routing.json (tracked, reached through the plugin directory) is now the single source of the phase table and of every skill/agent row, plus the decisions: confirmed rows/phases, changed rows (from/to) and projects exceptions keyed by a normalized git remote (credentials never stored, no machine paths). First use of a rowed typed skill, a rowed agent spawn or a main-loop phase opens the engine's dialog (Later / Keep / two alternative phases; Other = a phase name); a change asks Everywhere or This project only. One dialog at a time, never in headless, never inside an agent, never written by the model: only a dialog answer or /route ask writes, serialized, size-capped, never creating the file. Layers: routing.json < ~/.claude/model-router.json; the project tree is never read. /route pending, /route ask on|off. Census reads rows and phases from the file and tolerates a user-changed row (WARN). Kit suite 86 → 190 tests. Contract .claude/tasks/contracts/2026-10-10-model-router-w3a-confirm-1201.md, plan r4: 3 lenses + 1 confirmation, feater + 4 rounds, GATE 0 MET, verifier CONFORME then re-verify after security, security BLOCK(1) fixed then PASS. Live: T2 dialogs answered by the user from the hot-loaded mod.
This commit is contained in:
@@ -48,6 +48,10 @@ Builtin `/effort` is NOT a lever inside a run: rows and routes outrank it.
|
|||||||
typed marker (unverified live 2026-10-10).
|
typed marker (unverified live 2026-10-10).
|
||||||
- Headless (`-p`, SDK) runs the hooks, so routing works there too.
|
- Headless (`-p`, SDK) runs the hooks, so routing works there too.
|
||||||
- Mod off: typed agents fall back to their `model:`/`effort:` frontmatter.
|
- Mod off: typed agents fall back to their `model:`/`effort:` frontmatter.
|
||||||
|
- First use of a row asks once (Keep, Later or another phase, then
|
||||||
|
Everywhere or this project only); the answer is kept in
|
||||||
|
`mods/model-router/routing.json`. `/route pending` lists what is still
|
||||||
|
unconfirmed, `/route ask off|on` toggles the dialog.
|
||||||
|
|
||||||
Measure the split any time: `python3 ~/.claude/lib/effort-audit.py`
|
Measure the split any time: `python3 ~/.claude/lib/effort-audit.py`
|
||||||
(thinking/output/cache tokens per scope, model and effort).
|
(thinking/output/cache tokens per scope, model and effort).
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# lib/tests/effort-routing.test.sh — wave-2 census of the model-router rows.
|
# lib/tests/effort-routing.test.sh — wave-2 census of the model-router rows.
|
||||||
# Drift lock: every tracked skill/agent row in mods/model-router/hooks/
|
# Drift lock: every tracked skill/agent row of mods/model-router/routing.json
|
||||||
# register.ts equals its frontmatter (the off-state floor), the D3 wiring
|
# equals its frontmatter (the off-state floor), except a row the user changed
|
||||||
# markers sit in the orchestrators, no shifter citer survives.
|
# through the first-use dialog (WARN floor drift: the floor may lag a
|
||||||
|
# confirmed decision); the D3 wiring markers sit in the orchestrators, no
|
||||||
|
# shifter citer survives.
|
||||||
# shellcheck disable=SC2015,SC2016 # A && ok || ko is deliberate (ok/ko never fail)
|
# shellcheck disable=SC2015,SC2016 # A && ok || ko is deliberate (ok/ko never fail)
|
||||||
set -u
|
set -u
|
||||||
R="$(cd "$(dirname "$0")/../.." && pwd)"
|
R="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
REG="$R/mods/model-router/hooks/register.ts"
|
MOD="$R/mods/model-router"
|
||||||
|
RJ="$MOD/routing.json"
|
||||||
|
REG="$MOD/hooks/register.ts"
|
||||||
pass=0; fail=0
|
pass=0; fail=0
|
||||||
ok() { pass=$((pass+1)); }
|
ok() { pass=$((pass+1)); }
|
||||||
ko() { fail=$((fail+1)); printf 'FAIL %s\n' "$1"; }
|
ko() { fail=$((fail+1)); printf 'FAIL %s\n' "$1"; }
|
||||||
@@ -16,84 +20,145 @@ lacks() { if grep -qF "$2" "$R/$1"; then ko "$1 must NOT contain: $2"; else ok;
|
|||||||
fm() { awk 'NR==1&&/^---$/{p=1;next} p&&/^---$/{exit} p' "$1"; }
|
fm() { awk 'NR==1&&/^---$/{p=1;next} p&&/^---$/{exit} p' "$1"; }
|
||||||
fm_val() { fm "$1" | grep -E "^$2: [a-z]+$" | head -1 | cut -d' ' -f2; }
|
fm_val() { fm "$1" | grep -E "^$2: [a-z]+$" | head -1 | cut -d' ' -f2; }
|
||||||
|
|
||||||
# ── register.ts parsers (awk/sed on the DEFAULT_CONFIG literal) ──────────
|
# ── routing.json (rows, phases, decisions) and the tier heads ────────────
|
||||||
# rows <file> <agents|skills> -> "name phase" per row
|
# dump <routing.json> -> "skills|agents <name> <phase>", "phases <p> <tier>
|
||||||
rows() {
|
# <effort>", "changed <kind> <name> <from> <to>" lines
|
||||||
awk -v s="$2" '$0 ~ "^ "s": \\{"{f=1;next} f&&/^ \},?$/{f=0} f' "$1" \
|
dump() {
|
||||||
| grep -v '^ *//' | grep -oE "('[^']+'|[A-Za-z0-9_-]+): '[a-z]+'" \
|
python3 -I - "$1" <<'PY'
|
||||||
| sed -E "s/'//g; s/: / /"
|
import json, sys
|
||||||
}
|
d = json.load(open(sys.argv[1]))
|
||||||
# phase_effort <file> <phase> -> "<tier> <effort>"
|
for kind in ("skills", "agents"):
|
||||||
phase_effort() {
|
for k, v in d.get(kind, {}).items():
|
||||||
awk '/^ phases: \{/{f=1;next} f&&/^ \},?$/{f=0} f' "$1" \
|
print(kind, k, v)
|
||||||
| sed -nE "s/^ *$2: \{ tier: '([a-z]+)', effort: '([a-z]+)' \},?$/\1 \2/p"
|
for k, v in d.get("phases", {}).items():
|
||||||
|
print("phases", k, v.get("tier", ""), v.get("effort", ""))
|
||||||
|
for kind in ("skills", "agents"):
|
||||||
|
for k, v in d.get("changed", {}).get(kind, {}).items():
|
||||||
|
print("changed", kind, k, v["from"], v["to"])
|
||||||
|
PY
|
||||||
}
|
}
|
||||||
|
# lookups on a dump text: row_of D kind name · phase_effort D phase ·
|
||||||
|
# changed_of D kind name -> "from to"
|
||||||
|
row_of() { printf '%s\n' "$1" | awk -v k="$2" -v n="$3" '$1==k&&$2==n{print $3}'; }
|
||||||
|
phase_effort() { printf '%s\n' "$1" | awk -v p="$2" '$1=="phases"&&$2==p{print $3, $4}'; }
|
||||||
|
changed_of() { printf '%s\n' "$1" | awk -v k="$2" -v n="$3" '$1=="changed"&&$2==k&&$3==n{print $4, $5}'; }
|
||||||
# tier_head <file> <tier> -> first alias of the tier list
|
# tier_head <file> <tier> -> first alias of the tier list
|
||||||
tier_head() {
|
tier_head() {
|
||||||
awk '/^ tiers: \{/{f=1;next} f&&/^ \},?$/{f=0} f' "$1" \
|
awk '/^ tiers: \{/{f=1;next} f&&/^ \},?$/{f=0} f' "$1" \
|
||||||
| sed -nE "s/^ *$2: \['([a-z]+)'.*$/\1/p"
|
| sed -nE "s/^ *$2: \['([a-z]+)'.*$/\1/p"
|
||||||
}
|
}
|
||||||
row_of() { rows "$REG" "$1" | awk -v n="$2" '$1==n{print $2}'; }
|
# the fallback copy of the phases inside the mod's code: "<tier> <effort>"
|
||||||
|
code_phase() {
|
||||||
|
awk '/^ phases: \{/{f=1;next} f&&/^ \},?$/{f=0} f' "$REG" \
|
||||||
|
| sed -nE "s/^ *$1: \{ tier: '([a-z]+)', effort: '([a-z]+)' \},?$/\1 \2/p"
|
||||||
|
}
|
||||||
|
# field_of <dump> <phase> <effort|model> -> that phase's frontmatter value
|
||||||
|
field_of() {
|
||||||
|
local pe tier
|
||||||
|
pe="$(phase_effort "$1" "$2")"
|
||||||
|
if [ "$3" = effort ]; then printf '%s\n' "${pe#* }"; return; fi
|
||||||
|
tier="${pe% *}"; tier_head "$REG" "$tier"
|
||||||
|
}
|
||||||
|
# verdict <dump> <kind> <name> <effort|model> <got> <phase>: ok when the
|
||||||
|
# frontmatter equals the row's phase; warn when the row was changed through
|
||||||
|
# the dialog (changed.from is the shipped phase, changed.to the row) and the
|
||||||
|
# frontmatter still holds the shipped value; fail otherwise (a Keep alone,
|
||||||
|
# an empty or unknown value, a hand edit after a change)
|
||||||
|
verdict() {
|
||||||
|
local D="$1" kind="$2" name="$3" field="$4" got="$5" phase="$6" ch from fromval
|
||||||
|
[ -n "$got" ] || { echo fail; return; }
|
||||||
|
[ "$got" = "$(field_of "$D" "$phase" "$field")" ] && { echo ok; return; }
|
||||||
|
ch="$(changed_of "$D" "$kind" "$name")"; from="${ch% *}"
|
||||||
|
[ -n "$ch" ] && [ "${ch#* }" = "$phase" ] || { echo fail; return; }
|
||||||
|
fromval="$(field_of "$D" "$from" "$field")"
|
||||||
|
[ -n "$fromval" ] && [ "$got" = "$fromval" ] && echo warn || echo fail
|
||||||
|
}
|
||||||
|
# floor_check <dump> <kind> <name> <effort|model> <got> <phase> <label>
|
||||||
|
floor_check() {
|
||||||
|
case "$(verdict "$1" "$2" "$3" "$4" "$5" "$6")" in
|
||||||
|
ok) ok;;
|
||||||
|
warn) printf 'WARN floor drift: %s %s vs row %s (%s)\n' "$7" "$5" "$6" "$4"; ok;;
|
||||||
|
*) ko "$7: $4 '$5' != row $6 ($(field_of "$1" "$6" "$4"))";;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
RD="$(dump "$RJ")"
|
||||||
|
|
||||||
# ── flip-test: the parsers read a fixture, reject a missing key ──────────
|
# ── flip-test: the readers parse a fixture and reject the wrong verdicts ──
|
||||||
FIX="$(mktemp -d)"; trap 'rm -rf "$FIX"' EXIT
|
FIX="$(mktemp -d)"; trap 'rm -rf "$FIX"' EXIT
|
||||||
cat > "$FIX/reg.ts" <<'FX'
|
cat > "$FIX/reg.ts" <<'FX'
|
||||||
tiers: {
|
tiers: {
|
||||||
big: ['opus', 'fable'],
|
big: ['opus', 'fable'],
|
||||||
},
|
},
|
||||||
phases: {
|
|
||||||
judge: { tier: 'big', effort: 'xhigh' },
|
|
||||||
},
|
|
||||||
agents: {
|
|
||||||
// judge
|
|
||||||
Plan: 'judge', 'plan-challenger': 'judge',
|
|
||||||
},
|
|
||||||
skills: {
|
|
||||||
'ship-feature': 'plan', doc: 'apply',
|
|
||||||
},
|
|
||||||
FX
|
FX
|
||||||
[ "$(rows "$FIX/reg.ts" agents | tr '\n' ,)" = "Plan judge,plan-challenger judge," ] \
|
cat > "$FIX/routing.json" <<'FX'
|
||||||
&& ok || ko "flip: agents rows misparsed"
|
{
|
||||||
[ "$(rows "$FIX/reg.ts" skills | tr '\n' ,)" = "ship-feature plan,doc apply," ] \
|
"phases": {
|
||||||
&& ok || ko "flip: skills rows misparsed"
|
"judge": { "tier": "big", "effort": "xhigh" },
|
||||||
[ "$(phase_effort "$FIX/reg.ts" judge)" = "big xhigh" ] && ok || ko "flip: phase"
|
"reflect": { "tier": "best", "effort": "high" },
|
||||||
[ -z "$(phase_effort "$FIX/reg.ts" nothere)" ] && ok || ko "flip: ghost phase"
|
"implement": { "tier": "work", "effort": "medium" }
|
||||||
|
},
|
||||||
|
"skills": { "feat": "implement", "doc": "reflect" },
|
||||||
|
"agents": { "Plan": "judge" },
|
||||||
|
"changed": { "skills": { "feat": { "from": "reflect", "to": "implement" } } },
|
||||||
|
"ask": true
|
||||||
|
}
|
||||||
|
FX
|
||||||
|
FD="$(dump "$FIX/routing.json")"
|
||||||
|
[ "$(row_of "$FD" agents Plan)" = judge ] && ok || ko "flip: agents row misread"
|
||||||
|
[ "$(row_of "$FD" skills feat)" = implement ] && ok || ko "flip: skills row misread"
|
||||||
|
[ -z "$(row_of "$FD" skills ghost)" ] && ok || ko "flip: ghost row"
|
||||||
|
[ "$(phase_effort "$FD" judge)" = "big xhigh" ] && ok || ko "flip: phase"
|
||||||
|
[ -z "$(phase_effort "$FD" nothere)" ] && ok || ko "flip: ghost phase"
|
||||||
[ "$(tier_head "$FIX/reg.ts" big)" = "opus" ] && ok || ko "flip: tier head"
|
[ "$(tier_head "$FIX/reg.ts" big)" = "opus" ] && ok || ko "flip: tier head"
|
||||||
[ "$(rows "$REG" skills | wc -l)" -gt 40 ] && ok || ko "register.ts: skills rows not parsed"
|
[ "$(changed_of "$FD" skills feat)" = "reflect implement" ] && ok || ko "flip: changed entry"
|
||||||
[ "$(rows "$REG" agents | wc -l)" -gt 15 ] && ok || ko "register.ts: agents rows not parsed"
|
[ -z "$(changed_of "$FD" skills doc)" ] && ok || ko "flip: ghost changed entry"
|
||||||
|
# the drift verdicts (high = reflect's effort, medium = implement's)
|
||||||
|
[ "$(verdict "$FD" skills doc effort high reflect)" = ok ] && ok || ko "flip: equal must pass"
|
||||||
|
[ "$(verdict "$FD" skills doc effort medium reflect)" = fail ] && ok || ko "flip: a Keep-only drift must FAIL"
|
||||||
|
[ "$(verdict "$FD" skills feat effort high implement)" = warn ] && ok || ko "flip: changed.from drift must WARN"
|
||||||
|
[ "$(verdict "$FD" skills feat effort '' implement)" = fail ] && ok || ko "flip: an empty value must FAIL"
|
||||||
|
[ "$(verdict "$FD" skills feat effort banana implement)" = fail ] && ok || ko "flip: an unknown value must FAIL"
|
||||||
|
[ "$(verdict "$FD" skills feat effort low implement)" = fail ] && ok || ko "flip: a drift off the shipped value must FAIL"
|
||||||
|
[ "$(verdict "$FD" skills feat effort high reflect)" = ok ] && ok || ko "flip: row back to its shipped phase passes"
|
||||||
|
[ "$(verdict "$FD" skills feat effort high judge)" = fail ] && ok || ko "flip: a hand edit after a change must FAIL"
|
||||||
|
[ "$(echo "$RD" | grep -c '^skills ')" -gt 40 ] && ok || ko "routing.json: skills rows not read"
|
||||||
|
[ "$(echo "$RD" | grep -c '^agents ')" -gt 15 ] && ok || ko "routing.json: agents rows not read"
|
||||||
|
|
||||||
|
# ── the code's fallback phases equal routing.json's (never a stale route) ─
|
||||||
|
n_code="$(awk '/^ phases: \{/{f=1;next} f&&/^ \},?$/{f=0} f' "$REG" | grep -c "tier:")"
|
||||||
|
n_json="$(echo "$RD" | grep -c '^phases ')"
|
||||||
|
[ "$n_code" -eq "$n_json" ] && ok || ko "phases: $n_code in code vs $n_json in routing.json"
|
||||||
|
while read -r _ p tier effort; do
|
||||||
|
[ "$(code_phase "$p")" = "$tier $effort" ] && ok \
|
||||||
|
|| ko "phase $p: code '$(code_phase "$p")' != routing.json '$tier $effort'"
|
||||||
|
done < <(echo "$RD" | grep '^phases ')
|
||||||
|
|
||||||
# ── (b) tracked skills: row exists, frontmatter effort equals the row ────
|
# ── (b) tracked skills: row exists, frontmatter effort equals the row ────
|
||||||
NO_ROW_SKILLS=" find-docs graphify impeccable model-router "
|
NO_ROW_SKILLS=" find-docs graphify impeccable model-router "
|
||||||
check_skill() {
|
check_skill() {
|
||||||
local f="$1" name phase want got
|
local f="$1" name phase
|
||||||
name="$(basename "$(dirname "$f")")"
|
name="$(basename "$(dirname "$f")")"
|
||||||
case "$NO_ROW_SKILLS" in *" $name "*) return;; esac
|
case "$NO_ROW_SKILLS" in *" $name "*) return;; esac
|
||||||
phase="$(row_of skills "$name")"
|
phase="$(row_of "$RD" skills "$name")"
|
||||||
[ -n "$phase" ] || { ko "skills/$name: no row in register.ts"; return; }
|
[ -n "$phase" ] || { ko "skills/$name: no row in routing.json"; return; }
|
||||||
want="$(phase_effort "$REG" "$phase" | cut -d' ' -f2)"
|
[ -n "$(fm_val "$R/$f" effort)" ] || { ko "skills/$name: routed skill without effort:"; return; }
|
||||||
got="$(fm_val "$R/$f" effort)"
|
floor_check "$RD" skills "$name" effort "$(fm_val "$R/$f" effort)" "$phase" "skills/$name"
|
||||||
[ -n "$got" ] || { ko "skills/$name: routed skill without effort:"; return; }
|
|
||||||
[ "$got" = "$want" ] && ok || ko "skills/$name: effort $got != row $phase ($want)"
|
|
||||||
}
|
}
|
||||||
while IFS= read -r f; do check_skill "$f"; done < <(
|
while IFS= read -r f; do check_skill "$f"; done < <(
|
||||||
cd "$R" && git ls-files 'skills/*/SKILL.md' 'skills-external/*/SKILL.md')
|
cd "$R" && git ls-files 'skills/*/SKILL.md' 'skills-external/*/SKILL.md')
|
||||||
|
|
||||||
# ── (c) tracked agents with a row: tier head == model:, effort == effort: ─
|
# ── (c) tracked agents with a row: tier head == model:, effort == effort: ─
|
||||||
NO_ROW_AGENTS=" interviewer client-handover-writer "
|
NO_ROW_AGENTS=" interviewer client-handover-writer "
|
||||||
tier_alias() { tier_head "$REG" "$(phase_effort "$REG" "$1" | cut -d' ' -f1)"; }
|
|
||||||
check_agent() {
|
check_agent() {
|
||||||
local f="$1" name phase alias want got
|
local f="$1" name phase
|
||||||
name="$(basename "$f" .md)"
|
name="$(basename "$f" .md)"
|
||||||
case "$NO_ROW_AGENTS" in *" $name "*) return;; esac
|
case "$NO_ROW_AGENTS" in *" $name "*) return;; esac
|
||||||
case "$name" in impeccable-*) return;; esac
|
case "$name" in impeccable-*) return;; esac
|
||||||
phase="$(row_of agents "$name")"
|
phase="$(row_of "$RD" agents "$name")"
|
||||||
[ -n "$phase" ] || { ko "agents/$name: no row in register.ts"; return; }
|
[ -n "$phase" ] || { ko "agents/$name: no row in routing.json"; return; }
|
||||||
alias="$(tier_alias "$phase")"; got="$(fm_val "$R/$f" model)"
|
floor_check "$RD" agents "$name" model "$(fm_val "$R/$f" model)" "$phase" "agents/$name"
|
||||||
[ "$got" = "$alias" ] && ok || ko "agents/$name: model $got != row $phase ($alias)"
|
[ "$(field_of "$RD" "$phase" model)" = haiku ] && return
|
||||||
[ "$alias" = haiku ] && return
|
floor_check "$RD" agents "$name" effort "$(fm_val "$R/$f" effort)" "$phase" "agents/$name"
|
||||||
want="$(phase_effort "$REG" "$phase" | cut -d' ' -f2)"
|
|
||||||
got="$(fm_val "$R/$f" effort)"
|
|
||||||
[ "$got" = "$want" ] && ok || ko "agents/$name: effort $got != row $phase ($want)"
|
|
||||||
}
|
}
|
||||||
while IFS= read -r f; do check_agent "$f"; done < <(
|
while IFS= read -r f; do check_agent "$f"; done < <(
|
||||||
cd "$R" && git ls-files 'agents/*.md' | grep -E '^agents/[^/]+\.md$' \
|
cd "$R" && git ls-files 'agents/*.md' | grep -E '^agents/[^/]+\.md$' \
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+705
-106
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,144 @@
|
|||||||
|
{
|
||||||
|
"phases": {
|
||||||
|
"plan": {
|
||||||
|
"tier": "best",
|
||||||
|
"effort": "xhigh"
|
||||||
|
},
|
||||||
|
"reflect": {
|
||||||
|
"tier": "best",
|
||||||
|
"effort": "high"
|
||||||
|
},
|
||||||
|
"orchestrate": {
|
||||||
|
"tier": "best",
|
||||||
|
"effort": "medium"
|
||||||
|
},
|
||||||
|
"escalate": {
|
||||||
|
"tier": "best",
|
||||||
|
"effort": "max"
|
||||||
|
},
|
||||||
|
"judge": {
|
||||||
|
"tier": "big",
|
||||||
|
"effort": "xhigh"
|
||||||
|
},
|
||||||
|
"implement": {
|
||||||
|
"tier": "work",
|
||||||
|
"effort": "medium"
|
||||||
|
},
|
||||||
|
"write": {
|
||||||
|
"tier": "work",
|
||||||
|
"effort": "high"
|
||||||
|
},
|
||||||
|
"verify": {
|
||||||
|
"tier": "work",
|
||||||
|
"effort": "xhigh"
|
||||||
|
},
|
||||||
|
"explore": {
|
||||||
|
"tier": "work",
|
||||||
|
"effort": "medium"
|
||||||
|
},
|
||||||
|
"apply": {
|
||||||
|
"tier": "work",
|
||||||
|
"effort": "low"
|
||||||
|
},
|
||||||
|
"mechanical": {
|
||||||
|
"tier": "cheap",
|
||||||
|
"effort": "low"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"skills": {
|
||||||
|
"ship-feature": "plan",
|
||||||
|
"init-project": "plan",
|
||||||
|
"onboard": "plan",
|
||||||
|
"tour": "plan",
|
||||||
|
"audit-delta": "plan",
|
||||||
|
"analyze": "plan",
|
||||||
|
"code-clean": "plan",
|
||||||
|
"client-handover": "plan",
|
||||||
|
"brainstorming": "plan",
|
||||||
|
"writing-plans": "plan",
|
||||||
|
"requesting-code-review": "plan",
|
||||||
|
"21st-ui-review": "plan",
|
||||||
|
"feat": "reflect",
|
||||||
|
"hotfix": "reflect",
|
||||||
|
"bugfix": "reflect",
|
||||||
|
"refactor": "reflect",
|
||||||
|
"web-validate": "reflect",
|
||||||
|
"harden": "reflect",
|
||||||
|
"seo": "reflect",
|
||||||
|
"geo": "reflect",
|
||||||
|
"site-motion": "reflect",
|
||||||
|
"frontend-design": "reflect",
|
||||||
|
"emil-design-eng": "reflect",
|
||||||
|
"design-motion-principles": "reflect",
|
||||||
|
"21st-ui-build": "reflect",
|
||||||
|
"scroll-world-storytelling": "reflect",
|
||||||
|
"build-threejs-scroll-worlds": "reflect",
|
||||||
|
"scroll-scrubbed-visual-sequence": "reflect",
|
||||||
|
"scroll-scrubbed-word-reveal": "reflect",
|
||||||
|
"scroll-progress-timeline": "reflect",
|
||||||
|
"subagent-driven-development": "reflect",
|
||||||
|
"writing-skills": "reflect",
|
||||||
|
"deprecation-and-migration": "reflect",
|
||||||
|
"21st-ai": "reflect",
|
||||||
|
"21st-ui-explore": "reflect",
|
||||||
|
"gitflow": "implement",
|
||||||
|
"prune-memory": "implement",
|
||||||
|
"pdf-translate": "implement",
|
||||||
|
"ci-cd-and-automation": "implement",
|
||||||
|
"observability-and-instrumentation": "implement",
|
||||||
|
"test-driven-development": "implement",
|
||||||
|
"commit-change": "apply",
|
||||||
|
"release-candidate": "apply",
|
||||||
|
"doc": "apply",
|
||||||
|
"capitalize": "apply",
|
||||||
|
"close": "apply",
|
||||||
|
"reconcile": "apply",
|
||||||
|
"deploy": "apply",
|
||||||
|
"status": "mechanical",
|
||||||
|
"profile": "mechanical",
|
||||||
|
"plugin-check": "mechanical",
|
||||||
|
"skills-perso": "mechanical",
|
||||||
|
"using-git-worktrees": "mechanical",
|
||||||
|
"21st-cli-use": "mechanical",
|
||||||
|
"21st-registry": "mechanical",
|
||||||
|
"21st-design-sync": "mechanical"
|
||||||
|
},
|
||||||
|
"agents": {
|
||||||
|
"Explore": "explore",
|
||||||
|
"Plan": "judge",
|
||||||
|
"plan-challenger": "judge",
|
||||||
|
"plugin-advisor": "judge",
|
||||||
|
"seo-analyzer": "judge",
|
||||||
|
"geo-analyzer": "judge",
|
||||||
|
"analyzer": "judge",
|
||||||
|
"feater": "implement",
|
||||||
|
"bugfixer": "implement",
|
||||||
|
"code-cleaner": "implement",
|
||||||
|
"scaffolder": "implement",
|
||||||
|
"onboarder": "implement",
|
||||||
|
"commit-changer": "write",
|
||||||
|
"doc-syncer": "write",
|
||||||
|
"handover-doc-writer": "write",
|
||||||
|
"refactorer": "write",
|
||||||
|
"hotfixer": "apply",
|
||||||
|
"release-executor": "apply",
|
||||||
|
"plugin-probe": "apply",
|
||||||
|
"validator-analyzer": "apply",
|
||||||
|
"verifier": "verify",
|
||||||
|
"security-auditor": "verify",
|
||||||
|
"status-reporter": "mechanical"
|
||||||
|
},
|
||||||
|
"projects": {},
|
||||||
|
"confirmed": {
|
||||||
|
"agents": {
|
||||||
|
"verifier": "verify",
|
||||||
|
"feater": "implement"
|
||||||
|
},
|
||||||
|
"phases": {
|
||||||
|
"verify": "verify",
|
||||||
|
"implement": "implement"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"changed": {},
|
||||||
|
"ask": true
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user