This repo demonstrates a workflow for having a coding agent (e.g. Claude Code) build a Python function and review its own work through multiple independent "lenses" — separate reviewer personas that each focus on a different failure mode — before proposing a fix.
The point isn't the functions themselves. It's the process:
prompt → spec (human approval) → implementation + tests
→ parallel lens reviews → synthesis → scoped fix pass
A single pass of this loop is already checked into the repo as a worked example (see Sample run below), so you can see the shape of the output before running it yourself.
A single reviewer prompt tends to average across concerns — a bit of correctness, a bit of style, whatever it happens to notice first. Splitting review into named lenses (e.g. "an adversarial correctness engineer" vs. "a staff engineer optimizing for long-term ownership") gets each reviewer to dig deeper along its one axis instead of skimming several. The synthesis step then does the job a human tech lead would do anyway: merge, deduplicate, resolve disagreements, and decide what's actually worth fixing now.
Defined in AGENTS.md (CLAUDE.md is a symlink to the same
file, so it's picked up by either convention):
- Spec first. Given a prompt describing a function, the agent drafts
specs/function_spec_<stub>.md(signature, types, requirements, edge cases, out of scope) and presents it for approval before writing code. - Implement. Once approved, the agent generates the function in
src/plus unit tests, and doesn't move on until all tests pass. - Review, in parallel. The agent spawns one subagent per row in the
Agent Rolestable below, each reading its own prompt file and writing its findings toreviews/<lens>_review_<stub>.md. - Synthesize. Findings from all lenses are merged, deduplicated,
conflicts resolved, and prioritized into
reviews/synthesis_<stub>.md. - Human picks scope, agent fixes. You choose how much of the synthesis to act on; the agent applies it, updates the spec/tests if needed, and re-verifies everything still passes.
| Lens | Prompt | Focus |
|---|---|---|
| Correctness | prompts/correctness_reviewer.md |
Adversarial: concurrency, edge cases, contract violations, memory |
| Maintainability | prompts/maintainability_reviewer.md |
Staff-engineer lens: complexity, testability, extensibility, readability |
Adding a new lens (security, performance, API-design, whatever you want the
agent to dig into) is just: write a new prompts/<name>_reviewer.md in the
same format, and add a row to the Agent Roles table in AGENTS.md.
| Path | Contents |
|---|---|
AGENTS.md / CLAUDE.md |
Workflow definition, project parameters, spec template |
prompts/ |
Reviewer lens definitions |
specs/ |
Generated function specs |
reviews/ |
Generated per-lens reviews + synthesis |
src/ |
Generated implementation code |
tests/ |
Generated unit tests |
sample_session_summary.md |
Narrative write-up of the sample run below |
One full pass is already in the repo: a thread-safe, priority-lane rate limiter, built from the single prompt:
generate an efficient python function that enforces rate limits with thread safety and priority lanes
See sample_session_summary.md for the
narrative (spec, implementation, both reviews, synthesis, fix pass), or read
the raw artifacts directly:
specs/function_spec_priority_rate_limiter.mdsrc/code_review/priority_rate_limiter.pyreviews/correctness_review_priority_rate_limiter.mdreviews/maintainability_review_priority_rate_limiter.mdreviews/synthesis_priority_rate_limiter.md
Notably, the correctness lens caught two real, empirically-verified bugs a maintainability-only review would likely have missed (a NaN-cost bypass that silently disabled rate limiting, and a non-monotonic-clock bug that let tokens over-credit) — a concrete illustration of why a dedicated adversarial lens earns its keep.
Prerequisites: uv installed, and this
repo open in a coding agent that reads AGENTS.md/CLAUDE.md (e.g. run
claude from the repo root).
Give the agent one prompt describing a function to build — it drives the rest of the loop (spec → approval → implementation → parallel review → synthesis → fix) on its own from there. To try something other than the rate limiter already in the repo, here are a few prompts that tend to surface different kinds of findings:
-
Thread-safe LRU cache with per-entry TTL
Generate a thread-safe LRU cache with a fixed max size and a per-entry TTL, evicting on whichever comes first (capacity overflow or TTL expiry), with O(1) get/put.
Stresses the maintainability lens more than the correctness lens — eviction-policy interactions and state complexity tend to dominate over raw concurrency bugs.
-
Bounded blocking object pool
Generate a thread-safe bounded pool of reusable objects (e.g. connections) that blocks with a timeout when exhausted, and is safe to use as a context manager so a checked-out object is always returned even if the caller raises.
Stresses correctness around blocking/timeout semantics and resource-leak edge cases (exceptions mid-checkout, pool shutdown while threads are waiting).
-
Circuit breaker
Generate a thread-safe circuit breaker (closed/open/half-open states) wrapping calls to an unreliable dependency, with a configurable failure threshold, cooldown period, and limited trial calls while half-open.
Stresses state-machine correctness (valid/invalid transitions, races on the transition boundary) and gives the maintainability lens a meaty "is this cyclomatic complexity justified" question.
Run any of these (or your own idea) and compare the resulting
reviews/*_review_*.md and reviews/synthesis_*.md files against the sample
run — same process, different bugs surface depending on what the function
actually has to get right.
uv sync # install dependencies
uv run pytest tests/ -v # run the unit test suite