byaddyosmani· 31 skills
Delivers changes incrementally. Use when implementing any feature or change that touches more than one file. Use when you're about to write a large amount of code at once, or when a task feels too big to land in one step.
$npx -y skills add addyosmani/agent-skills --skill incremental-implementationInstalls into the current project.
Run `npx skills use "https://github.com/addyosmani/agent-skills" --skill "addyosmani/agent-skills/incremental-implementation"` and follow the generated skill instructions now. Read its complete output, redirecting it to a temporary file first if necessary. Resolve relative paths from the supporting-files directory it provides.
Use the skills in "https://github.com/addyosmani/agent-skills" that are relevant to the current task. Run `npx skills add "https://github.com/addyosmani/agent-skills"` and select the relevant skills, then follow their instructions.
| 1 | # Incremental Implementation |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Build in thin vertical slices — implement one piece, test it, verify it, then expand. Avoid implementing an entire feature in one pass. Each increment should leave the system in a working, testable state. This is the execution discipline that makes large features manageable. |
| 6 | |
| 7 | ## When to Use |
| 8 | |
| 9 | - Implementing any multi-file change |
| 10 | - Building a new feature from a task breakdown |
| 11 | - Refactoring existing code |
| 12 | - Any time you're tempted to write more than ~100 lines before testing |
| 13 | |
| 14 | **When NOT to use:** Single-file, single-function changes where the scope is already minimal. |
| 15 | |
| 16 | ## The Increment Cycle |
| 17 | |
| 18 | ``` |
| 19 | ┌──────────────────────────────────────┐ |
| 20 | │ │ |
| 21 | │ Implement ──→ Test ──→ Verify ──┐ │ |
| 22 | │ ▲ │ │ |
| 23 | │ └───── Commit ◄─────────────┘ │ |
| 24 | │ │ │ |
| 25 | │ ▼ │ |
| 26 | │ Next slice │ |
| 27 | │ │ |
| 28 | └──────────────────────────────────────┘ |
| 29 | ``` |
| 30 | |
| 31 | For each slice: |
| 32 | |
| 33 | 1. **Implement** the smallest complete piece of functionality |
| 34 | 2. **Test** — run the test suite (or write a test if none exists) |
| 35 | 3. **Verify** — confirm the slice works as expected (tests pass, build succeeds, manual check) |
| 36 | 4. **Commit** -- save your progress with a descriptive message (see `git-workflow-and-versioning` for atomic commit guidance) |
| 37 | 5. **Move to the next slice** — carry forward, don't restart |
| 38 | |
| 39 | ## Slicing Strategies |
| 40 | |
| 41 | ### Vertical Slices (Preferred) |
| 42 | |
| 43 | Build one complete path through the stack: |
| 44 | |
| 45 | ``` |
| 46 | Slice 1: Create a task (DB + API + basic UI) |
| 47 | → Tests pass, user can create a task via the UI |
| 48 | |
| 49 | Slice 2: List tasks (query + API + UI) |
| 50 | → Tests pass, user can see their tasks |
| 51 | |
| 52 | Slice 3: Edit a task (update + API + UI) |
| 53 | → Tests pass, user can modify tasks |
| 54 | |
| 55 | Slice 4: Delete a task (delete + API + UI + confirmation) |
| 56 | → Tests pass, full CRUD complete |
| 57 | ``` |
| 58 | |
| 59 | Each slice delivers working end-to-end functionality. |
| 60 | |
| 61 | ### Contract-First Slicing |
| 62 | |
| 63 | When backend and frontend need to develop in parallel: |
| 64 | |
| 65 | ``` |
| 66 | Slice 0: Define the API contract (types, interfaces, OpenAPI spec) |
| 67 | Slice 1a: Implement backend against the contract + API tests |
| 68 | Slice 1b: Implement frontend against mock data matching the contract |
| 69 | Slice 2: Integrate and test end-to-end |
| 70 | ``` |
| 71 | |
| 72 | ### Risk-First Slicing |
| 73 | |
| 74 | Tackle the riskiest or most uncertain piece first: |
| 75 | |
| 76 | ``` |
| 77 | Slice 1: Prove the WebSocket connection works (highest risk) |
| 78 | Slice 2: Build real-time task updates on the proven connection |
| 79 | Slice 3: Add offline support and reconnection |
| 80 | ``` |
| 81 | |
| 82 | If Slice 1 fails, you discover it before investing in Slices 2 and 3. |
| 83 | |
| 84 | ## Implementation Rules |
| 85 | |
| 86 | ### Rule 0: Simplicity First |
| 87 | |
| 88 | Before writing any code, ask: "What is the simplest thing that could work?" |
| 89 | |
| 90 | After writing code, review it against these checks: |
| 91 | - Can this be done in fewer lines? |
| 92 | - Are these abstractions earning their complexity? |
| 93 | - Would a staff engineer look at this and say "why didn't you just..."? |
| 94 | - Am I building for hypothetical future requirements, or the current task? |
| 95 | |
| 96 | ``` |
| 97 | SIMPLICITY CHECK: |
| 98 | ✗ Generic EventBus with middleware pipeline for one notification |
| 99 | ✓ Simple function call |
| 100 | |
| 101 | ✗ Abstract factory pattern for two similar components |
| 102 | ✓ Two straightforward components with shared utilities |
| 103 | |
| 104 | ✗ Config-driven form builder for three forms |
| 105 | ✓ Three form components |
| 106 | ``` |
| 107 | |
| 108 | Three similar lines of code is better than a premature abstraction. Implement the naive, obviously-correct version first. Optimize only after correctness is proven with tests. |
| 109 | |
| 110 | ### Rule 0.5: Scope Discipline |
| 111 | |
| 112 | Touch only what the task requires. |
| 113 | |
| 114 | Do NOT: |
| 115 | - "Clean up" code adjacent to your change |
| 116 | - Refactor imports in files you're not modifying |
| 117 | - Remove comments you don't fully understand |
| 118 | - Add features not in the spec because they "seem useful" |
| 119 | - Modernize syntax in files you're only reading |
| 120 | |
| 121 | If you notice something worth improving outside your task scope, note it — don't fix it: |
| 122 | |
| 123 | ``` |
| 124 | NOTICED BUT NOT TOUCHING: |
| 125 | - src/utils/format.ts has an unused import (unrelated to this task) |
| 126 | - The auth middleware could use better error messages (separate task) |
| 127 | → Want me to create tasks for these? |
| 128 | ``` |
| 129 | |
| 130 | ### Rule 1: One Thing at a Time |
| 131 | |
| 132 | Each increment changes one logical thing. Don't mix concerns: |
| 133 | |
| 134 | **Bad:** One commit that adds a new component, refactors an existing one, and updates the build config. |
| 135 | |
| 136 | **Good:** Three separate commits — one for each change. |
| 137 | |
| 138 | ### Rule 2: Keep It Compilable |
| 139 | |
| 140 | After each increment, the project must build and existing tests must pass. Don't leave the codebase in a broken state between slices. |
| 141 | |
| 142 | ### Rule 3: Feature Flags for Incomplete Features |
| 143 | |
| 144 | If a feature isn't ready for users but you need to merge increments: |
| 145 | |
| 146 | ```typescript |
| 147 | // Feature flag for work-in-progress |
| 148 | const ENABLE_TASK_SHARING = process.env.FEATURE_TASK_SHARING === 'true'; |
| 149 | |
| 150 | if (ENABLE_TASK_SHARING) { |
| 151 | // New sharing UI |
| 152 | } |
| 153 | ``` |
| 154 | |
| 155 | This lets you merge small increments to the main branch without exposing incomplete work. |
| 156 | |
| 157 | ### Rule 4: Safe Defaults |
| 158 | |
| 159 | New code should default to safe, conservative behavior: |
| 160 | |
| 161 | ```typescript |
| 162 | // Safe: disabled by default, opt-in |
| 163 | export function createTask(data: TaskInput, options?: { notify?: boolean }) { |
| 164 | const shouldNotify = options?.notify ?? false; |
| 165 | // ... |
| 166 | } |
| 167 | ``` |
| 168 | |
| 169 | ### Rule 5: Rollback-Friendly |
| 170 | |
| 171 | Each increment should be independently revertable: |
| 172 | |
| 173 | - Additive changes (new files, new functions) are easy to revert |
| 174 | - Modifications to existing code should be minimal and focused |
| 175 | - Database migrations should have corresponding rollback migrations |
| 176 | - Avoid deleting something in one commit and replacing it in the same commit — separate them |
| 177 | |
| 178 | ## Working with Agents |
| 179 | |
| 180 | When directing an agent to implement incrementally: |
| 181 | |
| 182 | ``` |
| 183 | "Let's implement Task 3 from the plan. |
| 184 | |
| 185 | Start with just the database schema change and the API endpoint. |
| 186 | Don't touch the UI yet — we'll do that in the next increment. |
| 187 | |
| 188 | After implementing, run the repository's test and build commands to |
| 189 | verify nothing is broken." |
| 190 | ``` |
| 191 | |
| 192 | Be explicit about what's in scope and what's NOT in scope for each increment. |
| 193 | |
| 194 | ## Increment Checklist |
| 195 | |
| 196 | After each increment, verify with the repository's own commands (see the test-driven-development skill's Discover the Stack First section): |
| 197 | |
| 198 | - [ ] The change does one thing and does it completely |
| 199 | - [ ] All existing tests still pass (the repository's test command: `npm test`, `./gradlew test`, `pytest`, ...) |
| 200 | - [ ] The build succeeds (the repository's build command) |
| 201 | - [ ] Type checking passes, where the stack has one (`npx tsc --noEmit`, `mypy`, ...) |
| 202 | - [ ] Linting passes (the repository's lint command) |
| 203 | - [ ] The new functionality works as expected |
| 204 | - [ ] The change is committed with a descriptive message |
| 205 | |
| 206 | **Note:** Run each verification command after a change that could affect it. After a successful run, don't repeat the same command unless the code has changed since — re-running on unchanged code adds no information. |
| 207 | |
| 208 | ## Common Rationalizations |
| 209 | |
| 210 | | Rationalization | Reality | |
| 211 | |---|---| |
| 212 | | "I'll test it all at the end" | Bugs compound. A bug in Slice 1 makes Slices 2-5 wrong. Test each slice. | |
| 213 | | "It's faster to do it all at once" | It *feels* faster until something breaks and you can't find which of 500 changed lines caused it. | |
| 214 | | "These changes are too small to commit separately" | Small commits are free. Large commits hide bugs and make rollbacks painful. | |
| 215 | | "I'll add the feature flag later" | If the feature isn't complete, it shouldn't be user-visible. Add the flag now. | |
| 216 | | "This refactor is small enough to include" | Refactors mixed with features make both harder to review and debug. Separate them. | |
| 217 | | "Let me run the build command again just to be sure" | After a successful run, repeating the same command adds nothing unless the code has changed since. Run it again after subsequent edits, not as reassurance. | |
| 218 | |
| 219 | ## Red Flags |
| 220 | |
| 221 | - More than 100 lines of code written without running tests |
| 222 | - Multiple unrelated changes in a single increment |
| 223 | - "Let me just quickly add this too" scope expansion |
| 224 | - Skipping the test/verify step to move faster |
| 225 | - Build or tests broken between increments |
| 226 | - Large uncommitted changes accumulating |
| 227 | - Building abstractions before the third use case demands it |
| 228 | - Touching files outside the task scope "while I'm here" |
| 229 | - Creating new utility files for one-time operations |
| 230 | - Running the same build/test command twice in a row without any intervening code change |
| 231 | |
| 232 | ## Verification |
| 233 | |
| 234 | After completing all increments for a task: |
| 235 | |
| 236 | - [ ] Each increment was individually tested and committed |
| 237 | - [ ] The full test suite passes |
| 238 | - [ ] The build is clean |
| 239 | - [ ] The feature works end-to-end as specified |
| 240 | - [ ] No uncommitted changes remain |
| 241 | |
| 242 | ## See Also |
| 243 | |
| 244 | Per-increment verification is the local check. Before declaring a task done, apply the project-wide Definition of Done as the final gate, the standing bar every increment clears regardless of the task. See `references/definition-of-done.md`. |