
Improve Codebase Architecture
Guide refactoring shallow modules into deep modules with ports, adapters, and boundary tests so solo builders can simplify architecture without losing coverage.
Install
npx skills add https://github.com/mattpocock/ai-engineer-workshop-2026-project --skill improve-codebase-architectureWhat is this skill?
- 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
Adoption & trust: 33 installs on skills.sh; 146 GitHub stars; 3/3 security scanners passed (skills.sh audits).
Recommended Skills
Journey fit
Canonical shelf is Build → backend because deepening modules and merging boundaries is primarily an implementation-time architecture change. Backend subphase covers service layers, dependency injection, and module boundaries where ports-and-adapters guidance applies most directly.
Common Questions / 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.
SKILL.md
READMESKILL.md - Improve Codebase Architecture
# 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> --- name: improve-codebase-architecture description: Explore a codebase to find opportunities for architectural improvement, focusing on making the codebase more testable by deepening shallow modules. Use when user wants to improve architecture, find refactoring opportunities, consolidate tightly-coupled modules, or make a codebase more AI-navigable. --- # 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 under