diff --git a/README.md b/README.md index 07dc4b8..49c690c 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Strict mode is on by default: specs need `## Acceptance criteria`, and reviews m Devloop ships two agent skills, installed into `~/.claude/skills` and `~/.agents/skills`: -- [`devloop-spec`](skills/devloop-spec/SKILL.md) — turns a rough idea, notes, a URL, or an interview into one concrete, devloop-ready spec. +- [`devloop-spec`](skills/devloop-spec/SKILL.md) — interviews when scope is unclear, then writes one concrete, devloop-ready spec. - [`devloop-review`](skills/devloop-review/SKILL.md) — judges each pass against the spec and engineering quality gates, returning ACCEPT, REJECT, or UNCLEAR with fix instructions. ## Runtime diff --git a/devloop b/devloop index da05bc1..ed3b69a 100755 --- a/devloop +++ b/devloop @@ -4402,9 +4402,12 @@ Spec directory: $target_dir $target_line $overwrite_line -If the source context is missing or too thin, follow the skill's cold-start -interview path before drafting. Ask one question at a time until the spec can be -written without invented requirements. +If the source context is missing, too thin, ambiguous, spans multiple possible +implementation slices, or has open questions that could change the work, follow +the skill's interview path before drafting. Do not turn a conversation, +artifact bundle, or notes into a spec until scope and acceptance criteria are +clear. Ask one question at a time until the spec can be written without invented +requirements. When ready, write exactly one devloop-ready markdown spec to the requested path. After writing the spec, tell the user the path and offer to continue with: diff --git a/scripts/devloop_test.sh b/scripts/devloop_test.sh index c3ed934..d9d9854 100755 --- a/scripts/devloop_test.sh +++ b/scripts/devloop_test.sh @@ -107,6 +107,10 @@ not_contains "$spec_skill_text" "render.py" "spec skill Python renderer" not_contains "$spec_skill_text" "python3" "spec skill Python renderer" not_contains "$spec_skill_text" "render.sh" "spec skill renderer" not_contains "$spec_skill_text" "HTML companion" "spec skill renderer" +contains "$spec_skill_text" "Do not convert a conversation, artifact bundle, or notes directly into a spec" "spec skill interview gate" +contains "$spec_skill_text" "If interactive and gaps remain, do not draft yet" "spec skill gap interview" +not_contains "$spec_skill_text" "offer to interview for only those gaps after producing the first draft" "spec skill gap interview" +contains "$spec_skill_text" "/.devloop/specs/YYYY-MM-DD-.md" "spec skill repo output" contains "$spec_template_text" $'\n```\n current' "spec template plain ASCII fence" contains "$spec_template_text" "Current behavior -> Implementation change -> Expected outcome" "spec template ASCII schematic" not_contains "$spec_template_text" '```mermaid' "spec template Mermaid fence" @@ -1614,6 +1618,8 @@ if [ -f "$repo_specs/$(date +%F)-shell-migration-spec.md" ]; then fail "spec com contains "$(cat /tmp/devloop-spec-agent-prompt.txt)" "Skill: use the installed devloop-spec skill." "spec prompt skill" contains "$(cat /tmp/devloop-spec-agent-prompt.txt)" "Keep devloop as Bash." "spec prompt" contains "$(cat /tmp/devloop-spec-agent-prompt.txt)" "Requested spec path: choose $repo_specs_real/$(date +%F)-.md" "spec prompt configured output" +contains "$(cat /tmp/devloop-spec-agent-prompt.txt)" "has open questions that could change the work" "spec prompt interview gate" +contains "$(cat /tmp/devloop-spec-agent-prompt.txt)" "Do not turn a conversation" "spec prompt interview gate" contains "$(cat /tmp/devloop-spec-agent-prompt.txt)" "Devloop owns the implementation" "spec prompt ownership" contains "$(cat /tmp/devloop-spec-agent-prompt.txt)" "devloop --create-pr " "spec prompt handoff" contains "$(absolute_path "$work/absolute-path/nested.md")" "/absolute-path/nested.md" "absolute path" diff --git a/skills/devloop-spec/SKILL.md b/skills/devloop-spec/SKILL.md index e67e6c2..7c8cc0e 100644 --- a/skills/devloop-spec/SKILL.md +++ b/skills/devloop-spec/SKILL.md @@ -1,6 +1,6 @@ --- name: devloop-spec -description: Use this skill when the user wants one devloop-ready implementation spec from a rough idea, interview, notes, file, URL, issue, research, or conversation context. Also use for /spec-style requests, "turn this into a spec", "write a spec", "spec out this research", "draft a devloop spec", or when devloop launches an agent to create a spec. Interview from a cold start; otherwise distill source material faithfully and flag gaps. +description: Use this skill when the user wants one devloop-ready implementation spec from a rough idea, interview, notes, file, URL, issue, research, or conversation context. Also use for /spec-style requests, "turn this into a spec", "write a spec", "spec out this research", "draft a devloop spec", or when devloop launches an agent to create a spec. Interview for cold starts, ambiguous scope, or open questions; distill only well-scoped source material. metadata: devloop-managed: "true" --- @@ -9,7 +9,7 @@ metadata: Produce exactly one implementation spec that conforms to the devloop standard. This is the canonical spec skill for devloop. -Use this skill for both cold-start interviews and distilling existing material. Do not hand off to a separate interview or spec-writing skill. +Use this skill for interviews and for distilling already well-scoped material. Do not hand off to a separate interview or spec-writing skill. The markdown spec is the source of truth that `devloop` will use as implementation input. Author diagrams as ASCII art inside plain code fences so terminal readers, GitHub, and plain text show the same schematic. @@ -21,7 +21,21 @@ Available resources: Write exactly one spec sized for one worktree and one PR. Push back before drafting when the request mixes multiple logical changes, depends on an unresolved preparatory refactor, or would plausibly exceed about 300 meaningful changed lines. -When interactive, name the overflow, propose the smallest useful slice, and ask the user to confirm before writing. When non-interactive, spec the first foundational slice and list deferred work in Notes as follow-up specs. +When interactive, name the overflow, propose the smallest useful slice, and ask the user to confirm before writing. When non-interactive and the source is otherwise implementation-ready, spec the first foundational slice and list deferred work in Notes as follow-up specs. + +## Interview Gate + +Before drafting, decide whether the source is implementation-ready. Start or continue an interview when any of these are true: + +- No source material was provided. +- The source is a conversation, artifact bundle, notes, or research with multiple plausible implementation slices. +- The problem, outcome, scope, behavior, acceptance criteria, test expectations, or owner repo is missing or contradictory. +- An open question could change the files touched, user-visible behavior, acceptance criteria, spec type, or implementation slice. +- The request is broad or vague, such as "fix this", "improve this", "audit this", or "turn this conversation into a spec" without a clear target outcome. + +Do not convert a conversation, artifact bundle, or notes directly into a spec just because there is enough text. Existing material only qualifies for direct distillation when it identifies one worktree-sized change and enough concrete requirements to draft without TODOs, TBDs, GAP markers, or invented detail. + +When interactive, ask one question at a time until the gate passes. When the environment cannot ask questions, write a marked draft only if the caller explicitly needs best-effort non-interactive output; otherwise stop with the questions that must be answered. ## Source Resolution @@ -31,13 +45,15 @@ Resolve the source material before drafting: - URL: fetch it if the environment allows web access; otherwise record the URL in Notes as a source to verify. - Pasted text: use it verbatim. - Current conversation: use only the part clearly about this task; ask for the boundary if the conversation covers unrelated work. -- No source material: use the cold-start interview path. +- No source material: use the interview path. + +After loading any source, run the Interview Gate. Source presence does not imply direct drafting. If a path or URL will not load, say so and stop unless the caller explicitly asks for a best-effort draft. -## Cold Start Interview +## Interview -Use this mode when there is no document, URL, issue, or concrete context to distill. +Use this mode when there is no document, URL, issue, or concrete context to distill, or when supplied material leaves scope or requirements open. - Ask one question at a time. - Ask why before what. @@ -45,7 +61,7 @@ Use this mode when there is no document, URL, issue, or concrete context to dist - Skip obvious questions the repository or prior answers already settle. - Push vague answers toward observable behavior and acceptance criteria. - Name contradictions and ask which statement is true. -- Stop only when the spec can be written without TODOs, TBDs, or invented requirements. +- Stop only when the spec can be written without TODOs, TBDs, GAP markers, or invented requirements. Cover these points: @@ -57,10 +73,12 @@ Cover these points: 6. Explicitly out-of-scope work. 7. Hard constraints, existing conventions, and test expectations. -If the environment cannot ask interactive questions, write a draft with explicit `> **GAP:** ...` markers rather than inventing missing facts. +If the environment cannot ask interactive questions and the caller needs best-effort output, write a draft with explicit `> **GAP:** ...` markers rather than inventing missing facts. ## Distill Existing Material +Use this path only after the Interview Gate passes. + Do not fill unsupported sections with plausible detail. Every line must trace to supplied context, repository evidence, or an explicit user answer. If the spec depends on something cheap to verify, verify it rather than asserting it. Examples: file existence, command names in `package.json` or `pyproject.toml`, API paths in a router, or repo-local test commands. @@ -134,7 +152,7 @@ pr: null ## Gaps -When required information is still missing, replace that section's placeholder with: +When required information is still missing and the caller explicitly needs a best-effort non-interactive draft, replace that section's placeholder with: ```markdown > **GAP:** @@ -142,16 +160,16 @@ When required information is still missing, replace that section's placeholder w Keep every standard section present, remove leftover placeholders, and list the count and names of remaining gaps in Notes. -If interactive and gaps remain, offer to interview for only those gaps after producing the first draft. Do not block delivery of a useful marked draft. +If interactive and gaps remain, do not draft yet. Ask the next interview question instead. ## Output Path Do not hard-code personal paths. Use this precedence: 1. If devloop or the caller provides a requested output path, write exactly there unless it would overwrite a file and overwrite permission is absent. -2. If devloop or the caller provides a requested output directory, write `YYYY-MM-DD-.md` there. +2. If devloop or the caller provides a requested output directory or spec directory, write `YYYY-MM-DD-.md` there. 3. If the user provides `target=`, write `/.md` for duet/devloop compatibility. -4. If the user requests repo-local output but no path, write `.devloop/specs/YYYY-MM-DD-.md` under the target repo. +4. If a target repo can be resolved from the current working directory, an explicit target repo, or a source file path, write `/.devloop/specs/YYYY-MM-DD-.md` and create the directory if needed. 5. Otherwise, write only the markdown spec to stdout. Do not wrap the spec in a code fence unless the caller explicitly asks for a fenced snippet.