tech
Codebase archaeology with coding agents
A list of 24 architectural prompts for coding agents mostly collapses into four questions. The part that matters is the demand for evidence.
I started with one prompt, "Find all the implicit state machines in my app," and asked an AI assistant for more like it. It came back with 24. Each asks an agent with repository access to find the hidden structure of a codebase instead of reviewing a diff: implicit state machines, unenforced contracts, invisible dependencies, non-atomic operations, retries that duplicate side effects, error handling that destroys evidence, and 18 more. The list ends with a master prompt that requires evidence for every finding and a follow-up question about shared causes.
I think the list is useful, but not for the reason it looks useful. The 24 prompts are mostly one question asked from different angles. The master prompt and the follow-up are where the value is. Together they make a short workflow:
- Investigate with one or more of four questions.
- Require traced evidence and a concrete failure scenario for every finding.
- Reproduce anything labeled a confirmed defect.
- Group findings by causes the evidence actually shows they share.
- Prefer one structural fix over a pile of separate patches.
Every prompt, including all 24 originals, is at the end of this essay, ready to copy.
Most of the 24 reduce to four questions
Read the list closely and the prompts start to overlap. "Find every place the system can disagree with itself" and "find the false sources of truth" both ask where one fact is stored twice. "Find the impossible states that are actually possible" and "find the invariants nobody owns" both ask what must stay true and which code is responsible for keeping it true. "Find the non-atomic business operations," "find the places retries make things worse," and "find the accidental distributed systems" all ask what happens when a multi-step operation fails halfway.
Grouped that way, I count four questions:
- Where is one fact represented more than once? Duplicated state, derived values, caches, semantic duplication, and false sources of truth.
- What must always be true, and who enforces it? Invariants, implicit contracts, impossible states, and concepts that deserve their own types.
- What happens when a sequence is interrupted or repeated? Non-atomic operations, retries, temporal coupling, partial failures, and timing assumptions.
- Does the code do what its names say? Misleading abstractions, undocumented business rules, complexity that outlived its reason, and workarounds for other code.
The four questions cover the correctness prompts, which are most of the list. A few of the 24 ask about something else. Change amplification is about the cost of making changes, the 10× prompt is about capacity, negative-space architecture is about what is missing, and error handling that destroys evidence is about how hard a failure is to diagnose. Those are maintenance, scale, and operations questions, and they are worth running separately.
The longer list still has a use. Different wording sends an agent down different paths through the same code, and a prompt about retries may find a bug that a prompt about atomicity misses. But running all 24 separately produces overlapping reports about the same few defects, and someone has to deduplicate them. I would run the four questions and use the specific prompts as follow-ups when one area looks weak.
Evidence is the actual instruction
The master prompt requires six things for every finding: exact files and symbols, traced execution or data flow, a concrete failure scenario, a label of confirmed defect, plausible risk, or tradeoff, a minimal and a structural fix, and ratings for severity, confidence, and effort.
This matters more than any individual prompt. Architectural questions invite plausible answers. Ask an agent whether a system has hidden coupling and it will find some, because every system has some, and the report will read the same whether the coupling causes bugs or not. The failure scenario is the test. A finding that cannot name the inputs and state that produce a wrong result is an observation, not a defect.
The confirmed-versus-plausible label does similar work. In my experience, agents report suspicions and verified bugs in the same confident tone. Making the agent sort its own findings forces it to check which ones it traced and which ones it inferred from a function name. I would go one step further and require a reproduction for anything labeled confirmed: a failing test, a script, or a command whose output shows the problem. Otherwise the label is still the agent's opinion of its own work.
The follow-up finds the design flaw
The suggested follow-up asks which three findings share an underlying cause and what single change would remove all three. This is the best part of the whole set, with one flaw in its wording.
Individual findings lead to individual patches. If a webhook handler double charges on retry, the local fix is an idempotency check in that handler. If the same codebase also has a background job that sends duplicate emails and an import that creates duplicate records, the three patches hide a single problem: the system has no general idea of an operation that has already happened. A shared approach to idempotency can prevent the whole category, including instances nobody has found yet. That means an operation record checked before each side effect, a transactional outbox for work that must follow a database write, and the provider's own idempotency key for external calls such as charges. A database transaction alone cannot cover a charge or an email, because neither can be rolled back with the row that records it.
The question works because it changes what the agent optimizes for. A list of findings rewards volume. A shared cause rewards understanding how the pieces fit, which is the thing the investigation was supposed to produce.
The flaw is that the question presupposes its answer. It asks for three findings with one cause and one change that removes them, so an agent may invent a unifying story to satisfy it. The evidence rule should apply here too. I ask instead which findings, if any, share a cause the evidence demonstrates, and for the smallest structural change that addresses them.
Where it does not fit
The assistant framed these prompts as best for mature codebases. I would put the line elsewhere: what matters is how complex the system is and how much a failure costs, not the size of the codebase or the team. A small project with no payments, webhooks, or background jobs usually returns tradeoffs the author already chose. A small project that takes payments through webhooks can have every failure this list describes.
The prompts also assume the agent can see the whole system. Many of the worst failures the list describes live outside the repository: a queue's delivery guarantees, a payment provider's retry policy, a database's isolation level, or a cron schedule set in a dashboard. An agent reading code will infer these, and inferred configuration is the kind of plausible risk that the evidence rules are meant to filter out. Telling the agent where its view ends, and asking it to list the external behavior each finding depends on, makes those findings easier to check.
The last limit is the reader. A report that ranks 40 findings by bugs prevented is still 40 findings. The follow-up about shared causes is the filter that makes the report usable, so I would ask it every time, not only when the first pass is interesting.
Copy the prompts
Run the master prompt with my addition first, then one of the four questions. Ask the follow-up after every pass. The 24 originals work as optional lenses when one area looks weak.
The master prompt:
Perform a repository-wide architectural investigation, not a conventional code review.
Uncover implicit structures, hidden contracts, unenforced invariants, accidental complexity, and systemic failure modes.
For every finding, require:
1. Exact files and symbols.
2. Evidence from traced execution or data flow.
3. A concrete failure scenario.
4. Confirmed defect vs. plausible risk vs. tradeoff.
5. Minimal fix and structural fix.
6. Severity, confidence, and remediation effort.
Avoid generic best practices and speculative rewrites. Rank discoveries by how many future bugs they could prevent. Do not modify code.
My addition to the master prompt:
For every finding labeled a confirmed defect, include a reproduction: a failing test, a script, or a command whose output shows the problem. List any behavior outside the repository that the finding depends on, such as queue delivery guarantees, provider retry policies, database isolation levels, or scheduled jobs.
The follow-up, in my wording:
Which findings, if any, share a demonstrable underlying architectural cause? Trace the evidence connecting them, and identify the smallest structural change that would address those failures. If no shared cause is supported by the evidence, say so.
The original follow-up, which presupposes a shared cause:
Which three findings share the same underlying architectural cause, and what single change would eliminate all three?
The four questions, in my wording:
| # | Group | Prompt |
|---|---|---|
| 1 | Duplicated facts | Find every fact this system represents more than once. Include duplicated state, derived values, caches, and code that implements the same decision in different places. For each, show how the copies can diverge and which one is the real source of truth. |
| 2 | Invariants | Find what must always be true, and who enforces it. Derive the invariants and implicit contracts the code relies on, then trace every write path, callback, migration, and entry point that could violate them. Name the component that should own each one. |
| 3 | Interrupted sequences | Find what happens when a sequence is interrupted or repeated. Trace multi-step operations, retries, jobs, webhooks, and ordering assumptions. Show the state left behind by a partial failure or a duplicate run, and whether anything detects or repairs it. |
| 4 | Names versus behavior | Find where the code does not do what its names say. Compare names, interfaces, comments, and directory structure with actual behavior. Include business rules that exist only as incidental code and workarounds that compensate for other code. |
The original 24:
| # | Group | Prompt |
|---|---|---|
| 01 | Hidden architecture | Find all the implicit state machines. Identify entities whose behavior depends on status flags, booleans, timestamps, or sequences of events. Reconstruct their states, transitions, guards, invalid states, and recovery paths. Highlight where transitions are distributed across unrelated files. |
| 02 | Hidden architecture | Find the implicit contracts. Identify assumptions between modules, services, APIs, and database tables that aren't enforced by types, schemas, tests, or validation. Show how each contract can be violated and what breaks downstream. |
| 03 | Hidden architecture | Find the hidden dependency graph. Identify modules that appear independent but are coupled through shared state, database tables, environment variables, event ordering, caches, or side effects. Rank the most dangerous invisible dependencies. |
| 04 | Hidden architecture | Find the accidental distributed systems. Identify workflows that span asynchronous jobs, queues, webhooks, database writes, caches, and external APIs. Analyze partial failures, retries, duplicate execution, ordering, and eventual consistency. |
| 05 | Hidden architecture | Find the undocumented business rules. Reconstruct the actual business rules from conditionals, validators, queries, feature flags, and exception handling. Identify contradictory implementations and rules that exist only as incidental code. |
| 06 | Hidden architecture | Find the architectural lies. Compare what names, interfaces, abstractions, comments, and directory structures imply against what the code actually does. Find abstractions that leak, boundaries that are violated, and modules with misleading responsibilities. |
| 07 | Bugs in plain sight | Find every place where the system can disagree with itself. Identify duplicated or derived state across the frontend, backend, database, caches, and external services. Find scenarios where two representations can diverge and remain inconsistent. |
| 08 | Bugs in plain sight | Find all non-atomic business operations. Locate operations that conceptually should succeed or fail together but are implemented as multiple independent steps. Identify partial-completion states and missing rollback, compensation, or reconciliation. |
| 09 | Bugs in plain sight | Find the temporal coupling. Identify code that only works if operations happen in a particular order, initialization has completed, a previous request has run, or another component has already mutated state. Find where ordering assumptions aren't enforced. |
| 10 | Bugs in plain sight | Find the impossible states that are actually possible. Derive the invariants the system appears to require. Then trace every write path, asynchronous callback, migration, and API entry point that could violate them. |
| 11 | Bugs in plain sight | Find all the places retries make things worse. Trace retryable operations and identify where repeated execution could duplicate charges, notifications, records, jobs, or external side effects. Evaluate idempotency guarantees. |
| 12 | Bugs in plain sight | Find the error handling that destroys evidence. Identify swallowed exceptions, misleading fallbacks, lossy error transformations, missing correlation IDs, and paths that report success despite partial failure. |
| 13 | Complexity | Find the complexity that no longer earns its keep. Identify abstractions, configuration, compatibility layers, indirection, and general-purpose infrastructure that support only one real use case or an obsolete requirement. Estimate what could be safely removed. |
| 14 | Complexity | Find the change amplification hotspots. Identify small business requirement changes that require edits across many unrelated files. Trace why the change propagates and propose architectural boundaries that would localize it. |
| 15 | Complexity | Find the concepts that deserve to be first-class. Identify important domain concepts represented as strings, booleans, loose objects, scattered conditionals, or conventions. Propose types, domain objects, or explicit interfaces that would make invalid usage harder. |
| 16 | Complexity | Find the code that exists to compensate for other code. Locate defensive checks, cleanup jobs, reconciliation logic, repeated normalization, and special-case handling whose primary purpose is to compensate for weaknesses elsewhere. Trace each workaround to its root cause. |
| 17 | Complexity | Find the false sources of truth. Identify values claimed to be authoritative that can actually be overwritten, reconstructed inconsistently, bypassed, or superseded by another system. Determine the real authority for each domain concept. |
| 18 | Complexity | Find the refactors that eliminate entire categories of bugs. Rather than suggesting cosmetic improvements, identify structural changes that make multiple existing failure modes impossible by construction. Rank by bugs prevented, implementation risk, and migration cost. |
| 19 | Deeper | Find the places where correctness depends on luck. Identify code whose correctness depends on timing, low concurrency, small data volume, predictable network behavior, stable external services, or users behaving as expected. Explain the conditions under which each assumption fails. |
| 20 | Deeper | Find the negative-space architecture. Analyze what is conspicuously missing from this codebase given the workflows it implements. Identify absent domain boundaries, validation layers, lifecycle management, authorization checks, observability, and recovery mechanisms. Distinguish genuine omissions from intentional simplicity. |
| 21 | Deeper | Find the semantic duplication. Identify places where the same business concept or decision is implemented multiple times using different code, names, data structures, or abstractions. Don't limit the search to syntactically similar code. Find duplicated meaning. |
| 22 | Deeper | Find the invariants nobody owns. Identify system-wide properties that must always remain true but are not enforced by any single component. Determine which modules collectively maintain them, how they can fail, and where enforcement should live. |
| 23 | Deeper | Find the code paths that have never been designed as a whole. Reconstruct complete user and business workflows across UI, API, services, persistence, background processing, and external integrations. Identify where locally reasonable implementations combine into globally incorrect behavior. |
| 24 | Deeper | Find the assumptions that will fail at 10× scale. Analyze how this system's behavior changes with 10× users, 10× data, 10× concurrency, and 10× external events. Focus on algorithmic behavior, contention, coordination, and operational assumptions rather than generic scaling advice. |