@shahboura/harness 3.0.4

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 (62) hide show
  1. package/.opencode/agents/developer.md +60 -0
  2. package/.opencode/agents/planner.md +51 -0
  3. package/.opencode/agents/reviewer.md +53 -0
  4. package/.opencode/commands/add-repo.md +26 -0
  5. package/.opencode/commands/dev-workflow.md +40 -0
  6. package/.opencode/commands/init-workspace.md +22 -0
  7. package/.opencode/commands/migrate-workspace.md +28 -0
  8. package/.opencode/commands/repo-map-refresh.md +23 -0
  9. package/.opencode/commands/story-workflow.md +24 -0
  10. package/.opencode/commands/workflow-status.md +23 -0
  11. package/.opencode/commands/workspace-config.md +27 -0
  12. package/.opencode/package.json +9 -0
  13. package/.opencode/plugins/harness-guards.ts +290 -0
  14. package/.opencode/skills/add-repo/SKILL.md +96 -0
  15. package/.opencode/skills/dev-workflow/SKILL.md +105 -0
  16. package/.opencode/skills/dev-workflow/shared/diagram-styling.md +65 -0
  17. package/.opencode/skills/dev-workflow/shared/engineering.md +14 -0
  18. package/.opencode/skills/dev-workflow/shared/status-block.md +29 -0
  19. package/.opencode/skills/dev-workflow/steps/analyze-comments.md +32 -0
  20. package/.opencode/skills/dev-workflow/steps/apply-fixes.md +24 -0
  21. package/.opencode/skills/dev-workflow/steps/comment-analysis.md +11 -0
  22. package/.opencode/skills/dev-workflow/steps/create-pr.md +39 -0
  23. package/.opencode/skills/dev-workflow/steps/develop-task.md +54 -0
  24. package/.opencode/skills/dev-workflow/steps/develop.md +60 -0
  25. package/.opencode/skills/dev-workflow/steps/fetch.md +34 -0
  26. package/.opencode/skills/dev-workflow/steps/fixup-task.md +12 -0
  27. package/.opencode/skills/dev-workflow/steps/gate.md +53 -0
  28. package/.opencode/skills/dev-workflow/steps/harden-task.md +12 -0
  29. package/.opencode/skills/dev-workflow/steps/harden.md +30 -0
  30. package/.opencode/skills/dev-workflow/steps/intake.md +52 -0
  31. package/.opencode/skills/dev-workflow/steps/metrics.md +21 -0
  32. package/.opencode/skills/dev-workflow/steps/plan-task.md +108 -0
  33. package/.opencode/skills/dev-workflow/steps/plan.md +80 -0
  34. package/.opencode/skills/dev-workflow/steps/pre-pr-fixes.md +16 -0
  35. package/.opencode/skills/dev-workflow/steps/pre-pr-review.md +14 -0
  36. package/.opencode/skills/dev-workflow/steps/pre-pr.md +14 -0
  37. package/.opencode/skills/dev-workflow/steps/preflight.md +32 -0
  38. package/.opencode/skills/dev-workflow/steps/quick-recheck.md +14 -0
  39. package/.opencode/skills/dev-workflow/steps/reconcile.md +27 -0
  40. package/.opencode/skills/dev-workflow/steps/review-task.md +32 -0
  41. package/.opencode/skills/dev-workflow/steps/security.md +18 -0
  42. package/.opencode/skills/dev-workflow/steps/triage-request.md +15 -0
  43. package/.opencode/skills/init-workspace/SKILL.md +155 -0
  44. package/.opencode/skills/migrate-workspace/SKILL.md +122 -0
  45. package/.opencode/skills/repo-map-refresh/SKILL.md +43 -0
  46. package/.opencode/skills/story-workflow/SKILL.md +78 -0
  47. package/.opencode/skills/story-workflow/commands/analyze.md +40 -0
  48. package/.opencode/skills/story-workflow/commands/groom.md +58 -0
  49. package/.opencode/skills/story-workflow/commands/improve.md +47 -0
  50. package/.opencode/skills/story-workflow/commands/refine.md +44 -0
  51. package/.opencode/skills/story-workflow/shared/context.md +22 -0
  52. package/.opencode/skills/story-workflow/shared/provider-io.md +73 -0
  53. package/.opencode/skills/story-workflow/templates/readiness-report.md +57 -0
  54. package/.opencode/skills/story-workflow/templates/story-template.md +51 -0
  55. package/.opencode/skills/story-workflow/templates/technical-notes.md +48 -0
  56. package/.opencode/skills/workflow-status/SKILL.md +30 -0
  57. package/.opencode/skills/workspace-config/SKILL.md +97 -0
  58. package/.opencode/tsconfig.json +11 -0
  59. package/CHANGELOG.md +396 -0
  60. package/LICENSE +21 -0
  61. package/README.md +351 -0
  62. package/package.json +32 -0
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: add-repo
3
+ version: "3.0.0"
4
+ author: "Mostafa Ashraf"
5
+ description: >
6
+ Register one new repo into an already-bootstrapped workspace, without
7
+ disturbing repos already registered or re-running the full interview.
8
+ USER-ENTRY — invoke only when the user explicitly runs /add-repo; never
9
+ ---
10
+
11
+
12
+ # add-repo
13
+
14
+ Every command below is `bin/harness <verb> …` — run it
15
+ yourself via Bash. Never ask the user to type a `harness` command; the user
16
+ only answers the questions below.
17
+
18
+ ## 1 · Ask
19
+
20
+ - Repo name (must be new — case-insensitively distinct from every
21
+ already-registered name) and its local path.
22
+
23
+ ## 2 · Discover, then confirm
24
+
25
+ `bin/harness discover --repo <path>` — same discovery
26
+ `/init-workspace` uses. It first ensures the repo is clean and on its
27
+ default branch: a dirty repo, or one mid-rebase/merge, refuses with a clear
28
+ error — surface that to the user verbatim, never auto-stash/discard. If the
29
+ guessed default branch doesn't resolve (no `origin/HEAD`), ask the user to
30
+ name it explicitly, then pass `--branch <name>` yourself; a repo with no
31
+ `origin` and a stray local branch that happens to be named `main` can't be
32
+ told apart from a genuine one, so confirm rather than assume.
33
+ **Known risk:** running `discover` against a path that's actually already
34
+ registered, with a `/dev-workflow` run in progress against it, can switch
35
+ that run's feature-branch checkout back to default — if there's any chance
36
+ the path is already registered, check first rather than running `discover`
37
+ on it.
38
+
39
+ Present the proposals (language, `test_cmd`, default branch) as
40
+ defaults-to-confirm, not facts:
41
+
42
+ - Confirm `test_cmd` by actually running it — don't accept the proposal
43
+ unconfirmed, and never collapse this repo's own command onto another
44
+ registered repo's.
45
+ - A `monorepo_split` proposal means this "one repo" is actually several
46
+ logical repos sharing one `.git` at the physical root. **This isn't yet
47
+ representable as separate registered repos** — `init-verify`'s
48
+ `repo:<name>` check requires a `.git` directly under the registered path,
49
+ which no subtree has, so registering subtrees separately leaves every one
50
+ of them permanently failing verification with no available fix. Tell the
51
+ user this is a known gap; register the repo once, at its physical root.
52
+
53
+ ## 3 · Register
54
+
55
+ ```
56
+ bin/harness add-repo --name <n> --path <path> --test-cmd '<confirmed cmd>'
57
+ ```
58
+
59
+ This merges into the existing repo/language config — every already-
60
+ registered repo survives untouched. It refuses (never renames/overwrites/
61
+ aliases) on:
62
+
63
+ - `--name` already registered, compared case-insensitively — surface this
64
+ verbatim and ask the user for a different name.
65
+ - `--path` already registered under a different name — surface this
66
+ verbatim; the repo is very likely already set up, so confirm with the
67
+ user rather than retrying with a new name.
68
+
69
+ `--test-cmd` is optional — omitting it registers the repo but leaves
70
+ `init-verify`'s `test_cmd:<name>` check failing until a command is set via
71
+ `init-section --section language` (merge the new repo's entry into the
72
+ existing `language.repos` map — that section is still full-replace, so
73
+ resupply the whole map, not just this repo's entry).
74
+
75
+ ## 4 · Verify + finish
76
+
77
+ 1. `bin/harness init-verify` — every check must pass
78
+ (or be `manual` with the user's explicit acknowledgment, for MCP-
79
+ transport work-item providers). **Do not proceed on failures** — show
80
+ the remediation, fix, re-run.
81
+ 2. `bin/harness init-finalize` — refreshes the
82
+ permission allowlist to cover the new repo (its `test_cmd` binary,
83
+ `Read` on its path). Confirm `.claude/settings.json` merged cleanly.
84
+ 3. **Repo-map**: offer to generate now — run `/repo-map-refresh`'s step 2
85
+ procedure for this repo (that skill owns the exact subagent_type-
86
+ guessing warning and the `harness-mode: repo-map` spawn/stamp sequence;
87
+ don't restate it here), pointed at
88
+ `.claude/context/repo-map/<repo-name>/`.
89
+ 4. Tell the user the new repo is ready for `/dev-workflow`.
90
+
91
+ ## Known risk
92
+
93
+ `security-scan` scans every registered repo in one call, regardless of
94
+ which repo a given `/dev-workflow` run's tasks touch — avoid running
95
+ `/add-repo` while another run is active for an unrelated repo, in case the
96
+ newly-added one isn't a valid checkout yet.
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: "dev-workflow"
3
+ description: "End-to-end SDLC workflow orchestration: fetch → plan → TDD → review → security → PR"
4
+ version: "3.0.0"
5
+ author: "Mostafa Ashraf"
6
+ ---
7
+
8
+ # dev-workflow — the thin orchestrator walker
9
+
10
+ You are the **orchestrator**: a coordinator, not an implementer. You never
11
+ write code, never touch `ai/<run>/` authority files directly, and never run
12
+ raw `git commit|merge|rebase` — every mutation goes through `harness`
13
+ (guards block the raw paths and redirect you here).
14
+
15
+ Every command below runs through `bin/harness` — a
16
+ wrapper script that resolves the plugin venv (created by /init-workspace,
17
+ either OS layout) and falls back to system `python3`/`python` pre-setup;
18
+ it runs under Git Bash on Windows too. `--workspace <ws>` and
19
+ `--run <run>` may go before or after the verb, in any mix — e.g. both
20
+ `harness --workspace <ws> --run <run> <verb> …` and
21
+ `harness <verb> --workspace <ws> --run <run> …` work. Always use the full
22
+ `.` path; a bare `harness` is not on PATH, and shell
23
+ variables do not persist between separate Bash calls. Non-zero exit =
24
+ refused; read the JSON error.
25
+
26
+ ## Startup
27
+
28
+ 1. `bin/harness fetch --id <work-item-id>` — refuses if bootstrap is incomplete
29
+ (run `/init-workspace` first) or a live run already exists (offer the user
30
+ **Resume or Abort** — never clobber). Abort is a real verb:
31
+ `bin/harness abort --run <run> --reason "<why>"` —
32
+ terminal (mutations refuse from then on), sweeps worktrees, keeps the
33
+ audit trail, and releases the work-item slot so a fresh fetch works.
34
+ On success note `run`, `mode`.
35
+ 2. The pipeline manifest (`pipeline/manifest.yaml`) is
36
+ the single source of truth for step order. Do not improvise steps.
37
+
38
+ ## The walk
39
+
40
+ Loop until the mode's sequence is exhausted, then close the run:
41
+ `bin/harness complete --run <run>` (terminal, the
42
+ successful sibling of abort — the final step's file says exactly when).
43
+
44
+ 1. `bin/harness show --run <run>` → current step, mode, tasks, gates.
45
+ 2. Read the step's file: `.opencode/skills/dev-workflow/steps/<step>.md`
46
+ — load ONE step file at a time (context economy). Gate steps all use
47
+ `steps/gate.md`.
48
+ 3. Execute it. Spawning a shape? The prompt MUST carry the structured headers
49
+ (`harness-mode`, `harness-task`, `harness-run`, `harness-repo`,
50
+ `harness-test-cmd`). Enforcement, precisely: the spawn guard BLOCKS a
51
+ harness-shape spawn missing `harness-mode`, and one missing
52
+ `harness-run` whenever the spawn is legalized by a run's current step
53
+ (the header must name THAT run). The remaining headers are capture
54
+ conventions — `harness-task` attributes the token ledger and reviewer
55
+ verdicts (a per-task review whose spawn omits it cannot satisfy the
56
+ task's completion guard), `harness-repo`/`harness-test-cmd` scope the
57
+ subagent's work. Before
58
+ every spawn, resolve its model: `bin/harness
59
+ resolve-model --shape <shape> --mode <mode>` (per-mode ?? per-shape
60
+ default ?? `inherit`, from `subagent_models`). Pass the result as the
61
+ spawn's `model` param — unless it's the literal string `inherit`, in
62
+ which case omit the `model` param entirely so the subagent runs on the
63
+ session model. Every harness-shape spawn runs FOREGROUND — pass
64
+ `run_in_background: false` explicitly (newer platforms default to
65
+ background, and capture reads the spawn's own tool_response; a
66
+ background spawn returns only a launch stub — verdict lost, stall
67
+ event fabricated; the guard blocks an explicit `true`). Parallelism =
68
+ batch multiple foreground spawns in ONE message, never backgrounding.
69
+ 4. Advance: `bin/harness cursor --to <next> --run <run>`. If refused, you are
70
+ off-manifest — re-read `show` and correct course; never force.
71
+
72
+ ## Cross-cutting rules
73
+
74
+ - **Session cwd:** stay at the workspace ROOT — the prompt-capture hook
75
+ defaults its workspace from cwd, so a bare `cd` into a repo silently
76
+ drops gate evidence (field-proven). Use absolute paths / `git -C` /
77
+ `(cd X && …)` subshells for repo work.
78
+ - **Gates:** always `gate --present`, show the artifact to the user verbatim,
79
+ wait for their reply, then `gate --decide`. The decision is derived from
80
+ captured human input — you cannot write it, only request the derivation.
81
+ The reply must be a plain typed chat message (never AskUserQuestion —
82
+ its answers bypass the capture hook and can never qualify). A refusal
83
+ means no qualifying reply: re-present or route to ad-hoc.
84
+ - **Stalls:** a subagent that stops without a status block → `bin/harness stall
85
+ --task <T>` and follow the returned action (`reinvoke` → `recovery` →
86
+ `human`). NEVER commit or write on a stalled agent's behalf.
87
+ - **Ad-hoc human requests mid-run:** spawn `reviewer` with
88
+ `harness-mode: request-triage` (always legal), surface the triage verdict
89
+ to the user; out-of-scope items are never silently merged.
90
+ - **Publish:** the mirror snapshots the run's audit trail INTO a registered
91
+ **project repo's** feature branch (so the governance record travels with
92
+ the code in the PR) — never into the workspace, which isn't a git repo and
93
+ isn't a mirror target. So it only makes sense once a repo has a feature
94
+ branch, i.e. **after `preflight`**. Rules:
95
+ - **Before preflight** (`fetch`/`intake`/`plan`/⟨approve-plan⟩): there is
96
+ no branch yet — **skip the mirror entirely**, don't guess a `--repo`.
97
+ - **After preflight** (task completion, and each later gate crossing):
98
+ mirror into **every preflighted repo** (the `branches` artifact in
99
+ `show` lists them) — one call per repo:
100
+ `bin/harness publish-mirror --repo <preflighted-repo-path> --run <run>`.
101
+ In a single-repo run that's one call; in a multi-repo run, one per repo.
102
+ - It's best-effort/non-blocking: a repo that can't be committed to (no
103
+ git, detached, etc.) just isn't mirrored — never block the run on it.
104
+ - **Status:** render progress with `bin/harness show`; the ledgers
105
+ (`events/tokens.ndjson`) are append-only — read, never write.
@@ -0,0 +1,65 @@
1
+ # Shared baseline: Mermaid diagram styling (cited by the planner)
2
+
3
+ Structural rules keep every plan diagram valid, renderable Mermaid.
4
+ **Mechanically enforced** by `bin/harness
5
+ validate-mermaid` (M8 WS-4), run by the orchestrator against `plan.md`
6
+ before the plan gate — a rule violation sends the planner back, it's not
7
+ just a convention to follow on trust.
8
+
9
+ - **HTML-entity escaping**: a node label containing `&`, `<`, `>`, or `|`
10
+ uses the entity form (`&amp;`, `&lt;`, `&gt;`, `&#124;`). Not `"` — that's
11
+ how a label is quoted in the first place; a mis-nested inner quote isn't
12
+ mechanically caught (would need a real parser, not a structural check).
13
+ - **Quoted subgraph titles**: `subgraph X["..."]`, never the unquoted
14
+ `subgraph X [...]` form.
15
+ - **classDef ↔ class-reference closure**: every `:::<class>` reference has a
16
+ matching `classDef <class>` line in the same diagram. The reverse isn't
17
+ required — an unreferenced `classDef` (e.g. `modified` on an all-new-types
18
+ diagram) is harmless boilerplate, not an error.
19
+ - **60-node ceiling**: split into sub-diagrams past 60 nodes. The count is by
20
+ distinct **node ID**, not by words — a descriptive multi-word label like
21
+ `A[user changes the value]` counts as the one node `A`. Write labels as
22
+ natural prose; you do **not** need to hyphenate multi-word labels to stay
23
+ under the cap.
24
+ - Comments use `%%`, never `<!-- -->` inside a fenced diagram.
25
+ - **Not mechanically checked** (Mermaid auto-declares any referenced node
26
+ ID, so there's no real "undefined" state to detect without a full grammar
27
+ parser — same scope decision the original ai-sdlc-harness's validator
28
+ made, though it never said so): node-ID closure, edge-label quoting.
29
+
30
+ ## Class-diagram convention (v3.0-specific, not ported)
31
+
32
+ A plan's diagrams show the **target codebase's** own types/flow/calls — a
33
+ different subject from the harness's own phase/workflow diagrams (which
34
+ color hook/skill/agent/orch nodes; that palette doesn't fit here). Plan
35
+ diagrams instead mark scope directly on the class diagram:
36
+
37
+ ```
38
+ classDef new fill:#ecffec,stroke:#3a7,stroke-width:1px,color:#063
39
+ classDef modified fill:#fff7d8,stroke:#b80,stroke-width:1px,color:#530
40
+ ```
41
+
42
+ Apply `:::new` / `:::modified` to each type so a reviewer sees scope at a
43
+ glance — **but in a `classDiagram` the style attaches ONLY on a dedicated
44
+ `class <Name>:::<style>` statement (or the class-body declaration), never
45
+ the flowchart idiom.** classDiagram grammar rejects `:::` on a relationship
46
+ endpoint or a bare reference (Mermaid raises `got 'STYLE_SEPARATOR'` and the
47
+ diagram won't render); `validate-mermaid`'s R12 catches it at the plan gate.
48
+
49
+ ```
50
+ %% RIGHT — scope styled on its own class statement:
51
+ classDiagram
52
+ classDef modified fill:#fff7d8,stroke:#b80
53
+ AdminController --> WorkflowController : dispatches
54
+ class WorkflowController:::modified {
55
+ +run()
56
+ }
57
+ class AdminController:::new
58
+
59
+ %% WRONG — :::modified on a relationship endpoint or bare ref (won't parse):
60
+ %% AdminController --> WorkflowController:::modified
61
+ %% WorkflowController:::modified
62
+ ```
63
+
64
+ Any `:::modified` type that is also a PATCH/partial-update DTO must satisfy
65
+ the wrapper-type rule (`shared/engineering.md` — `patch-dto-wrapper`).
@@ -0,0 +1,14 @@
1
+ # Shared baseline: engineering principles (cited by developer + reviewer)
2
+
3
+ - Match the surrounding code: its idioms, naming, error handling, comment
4
+ density. Consistency beats personal preference.
5
+ - Do the simplest thing that works well: no speculative abstractions, no
6
+ feature flags or compat shims where changing the code suffices, no error
7
+ handling for scenarios that cannot happen. Validate at system boundaries.
8
+ - Optional fields on partial-update DTOs use nullable/wrapper types
9
+ (review-policy `patch-dto-wrapper`) — a bare primitive cannot distinguish
10
+ "sent default" from "omitted".
11
+ - Tests assert the full observable contract (review-policy
12
+ `assertion-depth`), not just status codes.
13
+ - Every claim in a status block is evidence-grounded: cite the tool result
14
+ that proves it. Failures are reported verbatim, never aspirationally.
@@ -0,0 +1,29 @@
1
+ # Shared contract: the status block (every shape, every response)
2
+
3
+ End EVERY response with exactly this block — a capture hook checks for
4
+ it; a missing block triggers the stalled-agent procedure (reinvoke →
5
+ recovery → human).
6
+
7
+ ```
8
+ harness-status: SUCCESS | PARTIAL | FAILED
9
+ harness-task: <task-id or ->
10
+ verdict: <APPROVED | CHANGES_REQUESTED>
11
+ outcome: <one line — what actually happened, evidence-grounded>
12
+ details: <optional: findings list / clarifying questions / blocker>
13
+ ```
14
+
15
+ Rules:
16
+
17
+ - `verdict` is the REVIEWER's line — APPROVED or CHANGES_REQUESTED, alone
18
+ on its own line, in the block position shown (BEFORE the prose fields).
19
+ Non-reviewer shapes omit the line entirely. NEVER fold it into another
20
+ field's prose: `details: No findings. verdict: APPROVED` is
21
+ uncapturable — the hook reads only a line-anchored verdict, fail-closed
22
+ (three field re-reviews were paid for exactly that run-together shape;
23
+ the verdict used to be defined as part of `details`, which taught it).
24
+ - `outcome` claims only what a tool result in THIS session proves — report
25
+ failures faithfully ("tests fail with X"), never aspirationally.
26
+ - `PARTIAL` means you checkpointed (wip commit) and the work is resumable —
27
+ say exactly where you stopped.
28
+ - Reviewer findings go in `details` as a numbered list:
29
+ `[R1] <severity: CRITICAL|WARNING|SUGGESTION> <finding>`.
@@ -0,0 +1,32 @@
1
+ # Step: analyze-comments (reviewer shape; on-demand, repeatable group)
2
+
3
+ Triggered when PR review comments arrive (`reenter_when:
4
+ new_comments_present` — re-entry after apply-fixes is a declared edge).
5
+
6
+ 1. Fetch the comments via the git provider:
7
+ `bin/harness fetch-pr-comments --repo <repo> --run <run>`
8
+ (`local` provider returns none — paste them yourself for that case).
9
+ 2. Spawn `reviewer` with `harness-mode: analyze-comments` + the comments.
10
+ It follows `steps/comment-analysis.md`.
11
+ 3. Persist its analysis to `<run>/reports/comments-round-<n>.md`, numbering
12
+ each comment (`[1]`, `[2]`, …), and record the declared artifact:
13
+ `bin/harness artifact --name comment-analysis
14
+ --value reports/comments-round-<n>.md --run <run>`.
15
+ 4. Present ⟨select-comments⟩ — a `select` gate, not an approve/reject one.
16
+ The candidate list is supplied ONCE, at present time, and sealed into
17
+ state — decide replays that exact list, so the numbering the human saw
18
+ can never be redefined between present and decide (RC3):
19
+ ```
20
+ bin/harness gate --id select-comments --present \
21
+ --options <comment-id-1>,<comment-id-2>,... --run <run>
22
+ ```
23
+ Show the numbered list (same order), wait for the reply, then:
24
+ ```
25
+ bin/harness gate --id select-comments --decide --run <run>
26
+ ```
27
+ The human's reply (e.g. `1,3`) becomes a LIST decision — any parseable
28
+ selection is forward-legal, so this never routes to `on_reject`; it just
29
+ records which comments `apply-fixes` should address. To select nothing
30
+ (none of the comments need fixing), reply literally `NONE` — that's the
31
+ only input that parses to an empty selection; anything else either
32
+ matches real options or refuses as unparseable.
@@ -0,0 +1,24 @@
1
+ # Step: apply-fixes (developer shape, mode `fixup`)
2
+
3
+ Requires the ⟨select-comments⟩ token — a `select` gate (see `analyze-comments.md`):
4
+ its decision is a LIST of the comment IDs the human picked, read from
5
+ `state.gates["select-comments"].decision` (`bin/harness show`).
6
+
7
+ 1. Spawn `developer` with `harness-mode: fixup` + the SELECTED comments only
8
+ (look up each id's text from `<run>/reports/comments-round-<n>.md`).
9
+ Same rules as `fixup-task.md` (fixup commits, autosquash, locked tests).
10
+ 2. `bin/harness merge-task --autosquash
11
+ --base <default-branch> --repo <repo> --run <run>` — this REWRITES the
12
+ branch's history (fixups folded in), so the remote copy is now stale
13
+ regardless of whether the branch itself moved. Push it:
14
+ `bin/harness push --repo <repo> --branch <feature-branch>
15
+ --force-with-lease --run <run>`. If the base moved upstream too,
16
+ `bin/harness sync-branch --onto <default-branch>
17
+ --repo <repo> --run <run>` FIRST (rebase), then the push.
18
+ Record the declared artifact: `bin/harness artifact
19
+ --name fix-commits --value "<comment-ids fixed> @ <new HEAD sha>" --run <run>`.
20
+ 3. `bin/harness publish-mirror --repo <repo> --run <run>`.
21
+ From here the cursor has two
22
+ legal moves (`show` + the manifest tell you which): reenter `analyze-comments`
23
+ (declared repeatable edge — more comments arrived) or proceed to `reconcile`
24
+ (declared `returns_to` edge — done addressing comments, PR merged).
@@ -0,0 +1,11 @@
1
+ # Instruction: PR comment analysis (reviewer shape, mode `analyze-comments`)
2
+
3
+ For each PR comment, classify with evidence from the actual code:
4
+
5
+ - `VALID` — the comment is right; state the fix it implies and its cost.
6
+ - `INVALID` — the comment misunderstands; state the disproof (file:line).
7
+ - `PARTIAL` — right concern, wrong specifics; state which half holds.
8
+
9
+ Never soften a VALID into PARTIAL to avoid work; never argue an INVALID
10
+ without a concrete disproof. Numbered list, one verdict per comment, full
11
+ analysis in the status block `details`.
@@ -0,0 +1,39 @@
1
+ # Step: create-pr (orchestrator-owned, fully mechanical)
2
+
3
+ The feature branch must exist on the remote before the provider CLI can open
4
+ a PR/MR against it — push it first (owned entry point, RC1: never a raw
5
+ `git push`):
6
+
7
+ ```
8
+ bin/harness push --repo <repo> --branch <feature-branch> --run <run>
9
+ ```
10
+
11
+ Then create the PR:
12
+
13
+ ```
14
+ bin/harness create-pr --repo <repo> --run <run>
15
+ ```
16
+
17
+ Creates the PR via the configured git provider (title from the declared
18
+ `pr_title` template; base branch is the one `preflight` resolved and
19
+ recorded for this repo — never a hardcoded guess), records the `pr`
20
+ artifact (keyed by repo name — one PR per repo in multi-repo runs).
21
+
22
+ **Provider outage escape hatch:** if the provider CLI cannot create the
23
+ PR (infrastructure fault — e.g. a proxy 404ing path-encoded project
24
+ lookups) but the branch is pushed, the human creates the PR by hand and
25
+ you record it with `--url <its-url>` on the same command (the URL must
26
+ end in the PR/MR number — the comment loop derives the id from it).
27
+ Recording stays owned: same artifact, same locking, plus a
28
+ `pr-recorded-manually` audit event. Never hand-edit state.yaml, never
29
+ skip recording.
30
+
31
+ Then publish the mirror **once per preflighted repo** (SKILL.md's Publish
32
+ rule) so the final run snapshot lands in each PR's branch — `--push` is
33
+ REQUIRED here: the PR was created from the already-pushed branch, so a
34
+ mirror commit made after it stays local forever without its own push
35
+ (field finding: every run ended with its audit snapshot stranded one
36
+ commit ahead of the remote, invisible to the PR reviewer):
37
+ `bin/harness publish-mirror --repo <preflighted-repo-path> --push --run <run>`.
38
+ Advance to `reconcile`. The `pr-comments` group is now available on demand
39
+ (round-triggered, repeatable).
@@ -0,0 +1,54 @@
1
+ # Instruction: develop one task (developer shape, mode `develop`)
2
+
3
+ You own ONE task, in YOUR worktree (`harness-repo`), test-first.
4
+
5
+ **The rule is per-task data, not the mode's name:** if your task declares
6
+ `test_intents` (check it in `bin/harness show`'s task
7
+ list), the completion transition mechanically requires a red-proof — there
8
+ is no path to done that skips it. If it declares none, the red-proof
9
+ machinery is inactive and `task --to in-review` skips both verify-red and
10
+ verify-green entirely — step 3 below does not apply; write tests and
11
+ implementation together, then go straight to step 4. In practice:
12
+ plan-registered tasks carry intents unless the plan opted out
13
+ (`test_intents: []`, docs/chore); quick mode's fetch-seeded task declares
14
+ none — that's why quick runs are relaxed by design, not an oversight.
15
+
16
+ 1. **Read** the task's plan section (description, edge cases, test-intents,
17
+ `[API:]` annotations — verify those signatures before writing call sites,
18
+ pattern hints — start from them). Quick mode has no plan step, so there
19
+ are no declared test-intents to read — go straight to the work item's
20
+ own description.
21
+ 2. **Write the failing test(s)** implementing the declared test-intents.
22
+ No implementation yet — and this ordering is hook-ENFORCED, not advisory:
23
+ until your red-proof is sealed (step 3), writes to non-test paths in your
24
+ worktree are refused (test paths, test fixtures, and build manifests for
25
+ test dependencies stay writable). **Task declares NO test-intents**
26
+ (docs/chore — the plan-approved opt-out)? Skip steps 2–3 entirely: no
27
+ red-proof is needed or possible (verify-red refuses, the completion
28
+ guard exempts you) — implement, commit, report; review still applies.
29
+ (Quick mode: skip straight to writing test + implementation together —
30
+ there's no red-proof to prove first.)
31
+ 3. **Prove red (only when your task declares test-intents):**
32
+ `bin/harness verify-red --repo <repo> --task <T> --run <run>`
33
+ (`--test-cmd <cmd>` from your `harness-test-cmd` header; omit it and the
34
+ command auto-resolves from language-config for this task's registered
35
+ repo) — must succeed before any impl. If it reports "not red", your impl
36
+ already exists or the test is vacuous — fix the test.
37
+ From here your test files are LOCKED (blob-SHA): changing one fails the
38
+ completion check. Genuinely wrong test? Use the flagged path:
39
+ `verify-red --revise --reason "<why>"` — reviewer-visible, never silent.
40
+ The output's `missing_intents` (declared names not literally found in
41
+ your test files) is mechanical, not a suggestion — write ALL declared
42
+ tests before this call so it comes back empty; a non-empty result after
43
+ the fact means a declared test was skipped, and adding it now means the
44
+ same flagged `--revise` path as any other post-seal test change, not a
45
+ silent add.
46
+ 4. **Implement** until the test passes. Checkpoint with
47
+ `bin/harness commit --repo <repo> --task-id <T> --summary "<what>"`
48
+ (working commits; squashed later — never raw `git commit`).
49
+ 5. **Full-suite check:** run `<test-cmd>`; fix regressions you introduced.
50
+ 6. Report via the status block: `harness-status: SUCCESS` with
51
+ `verify-red`'s `missing_intents` value quoted verbatim in `details`
52
+ (empty if you closed every gap in step 3), or `PARTIAL` after a
53
+ `--commit-class wip` checkpoint near your turn ceiling, or `FAILED` with
54
+ the blocker.
@@ -0,0 +1,60 @@
1
+ # Step: develop (orchestrator loop — spawns developer + reviewer per task)
2
+
3
+ Lane policy (M5 charter): tasks run **sequentially within a repo, in
4
+ parallel across repos** (one developer per lane, spawned together). A lane's
5
+ stall pauses that lane only (fail-soft); gates and pre-pr require ALL lanes
6
+ complete (fail-closed sync points — mechanically enforced: the cursor cannot
7
+ leave `develop` while any task is still pending/in-progress/in-review).
8
+
9
+ Once, before the first task: `bin/harness write-back
10
+ --milestone develop_start --run <run>` (no-ops cleanly if
11
+ `write_back.on_develop_start` is off or the provider/type resolve no target;
12
+ for an MCP-transport work-item provider it also no-ops, returning
13
+ `mcp_guidance` — invoke the named tool yourself if you want live status
14
+ sync, otherwise nothing further to do).
15
+
16
+ Per task:
17
+
18
+ 1. **Worktree:** `bin/harness worktree-add --repo <repo> --task-id <T>
19
+ --base <feature-branch> --run <run>` — records `{path, branch}` in state;
20
+ idempotent on resume. If it fails twice it names the direct-branch
21
+ fallback — offer that choice to the user, never improvise.
22
+ 2. `bin/harness task --id <T> --to in-progress --run <run>`
23
+ 3. **Spawn `developer`** with headers (`harness-mode: develop`,
24
+ `harness-task: <T>`, `harness-run`, `harness-repo: <worktree-path>`,
25
+ `harness-test-cmd`: the task's registered repo's own `language.repos.<repo-name>.test_cmd`
26
+ — language-config is per repo, not one global command; look up the name
27
+ this task's repo was registered under in `repos.yaml`) + the task's plan
28
+ section. It follows `steps/develop-task.md` (TDD: verify-red, then
29
+ impl, then a harness commit).
30
+ 4. **Completion:** `bin/harness task --id <T> --to in-review --repo <worktree>
31
+ --run <run>` (`--test-cmd <cmd>` optional — omitted, it auto-resolves from
32
+ language-config for this task's registered repo) — runs verify-green +
33
+ the red-proof check; a refusal means the TDD contract wasn't met (send
34
+ the developer back; a locked-test change needs the flagged revision path).
35
+ 5. **Spawn `reviewer`** (`harness-mode: review`, same headers — the
36
+ `harness-task: <T>` header is load-bearing here: a capture hook
37
+ captures the reviewer's `verdict:` line into `reviews.ndjson` keyed by
38
+ it, and step 7's `task --to done` REFUSES without a captured APPROVED
39
+ for this task) on the task diff. `CHANGES_REQUESTED` →
40
+ `bin/harness task --id <T> --to in-progress --run <run>`
41
+ (round-bounded; a refusal = escalate to the human) and re-spawn the
42
+ developer with the findings. `APPROVED` → continue.
43
+ **Verdict not captured** (a `verdict-uncaptured` event, or step 7
44
+ refused with reviews.ndjson missing this task)? Re-spawn the reviewer
45
+ FRESH — foreground, same headers. NEVER SendMessage/resume the finished
46
+ one: continuation replies pass through no capture hook, so a restated
47
+ verdict there can never register, however clean (field finding).
48
+ 6. **Squash:** from the feature-branch checkout:
49
+ `bin/harness merge-task --repo <repo> --task-id <T> --task-branch
50
+ <worktree-branch> --summary "<task summary>" --run <run>`
51
+ 7. `bin/harness task --id <T> --to done --run <run>`
52
+ (refused unless the hook captured this task's reviewer APPROVED — spawn
53
+ the reviewer, don't restate its verdict) → `bin/harness worktree-remove --repo
54
+ <repo> --task-id <T> --run <run>` → `bin/harness publish-mirror --repo <repo> --run <run>`.
55
+
56
+ All tasks done → record the declared artifact the ⟨approve-impl⟩ gate
57
+ presents: `bin/harness artifact --name task-commits
58
+ --value "<T1>: <sha1>; <T2>: <sha2>; …" --run <run>` (the SHAs are in
59
+ `show`'s tasks) → `bin/harness cursor --to <next> --run <run>`
60
+ (⟨approve-impl⟩ in full; quick-recheck in quick).
@@ -0,0 +1,34 @@
1
+ # Step: fetch (orchestrator-owned, fully mechanical)
2
+
3
+ Already executed by `bin/harness fetch` at startup — it fetched the work item via
4
+ the configured provider, normalized it to `<run>/work-item.json`, resolved
5
+ `change_type`, ran the ex-ante quick classifier, and bootstrapped `state.yaml`
6
+ with a seeded task.
7
+
8
+ ## MCP-transport providers (ado-mcp / jira / zoho)
9
+
10
+ A script can't call an MCP tool, so `bin/harness fetch
11
+ --id` **refuses** for these, naming the tool + args to invoke (that refusal is
12
+ the instruction). Run step-one in the orchestrator instead:
13
+
14
+ 1. Invoke the mapped `work_item.fetch` tool (`bin/harness
15
+ provider --op work_item.fetch --id <id>` prints the exact tool + args;
16
+ `{project}` from `provider.ado_project`). Capture its raw JSON result.
17
+ 2. Pipe that raw result into the same bootstrap the CLI path runs:
18
+
19
+ ```
20
+ printf '%s' '<raw-json>' | bin/harness fetch --from-raw
21
+ ```
22
+
23
+ `--from-raw` runs the identical normalize → classify → bootstrap, writing
24
+ `work-item.json` and `state.yaml`. On success note `run`, `mode`.
25
+
26
+ ## Advance
27
+
28
+ Nothing further to do here. Advance:
29
+
30
+ ```
31
+ bin/harness cursor --to <next-per-manifest> --run <run>
32
+ ```
33
+
34
+ (`intake` in full mode, `preflight` in quick.)
@@ -0,0 +1,12 @@
1
+ # Instruction: post-squash fixes (developer shape, mode `fixup`)
2
+
3
+ You are fixing findings against ALREADY-SQUASHED task commits:
4
+
5
+ 1. For each finding, make the fix in the feature-branch checkout.
6
+ 2. Commit with `bin/harness commit --repo <repo> --fixup-of <task-id>` — the
7
+ bin/harness locates the task's integration commit and formats the `fixup!`
8
+ subject; autosquash folds it later.
9
+ 3. TDD-locked test files remain locked: a test change still requires the
10
+ flagged revision path (`verify-red --revise --reason`).
11
+ 4. Run the full suite before reporting. Status block lists finding → fix
12
+ mapping, evidence-grounded.
@@ -0,0 +1,53 @@
1
+ # Step: any gate (⟨approve-plan⟩, ⟨approve-impl⟩, ⟨approve-security⟩, …)
2
+
3
+ A gate derives its decision from CAPTURED human input — you present and
4
+ request; deterministic code decides (design.md RC3).
5
+
6
+ 1. `bin/harness gate --id <gate> --present --run <run>`
7
+ 2. Show the gate's artifact to the user **verbatim** (the manifest's
8
+ `presents:` names it — plan.md, task summary, security report…), plus the
9
+ options: plain gates → `APPROVED` / `rejected`; security gate →
10
+ `[1] fix-now [2] waive [3] defer`.
11
+ 3. Wait for the user's reply — it must arrive as a PLAIN TYPED CHAT
12
+ MESSAGE. The capture hook anchors decisions to UserPromptSubmit events
13
+ only; an AskUserQuestion answer arrives as a structured tool result,
14
+ is never captured, and the decide call will refuse with "no human
15
+ input after presentation" (dogfood-run finding — do not burn attempts
16
+ rediscovering this). Do not interpret the reply yourself.
17
+ 4. `bin/harness gate --id <gate> --decide --run <run>`
18
+ — never pass `--options` here: what a numbered reply means is DECLARED
19
+ data (the manifest's `dispositions`, e.g. the security gate's
20
+ `fix-now,waive,defer`), read by the CLI itself; a caller-supplied list
21
+ at decide time is refused (RC3).
22
+ 5. Outcomes:
23
+ - decision recorded → `bin/harness cursor --to <next>` (forward or the
24
+ declared `on_reject` target — `show` + the manifest tell you which).
25
+ - a REJECTION-side reply may carry notes after its option word
26
+ (`REJECTED — split T2 into two tasks` decides as rejected; the notes
27
+ ride into the on_reject step). FORWARD words stay bare: a qualified
28
+ approval like "APPROVED but…" (or "waive if…") never decides.
29
+ - refused (no qualifying reply / qualified FORWARD reply)
30
+ → the reply routes to **ad-hoc handling**: triage it
31
+ (`request-triage`), resolve with the user, then `--present` again
32
+ (re-presenting re-stamps the window) and repeat.
33
+ 6. Security gate only: a `defer` decision → the decide result carries a
34
+ `follow_up` field and logs a flagged `deferral-pending` event that
35
+ stays on the dashboard until you pair it — act on it now: create
36
+ the follow-up work item
37
+ `bin/harness provider --op work_item.create --title
38
+ "<summary>" --description "<finding + repo + severity>"` (github/gitlab/
39
+ local-markdown; a provider that declares it unsupported → comment on the
40
+ parent item instead), then clear the pending flag:
41
+ `bin/harness log-event --json
42
+ '{"kind": "deferral-recorded", "item": "<new-id>"}'`.
43
+ 7. Publish the mirror after the crossing — **once per preflighted repo**
44
+ (the `branches` artifact in `show` names them), never into the
45
+ workspace: `bin/harness publish-mirror --repo <preflighted-repo-path> --run <run>`.
46
+ **⟨approve-plan⟩ is BEFORE preflight** — no branch exists yet, so **skip
47
+ the mirror entirely at this gate** (there's nothing to snapshot into a
48
+ code branch). See SKILL.md's Publish rule. Best-effort/non-blocking.
49
+ 8. ⟨approve-impl⟩ only, BEFORE presenting: `bin/harness
50
+ write-back --milestone in_review --run <run>` (no-ops cleanly if
51
+ `write_back.on_in_review` is off, or — for an MCP-transport provider —
52
+ returning `mcp_guidance` instead of raising; invoke the named tool
53
+ yourself if you want live status sync).