@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.
- package/.opencode/agents/developer.md +60 -0
- package/.opencode/agents/planner.md +51 -0
- package/.opencode/agents/reviewer.md +53 -0
- package/.opencode/commands/add-repo.md +26 -0
- package/.opencode/commands/dev-workflow.md +40 -0
- package/.opencode/commands/init-workspace.md +22 -0
- package/.opencode/commands/migrate-workspace.md +28 -0
- package/.opencode/commands/repo-map-refresh.md +23 -0
- package/.opencode/commands/story-workflow.md +24 -0
- package/.opencode/commands/workflow-status.md +23 -0
- package/.opencode/commands/workspace-config.md +27 -0
- package/.opencode/package.json +9 -0
- package/.opencode/plugins/harness-guards.ts +290 -0
- package/.opencode/skills/add-repo/SKILL.md +96 -0
- package/.opencode/skills/dev-workflow/SKILL.md +105 -0
- package/.opencode/skills/dev-workflow/shared/diagram-styling.md +65 -0
- package/.opencode/skills/dev-workflow/shared/engineering.md +14 -0
- package/.opencode/skills/dev-workflow/shared/status-block.md +29 -0
- package/.opencode/skills/dev-workflow/steps/analyze-comments.md +32 -0
- package/.opencode/skills/dev-workflow/steps/apply-fixes.md +24 -0
- package/.opencode/skills/dev-workflow/steps/comment-analysis.md +11 -0
- package/.opencode/skills/dev-workflow/steps/create-pr.md +39 -0
- package/.opencode/skills/dev-workflow/steps/develop-task.md +54 -0
- package/.opencode/skills/dev-workflow/steps/develop.md +60 -0
- package/.opencode/skills/dev-workflow/steps/fetch.md +34 -0
- package/.opencode/skills/dev-workflow/steps/fixup-task.md +12 -0
- package/.opencode/skills/dev-workflow/steps/gate.md +53 -0
- package/.opencode/skills/dev-workflow/steps/harden-task.md +12 -0
- package/.opencode/skills/dev-workflow/steps/harden.md +30 -0
- package/.opencode/skills/dev-workflow/steps/intake.md +52 -0
- package/.opencode/skills/dev-workflow/steps/metrics.md +21 -0
- package/.opencode/skills/dev-workflow/steps/plan-task.md +108 -0
- package/.opencode/skills/dev-workflow/steps/plan.md +80 -0
- package/.opencode/skills/dev-workflow/steps/pre-pr-fixes.md +16 -0
- package/.opencode/skills/dev-workflow/steps/pre-pr-review.md +14 -0
- package/.opencode/skills/dev-workflow/steps/pre-pr.md +14 -0
- package/.opencode/skills/dev-workflow/steps/preflight.md +32 -0
- package/.opencode/skills/dev-workflow/steps/quick-recheck.md +14 -0
- package/.opencode/skills/dev-workflow/steps/reconcile.md +27 -0
- package/.opencode/skills/dev-workflow/steps/review-task.md +32 -0
- package/.opencode/skills/dev-workflow/steps/security.md +18 -0
- package/.opencode/skills/dev-workflow/steps/triage-request.md +15 -0
- package/.opencode/skills/init-workspace/SKILL.md +155 -0
- package/.opencode/skills/migrate-workspace/SKILL.md +122 -0
- package/.opencode/skills/repo-map-refresh/SKILL.md +43 -0
- package/.opencode/skills/story-workflow/SKILL.md +78 -0
- package/.opencode/skills/story-workflow/commands/analyze.md +40 -0
- package/.opencode/skills/story-workflow/commands/groom.md +58 -0
- package/.opencode/skills/story-workflow/commands/improve.md +47 -0
- package/.opencode/skills/story-workflow/commands/refine.md +44 -0
- package/.opencode/skills/story-workflow/shared/context.md +22 -0
- package/.opencode/skills/story-workflow/shared/provider-io.md +73 -0
- package/.opencode/skills/story-workflow/templates/readiness-report.md +57 -0
- package/.opencode/skills/story-workflow/templates/story-template.md +51 -0
- package/.opencode/skills/story-workflow/templates/technical-notes.md +48 -0
- package/.opencode/skills/workflow-status/SKILL.md +30 -0
- package/.opencode/skills/workspace-config/SKILL.md +97 -0
- package/.opencode/tsconfig.json +11 -0
- package/CHANGELOG.md +396 -0
- package/LICENSE +21 -0
- package/README.md +351 -0
- 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 (`&`, `<`, `>`, `|`). 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).
|