← Writing Build log

Building a feature bank: from idea to shipped

How I capture half-formed ideas in chat and turn them into ADRs, specs, designs, and shipped features without polluting my decision log or trusting stale notes.

Where does an idea go when you cannot build it yet?

the mechanism
chat → ideas/0142.md · no ADR yet
idea → ADR → spec → design · each a file, each gated
merge → changelog/vX.Y.md · the decision log never lied
  1. 01 of 03

    Captured, not decided

    An idea arrives mid-conversation with no capacity to act on it. It is written down as an idea, against the system as it is, and nothing is decided.

  2. 02 of 03

    Promoted when ready

    When the ground is firm the idea becomes a decision record, then a spec, then a design, each a file with its own gate.

  3. 03 of 03

    Shipped, and the log stays clean

    The decision log only ever holds decisions that were made, and the notes it was built from never had to be trusted stale.


Ideas never arrive when you’re ready to build them. They show up mid-conversation, three modes deep into a different problem, at the exact moment you have no capacity to act on them. So they go one of two places: lost, or, worse, prematurely formalized into a decision you’ll regret in three months.

I kept hitting this while building Alter, my AI capture app. I’d explore something genuinely good in a chat with Claude, and then have to choose: write it up as a formal architecture decision right now (against a system that’s about to change), or let it evaporate. Neither was right.

So I built a third option: a feature bank. This is the system I landed on, and the reasoning behind it.

The one rule: capture now, decide later

Here’s the mistake I almost made, and the one I think most people make. When you explore an idea, it’s tempting to immediately write it up as an ADR (Architecture Decision Record). It feels productive. It’s the wrong move.

An ADR is a dated decision. In my repo every ADR carries a Date, a Status: Decided, the deciders, and a “context doc” pointing at the state of the system it was decided against. That’s the whole point of an ADR: it’s a record of why you chose X over Y, given what was true at that moment.

But an idea you’ll build in three months will be decided against a different system. The schema will have moved. New services will exist. The constraint that made option A obvious today might be gone. If you write the ADR now, you’re either:

  • deciding against a snapshot that’s already going stale, or
  • creating a perpetual Status: Proposed entry that clutters an otherwise immutable, numbered decision log.

So the rule is simple: capture the idea now, write the ADR later, when you’re actually ready to build, grounded against the system as it exists that day.

The feature bank is the one layer in my whole documentation stack that’s allowed to go stale. Which means it has to be honest about being stale. Nothing in it is trusted literally at build time.

Where it sits

Everything in my build process flows down an abstraction ladder, from fuzzy to concrete. The feature bank is a new pre-stage that sits at the very top, above the line where things get grounded in reality:

  💡 ideas/            ← ungrounded, time-stamped thinking (the feature bank)
        │  promote (re-ground against today's system)
        ▼
  📐 ADR(s)            the decision, dated to build-time
        ▼
  📖 specs/            canonical "decided state"
        ▼
  🎨 designed UI       pixel-level mockups (only if there's a UI surface)
        ▼
  🗺️ build plan        which phase, what it owns, an estimate
        ▼
  ✅ backlog           one row per PR
        ▼
  📋 work-items        per-PR implementation contract
        ▼
  ⚙️ code + tests      the actual build

Everything from the ADR downward is grounded in the current state of the system. The feature bank is the only thing above that line, and that placement is the entire design.

What goes in an idea (and what doesn’t)

The trick to capturing an idea well is separating durable from perishable.

The durable stuff is expensive to reconstruct. It’s the actual thinking. The perishable stuff is cheap to re-derive later and actively harmful to over-specify now, because it creates false confidence in details that have since rotted.

Capture richly (durable)Sketch loosely + flag (perishable)
The pull: the problem / pain it solvesExact schema (tables, columns)
The conceptual shape of the solutionExact API endpoints
The options you weighed + gut-feel tradeoffsWhich service owns it
Constraints and invariants it must respectPhasing, sequencing, dependencies
The open questionsSpecific component names / pixel layout

The most valuable section turns out to be the option space: the approaches you considered and why you leaned one way. When you eventually promote the idea, that section becomes the “Options Considered” table in the ADR almost verbatim. You did the hard thinking once, while it was fresh.

And the perishable stuff still goes in, under an explicit ⚠️ Sketch — re-derive at build time banner, date-stamped with the system state it was written against. It’s there to jog your memory and prove the idea is feasible. It is not there to be copied into code.

Turning an idea into a feature

Capture is cheap and that’s deliberate: write the idea doc, add a row to an index, stop. No ADR, no spec, no backlog. Done in five minutes.

The interesting part is promotion: the sequence I run when I decide an idea is worth building. The steps are ordered because each artifact references the ones before it.

Step 1: Re-ground against today’s system. Re-read the idea. Scan what’s actually true now: the spec index, the decision log, the current build status, the relevant service code. Note what’s changed since you captured it. Then throw away the sketch’s specifics. You’re about to re-derive them, grounded. This step is the reason the whole system works.

Step 2: Decide → ADR(s). For each real architectural choice the feature forces, write an ADR now, against the current system. The option space you captured months ago seeds the “Options Considered” table. Many features need zero or one ADR; a pure-UI feature often needs none.

Step 3: Update the specs. Update only the spec files the feature actually touches, and do it in dependency order (glossary first, so no spec references a term that isn’t defined yet; the index last). Specs describe the decided state; they reference the ADR for the why.

Step 4: Design the UI (if there’s a UI surface). 🎨 This is the step I’d skipped early on, and regretted. If the feature adds or changes any screen, it gets a dedicated design pass after the specs and before any implementation. The output is a pixel-level HTML mockup that becomes the visual source of truth: built from the existing design tokens and sibling screens, then reviewed before a single line of UI code is written.

Why a separate stage? Because implementation has to be grounded in a designed UI, not improvised from a paragraph of prose. Every UI work-item in my repo is required to name its mockup file and carry a “visual-match” acceptance criterion. If you skip the design pass, the work-item has nothing to be graded against, and you discover the layout problems in React, which is the most expensive possible place to discover them. Pure backend/schema ideas skip this step entirely.

Step 5: Phase it. Slot the work into the roadmap: which phase, what it owns, a rough estimate.

Step 6: Decompose to the backlog. One row per PR, with dependencies and ownership spelled out.

Step 7: Write the work-item contracts. One implementation brief per PR: intent, acceptance criteria, deliverables, a copy-pasteable verification block, explicit out-of-scope. (UI work-items name the mockup from Step 4.)

Step 8: Close the loop. Flip the idea’s status to ✅ Promoted and fill in a “promotion record” linking to everything it became: the ADR, the spec sections, the design screens, the backlog IDs, the work-items. The idea doc is now a historical index into the build machine.

Then the normal build loop takes over: branch, implement with tests, verify, PR, merge.

Here’s the whole thing as a checklist of what gets written when:

WhenWhatAction
Capturethe idea doc + an index rowcreate (status: Explored)
Promote 1—re-ground (read & think only)
Promote 2ADR(s)create 0..n
Promote 3the touched spec filesupdate (in dependency order)
Promote 4 🎨the UI mockup(s)create/update, UI features only
Promote 5the build planadd phase + estimate
Promote 6the backlogadd one row per PR
Promote 7the work-item brief(s) + indexcreate 1..n
Promote 8the idea docflip to Promoted, link everything
Buildcode + teststhe normal iteration loop

Two decision rules that keep it honest

Does it need an ADR? Only if the choice is expensive to reverse, picks between real alternatives with real tradeoffs, or sets an invariant or a service boundary. A new table shape or a new service boundary earns an ADR. A new page built from existing primitives does not. That’s just a work-item.

Does it need the design stage? Only if it adds or changes a real UI surface. Everything else skips it.

The lifecycle is deliberately small: Seed → Explored → Promoted, with Parked and Dropped as off-ramps (each with a one-line reason, so a dead idea doesn’t keep getting re-proposed).

Why I like this

The thing I was really after was permission to not finish thinking. Before, an idea was a debt: either act on it now or lose it. The feature bank turns it into a deposit. I can explore something fully, capture the part that’s expensive to reconstruct, and walk away knowing that future-me (or a future agent) will re-ground it properly before building anything.

The separation is the whole game: decisions belong to the moment they’re made; ideas outlive the system they were born in. Keep them in different drawers, and neither one rots the other.


Postscript, September 2026

Three months and about seventy idea docs later, the shape above has held, but three parts of it have changed enough to be worth correcting.

Capture stopped being the bottleneck; selection did. With that many ideas banked, “what should I build next?” became its own problem. There’s now an analyst that reads the whole bank on a schedule, ranks the top five, and pushes a one-screen brief to my phone with a plain-English what/why and a rough cost. I reply with numbers (“2, 5, 1”) and those become the queue, in that order. Capture is cheap; choosing is the part that deserved automating.

The design stage moved earlier, and got an owner. Step 4 used to be something I did during promotion. It now runs before promotion for anything user-facing: a designer agent turns the idea doc into static mockups, and I sign those off before any ADR gets written. The reason is that mockups routinely change the promotion. You find out the feature is two features, or that it doesn’t need the schema change you assumed. Designing after deciding meant re-deciding.

Steps 6 and 7 collapsed into one. The backlog is no longer hand-edited. Per-item status lives in each work-item brief’s own frontmatter, and a compiler derives the aggregate view after merge. This wasn’t a documentation improvement: it was a concurrency fix. Several agents hand-editing one backlog file deadlocked them on prose conflicts.

What hasn’t changed is the rule the whole thing exists for, and I’d still defend it against anyone who wants to write the ADR at capture time: decisions belong to the moment they’re made; ideas outlive the system they were born in.