@popoverai/dotrequirements 0.24.2 → 0.24.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/codebase-to-spec/cache.d.ts +6 -0
- package/dist/codebase-to-spec/cache.js +1 -0
- package/dist/codebase-to-spec/dispatch.d.ts +69 -0
- package/dist/codebase-to-spec/dispatch.js +484 -0
- package/dist/codebase-to-spec/schemas.d.ts +375 -0
- package/dist/codebase-to-spec/schemas.js +133 -0
- package/dist/codebase-to-spec/skill-install.d.ts +36 -12
- package/dist/codebase-to-spec/skill-install.js +127 -26
- package/dist/commands/codebase-to-spec/compose-orchestrator.d.ts +14 -0
- package/dist/commands/codebase-to-spec/compose-orchestrator.js +54 -0
- package/dist/commands/codebase-to-spec/dispatch-context.d.ts +12 -0
- package/dist/commands/codebase-to-spec/dispatch-context.js +22 -0
- package/dist/commands/codebase-to-spec/dispatch-editor.d.ts +16 -0
- package/dist/commands/codebase-to-spec/dispatch-editor.js +71 -0
- package/dist/commands/codebase-to-spec/dispatch-planner.d.ts +19 -0
- package/dist/commands/codebase-to-spec/dispatch-planner.js +90 -0
- package/dist/commands/codebase-to-spec/dispatch-spec.d.ts +16 -0
- package/dist/commands/codebase-to-spec/dispatch-spec.js +59 -0
- package/dist/commands/codebase-to-spec/index.js +56 -1
- package/dist/commands/codebase-to-spec/present-orchestrator.d.ts +20 -0
- package/dist/commands/codebase-to-spec/present-orchestrator.js +81 -0
- package/dist/commands/codebase-to-spec/skill-install.js +12 -1
- package/dist/templates/agents/cts-worker.md +9 -0
- package/dist/templates/hooks/cts-worker-persona.sh +76 -0
- package/dist/templates/skills/codebase-to-spec/SKILL.md +159 -68
- package/package.json +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dotrequirements codebase-to-spec present-orchestrator` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Conversational-orchestrator variant of `present`. Reads outline.yaml +
|
|
5
|
+
* composedSpec (produced by compose-orchestrator), writes the final spec
|
|
6
|
+
* to `.requirements/`. The orchestrator doesn't have a separate
|
|
7
|
+
* document-level edit-loop, so this reads from composedSpec directly
|
|
8
|
+
* rather than specFinal.
|
|
9
|
+
*
|
|
10
|
+
* Requirements covered:
|
|
11
|
+
* - CTS-PRESENT-1..4 (reuses the legacy present logic)
|
|
12
|
+
* - CTSO-INTEG-1: orchestrator uses existing deterministic stages unchanged
|
|
13
|
+
*/
|
|
14
|
+
export interface PresentOrchestratorOptions {
|
|
15
|
+
forceMode?: "interactive" | "non-interactive";
|
|
16
|
+
overwrite?: boolean;
|
|
17
|
+
skipExisting?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function presentOrchestratorCommand(options?: PresentOrchestratorOptions): Promise<void>;
|
|
20
|
+
//# sourceMappingURL=present-orchestrator.d.ts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dotrequirements codebase-to-spec present-orchestrator` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Conversational-orchestrator variant of `present`. Reads outline.yaml +
|
|
5
|
+
* composedSpec (produced by compose-orchestrator), writes the final spec
|
|
6
|
+
* to `.requirements/`. The orchestrator doesn't have a separate
|
|
7
|
+
* document-level edit-loop, so this reads from composedSpec directly
|
|
8
|
+
* rather than specFinal.
|
|
9
|
+
*
|
|
10
|
+
* Requirements covered:
|
|
11
|
+
* - CTS-PRESENT-1..4 (reuses the legacy present logic)
|
|
12
|
+
* - CTSO-INTEG-1: orchestrator uses existing deterministic stages unchanged
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
15
|
+
import { cachePaths } from "../../codebase-to-spec/cache.js";
|
|
16
|
+
import { ExitCode } from "../../codebase-to-spec/exit-codes.js";
|
|
17
|
+
import { detectMode } from "../../codebase-to-spec/interactive.js";
|
|
18
|
+
import { runPresent, } from "../../codebase-to-spec/present.js";
|
|
19
|
+
import { conversationalOutlineToLegacy, parseConversationalOutline, } from "../../codebase-to-spec/schemas.js";
|
|
20
|
+
import { findProjectRoot } from "../../utils/project-settings.js";
|
|
21
|
+
function resolvePolicy(isInteractive, options) {
|
|
22
|
+
if (options.overwrite && options.skipExisting) {
|
|
23
|
+
return { error: "--overwrite and --skip-existing are mutually exclusive." };
|
|
24
|
+
}
|
|
25
|
+
if (options.overwrite)
|
|
26
|
+
return "overwrite";
|
|
27
|
+
if (options.skipExisting)
|
|
28
|
+
return "skip-existing";
|
|
29
|
+
if (isInteractive)
|
|
30
|
+
return "prompt";
|
|
31
|
+
return "fail-fast";
|
|
32
|
+
}
|
|
33
|
+
export async function presentOrchestratorCommand(options = {}) {
|
|
34
|
+
const projectRoot = findProjectRoot(process.cwd()) ?? process.cwd();
|
|
35
|
+
const paths = cachePaths(projectRoot);
|
|
36
|
+
if (!existsSync(paths.outline)) {
|
|
37
|
+
process.stderr.write(`No outline.yaml found at ${paths.outline}. Run the orchestrator's planner first.\n`);
|
|
38
|
+
process.exitCode = ExitCode.MissingInput;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (!existsSync(paths.composedSpec)) {
|
|
42
|
+
process.stderr.write(`No composed spec at ${paths.composedSpec}. Run \`cts compose-orchestrator\` first.\n`);
|
|
43
|
+
process.exitCode = ExitCode.MissingInput;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
let outline;
|
|
47
|
+
try {
|
|
48
|
+
outline = parseConversationalOutline(readFileSync(paths.outline, "utf-8"));
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
process.stderr.write(`Outline at ${paths.outline} is invalid: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
52
|
+
process.exitCode = ExitCode.MissingInput;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const { isInteractive } = detectMode(options.forceMode);
|
|
56
|
+
const policy = resolvePolicy(isInteractive, options);
|
|
57
|
+
if (typeof policy === "object") {
|
|
58
|
+
process.stderr.write(`${policy.error}\n`);
|
|
59
|
+
process.exitCode = ExitCode.InvalidFlags;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const legacyOutline = conversationalOutlineToLegacy(outline);
|
|
63
|
+
const result = await runPresent({
|
|
64
|
+
outline: legacyOutline,
|
|
65
|
+
finalSpecPath: paths.composedSpec,
|
|
66
|
+
projectRoot,
|
|
67
|
+
overwritePolicy: policy,
|
|
68
|
+
});
|
|
69
|
+
if (!result.allWritten) {
|
|
70
|
+
if (result.conflictPath) {
|
|
71
|
+
process.stderr.write(`Refusing to overwrite ${result.conflictPath}. Pass --overwrite or --skip-existing.\n`);
|
|
72
|
+
}
|
|
73
|
+
process.exitCode = ExitCode.OverwriteRefused;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
for (const action of result.actions) {
|
|
77
|
+
process.stdout.write(` ${action.action}: ${action.path}\n`);
|
|
78
|
+
}
|
|
79
|
+
process.stdout.write(`Wrote ${result.actions.filter((a) => a.action === "created" || a.action === "overwrote").length} file(s) to .requirements/\n`);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=present-orchestrator.js.map
|
|
@@ -41,7 +41,18 @@ export async function skillInstallCommand(options = {}) {
|
|
|
41
41
|
else {
|
|
42
42
|
process.stdout.write(`SKILL.md already up to date at ${result.installedPath}\n`);
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
if (result.companions) {
|
|
45
|
+
process.stdout.write(`Installed cts-worker agent at ${result.companions.agentPath}\n`);
|
|
46
|
+
process.stdout.write(`Installed persona-injection hook at ${result.companions.hookScriptPath}\n`);
|
|
47
|
+
if (result.companions.hookRegistered) {
|
|
48
|
+
process.stdout.write(`Registered PreToolUse hook in ${result.companions.settingsPath}\n`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
process.stdout.write(`PreToolUse hook already registered in ${result.companions.settingsPath}\n`);
|
|
52
|
+
}
|
|
53
|
+
process.stdout.write("\n⚠️ The hook script uses `dotrequirements` from PATH. If you're working in a local dev clone, set DOTREQUIREMENTS_CLI to override (see the hook script for details).\n");
|
|
54
|
+
}
|
|
55
|
+
process.stdout.write("\nSkill ready. In Claude Code, invoke it with `/codebase-to-spec` (or via natural language).\n");
|
|
45
56
|
}
|
|
46
57
|
catch (err) {
|
|
47
58
|
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cts-worker
|
|
3
|
+
description: Generic worker subagent for the codebase-to-spec conversational orchestrator. Used for planner, specifier, editor, and reviewer dispatches. The per-dispatch persona is injected by the cts-worker-persona PreToolUse hook at dispatch time.
|
|
4
|
+
tools: Bash, Read, Edit, Write, Glob, Grep
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You are a codebase-to-spec worker. Your dispatched prompt is composed externally and supplied to you at dispatch time. It will specify your role for this dispatch (planner, specifier, editor, or reviewer), the artifacts you're working with, and the output convention you must follow.
|
|
8
|
+
|
|
9
|
+
Follow the dispatched prompt exactly. Do not improvise behavior beyond what it asks. When your work is done, submit via the convention specified in the dispatch (typically a `dotrequirements cts submit` call).
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PreToolUse hook for Task(subagent_type=cts-worker) dispatches.
|
|
3
|
+
# Composes the worker's first-turn prompt by calling
|
|
4
|
+
# `dotrequirements cts dispatch-context <dispatch-id>` and emits the
|
|
5
|
+
# result via `updatedInput.prompt`.
|
|
6
|
+
#
|
|
7
|
+
# The orchestrator's convention: the original Task prompt MUST include
|
|
8
|
+
# the verbatim token `dispatch-id=<id>` so the hook can extract it.
|
|
9
|
+
#
|
|
10
|
+
# Bundled with the codebase-to-spec skill (CTSO-CLI-1).
|
|
11
|
+
#
|
|
12
|
+
# CLI resolution order:
|
|
13
|
+
# 1. DOTREQUIREMENTS_CLI env var (explicit override)
|
|
14
|
+
# 2. If running inside the dotrequirements monorepo itself
|
|
15
|
+
# ($CLAUDE_PROJECT_DIR/packages/cli/dist/cli.js exists), use that
|
|
16
|
+
# local build. Lets dotrequirements developers use the orchestrator
|
|
17
|
+
# against any worktree without a global install.
|
|
18
|
+
# 3. `dotrequirements` from PATH (the canonical end-user setup).
|
|
19
|
+
|
|
20
|
+
INPUT=$(cat)
|
|
21
|
+
SUBAGENT_TYPE=$(echo "$INPUT" | jq -r '.tool_input.subagent_type // ""')
|
|
22
|
+
|
|
23
|
+
# Self-filter: only act on cts-worker dispatches.
|
|
24
|
+
if [[ "$SUBAGENT_TYPE" != "cts-worker" ]]; then
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
ORIGINAL_PROMPT=$(echo "$INPUT" | jq -r '.tool_input.prompt // ""')
|
|
29
|
+
|
|
30
|
+
# Extract dispatch-id token from the original prompt.
|
|
31
|
+
DISPATCH_ID=$(echo "$ORIGINAL_PROMPT" | grep -oE 'dispatch-id=[a-zA-Z0-9_-]+' | head -1 | sed 's/dispatch-id=//')
|
|
32
|
+
|
|
33
|
+
if [[ -z "$DISPATCH_ID" ]]; then
|
|
34
|
+
# No dispatch-id in the prompt — let it through unmodified.
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Resolve the CLI invocation (see header for order).
|
|
39
|
+
if [[ -n "${DOTREQUIREMENTS_CLI:-}" ]]; then
|
|
40
|
+
CLI="$DOTREQUIREMENTS_CLI"
|
|
41
|
+
elif [[ -n "${CLAUDE_PROJECT_DIR:-}" && -f "$CLAUDE_PROJECT_DIR/packages/cli/dist/cli.js" ]]; then
|
|
42
|
+
CLI="node $CLAUDE_PROJECT_DIR/packages/cli/dist/cli.js"
|
|
43
|
+
else
|
|
44
|
+
CLI="dotrequirements"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Compose the dispatch context. CLI returns JSON like {"prompt": "..."}.
|
|
48
|
+
COMPOSED=$($CLI cts dispatch-context "$DISPATCH_ID" 2>/dev/null)
|
|
49
|
+
COMPOSE_STATUS=$?
|
|
50
|
+
|
|
51
|
+
if [[ $COMPOSE_STATUS -ne 0 || -z "$COMPOSED" ]]; then
|
|
52
|
+
# CLI call failed — let the dispatch through unmodified so the
|
|
53
|
+
# worker's failure is legible.
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
PROMPT=$(echo "$COMPOSED" | jq -r '.prompt // ""')
|
|
58
|
+
|
|
59
|
+
if [[ -z "$PROMPT" ]]; then
|
|
60
|
+
exit 0
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# Emit updatedInput so the worker subagent sees the composed prompt
|
|
64
|
+
# as its first-turn input. (Field name is `updatedInput`, not
|
|
65
|
+
# `modifiedInput` — verified by spike work; see working doc.)
|
|
66
|
+
jq -nc --arg p "$PROMPT" '{
|
|
67
|
+
hookSpecificOutput: {
|
|
68
|
+
hookEventName: "PreToolUse",
|
|
69
|
+
permissionDecision: "allow",
|
|
70
|
+
updatedInput: {
|
|
71
|
+
prompt: $p
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}'
|
|
75
|
+
|
|
76
|
+
exit 0
|
|
@@ -1,118 +1,209 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: codebase-to-spec
|
|
3
|
-
description: Generate dotrequirements behavioral specifications from a codebase. Use this when the user wants to capture what an existing codebase does as a set of testable behavioral requirements
|
|
3
|
+
description: Generate dotrequirements behavioral specifications from a codebase via the conversational orchestrator. The user's CC session drives the pipeline directly — dispatching workers as subagents, reviewing per-area drafts, and iterating with editor passes. Use this when the user wants to capture what an existing codebase does as a set of testable behavioral requirements (legacy systems, third-party libraries, before refactoring).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Codebase to Spec
|
|
6
|
+
# Codebase to Spec — Conversational Orchestrator
|
|
7
7
|
|
|
8
|
-
You are
|
|
8
|
+
You are the conversational orchestrator for codebase-to-spec. Unlike a thin CLI wrapper, **you drive the pipeline directly** — dispatching workers as `cts-worker` subagents (via the Task tool), reading their outputs, writing per-stage reviews into `.dotrequirements-cache/outline.yaml`, and looping until each stage converges.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
2. Run the CLI via the Bash tool.
|
|
12
|
-
3. Narrate progress as the CLI emits it.
|
|
13
|
-
4. Surface the final summary and residual notes.
|
|
14
|
-
5. Offer sensible follow-ups (push to cloud, re-run, narrow scope, etc.).
|
|
10
|
+
The CLI provides dispatch-instruction commands (`cts dispatch-*`) that you call to scaffold each step; you then dispatch the worker subagent yourself. The substrate is the single evolving `outline.yaml` file — it carries both the spec content (areas, customers, source files) and the review thread for each stage.
|
|
15
11
|
|
|
16
12
|
## When this skill is right
|
|
17
13
|
|
|
18
|
-
Use
|
|
14
|
+
Use when the user wants behavioral requirements *from* code that already exists. Typical phrasings:
|
|
19
15
|
- "Generate requirements from this codebase"
|
|
20
16
|
- "Capture the behavior of this library"
|
|
21
17
|
- "I want a behavioral spec for the auth module"
|
|
22
18
|
- "Document what this service does"
|
|
23
19
|
|
|
24
|
-
Do **not** use
|
|
25
|
-
- New feature design (use `dotreq-requirements` / the capture flow instead)
|
|
26
|
-
- Bug investigation
|
|
27
|
-
- Code review
|
|
20
|
+
Do **not** use for new feature design (use the `dotreq-requirements` skill instead), bug investigation, or code review.
|
|
28
21
|
|
|
29
22
|
## Workflow
|
|
30
23
|
|
|
31
24
|
### Step 1 — Confirm scope
|
|
32
25
|
|
|
33
|
-
If the user passed a scope argument (
|
|
26
|
+
If the user passed a scope argument (path), use it. Otherwise ask one concise question:
|
|
34
27
|
|
|
35
|
-
> "Which part of the codebase should I spec?
|
|
28
|
+
> "Which part of the codebase should I spec? Give me a path (e.g. `src/auth`) or say 'the whole thing'."
|
|
36
29
|
|
|
37
|
-
|
|
30
|
+
For larger codebases, encourage scoping to a single area. The CLI will surface a `BudgetExceeded` exit code if the compressed pack is too large.
|
|
38
31
|
|
|
39
|
-
### Step 2 —
|
|
32
|
+
### Step 2 — Pack
|
|
40
33
|
|
|
41
|
-
|
|
34
|
+
Run `dotrequirements cts pack --scope <PATH>` via Bash. This is deterministic — no LLM work. The CLI emits `[CTS] pack/done` and `[CTS] pack/budget-ok` lines.
|
|
35
|
+
|
|
36
|
+
### Step 3 — Plan: dispatch the planner, review, iterate to approval
|
|
37
|
+
|
|
38
|
+
**3a. Initial planner dispatch.** Run `dotrequirements cts dispatch-planner` via Bash. The output is JSON like `{ "dispatch_id": "planner-initial", "output_path": "..." }`. Dispatch the worker:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Task(subagent_type="cts-worker", prompt="dispatch-id=planner-initial")
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The PreToolUse hook composes the full planner prompt; the worker writes `outline.yaml` and signals completion.
|
|
45
|
+
|
|
46
|
+
**3b. Review the outline.** Read `.dotrequirements-cache/outline.yaml`. Assess:
|
|
47
|
+
- **Customer naming**: Each area must have ≥1 customers with concrete, area-scoped descriptions (not "a developer" — "a Python data engineer building ETL pipelines"). Same role across areas is OK if described freshly per area's context.
|
|
48
|
+
- **Area set**: Customer-vocabulary names, not architectural labels. Coverage of substantive files; non-behavioral files (tests, build infrastructure) excluded.
|
|
49
|
+
- **Mechanical correctness**: distinct prefixes per area; paths matching the pack; ≥1 customer per area.
|
|
50
|
+
|
|
51
|
+
**3c. Write your review into outline.yaml.** Edit the outline to add a top-level `review:` section. Two shapes:
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
# Approved
|
|
55
|
+
review:
|
|
56
|
+
result: approved
|
|
57
|
+
thread:
|
|
58
|
+
- result: approved
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
# Needs revision (revisions list is required, ≥1 entries)
|
|
63
|
+
review:
|
|
64
|
+
result: needs-revision
|
|
65
|
+
thread:
|
|
66
|
+
- result: needs-revision
|
|
67
|
+
revisions:
|
|
68
|
+
- "Split the FOO area into two areas, separating the producer behavior from the reviewer behavior. Each should have its own customer and source files."
|
|
69
|
+
- "Tighten the customer description on BAR — it currently reads as generic 'a developer'; ground it in what the customer is doing at this specific moment in the system."
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Revisions must be specific, actionable directives the planner can apply mechanically. Avoid "this feels off" — say what to change.
|
|
73
|
+
|
|
74
|
+
**3d. If needs-revision, dispatch the planner again.** Run `dotrequirements cts dispatch-planner --revise`. Dispatch:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Task(subagent_type="cts-worker", prompt="dispatch-id=planner-revise-<N>")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
(N comes from the CLI's payload — `planner-revise-2` for the 2nd round, `planner-revise-3` for the 3rd, etc.)
|
|
81
|
+
|
|
82
|
+
The worker rewrites outline.yaml's content while preserving the existing `review` section. After it completes, return to step 3b and review the revised outline. Append another entry to the `review.thread` array based on what you find.
|
|
83
|
+
|
|
84
|
+
**3e. Approval.** When you're satisfied, edit outline.yaml to set `review.result: approved` and append a `{ result: approved }` entry to the thread. Proceed to step 4.
|
|
85
|
+
|
|
86
|
+
### Step 4 — Fan out: dispatch all specifiers in parallel
|
|
87
|
+
|
|
88
|
+
Run `dotrequirements cts dispatch-spec`. The output is a JSON array of N payloads, one per area:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
[
|
|
92
|
+
{ "dispatch_id": "specifier-PLAN", "output_path": "...", "area_name": "...", "area_prefix": "PLAN" },
|
|
93
|
+
...
|
|
94
|
+
]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Fire all N background Task dispatches in **one message** (parallel, not sequential):
|
|
42
98
|
|
|
43
|
-
```bash
|
|
44
|
-
dotrequirements cts run --scope <PATH> --non-interactive
|
|
45
99
|
```
|
|
100
|
+
Task(subagent_type="cts-worker", prompt="dispatch-id=specifier-PLAN", run_in_background=true)
|
|
101
|
+
Task(subagent_type="cts-worker", prompt="dispatch-id=specifier-OREV", run_in_background=true)
|
|
102
|
+
... etc
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Each worker:
|
|
106
|
+
- Reads the area's source files via Read tool (from `.dotrequirements-cache/source.txt` or directly from the worktree)
|
|
107
|
+
- Drafts the partial at `.dotrequirements-cache/partials/<sanitized-area>.partial.md`
|
|
108
|
+
- Runs `cts validate` + `cts style-check` on its own draft via Bash (self-style-check loop, capped at 2 runs)
|
|
109
|
+
- Signals completion via task-notification
|
|
110
|
+
|
|
111
|
+
### Step 5 — Per-area review and editor loops
|
|
112
|
+
|
|
113
|
+
As each specifier's task-notification arrives, review that area's partial:
|
|
114
|
+
|
|
115
|
+
**5a. Read the partial.** Pull up the file the worker wrote.
|
|
46
116
|
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
117
|
+
**5b. Review against per-area criteria.** The area's customer descriptions in outline.yaml ground your review. Look for:
|
|
118
|
+
- **Customer-grounding**: requirements use named personas from the area's customers
|
|
119
|
+
- **Behavioral framing**: requirements describe what the customer observes, not API contracts or implementation mechanics
|
|
120
|
+
- **Independent testability**: no cross-references between requirements; each readable on its own
|
|
121
|
+
- **Coverage**: behaviors visible in source files are captured; tests/recipes informed but didn't drift into the spec
|
|
122
|
+
- **Schema cleanliness**: validate already ran (worker self-validated); just sanity-check
|
|
53
123
|
|
|
54
|
-
|
|
124
|
+
**5c. Write your review into outline.yaml's area section.** Same shape as the project-level review, on the area:
|
|
55
125
|
|
|
56
|
-
|
|
126
|
+
```yaml
|
|
127
|
+
areas:
|
|
128
|
+
- name: ...
|
|
129
|
+
prefix: PLAN
|
|
130
|
+
review:
|
|
131
|
+
result: approved
|
|
132
|
+
thread:
|
|
133
|
+
- result: approved
|
|
134
|
+
...
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Or needs-revision with a revisions list (≥1 entries).
|
|
57
138
|
|
|
58
|
-
|
|
139
|
+
**5d. If needs-revision, dispatch the editor.** Run `dotrequirements cts dispatch-editor <area-prefix>`. Then:
|
|
59
140
|
|
|
60
141
|
```
|
|
61
|
-
|
|
62
|
-
[CTS] plan/done Plan loop converged at turn 1 with verdict: approved-with-revisions
|
|
63
|
-
[CTS] specify/summary Completed: 7 / Skipped (resume): 0 / Failed: 0
|
|
64
|
-
[CTS] spec-review/done Edit loop converged at turn 1 with verdict: approved-with-revisions
|
|
65
|
-
[CTS] present/created created: .../sample.requirements.md
|
|
142
|
+
Task(subagent_type="cts-worker", prompt="dispatch-id=editor-<prefix>")
|
|
66
143
|
```
|
|
67
144
|
|
|
68
|
-
|
|
145
|
+
The worker reads the current partial + the revisions list inline (in the composed prompt), applies each revision via Edit, runs validate + style-check, signals completion. Return to 5a and re-review.
|
|
146
|
+
|
|
147
|
+
**5e. Convergence.** Continue per-area loops until every area's `review.result` is `approved`. Each area can converge independently; don't block on one area to start reviewing another.
|
|
148
|
+
|
|
149
|
+
### Step 6 — Cross-area review
|
|
150
|
+
|
|
151
|
+
Once all per-area reviews are approved, run `cts compose-orchestrator` to assemble the composed spec. Then read it and check:
|
|
152
|
+
|
|
153
|
+
- **Persona consistency**: same role mentioned across areas should use consistent naming
|
|
154
|
+
- **Duplicated behaviors**: same behavior captured in two areas (one should own it)
|
|
155
|
+
- **Cross-area gaps**: behaviors that fell between areas
|
|
156
|
+
- **Framing drift**: areas in different voices
|
|
157
|
+
|
|
158
|
+
If cross-area concerns surface, edit the affected areas' `review` to needs-revision with appropriate revisions, dispatch editors per 5d, then re-compose. Otherwise proceed to step 7.
|
|
159
|
+
|
|
160
|
+
### Step 7 — Present
|
|
161
|
+
|
|
162
|
+
Run `dotrequirements cts present-orchestrator [--overwrite] [--skip-existing]` via Bash. Writes the final files under `.requirements/`. Per CTS-PRESENT-1, splits into per-area files when the outline has ≥5 areas; single file otherwise.
|
|
163
|
+
|
|
164
|
+
In non-interactive mode without `--overwrite` / `--skip-existing`, the CLI errors on conflicts. Ask the user which they want when a conflict is detected.
|
|
69
165
|
|
|
70
|
-
### Step
|
|
166
|
+
### Step 8 — Summarize and offer follow-ups
|
|
71
167
|
|
|
72
|
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
- specifier completion count
|
|
77
|
-
- spec review turns and verdict
|
|
78
|
-
- the list of output files written
|
|
79
|
-
- residual notes (issues the reviewer flagged in `approved-with-revisions` outcomes)
|
|
168
|
+
Present the final summary in conversational form:
|
|
169
|
+
- How many areas, how many requirements
|
|
170
|
+
- Any unconverged areas (latest thread entry was max-turns-hit)
|
|
171
|
+
- File paths written
|
|
80
172
|
|
|
81
|
-
|
|
82
|
-
- `
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
- `spec.cross_area` — duplication across areas
|
|
86
|
-
- `spec.internal_mechanics` — internal vocabulary that leaked into a user-facing spec
|
|
173
|
+
Offer useful follow-ups:
|
|
174
|
+
- **Push to cloud** — `dotrequirements push` syncs to dotrequirements cloud. Only suggest if the user has cloud configured (check `.dotrequirements/config.json` or ask).
|
|
175
|
+
- **Refine an area** — re-review one area; mark needs-revision; re-dispatch editor.
|
|
176
|
+
- **Re-run on different scope** — start over with a different `--scope` path.
|
|
87
177
|
|
|
88
|
-
|
|
178
|
+
## Pausing for user input
|
|
89
179
|
|
|
90
|
-
|
|
180
|
+
These moments naturally invite user judgment — surface them in conversation rather than auto-deciding:
|
|
181
|
+
- **Scope confirmation** at the start
|
|
182
|
+
- **Outline approval** before fan-out (the area decomposition is high-leverage)
|
|
183
|
+
- **Cross-area concerns** that look like the user's call (e.g., "should X and Y be one area or two?")
|
|
184
|
+
- **Residual concerns** at the end (anything the loop didn't fully address)
|
|
91
185
|
|
|
92
|
-
|
|
93
|
-
- **Refine a specific area** — re-run `dotrequirements cts specify-area "<name>"` for one area, optionally with `--model <name>` for a stronger model.
|
|
94
|
-
- **Refine the whole spec** — re-run `dotrequirements cts edit-loop` to iterate on the composed spec.
|
|
95
|
-
- **Narrow the scope** — re-run with a smaller `--scope`.
|
|
96
|
-
- **Hand-edit** — the output files are plain Markdown; the user can edit them directly.
|
|
186
|
+
Routine progress narration ("dispatching planner...", "fan-out complete...") should NOT interrupt the user. Only judgment-requiring moments surface as questions.
|
|
97
187
|
|
|
98
188
|
## Failure handling
|
|
99
189
|
|
|
100
|
-
The CLI uses stable exit codes
|
|
190
|
+
The CLI uses stable exit codes:
|
|
101
191
|
|
|
102
|
-
- **Exit
|
|
103
|
-
- **Exit
|
|
104
|
-
- **Exit
|
|
105
|
-
- **Exit
|
|
106
|
-
- **
|
|
192
|
+
- **Exit 10 (BudgetExceeded)** — codebase too large after compression. Surface, offer narrower `--scope`.
|
|
193
|
+
- **Exit 11 (MaxTurnsHit)** — review loop hit its cap. Latest artifact is on disk; surface residual notes and ask user whether to ship, re-iterate, or hand-edit.
|
|
194
|
+
- **Exit 12 (OverwriteRefused)** — present found existing files. Offer `--overwrite` or `--skip-existing`.
|
|
195
|
+
- **Exit 2 (MissingInput)** — usually means a prior step wasn't run. Surface CLI message verbatim.
|
|
196
|
+
- **Exit 3 (StageFailed)** — a stage errored. Read stderr; offer resume (re-run same command — the cache means earlier stages are skipped), restart fresh (`--fresh`), or investigate.
|
|
107
197
|
|
|
108
198
|
## What you must NOT do
|
|
109
199
|
|
|
110
|
-
- Don't try to generate requirements yourself; always
|
|
111
|
-
- Don't paraphrase
|
|
112
|
-
- Don't claim
|
|
200
|
+
- Don't try to generate requirements yourself; always dispatch workers.
|
|
201
|
+
- Don't paraphrase the CLI's progress lines in misleading ways. If the CLI emits "specifier failed", don't say "specifier completed."
|
|
202
|
+
- Don't claim convergence when an area's thread ends with `needs-revision`. The loop hasn't closed.
|
|
113
203
|
- Don't push to cloud without asking — `dotrequirements push` is a destructive sync.
|
|
114
|
-
- Don't
|
|
204
|
+
- Don't edit files inside `.dotrequirements-cache/` other than `outline.yaml` (which you DO edit, to write reviews). Other cache files are managed by the CLI and workers.
|
|
205
|
+
- Don't dispatch a worker without the corresponding `cts dispatch-*` call first — the dispatch-id must match what the CLI scaffolded.
|
|
115
206
|
|
|
116
207
|
## Host portability
|
|
117
208
|
|
|
118
|
-
This skill
|
|
209
|
+
This skill relies on Claude Code's Task tool, PreToolUse hook, and Bash. It does not work on hosts without subagent dispatch (Cursor, Codex) — those should use the legacy `cts run` CLI directly. The skill is bundled with `dotrequirements ai-setup` for Claude Code; the `cts-worker` agent definition and persona-injection hook are installed at the same time.
|