@plainconceptsplatform/agent-harness 3.1.0 → 3.2.0

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.
Files changed (65) hide show
  1. package/README.md +452 -434
  2. package/cli/commands/update.js +1 -1
  3. package/cli/fragments/archive/az.md +97 -97
  4. package/cli/fragments/archive/gh.md +96 -96
  5. package/cli/fragments/archive/gl.md +96 -96
  6. package/cli/fragments/archive/none.md +75 -75
  7. package/cli/fragments/guardrails/codegraph.md +5 -5
  8. package/cli/fragments/guardrails/humanizer.md +4 -4
  9. package/cli/fragments/guardrails/memory.md +4 -4
  10. package/cli/fragments/guardrails/rtk.md +3 -3
  11. package/cli/fragments/guardrails/simple-english.md +4 -4
  12. package/cli/fragments/ops-ship/az.md +81 -81
  13. package/cli/index.js +0 -0
  14. package/cli/presets/agents-content.json +34 -34
  15. package/cli/presets/browser.json +10 -10
  16. package/cli/steps/browser/index.js +48 -48
  17. package/cli/steps/copy/commands.js +79 -79
  18. package/cli/steps/copy/index.js +88 -88
  19. package/cli/steps/copy/skills.js +307 -307
  20. package/cli/steps/metadata/index.js +5 -2
  21. package/cli/steps/models/write.js +5 -1
  22. package/cli/utils/copy.js +5 -2
  23. package/cli/utils/paths.js +80 -80
  24. package/harness/.opencode/_gitignore +9 -9
  25. package/harness/.opencode/commands/init.md +5 -5
  26. package/harness/.opencode/commands/make-architecture.md +5 -5
  27. package/harness/.opencode/commands/make-design.md +5 -5
  28. package/harness/.opencode/commands/make-engineer.md +5 -5
  29. package/harness/.opencode/commands/make-guardrails.md +5 -5
  30. package/harness/.opencode/commands/make-user-model.md +5 -5
  31. package/harness/.opencode/commands/plan-apply.md +9 -9
  32. package/harness/.opencode/commands/plan-goal.md +5 -5
  33. package/harness/.opencode/commands/plan-quick.md +5 -5
  34. package/harness/.opencode/commands/plan-story.md +9 -9
  35. package/harness/.opencode/commands/repo-audit.md +5 -5
  36. package/harness/.opencode/commands/repo-initialize.md +5 -5
  37. package/harness/.opencode/commands/repo-onboard.md +5 -5
  38. package/harness/.opencode/commands/repo-verify.md +5 -5
  39. package/harness/.opencode/scripts/check-diff.mjs +225 -0
  40. package/harness/.opencode/scripts/code-rules.mjs +280 -0
  41. package/harness/AGENTS.md +49 -49
  42. package/package.json +12 -14
  43. package/skills/README.md +18 -18
  44. package/skills/browser-automation/SKILL.md +72 -72
  45. package/skills/pc-guardrails-generic/SKILL.md +2 -1
  46. package/skills/pc-make-architecture/SKILL.md +32 -32
  47. package/skills/pc-make-design/SKILL.md +45 -45
  48. package/skills/pc-make-engineer/signal-mapping.md +53 -53
  49. package/skills/pc-make-guardrails/SKILL.md +44 -44
  50. package/skills/pc-make-user-model/SKILL.md +56 -56
  51. package/skills/pc-plan-apply/SKILL.md +1 -1
  52. package/skills/pc-plan-apply/simple-mode.md +21 -21
  53. package/skills/pc-plan-archive/SKILL.md +66 -66
  54. package/skills/pc-plan-goal/branching.md +39 -39
  55. package/skills/pc-plan-goal/output.md +71 -71
  56. package/skills/pc-plan-quick/SKILL.md +46 -46
  57. package/skills/pc-plan-story/SKILL.md +93 -93
  58. package/skills/pc-repo-help/SKILL.md +87 -87
  59. package/skills/pc-repo-initialize/SKILL.md +119 -119
  60. package/skills/pc-repo-onboard/SKILL.md +32 -32
  61. package/skills/pc-repo-verify/SKILL.md +150 -150
  62. package/skills/pc-userstory-az/SKILL.md +71 -71
  63. package/skills/pc-userstory-browser/SKILL.md +64 -64
  64. package/skills/pc-userstory-gh/SKILL.md +63 -63
  65. package/skills/pc-userstory-jira/SKILL.md +74 -74
@@ -1,66 +1,66 @@
1
- ---
2
- name: pc-plan-archive
3
- description: Archive a completed OpenSpec change and update documentation. Interactive mode finds the oldest merged unarchived change and opens an archive PR; autonomous mode archives a named change in place on the current branch. Invoked by the /plan-archive command (interactive) and the plan-goal pipeline (autonomous).
4
- license: MIT
5
- ---
6
-
7
- # Plan Archive
8
-
9
- <!-- PC-OPTIMIZATION-MEMORY-START -->
10
- <!-- PC-OPTIMIZATION-MEMORY-END -->
11
-
12
- ## Input
13
-
14
- The caller provides (all optional):
15
- - A mode (see below). Default: `interactive`.
16
- - In autonomous mode: the change id to archive (required in that mode; the caller knows which change it just implemented).
17
-
18
- ## Modes
19
-
20
- - interactive (default): full flow below. Find the oldest unarchived change with a completed PR, confirm with the user, archive it, update docs with approval, and open an archive PR. No input required.
21
- - autonomous: the caller names the change to archive. Skip the working-tree prep, the PR lookup, the confirmation prompt, and the archive-PR step. Instead, archive in place on the current branch:
22
- 1. Archive the change by its id. Prefer the `@openspec-archive-change` skill if it is available. If it is not available, run the CLI directly, and it must be non-interactive, because there is no user to answer prompts:
23
-
24
- ```bash
25
- openspec archive "<change-id>" -y
26
- ```
27
-
28
- `-y` skips the confirmation prompt (without it the command blocks forever in an unattended run). Add `--skip-specs` only for infra/tooling/doc-only changes that produced no spec deltas. If the command reports the change is already archived, treat that as success.
29
- 2. Verify the archive actually moved. The change folder must no longer exist at `openspec/changes/<change-id>/`, and a dated copy must now exist under `openspec/changes/archive/` (the CLI renames it to `archive/YYYY-MM-DD-<change-id>/`):
30
-
31
- ```bash
32
- REPO_ROOT="$(git rev-parse --show-toplevel)"
33
- test ! -d "$REPO_ROOT/openspec/changes/<change-id>" \
34
- && ls -d "$REPO_ROOT/openspec/changes/archive/"*"<change-id>" >/dev/null 2>&1 \
35
- && echo ARCHIVED_OK || echo ARCHIVE_FAILED
36
- ```
37
-
38
- If this prints `ARCHIVE_FAILED`, run the archive once more and repeat the check. If it still fails, report it to the caller as a failure; do not pretend it succeeded.
39
- 3. Compare the archived change's specs against `ARCHITECTURE.md` and `DESIGN.md`; apply any needed doc updates directly (no approval prompt).
40
- 4. If the change was a bug fix or new functionality with important impact, check if `@pc-guardrails-project` exists and update it.
41
- 5. Do not commit or push: the caller owns the git operations.
42
- 6. The ARCHIVE stage is complete. Hand control back to the caller (the `/plan-goal` pipeline) so it continues with output. Do not stop or end the turn here; archiving is not the end of the run.
43
-
44
- ---
45
-
46
- ## Interactive flow
47
-
48
- Steps
49
-
50
- 1. Prepare working tree
51
-
52
- ```bash
53
- REPO_ROOT="$(git rev-parse --show-toplevel)"
54
- DEFAULT_BRANCH="$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')"
55
- [ -z "$DEFAULT_BRANCH" ] && DEFAULT_BRANCH="main"
56
- ```
57
-
58
- 1. If the tree has uncommitted changes: `git stash push -u -m "WIP before archive"` and tell the user their work is stashed (it is restored in step 6).
59
- 2. Sync the default branch (skip the pull if there is no `origin` remote):
60
-
61
- ```bash
62
- git switch "$DEFAULT_BRANCH" && git pull origin "$DEFAULT_BRANCH"
63
- ```
64
-
65
- <!-- PC-PLATFORM-ARCHIVE-START -->
66
- <!-- PC-PLATFORM-ARCHIVE-END -->
1
+ ---
2
+ name: pc-plan-archive
3
+ description: Archive a completed OpenSpec change and update documentation. Interactive mode finds the oldest merged unarchived change and opens an archive PR; autonomous mode archives a named change in place on the current branch. Invoked by the /plan-archive command (interactive) and the plan-goal pipeline (autonomous).
4
+ license: MIT
5
+ ---
6
+
7
+ # Plan Archive
8
+
9
+ <!-- PC-OPTIMIZATION-MEMORY-START -->
10
+ <!-- PC-OPTIMIZATION-MEMORY-END -->
11
+
12
+ ## Input
13
+
14
+ The caller provides (all optional):
15
+ - A mode (see below). Default: `interactive`.
16
+ - In autonomous mode: the change id to archive (required in that mode; the caller knows which change it just implemented).
17
+
18
+ ## Modes
19
+
20
+ - interactive (default): full flow below. Find the oldest unarchived change with a completed PR, confirm with the user, archive it, update docs with approval, and open an archive PR. No input required.
21
+ - autonomous: the caller names the change to archive. Skip the working-tree prep, the PR lookup, the confirmation prompt, and the archive-PR step. Instead, archive in place on the current branch:
22
+ 1. Archive the change by its id. Prefer the `@openspec-archive-change` skill if it is available. If it is not available, run the CLI directly, and it must be non-interactive, because there is no user to answer prompts:
23
+
24
+ ```bash
25
+ openspec archive "<change-id>" -y
26
+ ```
27
+
28
+ `-y` skips the confirmation prompt (without it the command blocks forever in an unattended run). Add `--skip-specs` only for infra/tooling/doc-only changes that produced no spec deltas. If the command reports the change is already archived, treat that as success.
29
+ 2. Verify the archive actually moved. The change folder must no longer exist at `openspec/changes/<change-id>/`, and a dated copy must now exist under `openspec/changes/archive/` (the CLI renames it to `archive/YYYY-MM-DD-<change-id>/`):
30
+
31
+ ```bash
32
+ REPO_ROOT="$(git rev-parse --show-toplevel)"
33
+ test ! -d "$REPO_ROOT/openspec/changes/<change-id>" \
34
+ && ls -d "$REPO_ROOT/openspec/changes/archive/"*"<change-id>" >/dev/null 2>&1 \
35
+ && echo ARCHIVED_OK || echo ARCHIVE_FAILED
36
+ ```
37
+
38
+ If this prints `ARCHIVE_FAILED`, run the archive once more and repeat the check. If it still fails, report it to the caller as a failure; do not pretend it succeeded.
39
+ 3. Compare the archived change's specs against `ARCHITECTURE.md` and `DESIGN.md`; apply any needed doc updates directly (no approval prompt).
40
+ 4. If the change was a bug fix or new functionality with important impact, check if `@pc-guardrails-project` exists and update it.
41
+ 5. Do not commit or push: the caller owns the git operations.
42
+ 6. The ARCHIVE stage is complete. Hand control back to the caller (the `/plan-goal` pipeline) so it continues with output. Do not stop or end the turn here; archiving is not the end of the run.
43
+
44
+ ---
45
+
46
+ ## Interactive flow
47
+
48
+ Steps
49
+
50
+ 1. Prepare working tree
51
+
52
+ ```bash
53
+ REPO_ROOT="$(git rev-parse --show-toplevel)"
54
+ DEFAULT_BRANCH="$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')"
55
+ [ -z "$DEFAULT_BRANCH" ] && DEFAULT_BRANCH="main"
56
+ ```
57
+
58
+ 1. If the tree has uncommitted changes: `git stash push -u -m "WIP before archive"` and tell the user their work is stashed (it is restored in step 6).
59
+ 2. Sync the default branch (skip the pull if there is no `origin` remote):
60
+
61
+ ```bash
62
+ git switch "$DEFAULT_BRANCH" && git pull origin "$DEFAULT_BRANCH"
63
+ ```
64
+
65
+ <!-- PC-PLATFORM-ARCHIVE-START -->
66
+ <!-- PC-PLATFORM-ARCHIVE-END -->
@@ -1,39 +1,39 @@
1
- # Branching procedure
2
-
3
- Resolve and record the branch names. If the invoking workflow already placed you on a feature branch (`feature/*`, `fix/*`, etc.), it owns the branch: do not stash, switch, pull, or rename. The sandbox hosting the workflow has no git credentials, so those commands would either corrupt the tree or hang, and the workflow has already cut the branch from the default branch. Treat its result as given.
4
-
5
- ```bash
6
- BRANCH="$(git branch --show-current)"
7
- case "$BRANCH" in
8
- feature/*|fix/*|chore/*|docs/*|refactor/*)
9
- START_BRANCH="$BRANCH"
10
- DEFAULT_BRANCH="$BRANCH"
11
- GOAL_STASH="none"
12
- ;;
13
- *)
14
- START_BRANCH="$BRANCH"
15
- DEFAULT_BRANCH="$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')"
16
- [ -z "$DEFAULT_BRANCH" ] && DEFAULT_BRANCH="main"
17
-
18
- # Stash uncommitted work when needed and record that the goal stash exists.
19
- git stash push -u -m "goal-wip"
20
- GOAL_STASH="goal-wip"
21
-
22
- # Create the feature branch from the synchronized default branch.
23
- git switch "$DEFAULT_BRANCH"
24
-
25
- if git remote get-url origin >/dev/null 2>&1; then
26
- git pull origin "$DEFAULT_BRANCH"
27
- fi
28
-
29
- git switch -c "feature/{slug}"
30
- BRANCH="$(git branch --show-current)"
31
- ;;
32
- esac
33
- ```
34
-
35
- Record the branch name and that `feature/{slug}` was applied unconditionally, so downstream phases can restore if they move off it.
36
-
37
- Everything through archive happens on `$BRANCH`.
38
-
39
- When a later phase renames `$BRANCH` to match the canonical change slug (Phase 3 of `pc-plan-goal`), skip the rename if the workflow already fixed the name. Renaming would call `git branch -m`, which a credentialless sandbox refuses, and the workflow's `create_pull_request` is told to use the branch as named. Detect this by checking that `$BRANCH` already starts with `feature/`; if it does, keep it.
1
+ # Branching procedure
2
+
3
+ Resolve and record the branch names. If the invoking workflow already placed you on a feature branch (`feature/*`, `fix/*`, etc.), it owns the branch: do not stash, switch, pull, or rename. The sandbox hosting the workflow has no git credentials, so those commands would either corrupt the tree or hang, and the workflow has already cut the branch from the default branch. Treat its result as given.
4
+
5
+ ```bash
6
+ BRANCH="$(git branch --show-current)"
7
+ case "$BRANCH" in
8
+ feature/*|fix/*|chore/*|docs/*|refactor/*)
9
+ START_BRANCH="$BRANCH"
10
+ DEFAULT_BRANCH="$BRANCH"
11
+ GOAL_STASH="none"
12
+ ;;
13
+ *)
14
+ START_BRANCH="$BRANCH"
15
+ DEFAULT_BRANCH="$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')"
16
+ [ -z "$DEFAULT_BRANCH" ] && DEFAULT_BRANCH="main"
17
+
18
+ # Stash uncommitted work when needed and record that the goal stash exists.
19
+ git stash push -u -m "goal-wip"
20
+ GOAL_STASH="goal-wip"
21
+
22
+ # Create the feature branch from the synchronized default branch.
23
+ git switch "$DEFAULT_BRANCH"
24
+
25
+ if git remote get-url origin >/dev/null 2>&1; then
26
+ git pull origin "$DEFAULT_BRANCH"
27
+ fi
28
+
29
+ git switch -c "feature/{slug}"
30
+ BRANCH="$(git branch --show-current)"
31
+ ;;
32
+ esac
33
+ ```
34
+
35
+ Record the branch name and that `feature/{slug}` was applied unconditionally, so downstream phases can restore if they move off it.
36
+
37
+ Everything through archive happens on `$BRANCH`.
38
+
39
+ When a later phase renames `$BRANCH` to match the canonical change slug (Phase 3 of `pc-plan-goal`), skip the rename if the workflow already fixed the name. Renaming would call `git branch -m`, which a credentialless sandbox refuses, and the workflow's `create_pull_request` is told to use the branch as named. Detect this by checking that `$BRANCH` already starts with `feature/`; if it does, keep it.
@@ -1,71 +1,71 @@
1
- # Output procedure
2
-
3
- Before output, require `verify`, `archive`, a clean working tree, no active change directory, and an archive directory for `{change-id}`.
4
-
5
- ## Restore stash
6
-
7
- If the goal created `goal-wip`, restore it after the mode-specific operation. When restoration conflicts, leave the stash intact, report its `git stash list` reference, and do not drop user work.
8
-
9
- ## Default mode
10
-
11
- Synchronize the default branch, merge, delete the feature branch, then restore the stash:
12
-
13
- ```bash
14
- git switch "$DEFAULT_BRANCH"
15
-
16
- if git remote get-url origin >/dev/null 2>&1; then
17
- git pull origin "$DEFAULT_BRANCH"
18
- fi
19
-
20
- git merge --no-ff "$BRANCH" -m "goal: {title} ({change-id})"
21
- git branch -d "$BRANCH"
22
- ```
23
-
24
- If the merge conflicts, abort it and use the failure policy. Do not push the default branch.
25
-
26
- ## Push mode
27
-
28
- Push the feature branch:
29
-
30
- ```bash
31
- git push -u origin "$BRANCH"
32
- ```
33
-
34
- Restore the stash and leave the branch available.
35
-
36
- ## PR mode
37
-
38
- Push the feature branch, then load `pc-ops-ship` to create a PR into `$DEFAULT_BRANCH`. Supply title, change id, functional summary, delivered acceptance criteria, task count, verification result, archive path, and commits. Do not merge the PR.
39
-
40
- Restore the stash.
41
-
42
- ## Branch mode
43
-
44
- Leave `$BRANCH` in place with its commits. Merge nothing, push nothing, delete nothing.
45
-
46
- Restore the stash.
47
-
48
- ## Final report
49
-
50
- Print:
51
-
52
- ```text
53
- Goal: {title}
54
- Change ID: {change-id}
55
- Scope classification: focused | standard | complex
56
- Functional outcome: {one-sentence result}
57
- Branch: {branch}
58
- Tasks: {completed}/{total}
59
- Acceptance criteria: {passed}/{total}
60
- Commits: {proposal, apply, archive}
61
- Verification: passed | failed
62
- Archived: yes | no
63
- Archive path: {path or none}
64
- Output mode: default | push | pr | branch
65
- Final state: merged locally | pushed branch | PR URL | branch preserved | branch preserved after failure
66
- Stash restoration: not needed | restored | preserved after conflict
67
- ```
68
-
69
- ## External gate
70
-
71
- An unattended caller must verify `openspec list --json` is empty and run the project's lint and typecheck commands before any later git operation.
1
+ # Output procedure
2
+
3
+ Before output, require `verify`, `archive`, a clean working tree, no active change directory, and an archive directory for `{change-id}`.
4
+
5
+ ## Restore stash
6
+
7
+ If the goal created `goal-wip`, restore it after the mode-specific operation. When restoration conflicts, leave the stash intact, report its `git stash list` reference, and do not drop user work.
8
+
9
+ ## Default mode
10
+
11
+ Synchronize the default branch, merge, delete the feature branch, then restore the stash:
12
+
13
+ ```bash
14
+ git switch "$DEFAULT_BRANCH"
15
+
16
+ if git remote get-url origin >/dev/null 2>&1; then
17
+ git pull origin "$DEFAULT_BRANCH"
18
+ fi
19
+
20
+ git merge --no-ff "$BRANCH" -m "goal: {title} ({change-id})"
21
+ git branch -d "$BRANCH"
22
+ ```
23
+
24
+ If the merge conflicts, abort it and use the failure policy. Do not push the default branch.
25
+
26
+ ## Push mode
27
+
28
+ Push the feature branch:
29
+
30
+ ```bash
31
+ git push -u origin "$BRANCH"
32
+ ```
33
+
34
+ Restore the stash and leave the branch available.
35
+
36
+ ## PR mode
37
+
38
+ Push the feature branch, then load `pc-ops-ship` to create a PR into `$DEFAULT_BRANCH`. Supply title, change id, functional summary, delivered acceptance criteria, task count, verification result, archive path, and commits. Do not merge the PR.
39
+
40
+ Restore the stash.
41
+
42
+ ## Branch mode
43
+
44
+ Leave `$BRANCH` in place with its commits. Merge nothing, push nothing, delete nothing.
45
+
46
+ Restore the stash.
47
+
48
+ ## Final report
49
+
50
+ Print:
51
+
52
+ ```text
53
+ Goal: {title}
54
+ Change ID: {change-id}
55
+ Scope classification: focused | standard | complex
56
+ Functional outcome: {one-sentence result}
57
+ Branch: {branch}
58
+ Tasks: {completed}/{total}
59
+ Acceptance criteria: {passed}/{total}
60
+ Commits: {proposal, apply, archive}
61
+ Verification: passed | failed
62
+ Archived: yes | no
63
+ Archive path: {path or none}
64
+ Output mode: default | push | pr | branch
65
+ Final state: merged locally | pushed branch | PR URL | branch preserved | branch preserved after failure
66
+ Stash restoration: not needed | restored | preserved after conflict
67
+ ```
68
+
69
+ ## External gate
70
+
71
+ An unattended caller must verify `openspec list --json` is empty and run the project's lint and typecheck commands before any later git operation.
@@ -1,46 +1,46 @@
1
- ---
2
- name: pc-plan-quick
3
- description: "Quick plan: analyze the codebase and create a task checklist using the Todo pane. No files, no OpenSpec. Invoked by the /plan-quick command."
4
- license: MIT
5
- ---
6
-
7
- Lightweight planning for a change that is already clear: read the codebase, write the task list to the Todo pane, stop. Use `/plan-explore` then `/plan-propose` instead when the idea is half-formed, the alternatives need thinking through, or the result should outlive the session.
8
-
9
- ## Rules
10
-
11
- - Never write, edit, or create a file. The only artefacts are Todo items and one question, so there is nothing to review afterwards and nothing to undo.
12
- - Never start the work, and never invoke `/plan-apply` or `/plan-propose` on the user's behalf. The question at the end is where they choose.
13
-
14
- ## Contracts
15
-
16
- One Todo item per task, in dependency order, each one action naming the files it touches:
17
-
18
- ```json
19
- {
20
- "todos": [
21
- { "content": "Add Project model to src/types.ts", "status": "pending", "priority": "high" },
22
- { "content": "Add projectId field to LoopOptions in src/types.ts", "status": "pending", "priority": "high" },
23
- { "content": "Create Project RPC endpoints in src/rpc/project/", "status": "pending", "priority": "medium" },
24
- { "content": "Build Accept page UI in src/board/components/CreateForm.tsx", "status": "pending", "priority": "medium" },
25
- { "content": "Run typecheck and fix errors", "status": "pending", "priority": "low" }
26
- ]
27
- }
28
- ```
29
-
30
- Then ask:
31
-
32
- ```json
33
- {
34
- "questions": [
35
- {
36
- "header": "What next",
37
- "question": "What next?",
38
- "options": [
39
- { "label": "/plan-apply", "description": "Implement these tasks now (creates a feature branch and works through them)." },
40
- { "label": "/plan-propose", "description": "Turn this into a full OpenSpec proposal with agent assignments." },
41
- { "label": "Start on specific tasks", "description": "Tell me which tasks to start on." }
42
- ]
43
- }
44
- ]
45
- }
46
- ```
1
+ ---
2
+ name: pc-plan-quick
3
+ description: "Quick plan: analyze the codebase and create a task checklist using the Todo pane. No files, no OpenSpec. Invoked by the /plan-quick command."
4
+ license: MIT
5
+ ---
6
+
7
+ Lightweight planning for a change that is already clear: read the codebase, write the task list to the Todo pane, stop. Use `/plan-explore` then `/plan-propose` instead when the idea is half-formed, the alternatives need thinking through, or the result should outlive the session.
8
+
9
+ ## Rules
10
+
11
+ - Never write, edit, or create a file. The only artefacts are Todo items and one question, so there is nothing to review afterwards and nothing to undo.
12
+ - Never start the work, and never invoke `/plan-apply` or `/plan-propose` on the user's behalf. The question at the end is where they choose.
13
+
14
+ ## Contracts
15
+
16
+ One Todo item per task, in dependency order, each one action naming the files it touches:
17
+
18
+ ```json
19
+ {
20
+ "todos": [
21
+ { "content": "Add Project model to src/types.ts", "status": "pending", "priority": "high" },
22
+ { "content": "Add projectId field to LoopOptions in src/types.ts", "status": "pending", "priority": "high" },
23
+ { "content": "Create Project RPC endpoints in src/rpc/project/", "status": "pending", "priority": "medium" },
24
+ { "content": "Build Accept page UI in src/board/components/CreateForm.tsx", "status": "pending", "priority": "medium" },
25
+ { "content": "Run typecheck and check-diff, fix errors", "status": "pending", "priority": "low" }
26
+ ]
27
+ }
28
+ ```
29
+
30
+ Then ask:
31
+
32
+ ```json
33
+ {
34
+ "questions": [
35
+ {
36
+ "header": "What next",
37
+ "question": "What next?",
38
+ "options": [
39
+ { "label": "/plan-apply", "description": "Implement these tasks now (creates a feature branch and works through them)." },
40
+ { "label": "/plan-propose", "description": "Turn this into a full OpenSpec proposal with agent assignments." },
41
+ { "label": "Start on specific tasks", "description": "Tell me which tasks to start on." }
42
+ ]
43
+ }
44
+ ]
45
+ }
46
+ ```