Code Review
You are conducting a code review using Draft's Context-Driven Development methodology.
Red Flags - STOP if you're:
- Reviewing without reading the track's spec.md and plan.md first
- Reporting findings without reading the actual code
- Skipping spec compliance stage and jumping to code quality
- Making up file locations or line numbers
- Claiming "no issues" without systematic analysis evidence
Read before you review. Evidence over opinion.
Overview
This command orchestrates code review workflows at two levels:
- Track-level: Review against spec.md and plan.md (three-stage: automated validation, spec compliance, code quality)
- Project-level: Review arbitrary changes (automated validation + code quality)
Optionally integrates /draft:bughunt for finding logic errors and writing regression tests.
Note: Automated static validation (OWASP secrets, dead code, dependency cycles, N+1 patterns) is natively built into Phase 1 of this review.
Step 1: Parse Arguments
Extract and validate command arguments from user input.
Supported Arguments
Scope specifiers (mutually exclusive):
track <id|name>- Review specific track (exact ID or fuzzy name match)project- Review uncommitted changes (git diff HEAD)files <pattern>- Review specific file pattern (e.g.,src/**/*.ts)commits <range>- Review commit range (e.g.,main...HEAD,abc123..def456)
Quality integration modifiers:
with-bughunt- Include/draft:bughuntresultsfull- Include bughunt results
Validation Rules
- Scope requirement: At least one scope specifier OR no arguments (auto-detect track)
- Mutual exclusivity: Only one of
track,project,files,commits - Modifier normalization: If
fullis present, enablewith-bughunt, discarding redundant individual modifiers. No error — silently normalize.
Default Behavior
If no arguments provided:
- Auto-detect active
[~]In Progress track fromdraft/tracks.md - If no
[~]track, find first[ ]Pending track - Display:
Auto-detected track: <id> - <name> [<status>]and proceed - If no tracks available, error: "No tracks found. Run
/draft:new-trackto create one."
Step 2: Determine Review Scope
Based on parsed arguments, determine review scope and load appropriate context.
Track-Level Review
Trigger: track <id|name> argument OR auto-detected track
2.1: Resolve Track
Check if argument is exact directory match:
ls draft/tracks/<arg>/ 2>/dev/nullIf exists → use this track
Parse tracks.md for fuzzy matching:
- Read
draft/tracks.md - Split by
---separators - For each section, extract:
- Track ID (from path:
./tracks/<id>/) - Track name (from heading:
### <id> - <name>)
- Track ID (from path:
- Match input against:
- Exact ID (case-insensitive)
- Partial ID (substring)
- Partial name (substring, case-insensitive)
- Read
Handle matches:
- Exact match: Use immediately
- Multiple matches: Display numbered list with format:
Validate selection is within 1-N range. Re-prompt on invalid input.Multiple tracks match '<input>': 1. <id> - <name> [<status>] 2. <id> - <name> [<status>] Select track (1-N): - No matches: Error with suggestions (closest 3 by edit distance)
2.2: Load Track Context
Once track is resolved:
Verify track directory exists:
ls draft/tracks/<id>/ 2>/dev/nullRead spec.md:
- Load
draft/tracks/<id>/spec.md - Extract: Summary, Requirements, Acceptance Criteria, Non-Goals
- Store for Stage 1 compliance checks
- Load
Read plan.md:
- Load
draft/tracks/<id>/plan.md - Extract commit SHAs from completed
[x]task lines only. Match pattern: 7+ character hex strings in parentheses, regex\(([a-f0-9]{7,})\). Example:- [x] **Task 1.1:** Description (7a7dc85). Collect SHAs in order of appearance; deduplicate keeping first occurrence. - Determine commit range:
- First commit parent: run
git rev-parse <first_SHA>^ 2>/dev/null - If the parent exists: use
<first_SHA>^..<last_SHA>as the range - If the parent does NOT exist (first commit in the repo —
git rev-parsefails): use the empty tree SHA4b825dc642cb6eb9a060e54bf8d69288fbee4904as the range start, i.e.,4b825dc642cb6eb9a060e54bf8d69288fbee4904..<last_SHA>. Alternatively, for single-commit ranges, usegit diff-tree --root -p <first_SHA>to obtain the diff. - Last commit:
<last_SHA>
- First commit parent: run
- Load
Check for incomplete work:
- Parse plan.md task statuses
- Count
[ ],[~],[x],[!]tasks - If
[ ]or[~]tasks exist: Display warning and proceed:Warning: Track has N incomplete tasks (M in-progress, K pending). Reviewing completed work only.
Handle missing files:
- Missing spec.md: Error "spec.md not found for track "
- Missing plan.md: Warn "plan.md not found, skipping commit extraction"
- No commits found: Warn "No commits found in plan.md, review may be incomplete"
Project-Level Review
Trigger: project, files <pattern>, or commits <range> argument
2.3: Project Scope Detection
projectargument:- Scope: Uncommitted changes
- Command:
git diff HEAD
files <pattern>argument:- Scope: Specific files matching glob pattern
- Command:
git diff HEAD -- <pattern> - Validate pattern matches files:
If empty: Error "No files match pattern ''"git ls-files <pattern> | head -1
commits <range>argument:- Scope: Commit range
- Validate range exists:
If fails: Error "Invalid commit range ''"git rev-parse <range> 2>/dev/null - Command:
git diff <range>
2.4: Load Project Context
For project-level reviews (no track context):
Load Draft context (if available): Follow the base procedure in
core/shared/draft-context-loading.md. Honor Accepted Patterns and enforce Guardrails as defined there.Note limitations:
- No spec.md → Skip Stage 1 (spec compliance)
- Run Stage 2 (code quality) only
Step 3: Generate Git Diff (Smart Chunking)
Generate diff output using smart chunking to avoid context overflow.
3.1: Determine Diff Size
Run shortstat to check diff size:
git diff --shortstat <range>
Parse output robustly — handle both singular (1 file changed) and plural (N files changed) forms. Extract numeric values for files, insertions, and deletions. Use total lines changed (insertions + deletions) for the chunking threshold.
3.2: Smart Chunking Strategy
Small/Medium changes (<300 lines changed):
- Run full diff in one pass:
git diff <range> - Store complete diff for analysis
Large changes (≥300 lines changed):
- Announce: "Large changeset detected (N files). Using file-by-file review mode."
- Get file list:
git diff --name-only <range> - For each file:
- Display progress:
[N/M] Reviewing <filename> - Run:
git diff <range> -- <file> - Analyze immediately (don't store all)
- Track findings in temporary structure
- Display progress:
- Aggregate findings after all files processed
3.3: Filter Files (Optional)
Skip non-source files to focus review:
- Ignore lock/minified:
*.lock,package-lock.json,yarn.lock,*.min.js,*.min.css,*.map - Ignore build artifacts:
dist/,build/,target/,out/,__pycache__/,*.pyc - Ignore vendored:
node_modules/,vendor/,.git/ - Ignore binaries: images, fonts, compiled assets
- Ignore generated files: check first 10 lines for
@generatedmarker (case-insensitive, any comment syntax:/* @generated */,// @generated,# @generated)
Step 4: Run Reviewer Agent
Apply a three-stage review process (merging static validation and semantic review).
Stage 1: Automated Validation
Goal: Detect structural, security, and performance issues using fast, objective searches across the diff.
For the files changed in the diff, perform static checks using grep or similar tools:
Architecture Conformance: Search for pattern violations documented in
draft/.ai-context.md. (e.g.import * from 'database'in a React component).Dead Code: Check for newly exported functions/classes in the diff that have 0 references across the codebase.
Dependency Cycles: Trace the import chains for new imports to ensure no circular dependencies (e.g., A → B → C → A) are introduced.
Security Scan (OWASP): Scan the diff for:
- Hardcoded secrets and API keys
- SQL injection risks (string concatenation in queries)
- XSS vulnerabilities (
innerHTMLor raw DOM insertion)
Performance Anti-patterns: Scan the diff for:
- N+1 database queries (loops containing queries)
- Blocking synchronous I/O within async functions
- Unbounded queries lacking pagination
Context-Specific Checks: Identify the primary domain of changed files and apply domain-specific checks:
- Crypto/Security changes (files matching
auth,crypto,security,token,password,hash,encrypt):- Timing-safe comparisons used (no
==for secret comparison) - Constant-time operations for sensitive data
- Secure random generation (no
Math.random()for security) - Key length meets minimum requirements
- Timing-safe comparisons used (no
- Database/Migration changes (files matching
migration,schema,model,entity,repository):- Backward compatibility preserved (no destructive column drops without migration path)
- Index coverage for new queries
- Constraint preservation (foreign keys, unique constraints)
- Zero-downtime migration safety (no table locks on large tables)
- API Endpoint changes (files matching
controller,handler,route,endpoint,resolver):- Backward compatibility of public signatures (no breaking param changes)
- Input validation present for all new parameters
- Rate limiting configured for new endpoints
- Authentication/authorization checks in place
- Configuration changes (files matching
config,env,settings):- No secrets exposed in plaintext
- Validation at startup for required config values
- Fallback defaults provided where appropriate
- UI/Frontend changes (files matching
component,view,page,template):- No XSS vectors (
innerHTML,dangerouslySetInnerHTML,v-html) - Accessibility present (ARIA attributes, keyboard navigation)
- Performance impact considered (bundle size, render cycles)
- No XSS vectors (
- Crypto/Security changes (files matching
Breaking Change Detection: Check for public API changes in the diff:
- Exported function/method signatures unchanged (no added required params, no changed return types)
- No removed or renamed exported symbols
- Error types and error codes unchanged
- Serialization format preserved (JSON field names, protobuf field numbers)
- Flag as CRITICAL if breaking change found with no deprecation period or version bump
Threat Model (STRIDE): For new endpoints or data mutations, check:
- Spoofing: Can the caller's identity be faked? (authentication check)
- Tampering: Can request data be modified in transit? (integrity check)
- Repudiation: Are actions logged for audit? (logging check)
- Information Disclosure: Does the response leak internal details? (error message check)
- Denial of Service: Can the endpoint be abused? (rate limiting, resource limits)
- Elevation of Privilege: Are authorization checks in place? (RBAC/ABAC check)
Verdict:
- PASS: No critical issues found → Proceed to Stage 2
- FAIL: ANY Critical issue found (e.g., circular dependency, hardcoded secret, raw SQL injection) → List the static analysis failures, generate the review report, and STOP. Do not proceed to Stage 2. This prevents wasting effort on structurally broken code.
SAST Tool Recommendations
After completing Stage 1, recommend appropriate static analysis tools based on the project's tech-stack.md. Check if these tools are already configured in CI; if not, recommend adding them.
| Language | Recommended Tools |
|---|---|
| JavaScript/TypeScript | ESLint with eslint-plugin-security, Semgrep |
| Python | Bandit, Semgrep, pylint |
| Java | Error Prone, SpotBugs, Semgrep |
| Go | gosec, staticcheck |
| Rust | cargo clippy, cargo audit |
| C/C++ | Clang Static Analyzer, cppcheck |
| Multi-language | Semgrep (https://semgrep.dev/), CodeQL (https://codeql.github.com/) |
References: Meta Infer for CI integration patterns, Google Error Prone for compile-time analysis.
Include tool recommendations in the review report under Stage 1 as a "Recommended Tooling" subsection. Only recommend tools relevant to the languages detected in the diff.
Stage 2: Spec Compliance (Track-Level Only)
Skip for project-level reviews (no spec exists)
Load spec.md acceptance criteria and verify implementation:
4.1: Requirements Coverage
For each functional requirement in spec.md:
- Requirement implemented (find evidence in diff)
- Files modified/created match requirement
4.2: Acceptance Criteria
For each criterion in spec.md:
- Criterion met (check against diff)
- Test coverage exists (if TDD enabled)
4.3: Scope Adherence
- No missing features from spec
- No extra unneeded work (scope creep)
Verdict:
- PASS: All requirements implemented AND all acceptance criteria met → Proceed to Stage 3
- PASS WITH NOTES: All requirements met but minor gaps in acceptance criteria verification → Proceed to Stage 3 with notes
- FAIL: ANY requirement missing OR ANY acceptance criterion not met → List gaps, report, and stop (no Stage 3)
Stage 3: Code Quality
Run for both track-level (if Stage 2 passes) and project-level reviews
Analyze semantic code quality across four dimensions:
4.4: Architecture
- Follows project patterns (from tech-stack.md or CLAUDE.md)
- Appropriate separation of concerns
- Critical invariants honored (if
.ai-context.mdexists — check ## Critical Invariants section)
4.5: Error Handling
- Errors handled at appropriate level
- User-facing errors are helpful
- No silent failures
4.6: Testing
- Tests test real logic (not implementation details)
- Edge cases have test coverage
4.7: Maintainability
- Code is readable without excessive comments
- Consistent naming and style
4.8: Diff Complexity Metrics
- No functions exceeding cognitive complexity threshold (>15)
- No files with high churn + high complexity (flag as refactoring candidates)
- No deeply nested control flow (>3 levels of nesting)
For each flagged function, report: file path, function name, estimated complexity, and recommended action (split, extract, simplify).
Adversarial Pass (When Zero Findings)
If Stage 3 produces zero findings across all four dimensions, do NOT accept "clean" without one more look. Ask these 5 questions explicitly:
- Error paths — Is every error/exception handled? Are any failure modes silently swallowed?
- Edge cases — Are there boundary conditions (empty input, max values, concurrent access) not covered by tests?
- Implicit assumptions — Does code assume inputs are always valid, services always up, or state always consistent?
- Future brittleness — Is anything hardcoded that will break on scale or config change?
- Missing coverage — Is there behavior that should be tested but isn't?
- Guardrails — Do any changes violate learned anti-patterns from
guardrails.md? - Invariants — Do any changes violate critical invariants documented in
.ai-context.md?
If still zero after this pass, document it explicitly in the review report:
"Adversarial pass completed. Zero findings confirmed: [one sentence per question explaining why each is clean]"
This prevents lazy LGTM verdicts. It only adds work when a reviewer claims "nothing to find."
Issue Classification
Classify all findings by severity:
| Severity | Definition | Action |
|---|---|---|
| Critical | Blocks release, breaks functionality, security issue | Must fix before proceeding |
| Important | Degrades quality, technical debt | Should fix before phase complete |
| Minor | Style, optimization, nice-to-have | Note for later, don't block |
Scope-specific behavior:
- For track-level reviews: Run all three stages. Stage 2 uses
spec.mdacceptance criteria loaded in Step 2. - For project-level reviews: Skip Stage 2 (no spec). Run Stage 1 and Stage 3 only.
Issue format:
- [ ] [File:line] Description of issue
- **Impact:** [what breaks/degrades]
- **Suggested fix:** [how to address]
Step 5: Run Quality Tools (Optional)
If with-bughunt or full modifier is set, integrate bug hunting.
5.1: Run Bughunt
Track-level:
/draft:bughunt --track <id>
Project-level:
/draft:bughunt
Parse output from draft/tracks/<id>/bughunt-report-latest.md or draft/bughunt-report-latest.md
5.2: Aggregate Findings
Merge findings from:
- Reviewer agent (Stage 1, 2, 3)
- Bughunt results (if run)
Deduplication:
- Two findings are duplicates if they reference the same file and line number
- Severity ordering: Critical > Important > Minor
- On duplicate: keep the finding with highest severity; merge tool attribution as "Found by: reviewer, bughunt"
- If same severity from different tools: merge into single finding, combine descriptions
Step 6: Generate Review Report
Create unified review report in markdown format.
MANDATORY: Include YAML frontmatter with git metadata. Follow the procedure in core/shared/git-report-metadata.md to gather git info, generate frontmatter, and include the report header table. Use generated_by: "draft:review".
Track-Level Report
Path: draft/tracks/<id>/review-report-<timestamp>.md (where <timestamp> is generated via date +%Y-%m-%dT%H%M, e.g., 2026-03-15T1430)
After writing the timestamped report, create a symlink pointing to it:
ln -sf review-report-<timestamp>.md draft/tracks/<id>/review-report-latest.md
[YAML frontmatter — see core/shared/git-report-metadata.md, use track_id: "<id>"]
# Review Report: <Track Title>
[Report header table — see core/shared/git-report-metadata.md]
**Track ID:** <id>
**Reviewer:** [Current model name and context window from runtime]
**Commit Range:** <first_SHA>^..<last_SHA>
**Diff Stats:** N files changed, M insertions(+), K deletions(-)
---
## Stage 1: Automated Validation
**Status:** PASS / FAIL
- **Architecture Conformance:** PASS/FAIL
- **Dead Code:** N found
- **Dependency Cycles:** PASS/FAIL
- **Security Scan:** N issues found
- **Performance:** N anti-patterns detected
[If FAIL: List critical structural issues and stop here]
---
## Stage 2: Spec Compliance
**Status:** PASS / FAIL
### Requirements Coverage
- [x] Requirement 1 - Implemented in <file:line>
- [x] Requirement 2 - Implemented in <file:line>
- [ ] Requirement 3 - **MISSING**
### Acceptance Criteria
- [x] Criterion 1 - Verified in <file:line>
- [x] Criterion 2 - Verified in <file:line>
- [ ] Criterion 3 - **NOT MET**
[If FAIL: List gaps and stop here]
---
## Stage 3: Code Quality
**Status:** PASS / PASS WITH NOTES / FAIL
### Critical Issues
[None / List with file:line]
### Important Issues
[None / List with file:line]
### Minor Notes
[None / List items]
---
[If with-bughunt or full]
## Integrations
### Bug Hunt Results
- **Critical bugs:** N found
- **High severity:** N found
- **Medium severity:** N found
- Full report: `./bughunt-report-latest.md`
---
## Summary
**Total Semantic Issues:** N
- Critical: N
- Important: N
- Minor: N
**Verdict:** PASS / PASS WITH NOTES / FAIL
**Required Actions:**
1. [Action item if any]
2. [Action item if any]
---
## Recommendations
[If incomplete tasks found]
⚠️ **Warning:** This track has N incomplete tasks. Consider completing all tasks before marking track as done.
[If no critical issues]
✅ **No blocking issues found.** This track is ready to merge.
[If critical issues found]
❌ **Critical issues must be resolved before proceeding.**
Project-Level Report
Path: draft/review-report-<timestamp>.md (where <timestamp> is generated via date +%Y-%m-%dT%H%M, e.g., 2026-03-15T1430)
After writing the timestamped report, create a symlink pointing to it:
ln -sf review-report-<timestamp>.md draft/review-report-latest.md
Similar format but:
- No Stage 2 section (no spec compliance)
- Header shows scope instead of track ID:
project: "Scope: Uncommitted changes"files <pattern>: "Scope: Files matching ''"commits <range>: "Scope: Commits "
- Each run creates a new timestamped file; the
-latest.mdsymlink always points to the most recent report - Include "Previous review: " if a prior
-latest.mdsymlink exists (read its target to determine the previous timestamp)
Report History
Previous timestamped reports are preserved. The -latest.md symlink always points to the most recent report.
Step 7: Update Metadata (Track-Level Only)
For track-level reviews, update metadata.json with review status.
Condition: Always update metadata after generating the review report, regardless of verdict. This ensures review history is tracked for all outcomes (PASS, PASS_WITH_NOTES, or FAIL).
7.1: Read Current Metadata
Load draft/tracks/<id>/metadata.json
7.2: Add Review Fields
{
"id": "<track_id>",
...
"lastReviewed": "<ISO timestamp>",
"reviewCount": N,
"lastReviewVerdict": "PASS" | "PASS_WITH_NOTES" | "FAIL"
}
Increment reviewCount on each review.
7.3: Write Updated Metadata
Save updated metadata.json
Step 8: Present Results
Display summary to user with actionable next steps.
Success Output
✅ Review complete: <track_id>
Report: draft/tracks/<id>/review-report-<timestamp>.md (symlink: review-report-latest.md)
Summary:
- Stage 1 (Automated Validation): PASS
- Stage 2 (Spec Compliance): PASS
- Stage 3 (Code Quality): PASS WITH NOTES
- Total semantic issues: 12 (0 Critical, 3 Important, 9 Minor)
[If full]
Additional Checks:
- Bug Hunt: 5 medium-severity findings
Verdict: PASS WITH NOTES
Recommended actions:
1. Fix 3 Important issues (see report)
2. Review 9 Minor notes for future improvements
Next: Address findings and run /draft:review again, or mark track complete.
Failure Output
❌ Review failed: <track_id>
Report: draft/tracks/<id>/review-report-<timestamp>.md (symlink: review-report-latest.md)
Stage 1 (Automated Validation): PASS
Stage 2 (Spec Compliance): FAIL
- 3 requirements not implemented
- 2 acceptance criteria not met
Stage 3: SKIPPED (Stage 2 must pass first)
Verdict: FAIL
Required actions:
1. Implement missing requirements (see report)
2. Meet all acceptance criteria
3. Run /draft:implement to resume work
Next: Fix gaps and run /draft:review again.
Error Handling
Missing Draft Directory
Error: Draft not initialized.
Run /draft:init to set up Context-Driven Development.
No Tracks Found
Error: No tracks found in draft/tracks.md
Run /draft:new-track to create your first track.
Track Not Found
Error: Track 'xyz' not found.
Did you mean:
1. add-review-command
2. enterprise-readiness
Use exact track ID or run /draft:status to see all tracks.
Ambiguous Match
Multiple tracks match 'review':
1. add-review-command - Add /draft:review Command [~]
2. review-architecture-md - Review architecture.md [x]
Select track (1-2):
Invalid Git Range
Error: Invalid commit range 'main...feature'
Git error: fatal: ambiguous argument 'feature': unknown revision
Verify the range exists:
git log main...feature
Missing Commits in Plan
⚠️ Warning: No commit SHAs found in plan.md
Cannot determine commit range for review.
Options:
1. Manually specify range: /draft:review track <id> commits <range>
2. Review uncommitted changes: /draft:review project
Anti-Patterns
| Don't | Instead |
|---|---|
| Skip Stage 1 (Automated Validation) | Always run automated checks first |
| Skip Stage 2 (Spec Compliance) | Always verify spec compliance before quality checks |
| Run Stage 3 when Stage 2 fails | Fix spec gaps before quality checks |
| Ignore incomplete tasks | Warn user, suggest completing work first |
| Auto-fix issues found | Report only, let developer decide |
| Batch multiple tracks | Review one track at a time |
Pattern Learning
After generating the review report, execute the pattern learning phase from core/shared/pattern-learning.md to update draft/guardrails.md with patterns discovered during this review.
Examples
Review active track
/draft:review
Review specific track by ID
/draft:review track add-user-auth
Review specific track by name (fuzzy)
/draft:review track "user authentication"
Comprehensive track review
/draft:review track add-user-auth full
Review uncommitted changes
/draft:review project
Review specific files
/draft:review files "src/**/*.ts"
Review commit range
/draft:review commits main...feature-branch
Review with bughunt
/draft:review track my-feature with-bughunt
Cross-Skill Dispatch
- Auto-invokes:
/draft:coverageafter Stage 3 if TDD is enabled for the track - At completion, suggests based on findings:
- If tech debt patterns found: "Run
/draft:tech-debtto catalog and prioritize debt items" - If documentation gaps: "Run
/draft:documentationto address documentation findings" - If design decisions need recording: "Run
/draft:adrto document architectural decisions"
- If tech debt patterns found: "Run
- If architecture concerns found in review: "Consider running
/draft:deep-reviewfor a production-grade module audit" - If review passes and track modifies production code: "Consider running
/draft:deploy-checklistbefore deployment" - Jira sync: If ticket linked, attach review report and post comment: "[draft] review-complete: {verdict} — {n} findings ({critical} critical)" via
core/shared/jira-sync.md
Converted and distributed by TomeVault — claim your Tome and manage your conversions.