oh-my-customcode 2.0.7 → 2.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +3 -2
  2. package/dist/cli/index.js +28 -7
  3. package/dist/index.js +28 -7
  4. package/package.json +1 -1
  5. package/templates/.claude/hooks/hooks.json +29 -13
  6. package/templates/.claude/hooks/scripts/agent-teams-advisor.sh +47 -22
  7. package/templates/.claude/hooks/scripts/auto-continue-guard.sh +5 -5
  8. package/templates/.claude/hooks/scripts/auto-dev-token-tracker.sh +12 -1
  9. package/templates/.claude/hooks/scripts/bash-cd-advisor.sh +172 -0
  10. package/templates/.claude/hooks/scripts/content-hash-validator.sh +65 -48
  11. package/templates/.claude/hooks/scripts/destructive-git-guard.sh +32 -17
  12. package/templates/.claude/hooks/scripts/fail-axis-cause-advisor.sh +2 -2
  13. package/templates/.claude/hooks/scripts/failure-ledger.sh +18 -0
  14. package/templates/.claude/hooks/scripts/file-change-validator.sh +6 -3
  15. package/templates/.claude/hooks/scripts/git-delegation-guard.sh +178 -27
  16. package/templates/.claude/hooks/scripts/model-escalation-advisor.sh +43 -20
  17. package/templates/.claude/hooks/scripts/omcustom-auto-update.sh +19 -5
  18. package/templates/.claude/hooks/scripts/rule-deletion-guard.sh +118 -1
  19. package/templates/.claude/hooks/scripts/schema-validator.sh +8 -11
  20. package/templates/.claude/hooks/scripts/session-env-check.sh +20 -5
  21. package/templates/.claude/hooks/scripts/stall-detection-advisor.sh +9 -5
  22. package/templates/.claude/hooks/scripts/stuck-detector.sh +21 -4
  23. package/templates/.claude/hooks/scripts/subagent-failure-advisor.sh +48 -29
  24. package/templates/.claude/hooks/scripts/task-outcome-recorder.sh +15 -8
  25. package/templates/.claude/ontology/agents.yaml +71 -7
  26. package/templates/.claude/ontology/graphs/agent-skill.json +64 -5
  27. package/templates/.claude/ontology/graphs/full-graph.json +236 -3
  28. package/templates/.claude/ontology/skills.yaml +65 -1
  29. package/templates/.claude/rules/MUST-agent-design.md +1 -11
  30. package/templates/.claude/rules/MUST-enforcement-policy.md +7 -7
  31. package/templates/.claude/rules/MUST-orchestrator-coordination.md +1 -1
  32. package/templates/.claude/rules/SHOULD-memory-integration.md +1 -1
  33. package/templates/.claude/settings.json +29 -13
  34. package/templates/.claude/skills/fsd/SKILL.md +10 -9
  35. package/templates/.claude/skills/goal/SKILL.md +5 -5
  36. package/templates/.claude/skills/model-escalation/SKILL.md +16 -12
  37. package/templates/.claude/skills/omcustom-loop/SKILL.md +4 -4
  38. package/templates/.claude/skills/pipeline/workflows/auto-dev.yaml +13 -0
  39. package/templates/guides/claude-code/04-agent-skills.md +1 -1
  40. package/templates/guides/claude-code/15-version-compatibility.md +47 -47
  41. package/templates/guides/git-safety/README.md +4 -1
  42. package/templates/guides/middleware-patterns/README.md +4 -4
  43. package/templates/guides/multi-model-routing/README.md +1 -7
  44. package/templates/manifest.json +1 -1
  45. package/templates/workflows/auto-dev.yaml +13 -0
@@ -11,9 +11,11 @@ set -euo pipefail
11
11
  # array/scalar payloads gave rc=5 (unguarded `jq` agent_type extraction); a well-formed payload with a
12
12
  # 300KB `.description` gave rc=141 (5/5; 70KB rc=0; boundary near 81,920 bytes here, platform-dependent; `| head -c 80` SIGPIPE under pipefail). CC sends objects and
13
13
  # SubagentStop has no `.description`, so these paths are not reached at runtime.
14
- # Start-record `start_epoch`: "abc" gives rc=1 (`set -u`: "abc: unbound variable"); arithmetic-syntax
15
- # values ("1792939922.5", "09") print an error and give rc=1 (`set -u`: "duration_seconds: unbound
16
- # variable"); "" gives rc=0.
14
+ # Start-record `start_epoch` (also the still-running-agent `running_start`): a value that is not a
15
+ # positive decimal integer without a leading zero ("", "0", "null", "abc", "1792939922.5", "09", "-5")
16
+ # is treated as no start record: rc=0, nothing recorded for the completing agent, and the loop skips
17
+ # that running entry (measured on bash 3.2; before this check "abc"/"1792939922.5"/"09" gave rc=1 and
18
+ # "" recorded now_epoch, about 1.79e9, as the duration).
17
19
 
18
20
  # ORDERING: This hook MUST run AFTER task-outcome-recorder.sh in hooks.json SubagentStop array.
19
21
  # Reason: This script removes consumed entries from AGENT_START_FILE; task-outcome-recorder reads them first.
@@ -36,7 +38,9 @@ description=$(printf '%s\n' "$input" | jq -r '.description // ""' | head -c 80)
36
38
  # --- 2. Calculate duration from start record ---
37
39
  start_epoch=$(grep -F "\"agent_type\":\"${agent_type}\"" "$AGENT_START_FILE" 2>/dev/null | tail -1 | jq -r '.start_epoch // "0"' 2>/dev/null || echo "0")
38
40
 
39
- if [ "$start_epoch" = "0" ] || [ "$start_epoch" = "null" ]; then
41
+ # Only a positive decimal integer without a leading zero is a usable epoch; anything else
42
+ # ("", "0", "null", "abc", "1792939922.5", "09", negatives) is treated as no start record.
43
+ if ! [[ "$start_epoch" =~ ^[1-9][0-9]*$ ]]; then
40
44
  printf '%s\n' "$input"
41
45
  exit 0
42
46
  fi
@@ -70,7 +74,7 @@ if [ "$completed_count" -ge 1 ]; then
70
74
  running_desc=$(printf '%s\n' "$line" | jq -r '.description // ""' 2>/dev/null || true)
71
75
  running_model=$(printf '%s\n' "$line" | jq -r '.model // "inherit"' 2>/dev/null || true)
72
76
 
73
- if [ "$running_start" = "0" ] || [ "$running_start" = "null" ]; then continue; fi
77
+ if ! [[ "$running_start" =~ ^[1-9][0-9]*$ ]]; then continue; fi
74
78
 
75
79
  elapsed=$((now_epoch - running_start))
76
80
 
@@ -545,6 +545,7 @@ extraction_mode=$(printf '%s' "$input" | jq -er '
545
545
  elif ((.tool_name // "unknown" | type) != "string") then "legacy"
546
546
  elif ((.tool_input != null) and ((.tool_input | type) != "object")) then "legacy"
547
547
  elif ((.tool_output != null) and ((.tool_output | type) != "object")) then "legacy"
548
+ elif ((.tool_response != null) and ((.tool_response | type) != "object")) then "legacy"
548
549
  elif ((.tool_input.file_path // "" | type) != "string")
549
550
  or ((.tool_input.command // "" | type) != "string")
550
551
  or ((.tool_input.old_string // .tool_input.content // .tool_input.new_string // "" | type) != "string")
@@ -579,6 +580,22 @@ _read_stuck_fields() {
579
580
 
580
581
  TARGET_KEY_CAP=1000
581
582
 
583
+ # PostToolUse carries "tool_response", never "tool_output" (#1775; probe: CC
584
+ # 2.1.310, "claude -p", one run, model haiku). Measured Bash shape: object
585
+ # {interrupted,isImage,noOutputExpected,stderr,stdout}; no measured PostToolUse
586
+ # shape has is_error. Bash failures arrive via PostToolUseFailure (a Bash exit 3
587
+ # produced PostToolUseFailure with error "Exit code 3"), which this hook is not
588
+ # wired to, so the is_error path stays inert for Bash. Read tool_response first;
589
+ # ".tool_output" is a legacy fallback only. A non-object tool_response routes to
590
+ # the "legacy" extraction path (see extraction_mode) and is used as text only
591
+ # when it is a string.
592
+ JQ_IS_ERROR='((.tool_response | if type == "object" then .is_error else null end) // .tool_output.is_error // false)'
593
+ JQ_OUTPUT_PREVIEW='((.tool_response) as $r
594
+ | if ($r | type) == "object" and (($r.stdout | type) == "string") then $r.stdout
595
+ elif ($r | type) == "string" then $r
596
+ else (.tool_output.output // "") end
597
+ | tostring)[0:200]'
598
+
582
599
  truncate_key() {
583
600
  local v="$1"
584
601
  if [ "${#v}" -gt "$TARGET_KEY_CAP" ]; then
@@ -595,7 +612,7 @@ if [ "$extraction_mode" = "batched" ]; then
595
612
  (if (.tool_name // "unknown") == "Bash"
596
613
  then (.tool_input.command // .tool_input.file_path // "")
597
614
  else (.tool_input.file_path // "") end), "\u0000",
598
- (.tool_output.is_error // false), "\u0000"'
615
+ '"$JQ_IS_ERROR"', "\u0000"'
599
616
  [ "${#STUCK_FIELDS[@]}" -eq 3 ] || exit 1
600
617
  tool_name="${STUCK_FIELDS[0]}"
601
618
  if [ "$tool_name" = "Bash" ]; then
@@ -608,7 +625,7 @@ if [ "$extraction_mode" = "batched" ]; then
608
625
  fi
609
626
  is_error="${STUCK_FIELDS[2]}"
610
627
  output_preview=$(printf '%s' "$input" \
611
- | jq -r '(.tool_output.output // "" | tostring)[0:200]' \
628
+ | jq -r "$JQ_OUTPUT_PREVIEW" \
612
629
  | head -c 200 || true)
613
630
  _read_stuck_fields '(.tool_input.command // ""), "\u0000",
614
631
  (if (.tool_name == "Edit" or .tool_name == "Write")
@@ -653,7 +670,7 @@ else
653
670
  file_path=$(printf '%s' "$file_path_full" | head -c "$TARGET_KEY_CAP" || true)
654
671
  target_key=$(truncate_key "$file_path_full")
655
672
  fi
656
- is_error=$(printf '%s' "$input" | jq -r '.tool_output.is_error // false')
673
+ is_error=$(printf '%s' "$input" | jq -r "$JQ_IS_ERROR")
657
674
  # "head -c 200" closes the pipe after 200 bytes. Once tool_output.output is
658
675
  # larger than the pipe buffer (~64 KB), jq keeps writing, dies of SIGPIPE
659
676
  # (exit 141), and "set -o pipefail" + "set -e" aborted the ENTIRE hook before
@@ -664,7 +681,7 @@ is_error=$(printf '%s' "$input" | jq -r '.tool_output.is_error // false')
664
681
  # enforced by head (jq slices by codepoint, head by byte, and 200 codepoints
665
682
  # are always >= 200 bytes, so the resulting bytes are unchanged).
666
683
  output_preview=$(printf '%s' "$input" \
667
- | jq -r '(.tool_output.output // "" | tostring)[0:200]' \
684
+ | jq -r "$JQ_OUTPUT_PREVIEW" \
668
685
  | head -c 200 || true)
669
686
  raw_command=$(printf '%s' "$input" | jq -r '.tool_input.command // ""')
670
687
 
@@ -5,38 +5,57 @@ set -euo pipefail
5
5
  command -v jq >/dev/null 2>&1 || exit 0
6
6
 
7
7
  # Subagent Failure Advisor Hook
8
- # Trigger: SubagentStop
9
- # Purpose: Advisory-only replacement for the removed `type: "prompt"` SubagentStop hook
10
- # (#1631). The prompt hook asked an LLM judge whether the CURRENT session's own
11
- # background_tasks entry had transitioned to "completed" before allowing Stop —
12
- # but that transition only happens AFTER the SubagentStop hook chain resolves, so the
13
- # judgment was structurally always "not yet completed" for a subagent evaluating its
14
- # OWN stop. That produced a self-referential `Stop hook feedback:` re-injection loop
15
- # with no dedup, observed to repeat 8-10x per session before manual override.
16
- # Fix: replace the blocking LLM judge with a plain stderr-only warning that never
17
- # triggers the Stop-hook-feedback re-injection path. No block, no LLM call, no loop.
18
- # Protocol: stdin JSON -> read tool_output.is_error -> stderr warning if failed -> pass through -> exit 0
19
- # Exit status (MEASURED, bash 3.2, `set -euo pipefail`): rc=0 in every probe (well-formed payload,
20
- # is_error=true payload, malformed JSON, empty stdin, array/scalar payloads) except one synthetic case:
21
- # the jq calls for is_error and agent_type are guarded with `|| echo`, but the error_summary pipeline
22
- # (`jq ... | head -c 200`) is not; with is_error=true and a 300KB `tool_output.output` it gave rc=141
23
- # (SIGPIPE under pipefail, 3/3). SubagentStop payloads have no `tool_output`, so is_error is always
24
- # false there and that path is unreachable at runtime.
8
+ # Trigger: PostToolUseFailure (matcher: Agent / Task tool)
9
+ # Purpose: Advisory-only. When an Agent/Task tool call fails, tell the model not to
10
+ # auto-continue as if the subagent had succeeded. Replaces the removed
11
+ # `type: "prompt"` SubagentStop hook (#1631), whose LLM judge was structurally
12
+ # always "not yet completed" and produced a Stop-hook-feedback re-injection loop.
13
+ # Why not SubagentStop (#1775): the SubagentStop payload has no tool_response /
14
+ # tool_output / is_error (measured keys on CC 2.1.310, `claude -p`, haiku, one run, see
15
+ # https://github.com/baekenough/oh-my-customcode/issues/1775#issuecomment-6404861043: agent_id, agent_transcript_path, agent_type,
16
+ # background_tasks, cwd, effort, hook_event_name, last_assistant_message,
17
+ # permission_mode, prompt_id, session_crons, session_id, stop_hook_active,
18
+ # transcript_path), so a failure check there can never fire.
19
+ # Input (PostToolUseFailure; measured on CC 2.1.310, `claude -p`, haiku, one run, unknown
20
+ # subagent_type; additionalContext delivery evidence is weak because the probe prompt named
21
+ # the marker; measured fields only: tool_name, is_interrupt, error (string), see
22
+ # https://github.com/baekenough/oh-my-customcode/issues/1775#issuecomment-6405197553).
23
+ # Other fields (tool_input sub-fields, duration_ms, tool_use_id, hook_event_name, ...) come from
24
+ # the PostToolUseFailure input table in https://code.claude.com/docs/en/hooks.md, not measured.
25
+ # Output: stdout JSON {"hookSpecificOutput":{"hookEventName":"PostToolUseFailure",
26
+ # "additionalContext": "..."}} -- observed as delivered to the model (weak evidence, see above).
27
+ # Never a `decision` field; the only explicit exit is exit 0. Silent for interrupts, non-Agent/Task tools,
28
+ # missing error, or non-object stdin.
25
29
 
26
30
  input=$(cat)
27
31
 
28
- is_error=$(printf '%s\n' "$input" | jq -r '.tool_output.is_error // false' 2>/dev/null || echo "false")
32
+ # Single jq pass; any parse failure or non-object stdin -> silent exit 0.
33
+ fields=$(printf '%s' "$input" | jq -r '
34
+ if type == "object" then
35
+ [ (.tool_name // ""),
36
+ (if .is_interrupt == true then "1" else "0" end),
37
+ ((.tool_input.subagent_type // "unknown") | tostring | .[0:80]),
38
+ ((.tool_input.description // "") | tostring | gsub("[\n\r\t]"; " ") | .[0:120]),
39
+ ((.error // "") | tostring | gsub("[\n\r\t]"; " ") | .[0:200])
40
+ ] | join("\u001f")
41
+ else empty end' 2>/dev/null || true)
29
42
 
30
- if [ "$is_error" = "true" ]; then
31
- agent_type=$(printf '%s\n' "$input" | jq -r '.tool_input.subagent_type // .agent_type // "unknown"' 2>/dev/null || echo "unknown")
32
- error_summary=$(printf '%s\n' "$input" | jq -r '.tool_output.output // ""' 2>/dev/null | head -c 200)
33
- echo "" >&2
34
- echo "--- [Subagent Failure Advisor] background subagent (${agent_type}) reported an error ---" >&2
35
- echo " ${error_summary}" >&2
36
- echo " If it FAILED, do NOT auto-continue -- report the failure and wait for user input." >&2
37
- echo "-----------------------------------------------------------------------------------" >&2
38
- fi
43
+ [ -n "$fields" ] || exit 0
39
44
 
40
- # Always pass through -- advisory only, never blocks, never triggers Stop hook feedback re-injection
41
- printf '%s\n' "$input"
45
+ IFS=$'\x1f' read -r tool_name is_interrupt subagent_type description error_text <<EOT
46
+ $fields
47
+ EOT
48
+
49
+ case "$tool_name" in
50
+ Agent|Task) ;;
51
+ *) exit 0 ;;
52
+ esac
53
+ [ "$is_interrupt" = "0" ] || exit 0
54
+ [ -n "$error_text" ] || exit 0
55
+
56
+ msg="[Subagent Failure Advisor] ${tool_name} call failed (subagent_type=${subagent_type}"
57
+ [ -z "$description" ] || msg="${msg}, description=${description}"
58
+ msg="${msg}): ${error_text}. Fix the arguments (e.g. the subagent_type) and retry once; if the failure is a permission denial or repeats, report it and do not pretend the subagent ran."
59
+
60
+ jq -n --arg ctx "$msg" '{hookSpecificOutput:{hookEventName:"PostToolUseFailure",additionalContext:$ctx}}' 2>/dev/null || true
42
61
  exit 0
@@ -10,9 +10,10 @@ command -v jq >/dev/null 2>&1 || exit 0
10
10
  # Protocol: stdin JSON -> process -> stdout pass-through
11
11
  # Exit status (MEASURED, bash 3.2, `set -euo pipefail`): the only explicit exits are `exit 0`, but
12
12
  # there is no trap, so it is NOT guaranteed. rc=0 for a well-formed payload, malformed JSON, empty
13
- # stdin, array/scalar payloads and a corrupt AGENT_START_FILE, with start_epoch exceptions: "abc" gives
14
- # rc=1 (`set -u`: "abc: unbound variable"); arithmetic-syntax values ("1792939922.5", "09") print an
15
- # error but give rc=0 (bash 3.2 drops the line; duration stays 0); "" gives rc=0.
13
+ # stdin, array/scalar payloads and a corrupt AGENT_START_FILE. A start_epoch that is not a positive
14
+ # decimal integer without a leading zero ("", "0", "null", "abc", "1792939922.5", "09", "-5") is
15
+ # treated as no start record: rc=0 and duration_seconds 0 (measured on bash 3.2; before this check
16
+ # "abc" gave rc=1 and "" recorded now_epoch, about 1.79e9, as the duration).
16
17
  #
17
18
  # MEASURED SubagentStop payload (CC 2.1.259 embedded hook schema; #1656 B):
18
19
  # session_id, transcript_path, cwd, prompt_id?, permission_mode?, effort?,
@@ -35,8 +36,8 @@ command -v jq >/dev/null 2>&1 || exit 0
35
36
  # Outcome caveat: SubagentStop exposes no failure signal, so entries recorded
36
37
  # from that event are always outcome=success. There is no working hand-off for
37
38
  # that gap today: SubagentStop payload carries no failure signal;
38
- # subagent-failure-advisor.sh currently reads `.tool_output.is_error`, which is
39
- # absent here, so failure detection on this path is 0 until #1656 G is resolved.
39
+ # subagent-failure-advisor.sh reads `.error` from PostToolUseFailure (Agent/Task) payloads,
40
+ # not from SubagentStop, so this recorder still has no failure hand-off (#1656 G, #1775).
40
41
 
41
42
  input=$(cat)
42
43
 
@@ -65,8 +66,11 @@ description=$(printf '%s\n' "$input" | jq -r '
65
66
 
66
67
  # Extract skill name from description or prompt
67
68
  skill_name=""
68
- # `|| true`: a no-match grep exits 1 and `set -euo pipefail` would abort the hook
69
- # (this line's guard: rc=1 when text passes the gate below but not the name pattern; the later guard: rc=1 on {"agent_type":"X"}).
69
+ # `|| true`: a no-match grep exits 1 and `set -euo pipefail` would abort the hook.
70
+ # Two guards follow. The `|| true` at the end of the `grep -oiE '[a-z]+-[a-z]+...'` line inside the
71
+ # `if` below covers the case where the text passes the `grep -qiE` gate but not the name pattern.
72
+ # The `|| true` at the end of the later `grep -oiE 'Skill:...'` line covers a payload with no
73
+ # "Skill:" text, e.g. {"agent_type":"X"} (rc=1 without it).
70
74
  # Empty stdin now exits at the non-object guard above.
71
75
  if echo "$description" | grep -qiE '(skill:|routing|→.*skill)'; then
72
76
  skill_name=$(echo "$description" | grep -oiE '[a-z]+-[a-z]+(-[a-z]+)*-?(routing|skill|practices|detection|decomposition|orchestration|pipeline|guards|cycle|plan|review|refactor|publish|version|audit|exec|analyze|bundle|report|setup|watch|lists|status|help|save|recall)' | head -1 || true)
@@ -159,7 +163,10 @@ AGENT_START_FILE="/tmp/.claude-agent-starts-${PPID}"
159
163
  duration_seconds=0
160
164
  if [ -f "$AGENT_START_FILE" ]; then
161
165
  start_epoch=$(grep -F "\"agent_type\":\"${agent_type}\"" "$AGENT_START_FILE" 2>/dev/null | tail -1 | jq -r '.start_epoch // "0"' 2>/dev/null || echo "0")
162
- if [ "$start_epoch" != "0" ] && [ "$start_epoch" != "null" ]; then
166
+ # Only a positive decimal integer without a leading zero is a usable epoch. Anything else
167
+ # ("", "0", "null", "abc", "1792939922.5", "09", negatives) takes the no-start-record path
168
+ # (duration 0): bash arithmetic would otherwise read "" as 0 and record now_epoch as the duration.
169
+ if [[ "$start_epoch" =~ ^[1-9][0-9]*$ ]]; then
163
170
  now_epoch=$(date +%s)
164
171
  duration_seconds=$((now_epoch - start_epoch))
165
172
  fi
@@ -9,16 +9,16 @@ classes:
9
9
  agents: [lang-golang-expert, lang-python-expert, lang-rust-expert, lang-kotlin-expert, lang-typescript-expert, lang-java-expert]
10
10
  description: "Programming language specialists"
11
11
  BackendExpert:
12
- agents: [be-fastapi-expert, be-springboot-expert, be-go-backend-expert, be-express-expert, be-nestjs-expert]
12
+ agents: [be-fastapi-expert, be-springboot-expert, be-go-backend-expert, be-express-expert, be-nestjs-expert, be-django-expert]
13
13
  description: "Backend framework specialists"
14
14
  FrontendExpert:
15
- agents: [fe-vercel-agent, fe-vuejs-agent, fe-svelte-agent, fe-flutter-agent]
15
+ agents: [fe-vercel-agent, fe-vuejs-agent, fe-svelte-agent, fe-flutter-agent, fe-design-expert]
16
16
  description: "Frontend framework specialists"
17
17
  DataEngineer:
18
18
  agents: [de-airflow-expert, de-dbt-expert, de-spark-expert, de-kafka-expert, de-snowflake-expert, de-pipeline-expert]
19
19
  description: "Data engineering specialists"
20
20
  DatabaseExpert:
21
- agents: [db-postgres-expert, db-redis-expert, db-supabase-expert]
21
+ agents: [db-postgres-expert, db-redis-expert, db-supabase-expert, db-alembic-expert]
22
22
  description: "Database specialists"
23
23
  ToolingExpert:
24
24
  agents: [tool-npm-expert, tool-optimizer, tool-bun-expert]
@@ -103,14 +103,14 @@ agents:
103
103
 
104
104
  lang-java-expert:
105
105
  class: LanguageExpert
106
- description: "Expert Java 21 developer for modern Java with Virtual Threads, Pattern Matching, Record Patterns, and Sequenced Collections. Use for Java files (*.java, pom.xml, build.gradle), Java-related keywords, high-concurrency systems, data-centric APIs with Records, and migrating from older Java versions."
106
+ description: "Expert Java 25 LTS developer for modern Java with Virtual Threads, Pattern Matching, Record Patterns, and Sequenced Collections. Use for Java files (*.java, pom.xml, build.gradle), Java-related keywords, high-concurrency systems, data-centric APIs with Records, and migrating from older Java versions."
107
107
  model: sonnet
108
108
  memory: project
109
109
  effort: high
110
- skills: []
110
+ skills: [java-best-practices]
111
111
  tools: [Read, Write, Edit, Grep, Glob, Bash]
112
- summary: "Java 21 expert for modern features including virtual threads and pattern matching"
113
- keywords: [java, java21, virtual-threads, pattern-matching, records, sequenced-collections]
112
+ summary: "Java 25 LTS expert for modern features including virtual threads and pattern matching"
113
+ keywords: [java, java25, virtual-threads, pattern-matching, records, sequenced-collections]
114
114
  file_patterns: ["*.java", "pom.xml", "build.gradle", "build.gradle.kts"]
115
115
 
116
116
  be-fastapi-expert:
@@ -544,3 +544,67 @@ agents:
544
544
  summary: "Task tracker with proactive reminders for TODO management"
545
545
  keywords: [todo, tasks, reminders, tracking, deadlines, project-momentum]
546
546
  file_patterns: ["TODO.md", "*.todo"]
547
+
548
+ agora-runner:
549
+ description: "Executes exactly one agora session step (start, one round, or finish) via the skill scripts and returns only a verdict summary. Never returns reviewer text, vendor attribution or sealed paths."
550
+ model: claude-sonnet-5-5
551
+ skills: [agora]
552
+ tools: [Bash, Read, Write, Glob]
553
+
554
+ be-django-expert:
555
+ class: BackendExpert
556
+ description: "Expert Django developer for production-ready Python web applications. Use for Django projects, models/views/templates, Django REST Framework, authentication, admin customization, and deployment optimization."
557
+ model: claude-sonnet-5-5
558
+ memory: local
559
+ effort: high
560
+ skills: [django-best-practices]
561
+ tools: [Read, Write, Edit, Grep, Glob, Bash]
562
+
563
+ db-alembic-expert:
564
+ class: DatabaseExpert
565
+ description: "Alembic migration specialist for generating, reviewing, fixing, and advising on SQLAlchemy database migrations"
566
+ model: claude-opus-5-5
567
+ memory: local
568
+ effort: high
569
+ skills: [alembic-best-practices, postgres-best-practices]
570
+ tools: [Read, Write, Edit, Grep, Glob, Bash]
571
+
572
+ fe-design-expert:
573
+ class: FrontendExpert
574
+ description: "Use for design system review, typography audit, color palette evaluation, motion design, and AI-generated design quality assessment"
575
+ model: claude-sonnet-5-5
576
+ memory: local
577
+ effort: medium
578
+ skills: [impeccable-design, web-design-guidelines, diagram-design]
579
+ tools: [Read, Write, Edit, Grep, Glob]
580
+
581
+ sec-codeql-expert:
582
+ description: "Expert security code analyst using CodeQL for vulnerability detection, call graph analysis, and SARIF output. Use for security audits, CVE triage, code pattern analysis, and vulnerability validation."
583
+ model: claude-opus-5-5
584
+ memory: local
585
+ effort: high
586
+ skills: [cve-triage, adversarial-review]
587
+ tools: [Read, Write, Grep, Bash]
588
+
589
+ slack-cli-expert:
590
+ description: "Expert Slack CLI developer for Slack app management, deployment, triggers, and workspace automation"
591
+ model: claude-sonnet-5-5
592
+ effort: medium
593
+ skills: []
594
+ tools: [Read, Write, Edit, Grep, Glob, Bash]
595
+
596
+ tracker-checkpoint:
597
+ description: "Pipeline execution state tracker with checkpoint persistence. Reads/writes /tmp/.claude-pipeline-*-{PPID}.json state files and validates state transitions. Used by dag-orchestration for resume-after-failure and pipeline-guards for quality gate state."
598
+ model: haiku
599
+ memory: local
600
+ effort: medium
601
+ skills: [dag-orchestration, pipeline-guards]
602
+ tools: [Read, Write, Edit, Bash, Glob, Grep]
603
+
604
+ wiki-curator:
605
+ description: "Dedicated wiki page CRUD agent — creates, updates, and maintains wiki/ markdown pages for the codebase knowledge base"
606
+ model: claude-sonnet-5-5
607
+ memory: local
608
+ effort: medium
609
+ skills: []
610
+ tools: [Read, Write, Edit, Glob, Grep, Bash]
@@ -17,7 +17,9 @@
17
17
  "lang-typescript-expert": [
18
18
  "typescript-best-practices"
19
19
  ],
20
- "lang-java-expert": [],
20
+ "lang-java-expert": [
21
+ "java-best-practices"
22
+ ],
21
23
  "be-fastapi-expert": [
22
24
  "fastapi-best-practices"
23
25
  ],
@@ -105,7 +107,32 @@
105
107
  "claude-code-bible"
106
108
  ],
107
109
  "sys-memory-keeper": [],
108
- "sys-naggy": []
110
+ "sys-naggy": [],
111
+ "agora-runner": [
112
+ "agora"
113
+ ],
114
+ "be-django-expert": [
115
+ "django-best-practices"
116
+ ],
117
+ "db-alembic-expert": [
118
+ "alembic-best-practices",
119
+ "postgres-best-practices"
120
+ ],
121
+ "fe-design-expert": [
122
+ "impeccable-design",
123
+ "web-design-guidelines",
124
+ "diagram-design"
125
+ ],
126
+ "sec-codeql-expert": [
127
+ "cve-triage",
128
+ "adversarial-review"
129
+ ],
130
+ "slack-cli-expert": [],
131
+ "tracker-checkpoint": [
132
+ "dag-orchestration",
133
+ "pipeline-guards"
134
+ ],
135
+ "wiki-curator": []
109
136
  },
110
137
  "reverse": {
111
138
  "go-best-practices": [
@@ -136,7 +163,8 @@
136
163
  "fe-vercel-agent"
137
164
  ],
138
165
  "web-design-guidelines": [
139
- "fe-vercel-agent"
166
+ "fe-vercel-agent",
167
+ "fe-design-expert"
140
168
  ],
141
169
  "vercel-deploy": [
142
170
  "fe-vercel-agent"
@@ -163,7 +191,8 @@
163
191
  "de-pipeline-expert"
164
192
  ],
165
193
  "postgres-best-practices": [
166
- "db-postgres-expert"
194
+ "db-postgres-expert",
195
+ "db-alembic-expert"
167
196
  ],
168
197
  "redis-best-practices": [
169
198
  "db-redis-expert"
@@ -225,7 +254,37 @@
225
254
  "lists": [],
226
255
  "monitoring-setup": [],
227
256
  "result-aggregation": [],
228
- "status": []
257
+ "status": [],
258
+ "java-best-practices": [
259
+ "lang-java-expert"
260
+ ],
261
+ "agora": [
262
+ "agora-runner"
263
+ ],
264
+ "django-best-practices": [
265
+ "be-django-expert"
266
+ ],
267
+ "alembic-best-practices": [
268
+ "db-alembic-expert"
269
+ ],
270
+ "impeccable-design": [
271
+ "fe-design-expert"
272
+ ],
273
+ "diagram-design": [
274
+ "fe-design-expert"
275
+ ],
276
+ "cve-triage": [
277
+ "sec-codeql-expert"
278
+ ],
279
+ "adversarial-review": [
280
+ "sec-codeql-expert"
281
+ ],
282
+ "dag-orchestration": [
283
+ "tracker-checkpoint"
284
+ ],
285
+ "pipeline-guards": [
286
+ "tracker-checkpoint"
287
+ ]
229
288
  },
230
289
  "nodes": [],
231
290
  "links": []