Skip to content
Back to skills

Incremental Implementation

ASecurity

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.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 3, 2026
ai-agentstypescriptgotestingrefactoringgitapidatabasefrontendbackend

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 2, 2026

npx -y skills add Ghosteken/agent-harness --skill incremental-implementation --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Incremental Implementation?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Incremental Implementation
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ghosteken-incremental-implementation/badge)](https://www.skillsdirectory.com/skills/ghosteken-incremental-implementation)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: incremental-implementation
description: 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.
---

# Incremental Implementation

## Overview

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.

## When to Use

- Implementing any multi-file change
- Building a new feature from a task breakdown
- Refactoring existing code
- Any time you're tempted to write more than ~100 lines before testing

**When NOT to use:** Single-file, single-function changes where the scope is already minimal.

## Before You Start: Branch Setup

Before any implementation begins, use the `AskUserQuestion` tool to confirm branch setup — never create a branch silently, even when the answer seems obvious.

1. Check whether `dev` exists (locally or on the remote). If it does, fetch and pull it to make sure it's current *before* branching from it — a feature branch cut from a stale local `dev` silently misses whatever's landed since.
2. Ask via `AskUserQuestion`:
   - If `dev` exists: propose creating a feature branch from `dev` (pulled to latest) — confirm before creating it, don't assume yes.
   - If `dev` doesn't exist: say so explicitly in the same ask ("`dev` branch not found") and ask which branch to use instead, rather than guessing `main` or any other default.
3. Create the feature branch only after that confirmation comes back.

**Never run `git commit` when the work is done** — this applies to the whole increment cycle below, not just the branch-setup step. Draft commit messages and propose them; leave the actual commit to the user unless they've explicitly asked you to commit in that session.

## The Increment Cycle

```
┌────────────────────────────────────────────┐
│                                            │
│   Implement ──→ Test ──→ Verify ──┐        │
│       ▲                           │        │
│       └───── Propose commit ◄─────┘        │
│              │                             │
│              ▼                             │
│   More slices? ──yes──→ Next slice         │
│              │                             │
│              no                            │
│              ▼                             │
│   Run quality-assurance (mandatory,        │
│   not a checkbox) ──→ THEN task is done    │
│                                            │
└────────────────────────────────────────────┘
```

For each slice:

1. **Implement** the smallest complete piece of functionality
2. **Test** — every slice gets a unit test, not just slices that "need" one; if the slice has real core logic (a calculation, a state transition, a validation rule), the test must assert its actual expected behavior, not just that it runs without error (see `test-driven-development`'s core-component coverage) — that's what catches a regression later, not just now. That coverage must span every scenario type that genuinely applies to the slice's core logic — happy path, edge cases (boundary/empty/null/optional-absent), error handling (invalid/malformed input), and fix/regression confirmation when the slice exists to fix something — not just whichever one was fastest to write. Run the full suite alongside it.
3. **Verify** — confirm the slice works as expected (unit tests pass, build succeeds, manual check)
4. **Propose a commit** — draft a descriptive message and tell the user the slice is ready (see `git-workflow-and-versioning` for atomic commit guidance). **Never run `git commit` yourself** — leave the actual commit to the user unless they've explicitly asked you to commit in this session.
5. **Move to the next slice** — carry forward, don't restart, and don't wait for the commit to happen first

**When the last slice for this task is done — stop. Before saying the task is complete, actually invoke the `quality-assurance` skill against the spec, and it must be genuinely live — a real server, real database, real authenticated user — not mocked tests or a suite that merely happens to be named "e2e."** This is a mandatory action to take, not a box to mentally check off afterward: in practice, agents following this skill have skipped straight to declaring the task done with unit tests passing, and only run `quality-assurance` when the user notices and asks for it — and even then, have substituted mocked/unit-level tests for live verification without saying so. Don't let either be the trigger — run `quality-assurance` live yourself, unprompted, as the actual last step of the cycle. If full live verification is tedious to set up, `quality-assurance`'s own graduated fallback applies (a lighter live check via curl/CLI or an automated test against the real dev server, offered via `AskUserQuestion`) — never downgrade straight to mocks on your own.

## Slicing Strategies

### Vertical Slices (Preferred)

Build one complete path through the stack:

```
Slice 1: Create a task (DB + API + basic UI)
    → Tests pass, user can create a task via the UI

Slice 2: List tasks (query + API + UI)
    → Tests pass, user can see their tasks

Slice 3: Edit a task (update + API + UI)
    → Tests pass, user can modify tasks

Slice 4: Delete a task (delete + API + UI + confirmation)
    → Tests pass, full CRUD complete
```

Each slice delivers working end-to-end functionality.

### Contract-First Slicing

When backend and frontend need to develop in parallel:

```
Slice 0: Define the API contract (types, interfaces, OpenAPI spec)
Slice 1a: Implement backend against the contract + API tests
Slice 1b: Implement frontend against mock data matching the contract
Slice 2: Integrate and test end-to-end
```

### Risk-First Slicing

Tackle the riskiest or most uncertain piece first:

```
Slice 1: Prove the WebSocket connection works (highest risk)
Slice 2: Build real-time task updates on the proven connection
Slice 3: Add offline support and reconnection
```

If Slice 1 fails, you discover it before investing in Slices 2 and 3.

## Implementation Rules

### Rule 0: Simplicity First

Before writing any code, ask: "What is the simplest thing that could work?"

After writing code, review it against these checks:
- Can this be done in fewer lines?
- Are these abstractions earning their complexity?
- Would a staff engineer look at this and say "why didn't you just..."?
- Am I building for hypothetical future requirements, or the current task?

```
SIMPLICITY CHECK:
✗ Generic EventBus with middleware pipeline for one notification
✓ Simple function call

✗ Abstract factory pattern for two similar components
✓ Two straightforward components with shared utilities

✗ Config-driven form builder for three forms
✓ Three form components
```

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.

### Rule 0.5: Scope Discipline

Touch only what the task requires.

Do NOT:
- "Clean up" code adjacent to your change
- Refactor imports in files you're not modifying
- Remove comments you don't fully understand
- Add features not in the spec because they "seem useful"
- Modernize syntax in files you're only reading

If you notice something worth improving outside your task scope, note it — don't fix it:

```
NOTICED BUT NOT TOUCHING:
- src/utils/format.ts has an unused import (unrelated to this task)
- The auth middleware could use better error messages (separate task)
→ Want me to create tasks for these?
```

### Rule 1: One Thing at a Time

Each increment changes one logical thing. Don't mix concerns:

**Bad:** One proposed commit that adds a new component, refactors an existing one, and updates the build config.

**Good:** Three separately proposed commits — one for each change (the user runs them, or asks you to).

### Rule 2: Keep It Compilable

After each increment, the project must build and existing tests must pass. Don't leave the codebase in a broken state between slices.

### Rule 3: Feature Flags for Incomplete Features

If a feature isn't ready for users but you need to merge increments:

```typescript
// Feature flag for work-in-progress
const ENABLE_TASK_SHARING = process.env.FEATURE_TASK_SHARING === 'true';

if (ENABLE_TASK_SHARING) {
  // New sharing UI
}
```

This lets you merge small increments to the main branch without exposing incomplete work.

### Rule 4: Safe Defaults

New code should default to safe, conservative behavior:

```typescript
// Safe: disabled by default, opt-in
export function createTask(data: TaskInput, options?: { notify?: boolean }) {
  const shouldNotify = options?.notify ?? false;
  // ...
}
```

### Rule 5: Rollback-Friendly

Each increment should be independently revertable:

- Additive changes (new files, new functions) are easy to revert
- Modifications to existing code should be minimal and focused
- Database migrations should have corresponding rollback migrations
- Avoid deleting something in one commit and replacing it in the same commit — separate them

## Working with Agents

When directing an agent to implement incrementally:

```
"Let's implement Task 3 from the plan.

Start with just the database schema change and the API endpoint.
Don't touch the UI yet — we'll do that in the next increment.

After implementing, run `npm test` and `npm run build` to verify
nothing is broken."
```

Be explicit about what's in scope and what's NOT in scope for each increment.

## Increment Checklist

After each increment, verify:

- [ ] The change does one thing and does it completely
- [ ] A unit test was added for this increment's new logic
- [ ] All existing tests still pass (`npm test`)
- [ ] The build succeeds (`npm run build`)
- [ ] Type checking passes (`npx tsc --noEmit`)
- [ ] Linting passes (`npm run lint`)
- [ ] The new functionality works as expected
- [ ] A descriptive commit message has been proposed for the change (do not run `git commit` yourself — leave it to the user unless they've explicitly asked you to commit)

**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.

## Common Rationalizations

| Rationalization | Reality |
|---|---|
| "I'll test it all at the end" | Bugs compound. A bug in Slice 1 makes Slices 2-5 wrong. Test each slice. |
| "This slice is too trivial for a unit test" | Trivial slices are where regressions hide longest — no one re-checks something assumed too simple to break. |
| "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. |
| "These changes are too small to commit separately" | Small commits are free. Large commits hide bugs and make rollbacks painful — propose them as separate commits even though the user runs the actual `git commit`. |
| "I'll add the feature flag later" | If the feature isn't complete, it shouldn't be user-visible. Add the flag now. |
| "This refactor is small enough to include" | Refactors mixed with features make both harder to review and debug. Separate them. |
| "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. |
| "All the unit tests pass, so the feature works" | Unit tests confirm the code does what the code does — they don't confirm it does what the spec asked for. Run `quality-assurance` for that. |
| "I'll just branch from dev without asking, it's the obvious choice" | Ask anyway — confirming before creating a branch costs one question and prevents working on the wrong base entirely. |
| "dev doesn't exist, I'll just use main" | Guessing a fallback base branch silently can put the feature on the wrong branch structure for this project — ask which branch to use instead. |
| "I tested that this slice rejects bad input, it's covered" | That's one scenario type. A slice's core logic needs happy path, edge cases, error handling, and fix/regression confirmation covered together, as each genuinely applies — not just whichever was fastest to write. |

## Red Flags

- More than 100 lines of code written without running tests
- Multiple unrelated changes in a single increment
- "Let me just quickly add this too" scope expansion
- Skipping the test/verify step to move faster
- Build or tests broken between increments
- Large uncommitted changes accumulating
- Building abstractions before the third use case demands it
- Touching files outside the task scope "while I'm here"
- Creating new utility files for one-time operations
- Running the same build/test command twice in a row without any intervening code change
- Running `git commit` yourself without the user explicitly asking you to in that session
- The feature declared done once unit tests pass, without running `quality-assurance` against the spec
- `quality-assurance` run against mocks or a suite merely named "e2e", reported as if it were genuinely live verification
- A slice's core-logic test covering only one scenario type (e.g. only error/rejection handling) when happy path, edge cases, or fix confirmation genuinely applied too
- A feature branch created without asking first, or without pulling `dev` to latest before branching from it
- `dev` missing and a fallback branch picked silently instead of asked about

## Verification

Before starting:

- [ ] Branch setup was confirmed via `AskUserQuestion` before any implementation began — not assumed
- [ ] If `dev` existed, it was pulled to latest before the feature branch was created from it
- [ ] If `dev` didn't exist, that was stated explicitly and an alternative base branch was asked for, not guessed

After completing all increments for a task:

- [ ] Each increment was individually tested (a unit test was added, not just an existing-suite check) and left with a proposed commit message
- [ ] Each slice's core-logic test covers every scenario type that genuinely applies (happy path, edge cases, error handling, fix/regression confirmation) — not just the one type that was fastest to check
- [ ] The full test suite passes
- [ ] The build is clean
- [ ] The feature works end-to-end as specified — run the `quality-assurance` skill *live* (real server, real database, real authenticated user) against the spec/acceptance criteria to confirm this with real evidence, not just unit tests passing and not mocks substituted for live verification
- [ ] No unreviewed changes remain — the user has a summary and a proposed commit message for each increment; committing is theirs to do (or explicitly delegated to you)

## See Also

- `quality-assurance` — the live/end-to-end check once all increments are complete; unit tests alone don't confirm the feature works against the spec
- `references/coding-patterns.md` — structural patterns to apply while implementing each slice (clear main path, external systems behind a boundary, unrepresentable invalid states, decisions separated from actions, useful errors)
- `review-findings.md` at the project's external output location (see `references/external-output-paths.md`) — check it before starting a task, if it exists; it's a running log of patterns code review has already flagged in this project, and repeating one is avoidable

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…