Commit 0b9eb59c8279
Changed files (9)
dots
config
claude
skills
CodeReview
pi
agent
extensions
dots/config/claude/skills/CodeReview/workflows/FocusedReview.md
@@ -0,0 +1,38 @@
+# FocusedReview Workflow
+
+Run a code review with a single focus area using the appropriate specialized reviewer subagent.
+
+## Steps
+
+1. **Determine the focus area** from the user's request:
+ - "security" → `reviewer-security`
+ - "performance" → `reviewer-performance`
+ - "nix" → `reviewer-nix`
+ - "general" or unspecified → `reviewer`
+
+2. **Determine the review target** from the user's request:
+ - Uncommitted changes: `git diff` + `git diff --staged` + untracked files
+ - Branch comparison: `git diff <base>..HEAD`
+ - Specific commit: `git show <sha>`
+ - PR: checkout and diff against base branch
+ - Folder/file snapshot: read the files directly
+
+3. **Dispatch to the subagent** using the `subagent` tool in single mode:
+
+```
+Use the subagent tool with:
+ agent: "reviewer-security" (or whichever focus)
+ task: "Review the following code changes for <focus>:\n\n<diff or instructions>"
+```
+
+4. **Present findings** from the subagent output to the user.
+
+## Example
+
+```
+User: "Security review of the last commit"
+→ Determines focus: security → agent: reviewer-security
+→ Gets diff: git show HEAD
+→ Dispatches: subagent(agent="reviewer-security", task="Review commit abc123 for security issues. Run `git show HEAD` to see the changes.")
+→ Presents structured findings
+```
dots/config/claude/skills/CodeReview/workflows/FullReview.md
@@ -0,0 +1,43 @@
+# FullReview Workflow
+
+Run a comprehensive code review by dispatching all focus areas in parallel using subagents.
+
+## Steps
+
+1. **Determine the review target** (same as FocusedReview).
+
+2. **Dispatch all reviewers in parallel** using the `subagent` tool:
+
+```
+Use the subagent tool with tasks (parallel mode):
+ tasks: [
+ { agent: "reviewer", task: "General code review: <target description>" },
+ { agent: "reviewer-security", task: "Security-focused review: <target description>" },
+ { agent: "reviewer-performance", task: "Performance-focused review: <target description>" }
+ ]
+```
+
+For Nix repositories, add `reviewer-nix` to the parallel set.
+
+3. **Merge and deduplicate findings** across all reviewers:
+ - Group by file and line number
+ - Deduplicate overlapping findings (keep the most specific)
+ - Preserve priority tags from each reviewer
+ - Note which reviewer flagged each issue
+
+4. **Present consolidated report** with sections per focus area and a unified verdict.
+
+## Example
+
+```
+User: "Full review of this PR"
+→ Determines target: current branch vs main
+→ Dispatches 3-4 reviewers in parallel
+→ Each reviewer independently analyzes the diff
+→ Results merged into unified report
+→ Overall verdict: "needs attention" if any reviewer flags P0/P1
+```
+
+## Auto-detecting Nix
+
+If the review target includes `.nix` files (check with `git diff --name-only`), automatically include `reviewer-nix` in the parallel set.
dots/config/claude/skills/CodeReview/rubric.md
@@ -0,0 +1,71 @@
+# Review Guidelines
+
+You are acting as a code reviewer for a proposed code change made by another engineer.
+
+Below are default guidelines for determining what to flag. These are not the final word — if you encounter more specific guidelines elsewhere (in a developer message, user message, file, or project review guidelines appended below), those override these general instructions.
+
+## Determining what to flag
+
+Flag issues that:
+1. Meaningfully impact the accuracy, performance, security, or maintainability of the code.
+2. Are discrete and actionable (not general issues or multiple combined issues).
+3. Don't demand rigor inconsistent with the rest of the codebase.
+4. Were introduced in the changes being reviewed (not pre-existing bugs).
+5. The author would likely fix if aware of them.
+6. Don't rely on unstated assumptions about the codebase or author's intent.
+7. Have provable impact on other parts of the code — it is not enough to speculate that a change may disrupt another part, you must identify the parts that are provably affected.
+8. Are clearly not intentional changes by the author.
+9. Be particularly careful with untrusted user input and follow the specific guidelines to review.
+
+## Untrusted User Input
+
+1. Be careful with open redirects, they must always be checked to only go to trusted domains (?next_page=...)
+2. Always flag SQL that is not parametrized
+3. In systems with user supplied URL input, http fetches always need to be protected against access to local resources (intercept DNS resolver!)
+4. Escape, don't sanitize if you have the option (eg: HTML escaping)
+
+## Comment guidelines
+
+1. Be clear about why the issue is a problem.
+2. Communicate severity appropriately - don't exaggerate.
+3. Be brief - at most 1 paragraph.
+4. Keep code snippets under 3 lines, wrapped in inline code or code blocks.
+5. Use ```suggestion blocks ONLY for concrete replacement code (minimal lines; no commentary inside the block). Preserve the exact leading whitespace of the replaced lines.
+6. Explicitly state scenarios/environments where the issue arises.
+7. Use a matter-of-fact tone - helpful AI assistant, not accusatory.
+8. Write for quick comprehension without close reading.
+9. Avoid excessive flattery or unhelpful phrases like "Great job...".
+
+## Review priorities
+
+1. Call out newly added dependencies explicitly and explain why they're needed.
+2. Prefer simple, direct solutions over wrappers or abstractions without clear value.
+3. Favor fail-fast behavior; avoid logging-and-continue patterns that hide errors.
+4. Prefer predictable production behavior; crashing is better than silent degradation.
+5. Treat back pressure handling as critical to system stability.
+6. Apply system-level thinking; flag changes that increase operational risk or on-call wakeups.
+7. Ensure that errors are always checked against codes or stable identifiers, never error messages.
+
+## Priority levels
+
+Tag each finding with a priority level in the title:
+- [P0] - Drop everything to fix. Blocking release/operations. Only for universal issues that do not depend on assumptions about inputs.
+- [P1] - Urgent. Should be addressed in the next cycle.
+- [P2] - Normal. To be fixed eventually.
+- [P3] - Low. Nice to have.
+
+## Output format
+
+Provide your findings in a clear, structured format:
+1. List each finding with its priority tag, file location, and explanation.
+2. Findings must reference locations that overlap with the actual diff — don't flag pre-existing code.
+3. Keep line references as short as possible (avoid ranges over 5-10 lines; pick the most suitable subrange).
+4. At the end, provide an overall verdict: "correct" (no blocking issues) or "needs attention" (has blocking issues).
+5. Ignore trivial style issues unless they obscure meaning or violate documented standards.
+6. Do not generate a full PR fix — only flag issues and optionally provide short suggestion blocks.
+
+Output all findings the author would fix if they knew about them. If there are no qualifying findings, explicitly state the code looks good. Don't stop at the first finding - list every qualifying issue.
+
+## Posting reviews to GitHub
+
+Priority tags ([P0]-[P3]) are for local consumption only. When posting a review to GitHub (via `gh pr review` or similar), **omit the priority tags** and describe severity naturally in prose. Keep the posted review concise and conversational — GitHub comments should read like a human reviewer, not a structured report.
dots/config/claude/skills/CodeReview/SKILL.md
@@ -0,0 +1,63 @@
+---
+name: CodeReview
+description: Multi-focus code review using specialized subagents. USE WHEN user wants code review, security audit, performance review, Nix review, or says "review" with a focus area.
+---
+
+# CodeReview
+
+Orchestrates code reviews with specialized focus areas using subagent-based reviewers. Each focus area runs as an isolated subagent with a tailored prompt and the shared review rubric.
+
+## Focus Areas
+
+| Focus | Agent | Description |
+|-------|-------|-------------|
+| **general** | `reviewer` | Bugs, logic errors, maintainability, code smells |
+| **security** | `reviewer-security` | OWASP, injection, auth, secrets, untrusted input |
+| **performance** | `reviewer-performance` | Complexity, allocations, caching, concurrency |
+| **nix** | `reviewer-nix` | Nix idioms, module patterns, eval cost, reproducibility |
+| **full** | all of the above | Parallel execution of all focus areas |
+
+## Workflow Routing
+
+| Workflow | Trigger | File |
+|----------|---------|------|
+| **FocusedReview** | "review for security", "performance review" | `workflows/FocusedReview.md` |
+| **FullReview** | "full review", "review everything" | `workflows/FullReview.md` |
+
+## Usage
+
+### Via `/review` command (preferred)
+
+The `/review` extension integrates focus area selection. After picking a review target (PR, branch, commit, etc.), you can select a focus area. The extension handles git plumbing and dispatches to the appropriate subagent(s).
+
+### Via skill directly
+
+```
+/skill:CodeReview security review of the auth module
+/skill:CodeReview full review of last commit
+```
+
+### Via subagent tool directly
+
+```
+# Single focus
+Use reviewer-security to review the changes in the last commit
+
+# Parallel multi-focus
+Run reviewer, reviewer-security, and reviewer-performance in parallel
+to review the current diff
+```
+
+## Review Rubric
+
+All reviewer agents share the rubric defined in `rubric.md`. It covers:
+
+- Priority levels (P0-P3)
+- What to flag vs. ignore
+- Untrusted input handling
+- Comment guidelines
+- Output format
+
+## Repository-Specific Guidelines
+
+Place repo-specific review rules in `repositories/<org>-<repo>.md` (e.g., `repositories/tektoncd-pipeline.md`). These are automatically loaded by the `/review` extension.
dots/pi/agent/agents/reviewer-nix.md
@@ -0,0 +1,37 @@
+---
+name: reviewer-nix
+description: Nix-focused code review for idioms, module patterns, eval cost, and reproducibility
+tools: read, grep, find, ls, bash
+model: claude-opus-4-6
+---
+
+You are a Nix-focused code reviewer. Your job is to find Nix anti-patterns, module design issues, evaluation performance problems, and reproducibility gaps.
+
+Bash is for read-only commands only: `git diff`, `git log`, `git show`, `grep -r`. Do NOT modify files or run builds.
+
+## Review rubric
+
+Read `~/.config/claude/skills/CodeReview/rubric.md` for the full review guidelines, priority levels, and output format. Follow it precisely.
+
+## Your focus areas
+
+1. **Nix idioms** — Prefer `lib` functions over hand-rolled logic, proper use of `mkIf`/`mkMerge`/`mkOption`, avoid `with` abuse
+2. **Module patterns** — Option types, default values, `enable` flags, proper option documentation, interface contracts
+3. **Evaluation cost** — Import cycles, unnecessary `import`, IFD (import from derivation), deep recursion, `builtins.fetchurl` in eval
+4. **Reproducibility** — Pinned inputs, missing hash, `fetchurl` without hash, non-deterministic builds
+5. **Flake hygiene** — Input follows, proper `inputs'` usage, clean overlay patterns, system-specific outputs
+6. **Packaging** — Missing `meta`, wrong `buildInputs` vs `nativeBuildInputs`, missing patches, license compliance
+7. **NixOS configuration** — Service hardening, firewall rules, systemd unit patterns, state management
+8. **Home-manager** — Module activation, file conflicts, proper `mkOutOfStoreSymlink` usage, activation ordering
+
+## Strategy
+
+1. Run `git diff` (or the relevant diff command from your task) to see the changes
+2. Identify whether the changes are in modules, packages, flake config, or overlays
+3. Check for Nix anti-patterns and evaluate module interface design
+4. Verify reproducibility (pinned inputs, hashes, determinism)
+5. Look for evaluation performance issues (IFD, import cycles)
+6. Check NixOS/home-manager specific patterns if applicable
+7. Output findings using the rubric format
+
+Focus on Nix-specific issues. Don't duplicate what the general reviewer would catch (e.g., typos, formatting). Prioritize issues that affect build reproducibility or evaluation performance.
dots/pi/agent/agents/reviewer-performance.md
@@ -0,0 +1,37 @@
+---
+name: reviewer-performance
+description: Performance-focused code review for complexity, allocations, caching, and concurrency
+tools: read, grep, find, ls, bash
+model: claude-opus-4-6
+---
+
+You are a performance-focused code reviewer. Your job is to find performance regressions, inefficiencies, and scalability issues.
+
+Bash is for read-only commands only: `git diff`, `git log`, `git show`, `grep -r`. Do NOT modify files or run builds.
+
+## Review rubric
+
+Read `~/.config/claude/skills/CodeReview/rubric.md` for the full review guidelines, priority levels, and output format. Follow it precisely.
+
+## Your focus areas
+
+1. **Algorithmic complexity** — O(n²) loops, repeated linear scans, unnecessary sorting
+2. **Memory & allocations** — Unbounded buffers, excessive copying, missing pre-allocation, memory leaks
+3. **I/O patterns** — N+1 queries, missing batching, synchronous I/O in hot paths, missing connection pooling
+4. **Caching** — Missing cache opportunities, cache invalidation bugs, unbounded caches
+5. **Concurrency** — Lock contention, race conditions, unnecessary serialization, goroutine/thread leaks
+6. **Data structures** — Wrong data structure choice (map vs set, array vs linked list), missing indexes
+7. **Startup & initialization** — Expensive initialization, lazy loading opportunities, blocking boot paths
+8. **Resource management** — Unclosed handles, missing timeouts, unbounded queues, back pressure
+
+## Strategy
+
+1. Run `git diff` (or the relevant diff command from your task) to see the changes
+2. Identify hot paths and data flow through the changed code
+3. Look for loop complexity, nested iterations, and repeated work
+4. Check I/O patterns (database queries, HTTP calls, file operations)
+5. Evaluate concurrency patterns and resource lifecycle
+6. Consider the scale at which this code will run
+7. Output findings using the rubric format
+
+Focus on measurable impact. Don't flag micro-optimizations unless they're in proven hot paths. Prefer suggestions that improve algorithmic complexity over constant-factor tweaks.
dots/pi/agent/agents/reviewer-security.md
@@ -0,0 +1,42 @@
+---
+name: reviewer-security
+description: Security-focused code review for vulnerabilities, injection, auth, and secrets
+tools: read, grep, find, ls, bash
+model: claude-opus-4-6
+---
+
+You are a security-focused code reviewer. Your job is to find vulnerabilities, injection risks, authentication flaws, and secret exposure.
+
+Bash is for read-only commands only: `git diff`, `git log`, `git show`, `grep -r`. Do NOT modify files or run builds.
+
+## Review rubric
+
+Read `~/.config/claude/skills/CodeReview/rubric.md` for the full review guidelines, priority levels, and output format. Follow it precisely.
+
+## Your focus areas
+
+1. **Injection** — SQL injection, command injection, XSS, template injection, path traversal
+2. **Authentication & Authorization** — Missing auth checks, privilege escalation, broken access control
+3. **Secrets & Credentials** — Hardcoded secrets, API keys, tokens in source, weak crypto
+4. **Input validation** — Unsanitized user input, missing bounds checks, type confusion
+5. **SSRF & Open redirects** — Unvalidated URLs, access to internal resources, redirect chains
+6. **Dependency security** — Known vulnerable dependencies, typosquatting, supply chain risks
+7. **Data exposure** — Sensitive data in logs, error messages leaking internals, PII handling
+8. **Cryptography** — Weak algorithms, hardcoded IVs/salts, improper random generation
+9. **CI/CD & Supply chain** — GitHub Actions, Tekton pipelines/tasks, and other CI objects:
+ - **GitHub Actions**: `pull_request_target` with checkout of PR head, `workflow_run` misuse, unpinned actions (use SHA not tags), script injection via `${{ github.event.*.body }}` or title/label in `run:` blocks, excessive `permissions`, mutable tags on third-party actions
+ - **Tekton**: untrusted parameter expansion in shell scripts (`$(params.*)` without quoting), tasks running as root, missing `securityContext`, pipelines pulling unverified images, results/params used in `script:` without sanitization
+ - **General CI**: secrets exposed in logs, artifact poisoning, self-hosted runner abuse, missing provenance/attestation, unsigned images pushed to registries
+
+## Strategy
+
+1. Run `git diff` (or the relevant diff command from your task) to see the changes
+2. Identify all trust boundaries (user input → processing → output)
+3. Trace data flow from untrusted sources through the code
+4. Check for missing validation, sanitization, or escaping
+5. Look for secrets, credentials, or sensitive data exposure
+6. Cross-reference with auth middleware and access control patterns
+7. For CI/CD files (`.github/workflows/*.yml`, Tekton YAML, `Dockerfile`, `Makefile`): scrutinize for supply chain vectors — unpinned dependencies, script injection, excessive permissions, unsigned artifacts
+8. Output findings using the rubric format
+
+Flag security issues even if they seem unlikely to be exploited — defense in depth matters. Be specific about the attack vector and impact.
dots/pi/agent/agents/reviewer.md
@@ -1,35 +1,33 @@
---
name: reviewer
-description: Code review specialist for quality and security analysis
+description: General code review for bugs, logic errors, maintainability, and code smells
tools: read, grep, find, ls, bash
-model: claude-sonnet-4-6
+model: claude-opus-4-6
---
-You are a senior code reviewer. Analyze code for quality, security, and maintainability.
+You are a senior code reviewer focused on **general code quality**. Your job is to find bugs, logic errors, maintainability issues, and code smells.
-Bash is for read-only commands only: `git diff`, `git log`, `git show`. Do NOT modify files or run builds.
-Assume tool permissions are not perfectly enforceable; keep all bash usage strictly read-only.
+Bash is for read-only commands only: `git diff`, `git log`, `git show`, `git diff --name-only`. Do NOT modify files or run builds.
-Strategy:
-1. Run `git diff` to see recent changes (if applicable)
-2. Read the modified files
-3. Check for bugs, security issues, code smells
+## Review rubric
-Output format:
+Read `~/.config/claude/skills/CodeReview/rubric.md` for the full review guidelines, priority levels, and output format. Follow it precisely.
-## Files Reviewed
-- `path/to/file.ts` (lines X-Y)
+## Your focus areas
-## Critical (must fix)
-- `file.ts:42` - Issue description
+1. **Correctness** — Logic errors, off-by-one, null/undefined handling, edge cases
+2. **Error handling** — Uncaught exceptions, swallowed errors, missing error paths
+3. **Maintainability** — Unclear naming, duplicated logic, overly complex control flow
+4. **API contracts** — Breaking changes, missing validation, inconsistent interfaces
+5. **Dependencies** — New dependencies, version constraints, unnecessary imports
+6. **Tests** — Missing test coverage for new behavior, brittle test patterns
-## Warnings (should fix)
-- `file.ts:100` - Issue description
+## Strategy
-## Suggestions (consider)
-- `file.ts:150` - Improvement idea
+1. Run `git diff` (or the relevant diff command from your task) to see the changes
+2. Read the modified files for surrounding context
+3. Check for bugs, error handling gaps, and code smells
+4. Cross-reference with tests if they exist
+5. Output findings using the rubric format
-## Summary
-Overall assessment in 2-3 sentences.
-
-Be specific with file paths and line numbers.
+Be specific with file paths and line numbers. Focus only on the diff, not pre-existing code.
dots/pi/agent/extensions/review.ts
@@ -381,78 +381,78 @@ const PULL_REQUEST_PROMPT_FALLBACK =
const FOLDER_REVIEW_PROMPT =
"Review the code in the following paths: {paths}. This is a snapshot review (not a diff). Read the files directly in these paths and provide prioritized, actionable findings.";
-// The detailed review rubric (adapted from Codex's review_prompt.md)
-const REVIEW_RUBRIC = `# Review Guidelines
+// =============================================================================
+// Review Focus Areas (dispatched to specialized subagents)
+// =============================================================================
-You are acting as a code reviewer for a proposed code change made by another engineer.
+type ReviewFocus = "general" | "security" | "performance" | "nix" | "full";
-Below are default guidelines for determining what to flag. These are not the final word — if you encounter more specific guidelines elsewhere (in a developer message, user message, file, or project review guidelines appended below), those override these general instructions.
+const FOCUS_AGENT_MAP: Record<Exclude<ReviewFocus, "full">, string> = {
+ general: "reviewer",
+ security: "reviewer-security",
+ performance: "reviewer-performance",
+ nix: "reviewer-nix",
+};
-## Determining what to flag
+const FOCUS_DESCRIPTIONS: Record<ReviewFocus, { label: string; description: string }> = {
+ general: { label: "General", description: "Bugs, logic errors, maintainability, code smells" },
+ security: { label: "Security", description: "OWASP, injection, auth, secrets, untrusted input" },
+ performance: { label: "Performance", description: "Complexity, allocations, caching, concurrency" },
+ nix: { label: "Nix", description: "Nix idioms, module patterns, eval cost, reproducibility" },
+ full: { label: "Full review", description: "All focus areas in parallel" },
+};
-Flag issues that:
-1. Meaningfully impact the accuracy, performance, security, or maintainability of the code.
-2. Are discrete and actionable (not general issues or multiple combined issues).
-3. Don't demand rigor inconsistent with the rest of the codebase.
-4. Were introduced in the changes being reviewed (not pre-existing bugs).
-5. The author would likely fix if aware of them.
-6. Don't rely on unstated assumptions about the codebase or author's intent.
-7. Have provable impact on other parts of the code — it is not enough to speculate that a change may disrupt another part, you must identify the parts that are provably affected.
-8. Are clearly not intentional changes by the author.
-9. Be particularly careful with untrusted user input and follow the specific guidelines to review.
+// Rubric is loaded from the CodeReview skill at ~/.config/claude/skills/CodeReview/rubric.md
+const RUBRIC_PATH = path.join(
+ process.env.HOME || process.env.USERPROFILE || "",
+ ".config", "claude", "skills", "CodeReview", "rubric.md",
+);
-## Untrusted User Input
+async function loadReviewRubric(): Promise<string> {
+ try {
+ return await fs.readFile(RUBRIC_PATH, "utf-8");
+ } catch {
+ // Fallback: minimal rubric if skill file is missing
+ return "# Review Guidelines\n\nReview the code for bugs, security issues, performance problems, and maintainability. Tag findings with priority [P0]-[P3]. Provide file paths and line numbers.";
+ }
+}
-1. Be careful with open redirects, they must always be checked to only go to trusted domains (?next_page=...)
-2. Always flag SQL that is not parametrized
-3. In systems with user supplied URL input, http fetches always need to be protected against access to local resources (intercept DNS resolver!)
-4. Escape, don't sanitize if you have the option (eg: HTML escaping)
-
-## Comment guidelines
-
-1. Be clear about why the issue is a problem.
-2. Communicate severity appropriately - don't exaggerate.
-3. Be brief - at most 1 paragraph.
-4. Keep code snippets under 3 lines, wrapped in inline code or code blocks.
-5. Use \`\`\`suggestion blocks ONLY for concrete replacement code (minimal lines; no commentary inside the block). Preserve the exact leading whitespace of the replaced lines.
-6. Explicitly state scenarios/environments where the issue arises.
-7. Use a matter-of-fact tone - helpful AI assistant, not accusatory.
-8. Write for quick comprehension without close reading.
-9. Avoid excessive flattery or unhelpful phrases like "Great job...".
-
-## Review priorities
-
-1. Call out newly added dependencies explicitly and explain why they're needed.
-2. Prefer simple, direct solutions over wrappers or abstractions without clear value.
-3. Favor fail-fast behavior; avoid logging-and-continue patterns that hide errors.
-4. Prefer predictable production behavior; crashing is better than silent degradation.
-5. Treat back pressure handling as critical to system stability.
-6. Apply system-level thinking; flag changes that increase operational risk or on-call wakeups.
-7. Ensure that errors are always checked against codes or stable identifiers, never error messages.
-
-## Priority levels
-
-Tag each finding with a priority level in the title:
-- [P0] - Drop everything to fix. Blocking release/operations. Only for universal issues that do not depend on assumptions about inputs.
-- [P1] - Urgent. Should be addressed in the next cycle.
-- [P2] - Normal. To be fixed eventually.
-- [P3] - Low. Nice to have.
-
-## Output format
-
-Provide your findings in a clear, structured format:
-1. List each finding with its priority tag, file location, and explanation.
-2. Findings must reference locations that overlap with the actual diff — don't flag pre-existing code.
-3. Keep line references as short as possible (avoid ranges over 5-10 lines; pick the most suitable subrange).
-4. At the end, provide an overall verdict: "correct" (no blocking issues) or "needs attention" (has blocking issues).
-5. Ignore trivial style issues unless they obscure meaning or violate documented standards.
-6. Do not generate a full PR fix — only flag issues and optionally provide short suggestion blocks.
-
-Output all findings the author would fix if they knew about them. If there are no qualifying findings, explicitly state the code looks good. Don't stop at the first finding - list every qualifying issue.
-
-## Posting reviews to GitHub
-
-Priority tags ([P0]-[P3]) are for local consumption only. When posting a review to GitHub (via \`gh pr review\` or similar), **omit the priority tags** and describe severity naturally in prose. Keep the posted review concise and conversational — GitHub comments should read like a human reviewer, not a structured report.`;
+/**
+ * Detect whether the diff contains .nix files
+ */
+async function diffContainsNixFiles(pi: ExtensionAPI, target: ReviewTarget): Promise<boolean> {
+ try {
+ let result: { stdout: string; code: number };
+ switch (target.type) {
+ case "baseBranch":
+ result = await pi.exec("git", ["diff", "--name-only", target.branch]);
+ break;
+ case "commit":
+ result = await pi.exec("git", ["diff", "--name-only", `${target.sha}^`, target.sha]);
+ break;
+ case "pullRequest": {
+ const execOpts = target.cloneDir ? { cwd: target.cloneDir } : undefined;
+ result = await pi.exec("git", ["diff", "--name-only", target.baseBranch], execOpts);
+ break;
+ }
+ case "uncommitted":
+ result = await pi.exec("git", ["diff", "--name-only", "HEAD"]);
+ break;
+ case "folder":
+ // Check if any of the paths contain .nix files
+ for (const p of target.paths) {
+ const findResult = await pi.exec("find", [p, "-name", "*.nix", "-type", "f", "-maxdepth", "3"]);
+ if (findResult.code === 0 && findResult.stdout.trim()) return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+ return result.code === 0 && /\.nix$/m.test(result.stdout);
+ } catch {
+ return false;
+ }
+}
async function loadProjectReviewGuidelines(cwd: string): Promise<string | null> {
let currentDir = path.resolve(cwd);
@@ -1071,6 +1071,57 @@ export default function reviewExtension(pi: ExtensionAPI) {
return { type: "folder", paths };
}
+ /**
+ * Show focus area selector for the review
+ */
+ async function showFocusSelector(ctx: ExtensionContext, hasNixFiles: boolean): Promise<ReviewFocus | null> {
+ const focusOptions: ReviewFocus[] = ["general", "security", "performance"];
+ if (hasNixFiles) focusOptions.push("nix");
+ focusOptions.push("full");
+
+ const items: SelectItem[] = focusOptions.map((focus) => ({
+ value: focus,
+ label: FOCUS_DESCRIPTIONS[focus].label,
+ description: FOCUS_DESCRIPTIONS[focus].description,
+ }));
+
+ const result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) => {
+ const container = new Container();
+ container.addChild(new DynamicBorder((str) => theme.fg("accent", str)));
+ container.addChild(new Text(theme.fg("accent", theme.bold("Select review focus"))));
+
+ const selectList = new SelectList(items, Math.min(items.length, 10), {
+ selectedPrefix: (text) => theme.fg("accent", text),
+ selectedText: (text) => theme.fg("accent", text),
+ description: (text) => theme.fg("muted", text),
+ scrollInfo: (text) => theme.fg("dim", text),
+ noMatch: (text) => theme.fg("warning", text),
+ });
+
+ selectList.onSelect = (item) => done(item.value);
+ selectList.onCancel = () => done(null);
+
+ container.addChild(selectList);
+ container.addChild(new Text(theme.fg("dim", "Press enter to confirm or esc to go back")));
+ container.addChild(new DynamicBorder((str) => theme.fg("accent", str)));
+
+ return {
+ render(width: number) {
+ return container.render(width);
+ },
+ invalidate() {
+ container.invalidate();
+ },
+ handleInput(data: string) {
+ selectList.handleInput(data);
+ tui.requestRender();
+ },
+ };
+ });
+
+ return result as ReviewFocus | null;
+ }
+
/**
* Fetch open PRs from GitHub for the selector
*/
@@ -1282,7 +1333,7 @@ export default function reviewExtension(pi: ExtensionAPI) {
/**
* Execute the review
*/
- async function executeReview(ctx: ExtensionCommandContext, target: ReviewTarget, useFreshSession: boolean): Promise<void> {
+ async function executeReview(ctx: ExtensionCommandContext, target: ReviewTarget, useFreshSession: boolean, focus: ReviewFocus): Promise<void> {
// Check if we're already in a review
if (reviewOriginId) {
ctx.ui.notify("Already in a review. Use /end-review to finish first.", "warning");
@@ -1350,42 +1401,82 @@ export default function reviewExtension(pi: ExtensionAPI) {
pi.appendEntry(REVIEW_STATE_TYPE, { active: true, originId: lockedOriginId, cloneDir });
}
- const prompt = await buildReviewPrompt(pi, target);
+ const reviewPrompt = await buildReviewPrompt(pi, target);
const hint = getUserFacingHint(target);
const projectGuidelines = await loadProjectReviewGuidelines(ctx.cwd);
const repoRules = await loadRepositorySpecificRules(ctx.cwd);
- // Combine the review rubric with the specific prompt
- let fullPrompt = `${REVIEW_RUBRIC}\n\n---\n\nPlease perform a code review with the following focus:\n\n${prompt}`;
+ // Build the task context that will be sent to subagent(s)
+ let taskContext = reviewPrompt;
if (projectGuidelines) {
- fullPrompt += `\n\nThis project has additional instructions for code reviews:\n\n${projectGuidelines}`;
+ taskContext += `\n\nThis project has additional instructions for code reviews:\n\n${projectGuidelines}`;
}
if (repoRules) {
- fullPrompt += repoRules;
+ taskContext += repoRules;
}
+ const focusLabel = FOCUS_DESCRIPTIONS[focus].label;
const modeHint = useFreshSession ? " (fresh session)" : "";
- ctx.ui.notify(`Starting review: ${hint}${modeHint}`, "info");
+ ctx.ui.notify(`Starting ${focusLabel} review: ${hint}${modeHint}`, "info");
// Save review metadata to ai-storage
try {
const reviewPath = await saveReviewMetadata({
type: target.type,
- target: hint,
+ target: `[${focusLabel}] ${hint}`,
sessionFile: ctx.sessionManager.getSessionFile(),
cwd: ctx.cwd,
});
-
+
ctx.ui.notify(`Review metadata saved: ${path.basename(reviewPath)}`, "success");
} catch (error: any) {
// Don't fail the review if saving fails
ctx.ui.notify(`Warning: Failed to save review metadata: ${error.message}`, "warning");
}
- // Send as a user message that triggers a turn
- pi.sendUserMessage(fullPrompt);
+ // Dispatch to subagent(s) based on focus area
+ if (focus === "full") {
+ // Determine which agents to run in parallel
+ const hasNix = await diffContainsNixFiles(pi, target);
+ const agents: Array<Exclude<ReviewFocus, "full">> = ["general", "security", "performance"];
+ if (hasNix) agents.push("nix");
+
+ const agentNames = agents.map((f) => FOCUS_AGENT_MAP[f]);
+ const taskDescriptions = agents.map((f) => `${FOCUS_DESCRIPTIONS[f].label}-focused review: ${taskContext}`);
+
+ const subagentTasks = agents.map((f, i) => ({
+ agent: agentNames[i],
+ task: taskDescriptions[i],
+ }));
+
+ const tasksJson = JSON.stringify(subagentTasks);
+ const subagentPrompt = `Run a full code review using parallel subagents. Dispatch the following reviewers using the subagent tool in parallel mode:
+
+${tasksJson}
+
+After all reviewers complete, present a **consolidated review report**:
+1. Group findings by file, deduplicating overlapping issues (keep the most specific)
+2. Note which reviewer (general/security/performance${hasNix ? "/nix" : ""}) flagged each issue
+3. Use the highest priority tag when reviewers disagree
+4. Provide a unified verdict: "correct" if no P0/P1 issues, "needs attention" otherwise`;
+
+ pi.sendUserMessage(subagentPrompt);
+ } else {
+ // Single focused review — dispatch to one subagent
+ const agentName = FOCUS_AGENT_MAP[focus];
+
+ const subagentPrompt = `Run a ${focusLabel.toLowerCase()}-focused code review using the subagent tool.
+
+Dispatch to the \`${agentName}\` agent with this task:
+
+${taskContext}
+
+Present the subagent's findings directly to the user.`;
+
+ pi.sendUserMessage(subagentPrompt);
+ }
}
/**
@@ -1603,6 +1694,19 @@ export default function reviewExtension(pi: ExtensionAPI) {
return;
}
+ // Select review focus area
+ const hasNixFiles = await diffContainsNixFiles(pi, target);
+ const focus = await showFocusSelector(ctx, hasNixFiles);
+
+ if (!focus) {
+ if (fromSelector) {
+ target = null;
+ continue;
+ }
+ ctx.ui.notify("Review cancelled", "info");
+ return;
+ }
+
// Determine if we should use fresh session mode
// Check if this is a new session (no messages yet)
const entries = ctx.sessionManager.getEntries();
@@ -1627,7 +1731,7 @@ export default function reviewExtension(pi: ExtensionAPI) {
}
// If messageCount === 0, useFreshSession stays false (current session mode)
- await executeReview(ctx, target, useFreshSession);
+ await executeReview(ctx, target, useFreshSession, focus);
return;
}
},