Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Each released version is tagged in git (`v0.0.1`, `v0.1.0`, etc.) and includes t

### Added

- **`draftwise clarify [<feature>]` — surface gaps in an existing product spec before drafting the technical spec.** Reads `product-spec.md` and prints an instruction telling the host coding agent to audit the spec across four categories (ambiguities, untested assumptions, internal contradictions, missing edge cases), present each issue with a specific line/section pointer, walk the PM through them one at a time (defer / reject / answer), and rewrite the file in place — preserving the YAML frontmatter and any sections the PM didn't touch. Hard rule: don't widen scope; if the PM's answer expands the feature, push back — that's a new spec, not a clarification. Same shape as `tech` (auto-picks when one product spec exists; positional slug picks one when many; errors with the available list when ambiguous). Why: drafted specs are uneven — some sections are tight, others have hand-wavy acceptance criteria or untested assumptions buried in scope. Catching those *before* the technical spec gets drafted means the engineering plan isn't built on a shaky foundation, and PMs don't have to re-litigate the same ambiguity in three files. Companion to `draftwise refine` (queued in the same release): `clarify` is the upfront quality check, `refine` rewrites after PM edits. Prompt at `src/ai/prompts/clarify.js`; command at `src/commands/clarify.js`; routed via `COMMANDS` in `src/index.js`. — Ankur
- **`draftwise refine [<feature>] [--type=product|tech|tasks]` — re-ground an existing spec while preserving PM hand-edits.** Resolves CLAUDE.md's long-standing "AI-assisted spec merge mode" open question. Different shape from `clarify`: clarify finds gaps and walks the PM through them; refine takes the existing spec as ground truth for what the PM wants and improves how it's written and grounded. Reads the chosen file (`product-spec.md` by default, `technical-spec.md` for `--type=tech`, `tasks.md` for `--type=tasks`), prints it plus the upstream source-of-truth (scanner output for product/tech brownfield, `overview.md` for greenfield, plus the upstream spec for tech/tasks), then prints a three-phase instruction telling the host coding agent to (1) audit each section as strong-leave-alone or weak-rewrite — bar is "actively misleads or under-specifies," not "could be tighter"; (2) re-ground the weak sections against the source-of-truth, removing or marking `(unverified)` any code reference the scanner doesn't surface; (3) save the refined file back, preserving strong sections character-for-character and any YAML frontmatter at the top of `product-spec.md` verbatim. Hard rules in the prompt: no fabricated code references, no scope creep (refining ≠ adding new features / edge cases), don't touch sections that are already strong. Same auto-pick / multi-spec / unknown-slug ergonomics as `tech`. Filters specs by which file the requested type requires (product-spec for `product`, technical-spec for `tech`, tasks for `tasks`); tech/tasks additionally validate that the upstream spec exists. Why: re-running `new` / `tech` / `tasks` on an existing spec only offers Overwrite or Cancel — both blunt. PMs review and edit specs, then want a "tighten this up" pass that doesn't blow away their edits. Refine is that pass. Prompt at `src/ai/prompts/refine.js` (per-type metadata table for file name, source-of-truth labels, and section-preservation rules); command at `src/commands/refine.js`; routed via `COMMANDS` in `src/index.js`. — Ankur

- **`draftwise clarify [<feature>]` — surface gaps in an existing product spec before drafting the technical spec.** Reads `product-spec.md` and prints an instruction telling the host coding agent to audit the spec across four categories (ambiguities, untested assumptions, internal contradictions, missing edge cases), present each issue with a specific line/section pointer, walk the PM through them one at a time (defer / reject / answer), and rewrite the file in place — preserving the YAML frontmatter and any sections the PM didn't touch. Hard rule: don't widen scope; if the PM's answer expands the feature, push back — that's a new spec, not a clarification. Same shape as `tech` (auto-picks when one product spec exists; positional slug picks one when many; errors with the available list when ambiguous). Why: drafted specs are uneven — some sections are tight, others have hand-wavy acceptance criteria or untested assumptions buried in scope. Catching those *before* the technical spec gets drafted means the engineering plan isn't built on a shaky foundation, and PMs don't have to re-litigate the same ambiguity in three files. Companion to `draftwise refine` (also in this release): `clarify` is the upfront quality check, `refine` rewrites after PM edits. Prompt at `src/ai/prompts/clarify.js`; command at `src/commands/clarify.js`; routed via `COMMANDS` in `src/index.js`. — Ankur

- **`product-spec.md` opens with optional YAML frontmatter declaring `depends_on:` and `related:` slugs; `draftwise list` surfaces them.** `draftwise new` now instructs the host coding agent to list `.draftwise/specs/` first, then write a frontmatter block at the top of `product-spec.md` — `depends_on` for specs that must ship before this one, `related` for same-area specs that aren't a hard dependency. Both keys take a list of existing slugs (the agent is told never to invent slugs that aren't on disk; if there are no other specs yet the agent skips the block entirely). Frontmatter is parsed by a new `src/utils/frontmatter.js` (small wrapper over the `yaml` package — handles CRLF, malformed YAML, and non-object roots by falling back to empty data so a broken spec file doesn't break the whole list). `draftwise list` grew a fourth column — DEPENDS ON — between STATUS and TITLE; a spec with no frontmatter or no `depends_on` shows blank. Why: cross-spec dependencies were a deferred-for-later item in CLAUDE.md, but the cheap version (declarative, in the spec, surfaced in `list`) is enough to answer the actual question PMs ask ("which specs are ready to start?") without needing graph traversal, drift detection, or any of the heavier machinery. Stays in a frontmatter block so it doesn't bleed into the rendered spec body. — Ankur

Expand Down
9 changes: 7 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ scan:

**The constitution is the user's voice + spec-quality dial.** `draftwise init` writes `.draftwise/constitution.md` with five stable sections — Voice, Spec language, Edge case discipline, Project conventions, Domain glossary. Every drafting prompt (`new`, `tech`, `tasks`, `scan`, `explain`, greenfield Phase 3) tells the host agent to read this file before drafting and apply the relevant sections. `scan` and the greenfield Phase 3 also refine the **Project conventions** section from observed code / chosen stack, replacing the placeholder. The file is user-editable and version-controlled — changes are reviewable and travel with the repo. Backward compat: prompts say "skip silently if absent" so projects that ran `init` before this feature landed keep working. Reader at `src/utils/constitution.js` returns null on ENOENT. Replaces the role `principles.js` + `spec-quality.js` used to play before the api-mode drop — those modules injected rules into every system prompt; the constitution is the new home for those rules now that synthesis lives in the host agent.

**Refine, don't clobber.** Re-running `new` / `tech` / `tasks` would overwrite a hand-edited spec; `draftwise refine [<feature>] [--type=product|tech|tasks]` is the alternative. Reads the existing file, treats it as ground truth for what the PM wants, prints it plus its source-of-truth (scanner / overview, plus the upstream spec for tech/tasks), and tells the host agent to audit each section as strong-leave-alone or weak-rewrite. The bar for "weak" is "actively misleads or under-specifies," not "could be tighter" — so the agent doesn't churn good prose. Hard rules in the prompt: no fabricated code references, no scope creep (refine ≠ add new features / edge cases), preserve YAML frontmatter on `product-spec.md` verbatim. Same auto-pick / multi-spec / unknown-slug ergonomics as `tech`. Different shape from `clarify`: clarify finds gaps and walks the PM through them; refine takes the existing spec as ground truth and re-grounds the parts that need it. Per-type metadata table (file name, source-of-truth label, section-preservation rule) lives at the top of `src/ai/prompts/refine.js`.

**Cross-spec dependencies live in product-spec frontmatter.** The agent writes an optional YAML block at the top of `product-spec.md` — `depends_on: [<slug>...]` for specs that must ship before this one, `related: [<slug>...]` for same-area specs that aren't a hard dependency. `draftwise new`'s instruction tells the agent to list `.draftwise/specs/` first and only reference slugs that exist on disk. `draftwise list`'s DEPENDS ON column surfaces the `depends_on` array. This is the cheap version of cross-spec tracking — declarative, in the spec, no graph traversal or drift detection. The richer machinery (drift detection, full graph view, ripple analysis) stays deferred; the frontmatter is enough to answer "which specs are ready to start?" without dragging the rest in.

**Single repo, single feature spec at a time.** No cross-spec dependency tracking. No multi-repo. Keep scope tight.
Expand All @@ -125,6 +127,7 @@ draftwise new "<idea>" → conversational drafting → product-
draftwise clarify [<feature>] → audit a product spec for ambiguities + missing edge cases; rewrite in place
draftwise tech [<feature>] → technical-spec.md from approved product spec (host agent writes)
draftwise tasks [<feature>] → ordered tasks.md from technical spec (host agent writes)
draftwise refine [<feature>] [--type=product|tech|tasks] → re-ground a spec while preserving PM hand-edits
draftwise list → list all specs in .draftwise/specs/
draftwise show <feature> [type] → display a spec (type: product | tech | tasks; default: product)
draftwise skills install [--provider=...] [--scope=...] [--force] → install standalone skill across harnesses (Claude Code / Cursor / Gemini CLI; bare /draftwise <verb>)
Expand Down Expand Up @@ -179,9 +182,11 @@ Every command is implemented end-to-end and exercised by a vitest suite. The ori

7. **`tasks [<feature>]`** ✅ — reads `technical-spec.md`, prints it plus scanner output (brownfield) or the project plan (greenfield) plus an instruction for the host agent to write ordered `tasks.md` (Goal / Files / Depends on / Parallel with / Acceptance). Greenfield front-loads 1-3 scaffolding tasks. (`src/commands/tasks.js`, prompt in `src/ai/prompts/tasks.js`)

8. **`list` and `show <feature> [type]`** ✅ — file-system utilities, no AI. (`src/commands/list.js`, `src/commands/show.js`)
8. **`refine [<feature>] [--type=product|tech|tasks]`** ✅ — reads the chosen spec file plus its source-of-truth (scanner / overview, plus the upstream spec for tech/tasks) and prints a three-phase instruction telling the host agent to audit each section as strong/weak, re-ground only the weak ones, and write the file back — preserving the strong sections character-for-character and any YAML frontmatter at the top. Different shape from `clarify`: clarify walks the PM through gaps; refine takes the existing spec as ground truth and re-grounds the parts that need it. Same auto-pick / multi-spec / unknown-slug ergonomics as `tech`. (`src/commands/refine.js`, prompt in `src/ai/prompts/refine.js`)

9. **`list` and `show <feature> [type]`** ✅ — file-system utilities, no AI. (`src/commands/list.js`, `src/commands/show.js`)

9. **`scaffold`** ✅ — greenfield-only file scaffolder. Reads `.draftwise/scaffold.json` (written by the host coding agent during init's greenfield handoff), confirms with the user — including a warning that scaffolders like `create-next-app` should run first — then creates each `initial_files` entry with placeholder content (skipping any that already exist). Prints the `setup_commands` as a reminder; doesn't run them. (`src/commands/scaffold.js`)
10. **`scaffold`** ✅ — greenfield-only file scaffolder. Reads `.draftwise/scaffold.json` (written by the host coding agent during init's greenfield handoff), confirms with the user — including a warning that scaffolders like `create-next-app` should run first — then creates each `initial_files` entry with placeholder content (skipping any that already exist). Prints the `setup_commands` as a reminder; doesn't run them. (`src/commands/scaffold.js`)

---

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Claude Code namespaces plugin skills as `<plugin>:<skill>`, so the slash form is
| `draftwise clarify [<feature>]` | Audit a product spec for ambiguities, untested assumptions, and missing edge cases; rewrite in place. |
| `draftwise tech [<feature>]` | Technical spec from the product spec, grounded in real files. |
| `draftwise tasks [<feature>]` | Implementation tasks from the tech spec, dependency-ordered. |
| `draftwise refine [<feature>] [--type=...]` | Re-ground an existing spec (`product` / `tech` / `tasks`) while preserving PM hand-edits — only weak sections get rewritten. |
| `draftwise scaffold --yes` | Create initial files from a greenfield plan. |
| `draftwise list` | List all specs in `.draftwise/specs/`. |
| `draftwise show <feature> [type]` | Show a spec (`product`, `tech`, or `tasks`; default: `product`). |
Expand Down
60 changes: 60 additions & 0 deletions src/ai/prompts/refine.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const TYPE_META = {
product: {
file: 'product-spec.md',
sourcesBrownfield: 'the scanner output (the codebase as it exists today)',
sourcesGreenfield: 'overview.md (the project plan + chosen stack)',
forbidNewSections:
'Don\'t add or remove sections. Preserve any YAML frontmatter (`depends_on:` / `related:`) at the top of the file verbatim.',
},
tech: {
file: 'technical-spec.md',
sourcesBrownfield: 'the product spec above plus the scanner output',
sourcesGreenfield: 'the product spec above plus overview.md (the project plan + chosen stack)',
forbidNewSections: 'Don\'t add or remove sections.',
},
tasks: {
file: 'tasks.md',
sourcesBrownfield: 'the technical spec above plus the scanner output',
sourcesGreenfield: 'the technical spec above plus overview.md (the project plan + chosen stack)',
forbidNewSections:
'Don\'t change the task numbering scheme or drop tasks. You may rewrite task descriptions, but keep the same set of numbered tasks unless one is genuinely redundant.',
},
};

export function buildAgentInstruction(slug, type, projectState = 'brownfield') {
const meta = TYPE_META[type];
if (!meta) {
throw new Error(`Unknown spec type: ${type}`);
}
const sources =
projectState === 'greenfield' ? meta.sourcesGreenfield : meta.sourcesBrownfield;

return `The ${meta.file} above already exists in .draftwise/specs/${slug}/${meta.file}. The PM has hand-edited it since the last draft. Refine the file in place — preserve their edits, improve everything else.

Before refining, read .draftwise/constitution.md if it exists and apply its Voice and Spec language sections${
type === 'tech' ? ', plus its Edge case discipline section' : ''
}. Skip silently if absent.

Run a refinement pass in three phases:

PHASE 1 — Audit each section:
- Walk the spec section by section. For each one, decide: strong or weak.
- **Strong** = specific, grounded in real code/plan, written in active voice, internally consistent. The PM either wrote this themselves or the previous draft already nailed it. Leave it alone.
- **Weak** = vague claims, generic placeholders, contradictions, ungrounded references, copy that reads like a template. These need rewriting.
- Don't rewrite a section just because you'd word it differently. The bar is "this section actively misleads or under-specifies," not "this could be tighter."

PHASE 2 — Re-ground the weak sections:
- For each weak section, re-ground it against ${sources}.
- If the existing text references a file/route/model/component that doesn't appear in the source-of-truth, either remove the reference or mark it "(unverified)" — never silently keep a fabricated path.
- Match the language style of the strong sections — voice, sentence length, level of specificity. The output should read as one coherent document, not a patchwork.

PHASE 3 — Write the file back:
- Save the refined spec to .draftwise/specs/${slug}/${meta.file}, replacing the existing file.
- ${meta.forbidNewSections}
- Preserve the strong sections character-for-character. Only the weak sections change.

Hard rules:
- No fabricated code references. If the source-of-truth doesn't surface it, don't claim it exists.
- No scope creep. Refining means improving how the spec reads and how well it's grounded — not adding new features, edge cases, or requirements that weren't there before. If you spot a genuine gap, list it under "Open questions" (or the equivalent section if it exists) instead of writing new prose.
- Don't touch sections you'd classify as strong. If the whole spec is already strong, say so and exit without writing.`;
}
Loading