Why
Brownfield adoption is Specflow's highest-value use case: developers already have a working project (Vite, Next, Astro, etc.) and want to layer Specflow on top with `specflow init --here`. Every JS frontend scaffolder creates a `.gitignore`. Today Specflow treats that file as a managed conflict, blocking `init --here` at exit code 3, and silently destroying the user's ignore rules when they push through with `--force`. The architect's design call (2026-05-01) resolved the implementation strategy — a new `mergeable-project-root` bundle category with marker-fenced append-blocks — so this item is ready for implementation.
Acceptance criteria
- `specflow init --here` (no flags) on a Vite-style project whose `.gitignore` was NOT written by Specflow exits 0 without requiring `--force`.
- The resulting `.gitignore` contains both the user's original lines (e.g. `node_modules/`, `dist/`, `.DS_Store`) AND Specflow's entries, with Specflow's block fenced by `# --- Specflow: gitignore ---` / `# --- End Specflow: gitignore ---` markers.
- Re-running `specflow init --here` (with or without `--force`) on a project that already has the fenced Specflow block does not duplicate it — the block is replaced in-place (idempotent).
- When Specflow's block content changes between versions, `specflow upgrade` replaces only the fenced block; user-authored lines above and below the block are left untouched.
- Greenfield `init` (empty dir, no pre-existing `.gitignore`) produces a `.gitignore` with the same marker-fenced shape — the output format is identical whether the file pre-existed or not.
- `detectConflicts` does not return `.gitignore` when `mergeBlock` is set on its `TemplateFile` — it is never treated as a conflict candidate.
- `--force` continues to apply normally to all non-mergeable managed files; mergeable files ignore the flag entirely because merge is non-destructive by design.
- The lock file records the SHA of the Specflow block content alone (not the full merged file), so `upgrade` can distinguish spec changes from user-added lines.
- All 8 harnesses in `src/infrastructure/harness/` handle the new `mergeable-project-root` category consistently — no harness-specific divergence in `.gitignore` merge behavior.
- A new integration test (`tests/integration/init_brownfield_gitignore_test.ts`) covers: greenfield shape, brownfield merge, idempotent re-run, and upgrade block-replace.
Out of scope
- Extending merge semantics to any other file (`AGENTS.md`, `tasks/backlog.md`, `.editorconfig`, `README.md`, etc.) — those keep their current replace or preserve-if-customized logic unchanged.
- A user-configurable list of mergeable files.
- Backward-compatible migration of existing brownfield projects where a prior `--force` already destroyed the `.gitignore` (those users have a `.gitignore.specflow.bak` and must merge manually — not in scope here).
- Detecting which scaffolder authored the pre-existing `.gitignore`.
Notes
Architecture spec: `docs/superpowers/specs/2026-05-01-gitignore-merge-fix.md` — full design rationale, data-flow diagram, and edge-case decisions live there.
Files the implementation must touch (per architect's 2026-05-01 design call):
- `src/domain/core_bundle.ts` — extend `CoreCategory` union with `"mergeable-project-root"`
- `src/domain/template.ts` — add `mergeBlock?: string` to `TemplateFile`
- `templates/manifest.json` — change `.gitignore` category to `mergeable-project-root`
- `templates/core/root/.gitignore` — body-only content (markers are adapter-injected, not stored in the template)
- All 8 harness files in `src/infrastructure/harness/` — add `case "mergeable-project-root"`
- `src/infrastructure/deno_fs_writer.ts` — skip-in-detect logic + marker-aware merge-write
- `src/application/init_project.ts` — fix lock SHA computation to use block content for `mergeBlock` entries
- `tests/integration/init_brownfield_gitignore_test.ts` — new integration test (all four scenarios above)
Reproduction case: `test/vite-demo/` (gitignored locally) — `npm create vite@latest vite-demo -- --template react-ts` then `specflow init --here --no-git` reproduces exit-code-3 block; `--force` reproduces destructive overwrite.
Brownfield breakage shipped in v0.6.x. v0.7.0 (`dcaae33`) added a friendlier error message but did not fix detection or merge semantics. The `.gitignore.specflow.bak` safety net is not a fix — it is a workaround that still loses the conflict-detection skip.
Why
Brownfield adoption is Specflow's highest-value use case: developers already have a working project (Vite, Next, Astro, etc.) and want to layer Specflow on top with `specflow init --here`. Every JS frontend scaffolder creates a `.gitignore`. Today Specflow treats that file as a managed conflict, blocking `init --here` at exit code 3, and silently destroying the user's ignore rules when they push through with `--force`. The architect's design call (2026-05-01) resolved the implementation strategy — a new `mergeable-project-root` bundle category with marker-fenced append-blocks — so this item is ready for implementation.
Acceptance criteria
Out of scope
Notes
Architecture spec: `docs/superpowers/specs/2026-05-01-gitignore-merge-fix.md` — full design rationale, data-flow diagram, and edge-case decisions live there.
Files the implementation must touch (per architect's 2026-05-01 design call):
Reproduction case: `test/vite-demo/` (gitignored locally) — `npm create vite@latest vite-demo -- --template react-ts` then `specflow init --here --no-git` reproduces exit-code-3 block; `--force` reproduces destructive overwrite.
Brownfield breakage shipped in v0.6.x. v0.7.0 (`dcaae33`) added a friendlier error message but did not fix detection or merge semantics. The `.gitignore.specflow.bak` safety net is not a fix — it is a workaround that still loses the conflict-detection skip.