···11---
22name: code-writing
33-description: Enforces clean coding conventions for any implementation task. Covers guard clauses and early returns, happy-path left-alignment, pure functions separated from I/O, hexagonal architecture, error handling without panics, input validation at boundaries, parameterized queries, no hardcoded secrets, removing dead code, matching existing project patterns, and keeping functions small and single-responsibility. Use when writing new code, refactoring, fixing bugs, or reviewing code for quality.
33+description: >
44+ Enforces clean coding conventions for any implementation task. Covers guard
55+ clauses, extract method, pure functions, immutability, define errors out of
66+ existence, and interface comments before implementation. Use when writing,
77+ editing, fixing, implementing, or reviewing code at the function or file level.
88+ Do NOT use for API design, module boundaries, or service structure — use
99+ software-architecture instead.
410---
511612## Guard Clauses
···3945- MUST return on edge cases before the main work
4046- Good code reads top-to-bottom without jumping between branches
41474848+## Extract Method
4949+5050+Fowler, _Refactoring_: "Extract Method" when a fragment of code needs a name to
5151+explain its purpose, or when the fragment is too long to read at a glance.
5252+5353+- If a function does two things, split it.
5454+- If a block of code needs a comment to explain what it does, extract it into a
5555+ function whose name replaces the comment.
5656+- Small functions are easier to test, reuse, and reason about.
5757+5858+## Consolidate Conditional Expression
5959+6060+Fowler, _Refactoring_: "Consolidate Conditional Expression"
6161+6262+When a series of conditionals all produce the same result, combine them into a
6363+single conditional with a well-named function. The function name documents the
6464+intent.
6565+6666+BAD:
6767+6868+ if employee.seniority < 2 { return 0 }
6969+ if employee.monthsDisabled > 12 { return 0 }
7070+ if !employee.isPartTime { return 0 }
7171+7272+GOOD:
7373+7474+ if notEligibleForBonus(employee) { return 0 }
7575+7676+## Introduce Parameter Object
7777+7878+Fowler, _Refactoring_: "Introduce Parameter Object"
7979+8080+When a function has too many parameters, or a group of parameters naturally
8181+belong together, replace them with a single object. This reduces parameter count
8282+and makes the grouping explicit.
8383+4284## Pure Functions Preferred
43854486Evans, _Domain-Driven Design_: Domain logic should not depend on infrastructure.
···4688- SHOULD separate I/O from computation
4789- SHOULD push effects to function boundaries
4890- MUST NOT mix database calls, HTTP requests, or file I/O with business logic
4949- in the same function, because this makes the logic harder to test and reason
5050- about in isolation.
9191+ in the same function
9292+9393+## Immutability
9494+9595+Prefer immutable data. When a value does not change after construction, the
9696+reader can trust it forever. Mutable state forces the reader to track every
9797+assignment.
9898+9999+- SHOULD use const/readonly/final where possible
100100+- SHOULD return new values rather than modifying inputs
101101+- MUST NOT mutate shared state without explicit synchronization
102102+103103+## Variable Scope Minimization
104104+105105+Ousterhout, _A Philosophy of Software Design_: Reduce the scope of every
106106+variable to the smallest possible range. The fewer variables visible at any
107107+point, the less the reader must track.
108108+109109+- Declare variables as close to first use as possible
110110+- Prefer narrow scope over reuse across unrelated operations
111111+- A variable used in one block MUST NOT leak to the enclosing function
511125252-## I/O at Edges
113113+## Naming as Abstraction
531145454-Cockburn, Hexagonal Architecture: Core logic in the center, adapters at the edges.
115115+Ousterhout, _A Philosophy of Software Design_: A good name is an abstraction. If
116116+a name eliminates the need for a comment, it has done its job.
117117+118118+- Names MUST describe what, not how
119119+- If a name needs a comment to explain it, the name is wrong
120120+- Single-letter names are acceptable only for loop indices and math conventions
121121+122122+## Define Errors Out of Existence
123123+124124+Ousterhout, _A Philosophy of Software Design_: The best way to handle an
125125+exceptional condition is to redefine the problem so the condition cannot occur.
551265656-- **Edge layer**: handlers, CLI, HTTP - performs I/O, calls core
5757-- **Core layer**: pure functions, business rules - no I/O, testable in isolation
127127+- SHOULD design APIs where error cases are unrepresentable
128128+- MUST NOT propagate errors that could be eliminated by better design
129129+- SHOULD use sum types / enums instead of multiple dependent booleans
581305959-## Read Before Write
131131+## Interface Comments Before Implementation
601326161-MUST read a file before editing it. Blind edits create duplicates, miss context,
6262-and break subtle invariants.
133133+Ousterhout, _A Philosophy of Software Design_: Interface comments describe the
134134+abstraction — what it does and how to use it — NOT how it is implemented.
135135+136136+- MUST write interface comments before implementing the function
137137+- If a clean interface comment cannot be written, the design is likely wrong
138138+- Implementation comments MUST only appear when the code cannot express intent
6313964140## Error Handling
651416666-MUST NOT panic or crash on bad input, because panics bypass error handling and
6767-make recovery impossible. Return errors, validate boundaries, fail gracefully.
142142+MUST NOT panic or crash on bad input. Return errors, validate boundaries, fail
143143+gracefully.
6814469145## Security
7014671147- MUST validate inputs at system boundaries
7272-- MUST use parameterized queries - MUST NOT use string interpolation for SQL,
7373- because this creates SQL injection vulnerabilities.
7474-- MUST NOT hardcode secrets or credentials, because secrets in source code are
7575- leaked through version control and code sharing.
148148+- MUST use parameterized queries
149149+- MUST NOT hardcode secrets or credentials
7615077151## No Dead Code
781527979-MUST remove or complete incomplete code. Half-written branches and unused imports
8080-create confusion because readers cannot distinguish between intentional partial
8181-implementations and abandoned work.
153153+MUST remove or complete incomplete code. Half-written branches and unused
154154+imports create confusion.
8215583156## Familiar Code
841578585-MUST write code that is familiar to other writers of the codebase.
158158+MUST match the project's existing style. Reuse existing patterns. MUST NOT
159159+introduce novelty without reason.
861608787-- Reuse existing patterns
8888-- Match the project's style
8989-- MUST NOT introduce novelty without reason, because unfamiliar patterns slow
9090- down readers and increase maintenance burden.
161161+## Read Before Write
911629292-## Small Functions
9393-9494-MUST keep functions short and focused on a single responsibility. If a function
9595-does two things, split it.
163163+MUST read a file before editing it. Blind edits create duplicates and break
164164+subtle invariants.
···11---
22name: software-architecture
33description: >
44- Technical protocol for designing and refactoring non-trivial software. Focuses on the Impure-Pure-Impure sandwich, lifting I/O, and resource-aware orchestration. Use when the user asks to "design a component," "structure code," "refactor a service," or "handle side effects." Keywords: functional core, imperative shell, dependency rejection, deep modules, short-circuiting.
44+ Technical protocol for designing and structuring non-trivial software. Covers
55+ the impure-pure-impure sandwich, bounded contexts, event-driven patterns,
66+ dataflow modeling, and dependency rejection. Use when designing APIs, adding
77+ endpoints, defining module boundaries, structuring services, handling side
88+ effects, or deciding what should be public vs internal. Keywords: functional
99+ core, imperative shell, bounded context, event sourcing, CQRS, data pipeline,
1010+ idempotency, short-circuiting. Do NOT use for function-level code style or
1111+ refactoring within a single file — use code-writing instead.
512---
613714# Software Architecture Protocol
81599-This skill provides a systematic framework for managing complexity and side effects in software systems.
1616+This skill provides a systematic framework for managing complexity and side
1717+effects in software systems.
10181111-## 1. The "Impure-Pure-Impure" Sandwich Pattern
1919+## 0. Continuous Improvement
12201313-All non-trivial operations MUST follow this sequential workflow to isolate side effects from business logic.
2121+The goal of software architecture is to make the code more resilient to change
2222+over time. You MUST suggest architectural improvements even when you cannot
2323+implement them directly (e.g., out of scope for the current task, too large a
2424+change, or outside the current file).
2525+2626+- Flag architectural debt when you see it, even if you are only fixing a bug.
2727+- Suggest the ideal structure alongside the pragmatic fix.
2828+- Small improvements compound: a single well-placed extraction or boundary is
2929+ better than waiting for a perfect refactor.
3030+3131+## 1. Design Protocol
3232+3333+When approaching any architecture decision, follow this sequence:
3434+3535+1. **Identify the boundary.** What is public vs internal? Who calls this? What
3636+ does it depend on?
3737+2. **Gather constraints.** Latency requirements, consistency needs, failure
3838+ modes, team ownership.
3939+3. **Propose the simplest structure.** Start with a deep module: simple
4040+ interface, hidden complexity.
4141+4. **Check against patterns.** Does the impure-pure-impure sandwich apply? Are
4242+ bounded contexts clear? Is dataflow linear?
4343+5. **Flag what you cannot fix.** If the current structure violates these
4444+ principles, suggest the ideal alongside the pragmatic path.
4545+4646+## 2. The Impure-Pure-Impure Sandwich
4747+4848+All non-trivial operations MUST follow this sequential workflow to isolate side
4949+effects from business logic.
14501551### Workflow
16521717-1. **Gather (Impure Boundary):** Fetch all external state required for the decision.
1818- - _Examples:_ DB queries, API calls, reading system time, generating UUIDs.
1919-2. **Process (Functional Core):** Pass the gathered data into a pure function.
2020- - _Constraint:_ This function MUST be deterministic. It MUST NOT perform I/O or access global state. It MUST return data or a "Result" struct.
2121-3. **Commit (Impure Boundary):** Persist the output of the Functional Core.
2222- - _Examples:_ DB writes, sending HTTP responses, logging.
5353+1. **Gather (Impure Boundary):** Fetch all external state required for the
5454+ decision. Examples: DB queries, API calls, reading system time, generating
5555+ UUIDs.
5656+2. **Process (Functional Core):** Pass the gathered data into a pure function.
5757+ This function MUST be deterministic. It MUST NOT perform I/O or access global
5858+ state. It MUST return data or a Result struct.
5959+3. **Commit (Impure Boundary):** Persist the output of the Functional Core.
6060+ Examples: DB writes, sending HTTP responses, logging.
23612424-## 2. Resource-Aware Orchestration
6262+## 3. Bounded Contexts
25632626-Operations MUST be ordered to minimize the surface area of high-latency or locking operations.
6464+Evans, _Domain-Driven Design_: A bounded context is a boundary within which a
6565+particular model is defined and applicable.
27662828-- **Short-Circuiting:** Cheap local checks (logic/time guards) MUST occur before expensive remote checks (Network/API).
2929-- **Lock Minimization:** Database transactions (`WithTx`) SHOULD only wrap the final "Commit" phase.
3030-- **Dependency Rejection:** Business logic SHOULD accept raw data structures (e.g., `[]int`) rather than behavioral interfaces (e.g., `UserStore`) to avoid unnecessary "Interface Soup."
6767+- Each service or module MUST own its model. Shared models across boundaries
6868+ create coupling.
6969+- The same real-world concept (e.g., "Customer") can have different models in
7070+ different contexts. This is correct, not duplication.
7171+- Translation between contexts happens at the boundary, not in the core.
31723232-## 3. Structural Standards
7373+## 4. Dataflow and Pipelines
33743434-### Module Depth (Ousterhout's Principle)
7575+Kleppmann, _Designing Data-Intensive Applications_: Think of a system as a
7676+pipeline of data transformations, not as a collection of services calling each
7777+other.
35783636-- Modules MUST be "Deep": simple interfaces hiding significant internal complexity.
3737-- If an interface is as complex as its implementation, the abstraction SHOULD be removed (Compression-Oriented Design).
7979+- Each step transforms data and passes it to the next. The pipeline is the
8080+ architecture.
8181+- Idempotent operations allow safe retries and reprocessing. Design every
8282+ write operation to be idempotent where possible.
8383+- Derived data (caches, indexes, materialized views) should be reproducible
8484+ from the source of truth.
38853939-### State Integrity (Parse, Don't Validate)
8686+## 5. Event-Driven Patterns
40874141-- Invariants MUST be enforced via the type system (e.g., `NewUserID(string)` vs a raw `string`).
4242-- Invalid states SHOULD be unrepresentable. Use Enums/Sum types instead of multiple dependent Booleans.
8888+Kleppmann, _DDIA_ / Newman, _Building Microservices_: Events decouple producers
8989+from consumers in time and space.
43904444-## 4. Feedback Loop: Refactoring Pattern
9191+- Event sourcing: persist state changes as a sequence of immutable events. The
9292+ current state is a projection of the event log.
9393+- CQRS: separate read and write models when they have different scaling or
9494+ consistency requirements.
9595+- Consumers MUST NOT assume event ordering unless the system guarantees it.
9696+- Events describe what happened, not what to do. Commands describe what to do.
9797+9898+## 6. Resource-Aware Orchestration
9999+100100+Operations MUST be ordered to minimize the surface area of high-latency or
101101+locking operations.
102102+103103+- **Short-Circuiting:** Cheap local checks MUST occur before expensive remote
104104+ checks.
105105+- **Lock Minimization:** Database transactions SHOULD only wrap the final
106106+ commit phase.
107107+- **Dependency Rejection:** Business logic SHOULD accept raw data structures
108108+ rather than behavioral interfaces to avoid unnecessary coupling.
109109+110110+## 7. Structural Standards
111111+112112+### Information Hiding (Ousterhout)
113113+114114+The primary purpose of a module is to hide complexity. Design modules so that
115115+most of their knowledge is internal and invisible to callers. When information
116116+leaks across boundaries, every caller becomes coupled to implementation details.
117117+118118+### Deep Modules (Ousterhout)
119119+120120+Modules MUST be deep: simple interfaces hiding significant internal complexity.
121121+If an interface is as complex as its implementation, the abstraction SHOULD be
122122+removed.
123123+124124+### State Integrity
125125+126126+Invariants MUST be enforced via the type system. Invalid states SHOULD be
127127+unrepresentable.
128128+129129+### Compression-Oriented Design
130130+131131+Do not abstract prematurely. Extract a shared abstraction only after the second
132132+use case appears and the commonality is clear.
133133+134134+### Database Per Service
135135+136136+Newman, _Building Microservices_: Each service owns its data. No other service
137137+MUST access another service's database directly. Data sharing happens through
138138+APIs or events.
139139+140140+### API Backward Compatibility
141141+142142+Evolve APIs without breaking consumers. Additive changes only (new optional
143143+fields, new endpoints). Deprecation requires a migration window, not an
144144+immediate breaking change.
145145+146146+### Resilience Patterns
147147+148148+Kleppmann, _DDIA_: Services fail. The system must survive.
149149+150150+- Circuit breaker: stop calling a failing service after repeated failures.
151151+- Retry with backoff: transient failures are normal, but retry storms are not.
152152+- Bulkhead isolation: isolate components so failure in one does not cascade.
153153+154154+## 8. Feedback Loop: Refactoring Pattern
4515546156When refactoring existing code to this standard:
471574848-1. **Identify Side Effects:** Find all hidden I/O (e.g., `time.Now()`, `db.Get`).
4949-2. **Lift I/O:** Move those calls to the caller or the entry point of the function.
5050-3. **Purify:** Convert the remaining logic into a pure function that accepts the lifted data as parameters.
5151-4. **Verify:** The core logic MUST be unit-testable without a mocking framework.
158158+1. **Identify Side Effects:** Find all hidden I/O (e.g., `time.Now()`,
159159+ `db.Get`).
160160+2. **Lift I/O:** Move those calls to the caller or the entry point of the
161161+ function.
162162+3. **Purify:** Convert the remaining logic into a pure function that accepts
163163+ the lifted data as parameters.
164164+4. **Verify:** The core logic MUST be unit-testable without a mocking framework.
5216553166---
5416755168## Validation Checklist
5616957170- [ ] **Sandwich:** Is there a clear line where I/O ends and logic begins?
5858-- [ ] **Purity:** Does any business logic function take a `Context` or an interface that performs I/O? (It shouldn't).
5959-- [ ] **Ordering:** Are network calls happening inside a database transaction? (They shouldn't).
6060-- [ ] **Guard Clauses:** Is the code calling an external API before checking simple local requirements?
6161-- [ ] **Types:** Are we using primitives where a domain-specific type could prevent a bug?
171171+- [ ] **Purity:** Does any business logic function take a Context or an
172172+ interface that performs I/O? (It shouldn't.)
173173+- [ ] **Ordering:** Are network calls happening inside a database transaction?
174174+ (They shouldn't.)
175175+- [ ] **Boundaries:** Does each module own its model, or is there a shared
176176+ model leaking across contexts?
177177+- [ ] **Idempotency:** Can writes be safely retried?
178178+- [ ] **Depth:** Is the module deep, or is it a pass-through adding no
179179+ abstraction?
180180+- [ ] **Types:** Are we using primitives where a domain-specific type could
181181+ prevent a bug?
62182- [ ] **Mocks:** Can this logic be tested with simple value assertions?