Code Review — act101 Agent Skill
Review code for bugs, complexity, unused symbols, and structural issues using AST-aware analysis. Use when reviewing PRs, checking code quality, finding dead code, analyzing function complexity, auditing a codebase, or checking for type errors. Each call reports the kinds it modeled in `modeled_kinds` — that is the honest coverage signal; the supported-language list is whatever act ships.
Code Review with act
Analyze code for issues using act's query tools.
Start Here
Check workspace status first — some tools require LSP:
status()
Exploration Pattern
For systematic file exploration, use a two-pass approach: parser-only tools first (skeleton, symbols), then LSP tools (diagnostics, references, callers). Start broad (directory skeletons), narrow (file symbols), then deep (reference chains).
Core Review Tools
Always available (parser-only)
skeleton — Get file structure. Shows function signatures, class declarations, nesting depth.
skeleton(file="src/auth/login.ts")
symbols — List all symbols with kinds and locations. Spot missing exports, large symbol counts.
symbols(file="src/auth/login.ts")
unsafe_surface — Flag dangerous constructs: unsafe blocks, eval, raw SQL, FFI, reflective invocation, unsafe deserialization. Syntactic floor (works without LSP), upgrades confidence when LSP is warm. Run it on any file handling input, queries, or native interop.
unsafe_surface(file="src/db/query.ts")
Requires LSP
diagnostics — Compiler/linter errors, warnings, hints. The primary bug-finding tool.
diagnostics(file="src/auth/login.ts")
references — Find all references to a symbol. Detect unused exports (0 external references).
references(symbol="validateToken", file="src/auth/token.ts")
callers — Find functions that call a symbol. Understand coupling and blast radius.
callers(symbol="processPayment", file="src/billing.ts")
definition — Jump to where a symbol is defined. Trace imports to source.
definition(symbol="UserService", file="src/api.ts", line=15, column=10)
get_type — Get the inferred type at a position. Check type correctness.
get_type(file="src/api.ts", line=42, column=12)
Review Workflow
For a single file
diagnostics— get all errors/warningsskeleton— check structure (function sizes, nesting)symbols— check symbol density and naming
For a directory/module
skeletonon each file — build structural overviewdiagnosticson each file — collect all issuesreferenceson exports — find unused public APIcallerson key functions — check coupling
For a PR (changed files)
diagnosticson each changed fileskeletonon changed files — check new structurereferenceson renamed/moved symbols — verify all references updatedcallerson modified functions — assess impact (requires LSP)analyze_impact(symbol mode, Architecture) on modified functions — transitive callers without LSP. Useskeletonfirst to confirm the symbol name, then:analyze_impact(target=<file>, symbol=<name>). Reviewconfidence,modeled_kinds, andunresolvedfields for analysis gaps.analyze_api_diff(Architecture) on changed PUBLIC surfaces — run it against the PR base branch:analyze_api_diff(base_ref=<base>)(CLI twinact analyze api-diff --base-ref <base>; omitbase_refto diff against HEAD). It diffs the merge-base of the base branch and the working tree, returning per-symbolrowsandsummarycounts. Cite the verdicts — Breaking (e.g. a parameter added), PossiblyBreaking (other signature drift), Additive (a new export) — and report thesummarybreaking/possibly_breaking/additive counts. Surface any Unjudgeable rows: they name a grammar whose visibility act doesn't model, so the change is unjudged, NOT safe. Skip this step when the PR touches no public API.scan— AI-code security pass on the change: hardcoded credentials (pattern + entropy heuristic),.cursorrulesbackdoors, MCP-config RCE, typosquat/hallucinated dependencies, GitHub Actions expression injection, LLM-output-to-exec flows, prompt-injection surfaces, plus an AI-Code Health Score. Preferscan(root=<repo>, base_ref=<base branch>)— it computes the changed set itself (merge-base, rename-aware) and the report'sscopesection discloses the diff scoping; scores are diff-scoped, never comparable to full-repo scores. Fall back toscan(root=<repo>, files=[<changed files>])when there is no git base to diff against — path-scoped scans are cheap (the architecture graph builds over the selected files only) and equally disclosed via thescopesection (mode: "paths"); their scores carry the same never-comparable rule. With a committed.act/baseline.json, addbaseline=".act/baseline.json"—baseline.new_finding_idsis then exactly "findings this change introduces".- Merge-safety verdict — run
gate(base_ref=<base branch>)(MCP) oract gate --base-ref <base branch>(CLI) to get a deterministic per-function verdict for the entire changed set. Cite its output directly; do not re-derive merge-safety prose fromverify_diff_semantics,verify_test_impact, orverify_side_effectsindividually — those are the gate engine's inputs, and the gate is the rule owner. The safe-to-merge skill follows the same verdict rules and extends the gate workflow with post-merge validation.
Verdict semantics (exit codes: 0 MERGE, 1 BLOCK, 2 REVIEW, 3 UNKNOWN, 4 error):
- MERGE — every changed function cleared all three checks
- REVIEW — at least one function needs human judgment (no automatic block)
- BLOCK — at least one function failed a check; do not merge
- UNKNOWN — verification could not complete for at least one function;
treat as not-verified, never as a pass
Receipts: gate --receipts (or gate(receipts=true)) writes one
<id>.json file to .act/receipts/ per verified function. Functions whose
file, symbol, and span-hashes match a valid receipt are reported as
pre-verified by receipt <id> — reviewers may accept that as evidence without
re-running the trio. Any hash or schema mismatch discards the receipt and
re-verifies from scratch automatically. Emission mechanics and receipt schema
live in the refactor-receipt skill.
Worked example (fixture: auth.ts with two working-tree changes):
$ act gate --receipts
act gate — working tree vs HEAD (2 changed function(s))
MERGE auth.ts::formatLabel — format (format-only)
MERGE auth.ts::validateAge — format (format-only)
verdict: MERGE
$ echo $?
0
Second run (receipts already written, consumed from cache):
$ act gate --receipts
act gate — working tree vs HEAD (2 changed function(s))
MERGE auth.ts::formatLabel — format (pre-verified by receipt 60e278c850577270)
MERGE auth.ts::validateAge — format (pre-verified by receipt 8bb683bbfe8e27cf)
verdict: MERGE
$ echo $?
0
A behavior change without test reach blocks (same fixture, age >= 18
flipped to age > 18):
$ act gate
act gate — working tree vs HEAD (1 changed function(s))
BLOCK auth.ts::validateAge — behavior, NO test reaches it (behavior change with no test reaching it)
verdict: BLOCK
$ echo $?
1
What to Look For
| Signal | Tool | Severity |
|---|---|---|
| Compiler errors | diagnostics | Error |
| Type mismatches | diagnostics, get_type | Error |
| Unused imports/variables | diagnostics | Warning |
| Function >50 lines | skeleton | Warning |
| Function >5 parameters | skeleton | Warning |
| Nesting depth >4 | skeleton | Warning |
| Symbol with 0 references | references | Info |
| High caller count (>10) | callers | Info |
| eval / raw SQL / FFI / unsafe deserialize | unsafe_surface | Error/Warning |
Hardcoded credential / .cursorrules backdoor / MCP-config RCE |
scan | Error |
Advanced Patterns
See review-patterns.md for detailed review checklists and multi-file analysis strategies.
Error Recovery
See error-recovery.md for handling LSP failures, file-not-found, and ambiguous symbols.
Output Format
Report findings grouped by severity:
## Review: src/auth/login.ts
### Errors (2)
- Line 45: Type 'string' is not assignable to type 'number' [diagnostics]
- Line 72: Cannot find name 'authConfig' [diagnostics]
### Warnings (3)
- Line 15-80: Function `handleLogin` is 65 lines (>50 threshold) [skeleton]
- Line 23: Unused import 'lodash' [diagnostics]
- Line 90: `validateToken` has 0 external references — possibly dead code [references]
### Info (1)
- `processAuth` called from 12 locations — high coupling [callers]