
Improve Codebase Architecture
- 86 installs
- 193 repo stars
- Updated April 1, 2026
- mattpocock/ai-engineer-workshop-2026-project
Guide refactoring shallow modules into deep modules with ports, adapters, and boundary tests so developers can simplify architecture without losing coverage.
About
improve-codebase-architecture is a workshop-style agent skill that teaches solo builders how to deepen codebase structure instead of stacking thin wrappers. It classifies dependencies into in-process computation, local test substitutes such as PGLite, owned remote services that deserve a port at the boundary, and true externals that should be mocked. The testing strategy is blunt and practical: once interface-level boundary tests cover behavior, remove redundant shallow unit tests rather than maintaining duplicate suites. For indie SaaS and API projects, the skill pushes one deep module owning business logic with production HTTP or gRPC adapters and in-memory adapters in CI. Use it when a feature folder has grown into spaghetti adapters, when microservice calls obscure domain rules, or before a major refactor where you need a consistent rule for what to merge versus what to inject. It pairs naturally with code review and ship-phase hardening because the output is clearer modules and tests that assert observable outcomes at real seams.
- Four dependency categories: in-process, local-substitutable, remote-but-owned, true external
- Ports-and-adapters pattern for owned microservices with in-memory test adapters
- Replace-don't-layer testing: delete shallow unit tests after boundary tests exist
- Mock injected ports for third-party APIs like Stripe or Twilio
- Explicit recommendation shapes for HTTP vs in-memory adapters at module edges
Improve Codebase Architecture by the numbers
- 86 all-time installs (skills.sh)
- Ranked #473 of 1,382 Code Review & Quality skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mattpocock/ai-engineer-workshop-2026-project --skill improve-codebase-architectureAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 86 |
|---|---|
| repo stars | ★ 193 |
| Security audit | 3 / 3 scanners passed |
| Last updated | April 1, 2026 |
| Repository | mattpocock/ai-engineer-workshop-2026-project ↗ |
What it does
Guide refactoring shallow modules into deep modules with ports, adapters, and boundary tests so developers can simplify architecture without losing coverage.
Files
Improve Codebase Architecture
Explore a codebase like an AI would, surface architectural friction, discover opportunities for improving testability, and propose module-deepening refactors as GitHub issue RFCs.
A deep module (John Ousterhout, "A Philosophy of Software Design") has a small interface hiding a large implementation. Deep modules are more testable, more AI-navigable, and let you test at the boundary instead of inside.
Process
1. Explore the codebase
Use the Agent tool with subagent_type=Explore to navigate the codebase naturally. Do NOT follow rigid heuristics — explore organically and note where you experience friction:
- Where does understanding one concept require bouncing between many small files?
- Where are modules so shallow that the interface is nearly as complex as the implementation?
- Where have pure functions been extracted just for testability, but the real bugs hide in how they're called?
- Where do tightly-coupled modules create integration risk in the seams between them?
- Which parts of the codebase are untested, or hard to test?
The friction you encounter IS the signal.
2. Present candidates
Present a numbered list of deepening opportunities. For each candidate, show:
- Cluster: Which modules/concepts are involved
- Why they're coupled: Shared types, call patterns, co-ownership of a concept
- Dependency category: See REFERENCE.md for the four categories
- Test impact: What existing tests would be replaced by boundary tests
Do NOT propose interfaces yet. Ask the user: "Which of these would you like to explore?"
3. User picks a candidate
4. Frame the problem space
Before spawning sub-agents, write a user-facing explanation of the problem space for the chosen candidate:
- The constraints any new interface would need to satisfy
- The dependencies it would need to rely on
- A rough illustrative code sketch to make the constraints concrete — this is not a proposal, just a way to ground the constraints
Show this to the user, then immediately proceed to Step 5. The user reads and thinks about the problem while the sub-agents work in parallel.
5. Design multiple interfaces
Spawn 3+ sub-agents in parallel using the Agent tool. Each must produce a radically different interface for the deepened module.
Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category, what's being hidden). This brief is independent of the user-facing explanation in Step 4. Give each agent a different design constraint:
- Agent 1: "Minimize the interface — aim for 1-3 entry points max"
- Agent 2: "Maximize flexibility — support many use cases and extension"
- Agent 3: "Optimize for the most common caller — make the default case trivial"
- Agent 4 (if applicable): "Design around the ports & adapters pattern for cross-boundary dependencies"
Each sub-agent outputs:
1. Interface signature (types, methods, params) 2. Usage example showing how callers use it 3. What complexity it hides internally 4. Dependency strategy (how deps are handled — see REFERENCE.md) 5. Trade-offs
Present designs sequentially, then compare them in prose.
After comparing, give your own recommendation: which design you think is strongest and why. If elements from different designs would combine well, propose a hybrid. Be opinionated — the user wants a strong read, not just a menu.
6. User picks an interface (or accepts recommendation)
7. Write issue file
Write the refactor RFC as a local markdown file in issues/ using the template in REFERENCE.md. Do NOT ask the user to review before writing — just write it and share the path.
Reference
Dependency Categories
When assessing a candidate for deepening, classify its dependencies:
1. In-process
Pure computation, in-memory state, no I/O. Always deepenable — just merge the modules and test directly.
2. Local-substitutable
Dependencies that have local test stand-ins (e.g., PGLite for Postgres, in-memory filesystem). Deepenable if the test substitute exists. The deepened module is tested with the local stand-in running in the test suite.
3. Remote but owned (Ports & Adapters)
Your own services across a network boundary (microservices, internal APIs). Define a port (interface) at the module boundary. The deep module owns the logic; the transport is injected. Tests use an in-memory adapter. Production uses the real HTTP/gRPC/queue adapter.
Recommendation shape: "Define a shared interface (port), implement an HTTP adapter for production and an in-memory adapter for testing, so the logic can be tested as one deep module even though it's deployed across a network boundary."
4. True external (Mock)
Third-party services (Stripe, Twilio, etc.) you don't control. Mock at the boundary. The deepened module takes the external dependency as an injected port, and tests provide a mock implementation.
Testing Strategy
The core principle: replace, don't layer.
- Old unit tests on shallow modules are waste once boundary tests exist — delete them
- Write new tests at the deepened module's interface boundary
- Tests assert on observable outcomes through the public interface, not internal state
- Tests should survive internal refactors — they describe behavior, not implementation
Issue Template
<issue-template>
Problem
Describe the architectural friction:
- Which modules are shallow and tightly coupled
- What integration risk exists in the seams between them
- Why this makes the codebase harder to navigate and maintain
Proposed Interface
The chosen interface design:
- Interface signature (types, methods, params)
- Usage example showing how callers use it
- What complexity it hides internally
Dependency Strategy
Which category applies and how dependencies are handled:
- In-process: merged directly
- Local-substitutable: tested with [specific stand-in]
- Ports & adapters: port definition, production adapter, test adapter
- Mock: mock boundary for external services
Testing Strategy
- New boundary tests to write: describe the behaviors to verify at the interface
- Old tests to delete: list the shallow module tests that become redundant
- Test environment needs: any local stand-ins or adapters required
Implementation Recommendations
Durable architectural guidance that is NOT coupled to current file paths:
- What the module should own (responsibilities)
- What it should hide (implementation details)
- What it should expose (the interface contract)
- How callers should migrate to the new interface
</issue-template>
Related skills
FAQ
Is Improve Codebase Architecture safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.