Install
openclaw skills install solo-reviewFinal code review and quality gate — run tests, check coverage, audit security, verify acceptance criteria from spec, and generate ship-ready report. Use when user says "review code", "quality check", "is it ready to ship", "final review", or after /deploy completes. Do NOT use for planning (use /plan) or building (use /build).
openclaw skills install solo-reviewThis skill is self-contained — follow the instructions below instead of delegating to external review skills (superpowers, etc.) or spawning Task subagents. Run all checks directly.
Final quality gate before shipping. Runs tests, checks security, verifies acceptance criteria from spec.md, audits code quality, and generates a ship-ready report with go/no-go verdict.
After /deploy (or /build if deploying manually). This is the quality gate.
Pipeline: /deploy → /review
Can also be used standalone: /review on any project to audit code quality.
session_search(query) — find past review patterns and common issuesproject_code_search(query, project) — find similar code patterns across projectscodegraph_query(query) — check dependencies, imports, unused codeIf MCP tools are not available, fall back to Glob + Grep + Read.
codegraph_explain(project="{project name}")
Returns: stack, languages, directory layers, key patterns, top dependencies, hub files. Use this to detect stack and understand project structure.
CLAUDE.md — architecture, Do/Don't rulesdocs/plan/*/spec.md — acceptance criteria to verify (REQUIRED)docs/plan/*/plan.md — task completion status (REQUIRED)docs/workflow.md — TDD policy, quality standards, integration testing commands (if exists)Do NOT read source code at this stage. Only docs.
Use stack from codegraph_explain response (or CLAUDE.md if no MCP) to choose tools:
npm run build, npm test, npx next lintuv run pytest, uv run ruff checkswift test, swiftlint./gradlew test, ./gradlew lintDo NOT read random source files. Use the graph to find the most important code:
codegraph_query("MATCH (f:File {project: '{name}'})-[e]-() RETURN f.path, COUNT(e) AS edges ORDER BY edges DESC LIMIT 5")
Read only the top 3-5 hub files (most connected = most impactful). For security checks, use Grep with narrow patterns (sk_live, password\s*=) — not full file reads.
Makefile convention: If Makefile exists in project root, always prefer make targets over raw commands. Use make test instead of npm test, make lint instead of pnpm lint, make build instead of pnpm build. Run make help (or read Makefile) to discover available targets including integration tests.
Run all 12 dimensions in sequence. Report findings per dimension.
Run the full test suite (prefer make test if Makefile exists):
# If Makefile exists — use it
make test 2>&1 || true
# Fallback: Next.js / Node
npm test -- --coverage 2>&1 || true
# Python
uv run pytest --tb=short -q 2>&1 || true
# Swift
swift test 2>&1 || true
Report:
Integration tests — if docs/workflow.md has an "Integration Testing" section, run the specified commands:
# Next.js
pnpm lint 2>&1 || true
pnpm tsc --noEmit 2>&1 || true
# Python
uv run ruff check . 2>&1 || true
uv run ty check . 2>&1 || true
# Swift
swiftlint lint --strict 2>&1 || true
# Kotlin
./gradlew detekt 2>&1 || true
./gradlew ktlintCheck 2>&1 || true
Report: warnings count, errors count, top issues.
# Next.js
npm run build 2>&1 || true
# Python
uv run python -m py_compile src/**/*.py 2>&1 || true
# Astro
npm run build 2>&1 || true
Report: build success/failure, any warnings.
Dependency vulnerabilities:
# Node
npm audit --audit-level=moderate 2>&1 || true
# Python
uv run pip-audit 2>&1 || true
Code-level checks (Grep for common issues):
grep -rn "sk_live\|sk_test\|password\s*=\s*['\"]" src/ app/ lib/dangerouslySetInnerHTML without sanitization.gitignore includes .env*Report: vulnerabilities found, severity levels.
Read docs/plan/*/spec.md and check each acceptance criterion:
For each - [ ] criterion in spec.md:
Update spec.md checkboxes. After verifying each criterion, use Edit tool to change - [ ] to - [x] in spec.md. Leaving verified criteria unchecked causes staleness across pipeline runs — check them off as you go.
Acceptance Criteria:
- [x] User can sign up with email — found in app/auth/signup/page.tsx + test
- [x] Dashboard shows project list — found in app/dashboard/page.tsx
- [ ] Stripe checkout works — route exists but no test coverage
After updating checkboxes, commit: git add docs/plan/*/spec.md && git commit -m "docs: update spec checkboxes (verified by review)"
Read 3-5 key files (entry points, API routes, main components):
Report specific file:line references for any issues found.
Read docs/plan/*/plan.md:
[x] vs total tasks[ ] or [~] tasks still remainingIf the project has been deployed (deploy URL in CLAUDE.md, or .solo/states/deploy exists if pipeline state directory is present), check production logs for runtime errors.
Read the logs field from the stack YAML (templates/stacks/{stack}.yaml) to get platform-specific commands.
Vercel (Next.js):
vercel logs --output=short 2>&1 | tail -50
Look for: Error, FUNCTION_INVOCATION_FAILED, 504, unhandled rejections, hydration mismatches.
Cloudflare Workers:
wrangler tail --format=pretty 2>&1 | head -50
Look for: uncaught exceptions, D1 errors, R2 access failures.
Fly.io (Python API):
fly logs --app {name} 2>&1 | tail -50
Look for: ERROR, CRITICAL, OOM, connection refused, unhealthy instances.
Supabase Edge Functions:
supabase functions logs --scroll 2>&1 | tail -30
iOS (TestFlight):
log stream --predicate 'subsystem == "com.{org}.{name}"'Android:
adb logcat '*:E' --format=time 2>&1 | tail -30
If no deploy yet: skip this dimension, note in report as "N/A — not deployed".
If logs show errors:
Report:
Check adherence to dev principles. Look for templates/principles/dev-principles.md (bundled with this skill), or check CLAUDE.md or project docs for architecture and coding conventions.
Read the dev principles file, then spot-check 3-5 key source files for violations:
SOLID:
new ConcreteService() inside business logic instead of dependency injection.DRY vs Rule of Three:
KISS:
Schemas-First (SGR):
any / dict)?Clean Architecture:
Error Handling:
Report:
Check git history for the current track/feature:
git log --oneline --since="1 week ago" 2>&1 | head -30
Conventional commits format:
<type>(<scope>): <description> patternfeat, fix, refactor, test, docs, chore, perf, styleAtomicity:
git revert a single commit without side effects?SHAs in plan.md:
<!-- sha:abc1234 --> comments<!-- checkpoint:abc1234 -->grep -c "sha:" docs/plan/*/plan.md 2>/dev/null || echo "No SHAs found"
Pre-commit hooks:
Read the stack YAML pre_commit field to know what system is expected (husky/pre-commit/lefthook) and what it should run (linter + formatter + type-checker). Then verify:
# Detect what's configured
[ -f .husky/pre-commit ] && echo "husky" || [ -f .pre-commit-config.yaml ] && echo "pre-commit" || [ -f lefthook.yml ] && echo "lefthook" || echo "none"
core.hooksPath for husky, .git/hooks/pre-commit for pre-commit/lefthook).pre_commit field. Flag mismatch.--no-verify bypasses? Check if recent commits show signs of skipped hooks (e.g., lint violations that should've been caught). Flag as WARN.{pre_commit} but nothing found.Report:
Check that project documentation is up-to-date with the code.
Required files check:
ls -la CLAUDE.md README.md docs/prd.md docs/workflow.md 2>&1
CLAUDE.md:
# Check that files mentioned in CLAUDE.md actually exist
grep -oP '`[a-zA-Z0-9_./-]+\.(ts|py|swift|kt|md)`' CLAUDE.md | while read f; do [ ! -f "$f" ] && echo "MISSING: $f"; done
README.md:
docs/prd.md:
AICODE- comments:
grep -rn "AICODE-TODO" src/ app/ lib/ 2>/dev/null | head -10
grep -rn "AICODE-ASK" src/ app/ lib/ 2>/dev/null | head -10
AICODE-TODO items that were completed but not cleaned upAICODE-ASK questionsAICODE-NOTE on complex/non-obvious logicDead code check:
knip available (Next.js): pnpm knip 2>&1 | head -30Report:
If browser tools or device tools are available, run a visual smoke test.
Web projects (Playwright MCP or browser tools):
dev_server.command from stack YAML, e.g. pnpm dev)iOS projects (simulator):
xcodebuild -scheme {Name} -sdk iphonesimulator buildAndroid projects (emulator):
./gradlew assembleDebugadb logcat '*:E' --format=time -d 2>&1 | tail -20If tools are not available: skip this dimension, note as "N/A — no browser/device tools" in the report. Visual testing is never a blocker for SHIP verdict on its own.
Report:
Generate the final report:
Code Review: {project-name}
Date: {YYYY-MM-DD}
## Verdict: {SHIP / FIX FIRST / BLOCK}
### Summary
{1-2 sentence overall assessment}
### Tests
- Total: {N} | Pass: {N} | Fail: {N} | Skip: {N}
- Coverage: {N}%
- Status: {PASS / FAIL}
### Linter
- Errors: {N} | Warnings: {N}
- Status: {PASS / WARN / FAIL}
### Build
- Status: {PASS / FAIL}
- Warnings: {N}
### Security
- Vulnerabilities: {N} (critical: {N}, high: {N}, moderate: {N})
- Hardcoded secrets: {NONE / FOUND}
- Status: {PASS / WARN / FAIL}
### Acceptance Criteria
- Verified: {N}/{M}
- Missing: {list}
- Status: {PASS / PARTIAL / FAIL}
### Plan Progress
- Tasks: {N}/{M} complete
- Phases: {N}/{M} complete
- Status: {COMPLETE / IN PROGRESS}
### Production Logs
- Platform: {Vercel / Cloudflare / Fly.io / N/A}
- Errors: {N} | Warnings: {N}
- Status: {CLEAN / WARN / ERRORS / N/A}
### Dev Principles
- SOLID: {PASS / violations found}
- Schemas-first: {YES / raw data found}
- Error handling: {PASS / issues found}
- Status: {PASS / WARN / FAIL}
### Commits
- Total: {N} | Conventional: {N}/{M}
- Atomic: {YES / NO}
- Plan SHAs: {N}/{M}
- Status: {PASS / WARN / FAIL}
### Documentation
- CLAUDE.md: {CURRENT / STALE / MISSING}
- README.md: {CURRENT / STALE / MISSING}
- AICODE-TODO unresolved: {N}
- Dead code: {NONE / found}
- Status: {PASS / WARN / FAIL}
### Visual Testing
- Platform: {browser / simulator / emulator / N/A}
- Pages/screens: {N}
- Console errors: {N}
- Visual issues: {NONE / list}
- Status: {PASS / WARN / FAIL / N/A}
### Issues Found
1. [{severity}] {description} — {file:line}
2. [{severity}] {description} — {file:line}
### Recommendations
- {actionable recommendation}
- {actionable recommendation}
Verdict logic:
After the verdict report, revise the project's CLAUDE.md to keep it lean and useful for future agents.
wc -c CLAUDE.mdgit add CLAUDE.md && git commit -m "docs: revise CLAUDE.md (post-review)"Output pipeline signal ONLY if pipeline state directory (.solo/states/) exists.
Output the signal tag ONCE and ONLY ONCE. Do not repeat it. The pipeline detects the first occurrence.
If SHIP: output this exact line (once):
<solo:done/>
If FIX FIRST or BLOCK:
- [ ] Task per issue found)[x] Complete to [~] In Progressgit add docs/plan/ && git commit -m "fix: add review fix tasks"<solo:redo/>
The pipeline reads these tags and handles all marker files automatically. You do NOT need to create or delete any marker files yourself. Output the signal tag once — the pipeline detects the first occurrence.
Cause: Missing dependencies or test config.
Fix: Run npm install / uv sync, check test config exists (jest.config, pytest.ini).
Cause: No linter config file found. Fix: Note as a recommendation in the report, not a blocker.
Cause: Type errors, import issues, missing env vars. Fix: Report specific errors. This is a BLOCK verdict — must fix before shipping.
When reviewing significant work, use two stages:
Stage 1 — Spec Compliance:
Stage 2 — Code Quality:
No verdict without fresh evidence.
Before writing any verdict (SHIP/FIX/BLOCK):
Never write "tests should pass" — run them and show the output.
| Thought | Reality |
|---|---|
| "Tests were passing earlier" | Run them NOW. Code changed since then. |
| "It's just a warning" | Warnings become bugs. Report them. |
| "The build worked locally" | Check the platform too. Environment differences matter. |
| "Security scan is overkill" | One missed secret = data breach. Always scan. |
| "Good enough to ship" | Quantify "good enough". Show the numbers. |
| "I already checked this" | Fresh evidence only. Stale checks are worthless. |
/build fix them. Review only modifies plan.md, never source code.