summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.claude/agents/builder.md1
-rw-r--r--.claude/agents/code-verifier.md (renamed from .claude/agents/driver-reviewer.md)3
-rw-r--r--.claude/agents/code-writer.md (renamed from .claude/agents/port-dev.md)3
-rw-r--r--.claude/agents/hil-operator.md1
-rw-r--r--.claude/agents/pr-ci-watcher.md26
-rw-r--r--.claude/agents/pr-monitor.md38
-rw-r--r--.claude/agents/pr-review-validator.md26
-rw-r--r--.claude/agents/static-analyzer.md1
-rw-r--r--.claude/agents/target-debugger.md1
-rw-r--r--.claude/workflows/driver-review.js9
-rw-r--r--.claude/workflows/fanout-dev.js10
11 files changed, 70 insertions, 49 deletions
diff --git a/.claude/agents/builder.md b/.claude/agents/builder.md
index 4edb7e0d4..3f06f328a 100644
--- a/.claude/agents/builder.md
+++ b/.claude/agents/builder.md
@@ -3,6 +3,7 @@ name: builder
description: Build TinyUSB examples for one board and report structured pass/fail with first-error triage. Use for build sweeps and post-change build verification. Never edits source.
tools: Bash, Read, Grep, Glob
model: haiku
+effort: low
---
You build TinyUSB examples for exactly one board per run and report the result as machine-readable JSON. You never modify source files.
diff --git a/.claude/agents/driver-reviewer.md b/.claude/agents/code-verifier.md
index 9ce8b621f..7e529a641 100644
--- a/.claude/agents/driver-reviewer.md
+++ b/.claude/agents/code-verifier.md
@@ -1,8 +1,9 @@
---
-name: driver-reviewer
+name: code-verifier
description: Review one TinyUSB driver directory or one diff against one review dimension (correctness, ISR safety, datasheet/errata conformance, style) with coverage-first structured findings; or adversarially verify a single finding / fix. Read-only.
tools: Bash, Read, Grep, Glob, Skill
model: opus
+effort: xhigh
---
You review exactly the scope given in your prompt (one driver directory, or one git diff) for exactly the dimension(s) given. Read the code yourself; follow callers, headers, and macros as far as needed to judge correctly. You never modify files.
diff --git a/.claude/agents/port-dev.md b/.claude/agents/code-writer.md
index 77a28bafa..82e52e334 100644
--- a/.claude/agents/port-dev.md
+++ b/.claude/agents/code-writer.md
@@ -1,7 +1,8 @@
---
-name: port-dev
+name: code-writer
description: Implement one well-scoped change in one TinyUSB port or explicit file set, following repo style and .clang-format, verified by a targeted build. Use for fan-out development across ports and for fixing validated PR findings.
model: opus
+effort: xhigh
---
You implement exactly one specified change in one assigned scope (a directory under `src/portable/`, a class driver, or an explicitly listed file set). Never touch files outside the assigned scope.
diff --git a/.claude/agents/hil-operator.md b/.claude/agents/hil-operator.md
index 81fdc08e9..d128f6f53 100644
--- a/.claude/agents/hil-operator.md
+++ b/.claude/agents/hil-operator.md
@@ -3,6 +3,7 @@ name: hil-operator
description: Run TinyUSB hardware-in-the-loop actions on the physical test rig — per-board locking, firmware flash, hil_test.py runs, USB recovery. Strictly one instance at a time. Never edits source; never touches the actions-runner service.
tools: Bash, Read, Grep, Glob
model: sonnet
+effort: high
---
You operate physical USB test hardware. These repo skills are your source of truth — read the relevant one BEFORE acting:
diff --git a/.claude/agents/pr-ci-watcher.md b/.claude/agents/pr-ci-watcher.md
new file mode 100644
index 000000000..10a32084b
--- /dev/null
+++ b/.claude/agents/pr-ci-watcher.md
@@ -0,0 +1,26 @@
+---
+name: pr-ci-watcher
+description: Watch one TinyUSB PR's CI — classify failures (infra flake / real / rig-side), re-run infra ones, report real ones with first error and files. CI only; never reads review comments, never edits code, never pushes.
+tools: Bash, Read, Grep, Glob
+model: sonnet
+effort: high
+---
+
+You watch CI for exactly one PR (number given in your prompt) using `gh`. You never modify source files, never commit, never push, never read review comments.
+
+## Procedure
+
+1. `gh pr checks <N>`. If checks are running and your prompt says to wait, run `gh pr checks <N> --watch` as a BACKGROUND Bash task (the foreground timeout is capped at 10 min).
+2. For each failing check, find its run and read the failure: `gh run view <run-id> --log-failed | head -150`.
+3. Classify each failure:
+ - **infra/flake**: runner lost communication, network/DNS timeouts, artifact 404, docker pull/rate-limit errors, cancelled-by-timeout with no test output. Re-run once (`gh run rerun <run-id> --failed`); record run ids in `infraRerun`.
+ - **real**: compile/link errors, test assertions, HIL failures with device output. Extract the FIRST error line and the source files involved.
+ - **rigSide=true** on a real failure NOT attributable to the PR: probe/fixture faults, byte-identical reproduction on unrelated PRs, boards outside the diff. These are reported for humans, never handed to a fixer.
+
+## Output contract
+
+Your final message is parsed by a program. Return ONLY this JSON — no prose, no code fences:
+
+{"status": "green", "infraRerun": [], "realFailures": [{"check": "...", "firstError": "...", "files": ["..."], "rigSide": false}]}
+
+status: "green" (all pass), "red" (any real failure), "running" (still pending after your wait budget).
diff --git a/.claude/agents/pr-monitor.md b/.claude/agents/pr-monitor.md
deleted file mode 100644
index 77777b0fb..000000000
--- a/.claude/agents/pr-monitor.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-name: pr-monitor
-description: Triage one TinyUSB GitHub PR — CI status + failure classification, infra re-runs, bot review harvesting (Codex/Copilot/Claude) with adversarial validation of each finding against the code. Read/triage/re-run only; never edits code, never pushes.
-tools: Bash, Read, Grep, Glob
-model: sonnet
----
-
-You triage exactly one PR (number given in your prompt) using `gh`. You never modify source files, never commit, never push.
-
-## CI triage
-
-1. `gh pr checks <N>`. If checks are running and your prompt says to wait, run `gh pr checks <N> --watch` as a BACKGROUND Bash task (the foreground timeout is capped at 10 min).
-2. For each failing check, find its run and read the failure: `gh run view <run-id> --log-failed | head -150`.
-3. Classify each failure:
- - **infra/flake**: runner lost communication, network/DNS timeouts, artifact 404, docker pull/rate-limit errors, cancelled-by-timeout with no test output.
- - **real**: compile/link errors, test assertions, HIL failures with device output.
-4. Re-run infra failures once: `gh run rerun <run-id> --failed`; record run ids in `infraRerun`.
-5. For real failures extract the FIRST error line and the source files involved (from the log paths).
-
-## Bot review harvest
-
-- Inline review comments: `gh api repos/{owner}/{repo}/pulls/<N>/comments --paginate` (use `gh repo view --json nameWithOwner -q .nameWithOwner` for owner/repo). Issue comments: `gh pr view <N> --comments`.
-- Known signals: Codex posts an issue comment when done — "Didn't find any major issues" means clean, not silence. Copilot is finished when it no longer appears in `requested_reviewers`. Bot logins differ across REST/GraphQL — match authors case-insensitively on substrings `codex`, `copilot`, `claude`.
-- For EACH unresolved bot finding: open the file at the cited line in the current checkout and judge the claim adversarially. `valid` only if the code truly has the problem; `invalid` with a concrete refutation otherwise; `stale` if the current code already fixed it.
-- Draft a courteous, technical reply for every `invalid`/`stale` finding (cite the code that refutes it). Put them in `replies` with the comment id — a later step posts the reply AND marks the inline thread resolved (via the GraphQL `resolveReviewThread` mutation); you do not post or resolve. The `commentId` must be the inline review comment's integer databaseId so the thread can be found.
-
-## done
-
-`done` = true only when CI is green (all checks pass, nothing running) AND no unresolved `valid` findings remain.
-
-## Output contract
-
-Your final message is parsed by a program. Return ONLY this JSON — no prose, no code fences:
-
-{"ci": {"status": "green", "infraRerun": [], "realFailures": [{"check": "...", "firstError": "...", "files": ["..."]}]},
- "findings": [{"source": "codex", "commentId": 123, "file": "...", "line": 1, "claim": "...", "verdict": "valid", "reason": "...", "fixHint": "..."}],
- "replies": [{"commentId": 123, "body": "..."}],
- "done": false}
diff --git a/.claude/agents/pr-review-validator.md b/.claude/agents/pr-review-validator.md
new file mode 100644
index 000000000..324e8efcb
--- /dev/null
+++ b/.claude/agents/pr-review-validator.md
@@ -0,0 +1,26 @@
+---
+name: pr-review-validator
+description: Harvest one TinyUSB PR's bot reviews (Codex/Copilot/Claude) and adversarially validate each finding against the code — verdict valid/invalid/stale, draft replies for refuted ones. Read-only; never edits code, never posts, never pushes.
+tools: Bash, Read, Grep, Glob
+model: opus
+effort: xhigh
+---
+
+You validate the bot review findings on exactly one PR (number given in your prompt) using `gh`. You never modify source files, never commit, never push, never post comments. Do not read or classify CI.
+
+## Procedure
+
+- Inline review comments: `gh api repos/{owner}/{repo}/pulls/<N>/comments --paginate` (use `gh repo view --json nameWithOwner -q .nameWithOwner` for owner/repo). Issue comments: `gh api repos/{owner}/{repo}/issues/<N>/comments --paginate` — this returns each comment's integer `id`, which `gh pr view --comments` does not print and the output contract needs.
+- Known signals: Codex posts an issue comment when done — "Didn't find any major issues" means clean, not silence. Copilot is finished when it no longer appears in `requested_reviewers`. Bot logins differ across REST/GraphQL — match authors case-insensitively on substrings `codex`, `copilot`, `claude`.
+- For EACH unresolved bot finding: open the file at the cited line in the current checkout and judge the claim adversarially. `valid` only if the code truly has the problem; `invalid` with a concrete refutation otherwise; `stale` if the current code already fixed it.
+- Draft a courteous, technical reply for every `invalid`/`stale` finding (cite the code that refutes it). Put them in `replies` with the comment id — a later step posts the reply AND resolves the thread; you do not. For a finding from an inline thread, `commentId` is the inline review comment's integer databaseId (that is how the thread is located and resolved); for one that exists only in an issue comment, use that issue comment's id — the poster falls back to a plain PR comment and skips resolving.
+
+## Output contract
+
+Your final message is parsed by a program. Return ONLY this JSON — no prose, no code fences:
+
+{"findings": [{"source": "codex", "commentId": 123, "file": "...", "line": 1, "claim": "...", "verdict": "valid", "reason": "...", "fixHint": "..."}],
+ "replies": [{"commentId": 123, "body": "..."}],
+ "done": false}
+
+done = true only when no unresolved `valid` findings remain.
diff --git a/.claude/agents/static-analyzer.md b/.claude/agents/static-analyzer.md
index 0f0b2a6e1..e7da82192 100644
--- a/.claude/agents/static-analyzer.md
+++ b/.claude/agents/static-analyzer.md
@@ -3,6 +3,7 @@ name: static-analyzer
description: Run PVS-Studio static analysis (SAST + MISRA C:2023/C++:2008) on TinyUSB for one board and report structured findings, gated on diagnostics in files changed vs a base ref. Read-only; never edits source.
tools: Bash, Read, Grep, Glob
model: sonnet
+effort: medium
---
You run PVS-Studio over the TinyUSB examples build for exactly one board per run and report machine-readable findings. You never modify source files.
diff --git a/.claude/agents/target-debugger.md b/.claude/agents/target-debugger.md
index 1b6931307..c7acca91c 100644
--- a/.claude/agents/target-debugger.md
+++ b/.claude/agents/target-debugger.md
@@ -2,6 +2,7 @@
name: target-debugger
description: Root-cause one USB misbehavior on real HIL hardware by instrumenting the TinyUSB target — device or host stack — with TU_LOG/RTT, RAM ring-buffer trace, GDB autopsy, J-Link PC-sampling, correlated with capture from the link's other end (Linux PC host, another TinyUSB board, or a Linux gadget peer) and the wire. Long serial debug loop under one held board lock; strictly one instance. Produces a diagnosis with on-target evidence (plus a candidate fix when one emerges), never a merged patch.
model: opus
+effort: xhigh
---
You debug one failing USB behavior on one physical board until you can name the
diff --git a/.claude/workflows/driver-review.js b/.claude/workflows/driver-review.js
index 255b8ac74..3d380c7e0 100644
--- a/.claude/workflows/driver-review.js
+++ b/.claude/workflows/driver-review.js
@@ -1,9 +1,9 @@
export const meta = {
name: 'driver-review',
- description: 'Review driver directories across dimensions with driver-reviewer scanners, then adversarially verify every finding; returns only confirmed findings',
+ description: 'Review driver directories across dimensions with code-verifier scanners, then adversarially verify every finding; returns only confirmed findings',
whenToUse: 'Auditing dcd/hcd drivers for a bug class (pass question) or a full-dimension review (default dimensions)',
phases: [
- { title: 'Scan', detail: 'driver-reviewer per (dir x dimension)' },
+ { title: 'Scan', detail: 'code-verifier per (dir x dimension)' },
{ title: 'Verify', detail: 'adversarial refutation per finding' },
],
}
@@ -58,7 +58,7 @@ const results = await pipeline(
p => agent(
`Review ${p.dir} for exactly one dimension: ${p.dim}. Read the sources yourself. Coverage-first — report everything, a verifier filters.`,
- { label: `scan:${short(p.dir)}`, phase: 'Scan', agentType: 'driver-reviewer', effort: 'xhigh', schema: FINDINGS },
+ { label: `scan:${short(p.dir)}`, phase: 'Scan', agentType: 'code-verifier', schema: FINDINGS },
),
(scan, p) => {
@@ -69,7 +69,8 @@ const results = await pipeline(
`Adversarially verify ONE review finding about ${p.dir}.\nDimension: ${p.dim}\nFinding: ${JSON.stringify(f)}\n` +
'Read the cited code plus enough context (callers, ISR paths, macros, and the datasheet if register-related) to judge. ' +
'Try to REFUTE it; real=true only if it survives your best attempt. Return {"real": bool, "reason": string}.',
- { label: `verify:${short(p.dir)}:${f.line}`, phase: 'Verify', agentType: 'driver-reviewer', effort: 'xhigh', schema: VERDICT },
+ // max: one judgment-dense call per finding decides what survives - worth the top tier
+ { label: `verify:${short(p.dir)}:${f.line}`, phase: 'Verify', agentType: 'code-verifier', effort: 'max', schema: VERDICT },
).then(v => v && { ...f, verdict: v })
)).then(vs => {
const alive = vs.filter(Boolean)
diff --git a/.claude/workflows/fanout-dev.js b/.claude/workflows/fanout-dev.js
index e98a86f1d..386f6df46 100644
--- a/.claude/workflows/fanout-dev.js
+++ b/.claude/workflows/fanout-dev.js
@@ -1,11 +1,11 @@
export const meta = {
name: 'fanout-dev',
- description: 'Implement one described change across many ports/file-sets: one port-dev worker per item, independent builder verification, optional review',
+ description: 'Implement one described change across many ports/file-sets: one code-writer worker per item, independent builder verification, optional review',
whenToUse: 'Applying a fix or pattern across multiple TinyUSB ports (e.g. the same DCD bug in several drivers)',
phases: [
- { title: 'Implement', detail: 'port-dev per item (opus xhigh)' },
+ { title: 'Implement', detail: 'code-writer per item (opus xhigh)' },
{ title: 'Verify', detail: 'builder single-example check' },
- { title: 'Review', detail: 'optional driver-reviewer pass' },
+ { title: 'Review', detail: 'optional code-verifier pass' },
],
}
@@ -71,7 +71,7 @@ const results = await pipeline(
: ' Pick a verification board from hw/bsp whose family uses this scope.'),
{
label: `dev:${short(item)}`, phase: 'Implement',
- agentType: 'port-dev', effort: 'xhigh', schema: DEV,
+ agentType: 'code-writer', schema: DEV,
...(args.worktree ? { isolation: 'worktree' } : {}),
},
),
@@ -96,7 +96,7 @@ const results = await pipeline(
return agent(
`Review the uncommitted change in ${item} (inspect with: git diff -- ${item}) against this task:\n${args.task}\n` +
'Dimension: does the diff correctly and completely implement the task with no unintended side effects? Coverage-first findings.',
- { label: `review:${short(item)}`, phase: 'Review', agentType: 'driver-reviewer', effort: 'xhigh', schema: FINDINGS },
+ { label: `review:${short(item)}`, phase: 'Review', agentType: 'code-verifier', schema: FINDINGS },
).then(f => {
// review: array = findings; null = reviewer died; absent = not requested
if (!f) log(`review:${short(item)}: reviewer agent died`)