Detects time and space complexity hotspots via AST scan. Use when code feels slow, before performance-sensitive merges, or to find O(n²) regressions.
npx skills add https://github.com/athola/claude-night-market --skill performance-review
Static-analysis review of time and space complexity hotspots.
The skill runs in three escalating tiers. Tier 1 uses Python's
stdlib ast and always runs. Tier 2 uses gauntlet's tree-sitter
parser to extend detection across languages when gauntlet is
installed. Tier 3 uses the gauntlet code graph to upgrade
severity when hotspots reach other hotspots transitively. If
gauntlet is missing, Tiers 2 and 3 no-op and Tier 1 still
produces useful findings on Python source.
/performance-review # scan changed files
/performance-review path/to/file.py # scan one file
/performance-review --tier 1 # force Tier 1 only
Programmatic use:
from pensive.skills.performance_review import PerformanceReviewSkill
skill = PerformanceReviewSkill()
result = skill.analyze(context, "src/module.py")
for f in result.issues:
print(f"[{f.severity}] {f.file}:{f.line} {f.message}")
profiler.
are common.
time on real data). Use Skill(parseltongue:python-performance)
instead: that skill drives cProfile, py-spy, and benchmarks.
Skill(pensive:code-refinement) whose algorithm-efficiency
module covers broader optimization patterns. This skill
detects; that skill teaches.
SIMD, strength reduction) is worth keeping: use
Skill(leyline:loop-optimization) for the hand-vs-compiler rule.
This skill flags hotspot shapes, not transformation choices.
queue placement): use Skill(pensive:architecture-review).
perf-review:context-establishedperf-review:scan-completeperf-review:findings-categorizedperf-review:integration-checkedperf-review:report-generatedperf-review:findings-verifiedperf-review:context-established)git diff --name-only. If invoked with a path, scope to that.
files need gauntlet for Tier 2 coverage.
perf-review:scan-complete)Load modules/time-complexity.md for the time-side patterns and
modules/space-complexity.md for space-side. Each module
documents the AST shape of every detector.
Alongside the automated scan, load
modules/memory-allocation-lenses.md and apply its three
manual lenses (unbounded external-source collections, hot-path
recompute, serial blocking I/O) by reading the target files.
For each Python target file, call:
from pensive.skills.performance_review import PerformanceReviewSkill
result = PerformanceReviewSkill().analyze(context, path)
The visitor walks the AST once and emits ReviewFinding records.
perf-review:findings-categorized)Group findings by severity:
(T3, T4, S1, S3).
Within a severity, sort by file then line. Suppress findings
the user has explicitly marked acceptable (TODO/comment
markers) at module-load time of the target.
perf-review:integration-checked)Load modules/gauntlet-integration.md for the contract.
If gauntlet is installed, run Tier 2 on non-Python files that
were skipped at Step 2. If a .gauntlet/graph.db exists in the
working tree, run Tier 3 to upgrade severities based on
transitive hotspot reachability.
If gauntlet is missing, this step is a no-op and the report
notes "Tier 2/3 not available: install gauntlet for
multi-language and call-chain coverage."
perf-review:report-generated)Emit a markdown report:
## Performance Review: <target>
### HIGH (<count>)
- src/foo.py:42: Nested loop over the same iterable 'items'.
Suggestion: sort + two pointers, or hash-set membership.
### MEDIUM (<count>)
- ...
### LOW (<count>)
- ...
Tier coverage: 1 (always) | 2 (gauntlet ✓/✗) | 3 (graph ✓/✗)
The report is informational. Apply fixes via
Skill(pensive:code-refinement) or hand-merge.
| Tier | Source | When it runs | What it covers |
|------|--------|--------------|----------------|
| 1 | stdlib ast | Always (Python source only) | T1-T6, S1-S3 |
| 2 | gauntlet.treesitter_parser | When gauntlet importable | Same patterns adapted to JS/TS, Go, Rust, Java, C/C++ |
| 3 | gauntlet.graph.GraphStore | When .gauntlet/graph.db exists | Severity upgrade via transitive call chains |
Findings use the shared ReviewFinding dataclass from
pensive.skills.base:
ReviewFinding(
file="src/module.py",
line=42,
severity="HIGH", # LOW | MEDIUM | HIGH | CRITICAL
category="time", # time | space
message="Nested loop over the same iterable 'items'.",
suggestion="Sort + two pointers, or hash-set membership.",
anchor="verbatim source text at file:line",
code_snippet="",
)
This shape matches every other pensive review skill, so the
findings can flow into Skill(pensive:unified-review) without
translation.
| Dependency | Required? | Effect when missing |
|------------|-----------|---------------------|
| gauntlet.treesitter_parser | Optional | Tier 2 returns []; Python coverage unchanged |
| gauntlet.graph.GraphStore | Optional | Tier 3 returns []; severities are not upgraded |
The optional-import contract follows the precedent in
plugins/leyline/src/leyline/tokens.py:25-32 and
plugins/gauntlet/hooks/pr_blast_radius.py:52-56: try-import
to module-level sentinels, then early-return on None inside
each tier helper. See modules/gauntlet-integration.md for the
exact code shape.
modules/time-complexity.md: T1-T6 detector patterns and ASTshapes.
modules/space-complexity.md: S1-S3 detector patterns.modules/gauntlet-integration.md: Tier 2/3 contract,fallback semantics, examples.
modules/kuva-visualization.md: Rendering benchmark data ascharts with kuva (criterion, pytest-benchmark, ad-hoc tables).
Covers when chart evidence satisfies proof-of-work requirements.
modules/memory-allocation-lenses.md: Manual review lenses(not AST detectors) for unbounded collections fed from
external sources, hot-path recompute that should be memoized,
and serial blocking I/O over unbounded sets. Apply by reading
the code; the detector-test rule in Testing does not cover
these because nothing is automated.
A perf-review finding is only useful if the caller can confirm it
is real. Use this checklist before treating any finding as worth
fixing:
cProfile, py-spy, or thelanguage-specific equivalent on the hotspot. The findings
pinpoint AST shapes; the profiler validates the runtime impact.
benches/ exists, thehotspot should show up in numbers, not just AST scans.
is wrong if numbers do not move. Capture both timings as
evidence references like [E1] (before) and [E2] (after).
When 3+ data points exist, render a kuva chart and attach it
to the PR (see modules/kuva-visualization.md).
be true at the AST level and false at the call-graph level
when callers short-circuit. Manual sampling catches that.
The Skill(imbue:proof-of-work) discipline applies: claims like
"the hotspot is fixed" require evidence, not assertion.
A test file already lives at
plugins/pensive/tests/skills/test_performance_review.py covering
the AST-shape detectors. Two rules for changes here:
added to the modules ships with a test that has the smallest
AST sample exercising it.
the skill stops firing on a shape that used to look hot, the
reason should appear as a test case so the regression is
discoverable later.
The Iron Law applies: a new detector without a failing test first
is a request to skip TDD on a code-analysis component, which is
exactly the place where TDD pays off most.
perf-review:findings-verified)Every finding must cite a real location and a verbatim anchor. Write
findings to .review/findings.json and confirm each citation resolves:
python plugins/imbue/scripts/citation_verifier.py \
--findings .review/findings.json --repo-root .
Drop or label UNVERIFIED any finding the verifier fails (exit 1); only
verified findings enter the report. See Skill(imbue:review-core) Step 5
and Skill(imbue:structured-output) for the schema.
suggestion the caller can act on.
detectors have been run; tier coverage is reported.
contracts honor the optional-import sentinel: missing
modules return [] rather than raising.
fails before the detector exists; each removed false
positive ships with a regression test.
Skill(pensive:unified-review) withouttranslation when invoked from the unified entry point.
Location + verbatim Anchorconfirmed by citation_verifier.py (exit 0), or unverified
findings were dropped or labeled UNVERIFIED
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
Comprehensive GitHub release orchestration with AI swarm coordination for automated versioning, testing, deployment, and rollback management
Migrate test files from `as` type assertions to @total-typescript/shoehorn. Use when user mentions shoehorn, wants to replace `as` in tests, or needs partial test data.
Modern JavaScript/TypeScript development with Bun runtime. Covers package management, bundling, testing, and migration from Node.js. Use when working with Bun, optimizing JS/TS development speed, or migrating from Node.js to Bun.
You are a dependency management expert specializing in safe, incremental upgrades of project dependencies. Plan and execute dependency updates with minimal risk, proper testing, and clear migration pa
Master systematic debugging techniques, profiling tools, and root cause analysis to efficiently track down bugs across any codebase or technology stack. Use when investigating bugs, performance issues, or unexpected behavior.
Opinionated backend development standards for Node.js + Express + TypeScript microservices. Covers layered architecture, BaseController pattern, dependency injection, Prisma repositories, Zod validation, unifiedConfig, Sentry error tracking, async safety, and testing discipline.
Best practices for writing JavaScript/TypeScript tests using Jest, including mocking strategies, test structure, and common patterns.
Take athola/performance-review from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.