@ianwremmel/dispatch 0.32.1-bootstrap.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.
- package/.claude-plugin/plugin.json +59 -0
- package/.mcp.json +8 -0
- package/LICENSE +21 -0
- package/README.md +93 -0
- package/agents/.gitkeep +0 -0
- package/agents/build-graph.md +99 -0
- package/agents/milestone-reviewer.md +50 -0
- package/agents/pr-worker.md +172 -0
- package/agents/ticket-worker.md +97 -0
- package/bin/dispatch +101 -0
- package/bin/dispatch-mcp +19 -0
- package/bin/pr-status +931 -0
- package/commands/.gitkeep +0 -0
- package/commands/orchestrate.md +6 -0
- package/hooks/.gitkeep +0 -0
- package/hooks/claim-guard.mts +98 -0
- package/hooks/hooks.json +15 -0
- package/package.json +46 -0
- package/skills/.gitkeep +0 -0
- package/skills/land/SKILL.md +238 -0
- package/skills/land/credentials-dedicated.md +33 -0
- package/skills/land/credentials-shared.md +76 -0
- package/skills/land/mode-solo.md +76 -0
- package/skills/land/mode-team.md +103 -0
- package/skills/land/reference.md +152 -0
- package/skills/land/ticket.md +94 -0
- package/skills/orchestrate/SKILL.md +87 -0
- package/skills/tracker-adapter-linear/SKILL.md +142 -0
- package/src/commands/CLAUDE.md +12 -0
- package/src/commands/claim/check.mts +88 -0
- package/src/commands/claim/guard.mts +95 -0
- package/src/commands/claim/status.mts +49 -0
- package/src/commands/edge/add.mts +44 -0
- package/src/commands/edge/rm.mts +44 -0
- package/src/commands/edge/set.mts +56 -0
- package/src/commands/greet.mts +34 -0
- package/src/commands/mcp/ack.mts +43 -0
- package/src/commands/mcp/ping.mts +61 -0
- package/src/commands/mcp/status.mts +89 -0
- package/src/commands/mcp.mts +155 -0
- package/src/commands/milestone/rm.mts +35 -0
- package/src/commands/milestone/set.mts +49 -0
- package/src/commands/outcome/rm.mts +36 -0
- package/src/commands/outcome/set.mts +86 -0
- package/src/commands/pr/rm.mts +33 -0
- package/src/commands/pr/set.mts +110 -0
- package/src/commands/pr/yield.mts +114 -0
- package/src/commands/project/rm.mts +33 -0
- package/src/commands/project/set.mts +50 -0
- package/src/commands/queue.mts +41 -0
- package/src/commands/refresh/done.mts +42 -0
- package/src/commands/refresh/status.mts +40 -0
- package/src/commands/refresh.mts +56 -0
- package/src/commands/review/record.mts +46 -0
- package/src/commands/review/release.mts +49 -0
- package/src/commands/status.mts +85 -0
- package/src/commands/ticket/missing.mts +31 -0
- package/src/commands/ticket/rm.mts +33 -0
- package/src/commands/ticket/set.mts +134 -0
- package/src/commands/worker/rm.mts +46 -0
- package/src/commands/worker/set.mts +63 -0
- package/src/lib/cli/CLAUDE.md +13 -0
- package/src/lib/cli/cli.mts +226 -0
- package/src/lib/cli/index.mts +1 -0
- package/src/lib/command/CLAUDE.md +26 -0
- package/src/lib/command/__fixtures__/bad-export/oops.mts +1 -0
- package/src/lib/command/__fixtures__/bad-name/mismatch.mts +19 -0
- package/src/lib/command/__fixtures__/commands/cli-only.mts +20 -0
- package/src/lib/command/__fixtures__/commands/greet.mts +39 -0
- package/src/lib/command/__fixtures__/commands/math/add.mts +32 -0
- package/src/lib/command/__fixtures__/commands/mcp-only.mts +20 -0
- package/src/lib/command/__fixtures__/commands/needs-token.mts +19 -0
- package/src/lib/command/__fixtures__/commands/store/get.mts +26 -0
- package/src/lib/command/__fixtures__/commands/store.mts +26 -0
- package/src/lib/command/abstract-command.mts +104 -0
- package/src/lib/command/discovery.mts +100 -0
- package/src/lib/command/env.mts +19 -0
- package/src/lib/command/index.mts +6 -0
- package/src/lib/command/parse.mts +64 -0
- package/src/lib/command/test-support.mts +81 -0
- package/src/lib/command/transports.mts +17 -0
- package/src/lib/command/types.mts +53 -0
- package/src/lib/db/CLAUDE.md +13 -0
- package/src/lib/db/database.mts +160 -0
- package/src/lib/db/index.mts +4 -0
- package/src/lib/db/schema.mts +195 -0
- package/src/lib/db/time.mts +24 -0
- package/src/lib/db/with-database.mts +56 -0
- package/src/lib/errors/CLAUDE.md +18 -0
- package/src/lib/errors/command-error.mts +13 -0
- package/src/lib/errors/data-error.mts +12 -0
- package/src/lib/errors/definition-error.mts +6 -0
- package/src/lib/errors/dispatch-error.mts +27 -0
- package/src/lib/errors/ensure.mts +22 -0
- package/src/lib/errors/environment-error.mts +7 -0
- package/src/lib/errors/index.mts +8 -0
- package/src/lib/errors/json-rpc-error.mts +18 -0
- package/src/lib/errors/usage-error.mts +7 -0
- package/src/lib/graph/CLAUDE.md +17 -0
- package/src/lib/graph/anomalies.mts +110 -0
- package/src/lib/graph/derive.mts +96 -0
- package/src/lib/graph/index.mts +26 -0
- package/src/lib/graph/pipeline.mts +410 -0
- package/src/lib/graph/queries.mts +207 -0
- package/src/lib/graph/rows.mts +99 -0
- package/src/lib/graph/types.mts +137 -0
- package/src/lib/liveness/CLAUDE.md +14 -0
- package/src/lib/liveness/index.mts +10 -0
- package/src/lib/liveness/liveness.mts +147 -0
- package/src/lib/liveness/retire.mts +63 -0
- package/src/lib/logger/CLAUDE.md +12 -0
- package/src/lib/logger/index.mts +2 -0
- package/src/lib/logger/logger.mts +58 -0
- package/src/lib/logger/stream-sink.mts +23 -0
- package/src/lib/mcp/CLAUDE.md +21 -0
- package/src/lib/mcp/channel.mts +41 -0
- package/src/lib/mcp/dispatch.mts +60 -0
- package/src/lib/mcp/drain.mts +83 -0
- package/src/lib/mcp/index.mts +5 -0
- package/src/lib/mcp/mcp.mts +267 -0
- package/src/lib/mcp/tools.mts +77 -0
- package/src/lib/model/CLAUDE.md +8 -0
- package/src/lib/model/index.mts +3 -0
- package/src/lib/model/repo-caps.mts +95 -0
- package/src/lib/model/status.mts +91 -0
- package/src/lib/model/types.mts +83 -0
- package/src/lib/refresh/index.mts +2 -0
- package/src/lib/refresh/placeholders.mts +43 -0
- package/src/lib/refresh/refresh-service.mts +203 -0
- package/src/lib/schedule/CLAUDE.md +18 -0
- package/src/lib/schedule/caps.mts +113 -0
- package/src/lib/schedule/correlate.mts +69 -0
- package/src/lib/schedule/index.mts +7 -0
- package/src/lib/schedule/scheduler.mts +355 -0
- package/src/lib/schedule/tick.mts +266 -0
- package/src/lib/stores/CLAUDE.md +24 -0
- package/src/lib/stores/coordination.mts +359 -0
- package/src/lib/stores/cursor.mts +41 -0
- package/src/lib/stores/edge.mts +138 -0
- package/src/lib/stores/fetch-request.mts +346 -0
- package/src/lib/stores/index.mts +19 -0
- package/src/lib/stores/materialize.mts +69 -0
- package/src/lib/stores/milestone.mts +74 -0
- package/src/lib/stores/notice.mts +57 -0
- package/src/lib/stores/policy.mts +48 -0
- package/src/lib/stores/pr-event.mts +94 -0
- package/src/lib/stores/pr.mts +167 -0
- package/src/lib/stores/project.mts +79 -0
- package/src/lib/stores/refresh.mts +197 -0
- package/src/lib/stores/review.mts +113 -0
- package/src/lib/stores/session.mts +170 -0
- package/src/lib/stores/ticket.mts +246 -0
- package/src/lib/stores/watch.mts +360 -0
- package/src/lib/stores/worker.mts +121 -0
- package/src/lib/watch/adopt.mts +151 -0
- package/src/lib/watch/arm.mts +48 -0
- package/src/lib/watch/cadence.mts +45 -0
- package/src/lib/watch/diff.mts +274 -0
- package/src/lib/watch/index.mts +11 -0
- package/src/lib/watch/marker.mts +24 -0
- package/src/lib/watch/payload.mts +56 -0
- package/src/lib/watch/poll.mts +87 -0
- package/src/lib/watch/render.mts +61 -0
- package/src/lib/watch/snapshot.mts +312 -0
- package/src/main.mts +18 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dispatch",
|
|
3
|
+
"description": "Dispatch engineering work end-to-end: pull request lifecycle (drafting, review, CI triage, merge) and ticket-tracker project orchestration (triage, planning, status, cross-team sync) — Linear bundled, other trackers added by writing an adapter skill.",
|
|
4
|
+
"version": "0.33.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Ian Remmel"
|
|
7
|
+
},
|
|
8
|
+
"homepage": "https://github.com/ianwremmel/agentic",
|
|
9
|
+
"repository": "https://github.com/ianwremmel/agentic",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"github",
|
|
13
|
+
"pull-requests",
|
|
14
|
+
"ci",
|
|
15
|
+
"code-review",
|
|
16
|
+
"linear",
|
|
17
|
+
"project-management",
|
|
18
|
+
"issues",
|
|
19
|
+
"planning"
|
|
20
|
+
],
|
|
21
|
+
"userConfig": {
|
|
22
|
+
"copilot_available": {
|
|
23
|
+
"type": "boolean",
|
|
24
|
+
"title": "Copilot review available",
|
|
25
|
+
"description": "Whether GitHub Copilot review is expected to work on this installation. Set to false on GitHub Enterprise installations without Copilot review — the `land` skill will skip the Copilot phase and go straight to human review.",
|
|
26
|
+
"default": true
|
|
27
|
+
},
|
|
28
|
+
"worktree_base": {
|
|
29
|
+
"type": "directory",
|
|
30
|
+
"title": "Worktree base directory",
|
|
31
|
+
"description": "Root directory under which the `land` skill creates per-PR worktrees. Layout: <base>/<owner>/<repo>/<branch>.",
|
|
32
|
+
"default": "~/.worktrees"
|
|
33
|
+
},
|
|
34
|
+
"operator_mode": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"title": "Operator mode",
|
|
37
|
+
"description": "One of `solo` or `team`. `team`: land adds a private review stage in draft (operator only) before clearing draft for public review (team). `solo` (default): land clears draft after Copilot and the operator is the public reviewer \u2014 no separate private stage.",
|
|
38
|
+
"default": "solo"
|
|
39
|
+
},
|
|
40
|
+
"credential_mode": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"title": "Credential mode",
|
|
43
|
+
"description": "One of `dedicated` or `shared`. `dedicated`: the agent acts under its own dedicated account (bot or agent identity), separate from the operator's. `shared` (default): the agent shares the operator's platform credentials \u2014 agent posts are sparkle-wrapped and review requests can't target the operator. Skills read this value; they never infer it from account names.",
|
|
44
|
+
"default": "shared"
|
|
45
|
+
},
|
|
46
|
+
"operator_login": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"title": "Operator GitHub login",
|
|
49
|
+
"description": "GitHub login of the operator directing this agent. Required \u2014 the land skill and pr-status script always assume it is set. Targets the operator with PR review requests (credential_mode=dedicated) and classifies <review> elements in pr-status XML; the agent never falls back to the ticket assigner. With credential_mode=shared set this to the shared/authenticated account.",
|
|
50
|
+
"required": true
|
|
51
|
+
},
|
|
52
|
+
"tracker": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"title": "Work-item tracker",
|
|
55
|
+
"description": "Default work-item tracker for the orchestration workers and `land`, named by the id of its adapter skill: `tracker-adapter-<id>` (`tracker-adapter-linear` ships with the plugin). For ticket-backed work the tracker is resolved from the ticket's URL; this value is the fallback when the URL is ambiguous or the input is a bare id. (A bare PR has no ticket and is driven on the forge via the land skill regardless.) A tracker with no adapter skill is worked best-effort through its native MCP server; an installed adapter is authoritative.",
|
|
56
|
+
"default": "linear"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
package/.mcp.json
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ian Remmel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# dispatch
|
|
2
|
+
|
|
3
|
+
> Claude Code plugin for dispatching engineering work across pull requests and tracked work items.
|
|
4
|
+
|
|
5
|
+
Covers the full lifecycle: drafting PRs from a working branch, pushing and publishing, CI triage, responding to review comments, and merging — alongside driving whole tracker projects under deterministic scheduling. Tickets are worked through a tracker adapter; [Linear.app](https://linear.app) ships with the plugin.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
From inside Claude Code, after adding the `agentic` marketplace:
|
|
10
|
+
|
|
11
|
+
```shell
|
|
12
|
+
/plugin install dispatch@agentic
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
See the [root README](../../README.md#install) for marketplace setup.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
Once installed, the plugin's skills appear under the `dispatch:` namespace — invoke them as `/dispatch:orchestrate`, or by the bare name (`/orchestrate`) when no other plugin claims it. Run `/help` from inside Claude Code to list them.
|
|
20
|
+
|
|
21
|
+
## `land` vs `/orchestrate`
|
|
22
|
+
|
|
23
|
+
`land` drives one pull request to merge, standalone. It takes a PR URL, a
|
|
24
|
+
ticket URL, or a plain prompt, resolves that to a brief itself, and re-derives
|
|
25
|
+
every decision from `pr-status` each tick. It never decomposes work, walks a
|
|
26
|
+
dependency graph, or dispatches anything.
|
|
27
|
+
|
|
28
|
+
`/orchestrate <project>` drives a whole tracker project. The `dispatch` MCP
|
|
29
|
+
server builds the dependency graph through channel-pushed fetch instructions,
|
|
30
|
+
then schedules deterministically — ranking, milestone gates, claims — and
|
|
31
|
+
pushes work orders the session answers by launching the plugin's
|
|
32
|
+
agents: `build-graph` to answer each fetch instruction, `ticket-worker` to
|
|
33
|
+
coordinate each ticket, `pr-worker` to implement each PR item (via `land`),
|
|
34
|
+
and `milestone-reviewer` per review gate.
|
|
35
|
+
|
|
36
|
+
Reach for `land` when the unit of work is one PR; `/orchestrate` when it is a
|
|
37
|
+
project.
|
|
38
|
+
|
|
39
|
+
## Tracker adapters
|
|
40
|
+
|
|
41
|
+
The workers speak an abstract status vocabulary (`available`, `in-progress`, `in-review`, `delivered`, `verified`, …) and an abstract set of ticket operations; `build-graph` sweeps a tracker's projects through the same per-tracker lens. A **tracker adapter** — a skill named `tracker-adapter-<id>` — maps a platform's native states onto those roles, binds each ticket operation to a concrete tool call, and supplies the graph fetch and field mapping. Both skills prefer the adapter and fall back to best-effort use of the tracker's native MCP server when none is installed — an adapter records the state mappings and quirks best effort would have to work out from scratch. Working tickets reliably on Jira, GitLab, or an in-house tool therefore means adding a `tracker-adapter-<id>` skill — in your repo's `.claude/skills/`, personally, or via a plugin — not editing the skills.
|
|
42
|
+
|
|
43
|
+
The plugin bundles [`tracker-adapter-linear`](skills/tracker-adapter-linear/SKILL.md). A more specific skill with the same tracker id (repo over personal over plugin) shadows it wholesale — adapters replace rather than merge — and the same mechanism customizes the bundled Linear mapping, for instance to map the custom Backlog substates a team uses for `paused` and `awaiting-external`. Start from a copy of the adapter you're replacing — the bundled Linear adapter shows every section an adapter must supply. A tracker that cannot express a required role (`available`, `in-progress`, `verified`, `canceled`) cannot be adapted; the adapter should say so rather than approximate.
|
|
44
|
+
|
|
45
|
+
## CLI
|
|
46
|
+
|
|
47
|
+
`bin/dispatch` is the entry point skills shell out to. Claude Code puts a
|
|
48
|
+
plugin's `bin/` on `PATH`, so a skill can call it by name:
|
|
49
|
+
|
|
50
|
+
```shell
|
|
51
|
+
dispatch greet --name World # -> hello World
|
|
52
|
+
dispatch --help # list commands
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The CLI holds the project graph in a SQLite store (`node:sqlite`, at
|
|
56
|
+
`$DISPATCH_DB`, else `$XDG_STATE_HOME/dispatch/graph-v2.db`) and derives every
|
|
57
|
+
scheduling decision from it:
|
|
58
|
+
|
|
59
|
+
```shell
|
|
60
|
+
dispatch ticket set --id CLC-945 --project P --status in-progress # typed writes
|
|
61
|
+
dispatch status # counts, gates, anomalies, terminal verdict
|
|
62
|
+
dispatch queue # what the scheduler would hand out next
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Writes go through typed `project`/`milestone`/`ticket`/`edge`/`pr` commands;
|
|
66
|
+
effective blocking, ranking, cycle rejection, and milestone gating are computed
|
|
67
|
+
in the CLI so every consumer gets the same answer. Workers report with
|
|
68
|
+
`outcome set` and open milestone gates with `review record`. `dispatch mcp` runs the same command
|
|
69
|
+
surface as an MCP channel server that schedules and pushes work orders;
|
|
70
|
+
`mcp ack`/`mcp status` carry the channel handshake. Every command prints its
|
|
71
|
+
own flags: `dispatch <command> --help`.
|
|
72
|
+
|
|
73
|
+
`bin/dispatch` is a bash wrapper around `src/main.mts`. The wrapper checks that
|
|
74
|
+
Node is present and at least 24.18 — the CLI ships as unbuilt TypeScript and
|
|
75
|
+
relies on Node's native type stripping, so there is no build step and no
|
|
76
|
+
runtime dependencies. `DISPATCH_NODE` picks a specific Node binary.
|
|
77
|
+
|
|
78
|
+
Structured output goes to stdout; error messages go to stderr. A failure
|
|
79
|
+
prints an `error:` line and a `hint:` line saying what to do about it, and
|
|
80
|
+
exits with a code the caller can branch on: `2` called wrong, `3` the
|
|
81
|
+
environment refused (retry), `4` bad data (fix the payload), `1` a bug in the
|
|
82
|
+
CLI.
|
|
83
|
+
|
|
84
|
+
Add a command by writing a file under `src/commands/` — the folder path is the
|
|
85
|
+
invocation path, and discovery needs no registry.
|
|
86
|
+
|
|
87
|
+
## Contributing
|
|
88
|
+
|
|
89
|
+
See the [root README](../../README.md#contributing) for branch and commit conventions.
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
[MIT](./LICENSE) © Ian Remmel
|
package/agents/.gitkeep
ADDED
|
File without changes
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-graph
|
|
3
|
+
description: Answer one project-graph fetch instruction — scan the named projects' tickets, or fetch the single ticket named — and record what you find through the dispatch CLI. Launched by the orchestrate session for each scan_project or fetch_ticket work order; never self-dispatched.
|
|
4
|
+
model: opus
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You handle **one instruction**: the one your dispatch names. Fetch what it
|
|
8
|
+
names, write what you find, and stop. Do not decide what to fetch next, chase a
|
|
9
|
+
dependency you noticed, or judge whether the graph is complete — the CLI does
|
|
10
|
+
all three and will send another instruction if it needs one.
|
|
11
|
+
|
|
12
|
+
The `dispatch` commands below are also tools on the plugin's MCP server
|
|
13
|
+
(`ticket set` → the `ticket_set` tool). When the server is attached, call the
|
|
14
|
+
tools — the server delivers follow-up instructions after tool calls.
|
|
15
|
+
|
|
16
|
+
## The adapter
|
|
17
|
+
|
|
18
|
+
Read `tracker-adapter-${user_config.tracker}` first: it supplies the tools, the
|
|
19
|
+
field mapping, and the tracker's state → status table. A project on a different
|
|
20
|
+
tracker loads `tracker-adapter-<id>` for that tracker. Without an adapter, drive
|
|
21
|
+
the tracker's MCP server directly and map its fields onto the flags below
|
|
22
|
+
yourself.
|
|
23
|
+
|
|
24
|
+
## `scan_project`
|
|
25
|
+
|
|
26
|
+
Fetch every ticket in the named projects. When the instruction carries a cursor,
|
|
27
|
+
fetch only what changed since it. Do not filter further — a ticket you skip
|
|
28
|
+
becomes a placeholder the CLI has to ask for one at a time.
|
|
29
|
+
|
|
30
|
+
Write as you go, one command per item so a bad one fails only itself:
|
|
31
|
+
|
|
32
|
+
```shell
|
|
33
|
+
dispatch project set --id P --name "Platform" --tracker linear
|
|
34
|
+
dispatch milestone set --id M1 --project P --name "M1"
|
|
35
|
+
dispatch ticket set --id CLC-945 --project P --status in-progress \
|
|
36
|
+
--title "…" --url "…" [--priority 2] [--labels infra,qa]
|
|
37
|
+
dispatch edge add --blocker CLC-944 --blocked CLC-945
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Then report the scan complete, passing the tracker's own change token:
|
|
41
|
+
|
|
42
|
+
```shell
|
|
43
|
+
dispatch refresh done --tracker linear --cursor <token>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## `fetch_ticket`
|
|
47
|
+
|
|
48
|
+
Fetch the one ticket named and write it with `ticket set`. If the tracker has no
|
|
49
|
+
such ticket — deleted, or on a different tracker — say so instead:
|
|
50
|
+
|
|
51
|
+
```shell
|
|
52
|
+
dispatch ticket missing --id CLC-944
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Never guess a ticket into existence to clear an instruction.
|
|
56
|
+
|
|
57
|
+
## `refresh_ticket`
|
|
58
|
+
|
|
59
|
+
The server asking whether one ticket it already holds has moved. It only asks
|
|
60
|
+
about tickets whose tracker state can change under it — started, in review, or
|
|
61
|
+
parked — so the answer is usually "the same as before".
|
|
62
|
+
|
|
63
|
+
Re-read the ticket and write it with `ticket set`, exactly as in a scan. Write
|
|
64
|
+
it **even when nothing changed**: the write is what closes the ask, and an ask
|
|
65
|
+
left open suppresses every later one for that ticket, so the server stops
|
|
66
|
+
hearing about a ticket it is specifically watching. If the tracker no longer
|
|
67
|
+
has it, `dispatch ticket missing --id <id>` instead.
|
|
68
|
+
|
|
69
|
+
This is a re-read, not a materialization — `fetch_ticket` is the one that fills
|
|
70
|
+
in a ticket the graph has never seen.
|
|
71
|
+
|
|
72
|
+
## Writing rules
|
|
73
|
+
|
|
74
|
+
- **You map the state; the CLI knows only the vocabulary.** `--status` takes
|
|
75
|
+
`backlog`, `paused`, `awaiting-external`, `available`, `in-progress`,
|
|
76
|
+
`in-review`, `finished`, `delivered`, `verified`, or `canceled`. The adapter
|
|
77
|
+
carries the tracker's table and the rule for a state it does not cover: map it
|
|
78
|
+
only when the lifecycle meaning is unambiguous. Otherwise skip the write, flag
|
|
79
|
+
the unmapped state on the tracker (a comment on the ticket), and move on.
|
|
80
|
+
Never guess, and never block the session on a question (`AskUserQuestion` or
|
|
81
|
+
any blocking prompt) — an unattended run has nobody to answer, and a parked
|
|
82
|
+
modal stalls every project the session drives.
|
|
83
|
+
- **A milestone is joined by an edge.** `edge add --blocker CLC-945 --blocked M1`
|
|
84
|
+
puts CLC-945 in milestone M1. Milestones are sequenced the same way:
|
|
85
|
+
`edge add --blocker M1 --blocked M2` means M2's work waits on M1.
|
|
86
|
+
- **Redeclare a direction with `edge set`.** After re-fetching a ticket's
|
|
87
|
+
blockers, `edge set --node CLC-945 --direction blockers --others a,b` makes
|
|
88
|
+
the tracker's blockers exactly `{a,b}` (empty clears them). Use it instead of
|
|
89
|
+
diffing. It replaces only edges to tickets, so a PR item blocking the ticket
|
|
90
|
+
and the ticket's milestone membership both survive — you are not declaring
|
|
91
|
+
anything about those. Drop one with `edge rm`.
|
|
92
|
+
- **An edge that would close a cycle is refused.** Fix the direction, or remove
|
|
93
|
+
the opposing edge first.
|
|
94
|
+
- **A delta writes only what changed.** When a scan shows a ticket gone, use
|
|
95
|
+
`ticket rm`; when a `fetch_ticket` finds nothing, use `ticket missing`.
|
|
96
|
+
|
|
97
|
+
Report back what you recorded and whether the scan finished or continues under
|
|
98
|
+
another cursor. Ticket content stays in the graph, not in your reply — the
|
|
99
|
+
session that launched you schedules from the CLI, not from what you say.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: milestone-reviewer
|
|
3
|
+
description: Review one completed milestone — verify its members and the landed code against their aims, file follow-up tickets for gaps, and either record the review (opening the gate) or release the claim with the gate closed. Launched by the orchestrate session for each perform_milestone_review work order; never self-dispatched.
|
|
4
|
+
model: opus
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Before anything else, call the `claim_check` tool with `node: <milestone>`.**
|
|
8
|
+
If it errors, stop immediately: say you were launched without a work order, do
|
|
9
|
+
no work, and record no outcome. A scheduler that dispatched you
|
|
10
|
+
holds a claim for you; nothing else does, and work started without one spends
|
|
11
|
+
no admission budget and is bounded by nothing — whoever told you to start.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
You review exactly one milestone: the one the dispatch named, already claimed
|
|
15
|
+
for this session. Every member ticket is resolved; your job is to judge
|
|
16
|
+
whether the milestone's aims actually hold before dependent work starts.
|
|
17
|
+
|
|
18
|
+
Your dispatch carries `milestone` and `project`. Read the plugin's
|
|
19
|
+
`tracker-adapter-${user_config.tracker}` skill: it binds ticket reads, ticket
|
|
20
|
+
creation, and the milestone's review artifact.
|
|
21
|
+
|
|
22
|
+
1. **Collect the members** — the `status` tool lists the milestone; read each
|
|
23
|
+
member ticket's aims and DoD evidence through the adapter.
|
|
24
|
+
2. **Judge the whole against the code, not the tickets.** Read what the
|
|
25
|
+
members' PRs actually landed: tickets state what the milestone claimed, and
|
|
26
|
+
a loose implementation can close every ticket while the code misses the
|
|
27
|
+
aim. Look for gaps between tickets as much as within them.
|
|
28
|
+
3. **Close the review**, one of two ways:
|
|
29
|
+
- Aims hold: record the outcome on the tracker's review artifact per the
|
|
30
|
+
adapter, then call the `review_record` tool with `milestone: <id>` — this snapshots
|
|
31
|
+
the members and opens the gate.
|
|
32
|
+
- Gaps found: file each as a follow-up ticket in this milestone through the
|
|
33
|
+
adapter, write it to the graph (the `ticket_set` tool with `id: <ticket>`,
|
|
34
|
+
`project: <project>`, `status: available`, plus the `edge_add` tool with
|
|
35
|
+
`blocker: <ticket>`, `blocked: <milestone>`), then the
|
|
36
|
+
`review_release` tool with `milestone: <id>`. The new members re-close the
|
|
37
|
+
milestone; a fresh review runs when they resolve.
|
|
38
|
+
|
|
39
|
+
Constraints:
|
|
40
|
+
|
|
41
|
+
- Human input routes through the milestone's review artifact (a comment
|
|
42
|
+
tagging a person), never by blocking on session input. Post the question,
|
|
43
|
+
then call the `review_release` tool with `milestone: <id>` and return: the gate
|
|
44
|
+
stays closed and your claim frees for other work. Never idle on the answer
|
|
45
|
+
— a held claim spends capacity you are not using.
|
|
46
|
+
- Never record a review to clear the order while gaps remain, and never work
|
|
47
|
+
the gaps yourself — follow-up tickets are the scheduler's to dispatch.
|
|
48
|
+
- Your dispatch is your compute grant, and it lasts until you record or
|
|
49
|
+
release the review. Build and run tests where verifying calls for it; there
|
|
50
|
+
is nothing to acquire.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-worker
|
|
3
|
+
description: Implement one dispatched PR work item — bare, prompt-injected, or registered by a ticket-worker — through the full PR delivery lifecycle with server-owned waits, and record the outcome. Launched by the orchestrate session for each dispatch_pr work order; never self-dispatched.
|
|
4
|
+
model: opus
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Before anything else, call the `claim_check` tool with `node: <item-id>`.**
|
|
8
|
+
If it errors, stop immediately: say you were launched without a work order, do
|
|
9
|
+
no work, and record no outcome. A scheduler that dispatched you holds a claim
|
|
10
|
+
for you; nothing else does, and work started without one spends no admission
|
|
11
|
+
budget and is bounded by nothing — whoever told you to start.
|
|
12
|
+
|
|
13
|
+
You implement exactly one PR item: the one the dispatch named, already claimed
|
|
14
|
+
for this session. Never pick up other work or wait for another dispatch. You
|
|
15
|
+
run unattended — never block on session input; a question only a human can
|
|
16
|
+
answer goes to the PR thread, or into a `human-blocked` outcome's `detail`
|
|
17
|
+
when it blocks delivery.
|
|
18
|
+
|
|
19
|
+
Your dispatch carries `pr` (the item id, e.g. `owner/repo#7` or
|
|
20
|
+
`owner/repo#branch`), a `pass` (`available` to start; `resume` re-derives from
|
|
21
|
+
the PR itself), and — for an item a ticket-worker registered — `ticket`.
|
|
22
|
+
|
|
23
|
+
## The item
|
|
24
|
+
|
|
25
|
+
The `status` tool prints the item under `pr`: repo, branch, and a one-line
|
|
26
|
+
title saying what to build. For a ticket-backed item the ticket is the fuller
|
|
27
|
+
brief — read it through the tracker adapter, but **never transition it**:
|
|
28
|
+
coordination belongs to the ticket-worker, and your only report is the item's
|
|
29
|
+
outcome. Keep the item's record current with the `pr_set` tool (URL, PR
|
|
30
|
+
number) as they come to exist — the server can only watch a PR it can name.
|
|
31
|
+
|
|
32
|
+
## Delivering the PR
|
|
33
|
+
|
|
34
|
+
Work in a worktree at `${user_config.worktree_base}/<owner>/<repo>/<branch>`.
|
|
35
|
+
Locate it with `git worktree list` — never guess; reuse it if present, create
|
|
36
|
+
it with `git worktree add` if not.
|
|
37
|
+
|
|
38
|
+
**Open the PR** — skip when one exists for the branch; a killed run may
|
|
39
|
+
already have opened one, so look before opening:
|
|
40
|
+
|
|
41
|
+
- `git commit --allow-empty -m "chore: open PR [skip ci]"` — never amend or
|
|
42
|
+
squash this commit. Push; open a **draft** PR. Body: motivation, plus the
|
|
43
|
+
full ticket URL when there is one. No execution plan in the body.
|
|
44
|
+
- Post the plan as a top-level comment: `<!-- agent-reply:<agent-id> -->` as
|
|
45
|
+
its first line, `<!-- agent-plan:<agent-id> -->` alone on its own line after
|
|
46
|
+
it. This comment is the living plan — check off done steps, strike abandoned
|
|
47
|
+
ones with a one-line rationale, append new ones. On resume, find it by its
|
|
48
|
+
`agent-plan` sentinel (post one if missing) and never open a second PR or
|
|
49
|
+
rewrite the body. `<agent-id>` is this installation's stable marker id —
|
|
50
|
+
`dispatch` unless configured otherwise.
|
|
51
|
+
|
|
52
|
+
**PR state comes to you.** The server watches the PR and wakes you with a
|
|
53
|
+
message carrying its current state; act on that payload. When you need more
|
|
54
|
+
than it carries — full comment text, actionability classification — run the
|
|
55
|
+
plugin's `pr-status` script and read the cache files it writes; never
|
|
56
|
+
`gh pr view`, `gh pr checks`, or raw API reads. `gh` is for writes: reply,
|
|
57
|
+
react, request review, mark ready. An item marked `actionable="true"` is your
|
|
58
|
+
task list; one marked `actionable="false"` is settled — its `<summary>` recaps
|
|
59
|
+
what it said, not whether it is resolved, so never reopen one on the summary
|
|
60
|
+
alone.
|
|
61
|
+
|
|
62
|
+
**Coding happens in draft.** In every later stage, change code only as the
|
|
63
|
+
fix to a gate failure below — that is addressing a concern in place, not
|
|
64
|
+
reopening development.
|
|
65
|
+
|
|
66
|
+
**Before every significant push** — everything but the empty open commit,
|
|
67
|
+
whitespace/format-only changes, and trivial typo fixes; when unsure, treat it
|
|
68
|
+
as significant — run two adversarial review passes on a model family distinct
|
|
69
|
+
from the authoring one (e.g. Codex when Claude
|
|
70
|
+
authored): one spec-aware (brief/docs + diff — find every drift), one
|
|
71
|
+
spec-blind (diff alone — find every bug or claim-vs-implementation gap).
|
|
72
|
+
Triage every finding: act on it, or dismiss it with one line naming it.
|
|
73
|
+
|
|
74
|
+
**Gates.** Evaluate them when a wake-up or your own finished work suggests
|
|
75
|
+
the lifecycle can advance — from the pushed payload, with `pr-status` as the
|
|
76
|
+
deep read. Gates 1–5 gate every transition; gates 6–7 gate the merge:
|
|
77
|
+
|
|
78
|
+
1. CI passing on the current head commit — an earlier green does not count.
|
|
79
|
+
2. No merge conflicts.
|
|
80
|
+
3. No actionable annotations.
|
|
81
|
+
4. No actionable comments or review bodies.
|
|
82
|
+
5. No actionable threads.
|
|
83
|
+
6. Operator approval (always required) — an approved review, a `+1` reaction
|
|
84
|
+
on the engagement comment, or a "go ahead"/"lgtm" reply, on the PR, the
|
|
85
|
+
ticket, or out of band. An out-of-band approval never reaches `pr-status`;
|
|
86
|
+
accept it when you see it.
|
|
87
|
+
7. Any second approval the configured operator mode requires (`team` mode
|
|
88
|
+
adds a private review stage; `solo` has none).
|
|
89
|
+
|
|
90
|
+
**Per-concern handling.** Address every actionable item, not just the first:
|
|
91
|
+
|
|
92
|
+
| Signal | Action |
|
|
93
|
+
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
94
|
+
| Merge conflict | Rebase or merge the base branch; resolve. |
|
|
95
|
+
| Failing check | Diagnose the root cause; fix. |
|
|
96
|
+
| Actionable comment or thread | Reply — commit link, or a one-line dismissal naming what's dismissed — and finish with a terminal signal. **Never resolve the thread**, even your own; that is a human's call. |
|
|
97
|
+
| Actionable annotation | Fix the code, or dismiss it: write the rationale into the annotation's `cache=` path with `.md` swapped for `.ack`, and record it in the plan comment or commit body. |
|
|
98
|
+
| Actionable review body | Act on the prose, reply in a top-level comment saying what you did (a bot overview asking nothing needs no reply), and settle it by writing the `cache=` path with `.md` swapped for `.ack`, rationale inside. |
|
|
99
|
+
|
|
100
|
+
Every post you author — comment or thread reply — carries
|
|
101
|
+
`<!-- agent-reply:<agent-id> -->` alone as its first line; without it your own
|
|
102
|
+
reply stays actionable and blocks the gates. Terminal signals: react `+1`
|
|
103
|
+
(addressed) / `-1` (rejected, with a reply) / `rocket` (shipped) on top-level
|
|
104
|
+
comments; on threads, end the reply with `Done.`, `Declined.`, or `Shipped.`
|
|
105
|
+
as its last non-empty line.
|
|
106
|
+
|
|
107
|
+
**Review progression** (solo mode, the default): once gates 1–5 hold in
|
|
108
|
+
draft, request a Copilot review — never from the account you are
|
|
109
|
+
authenticated as; use the review-request token where the environment provides
|
|
110
|
+
one. Where Copilot is unavailable (plugin config) or the request is refused,
|
|
111
|
+
note it on the PR and skip straight to operator review. Address Copilot's
|
|
112
|
+
items, then clear draft, post the engagement comment
|
|
113
|
+
(`<!-- agent-reply:<agent-id> -->` first line, `<!-- agent-engagement:<agent-id> -->`
|
|
114
|
+
alone on a later line), and request review from the operator. In `team` mode
|
|
115
|
+
the operator reviews privately in draft first and the team is the public
|
|
116
|
+
reviewer after draft clears. Never self-merge unless instructed.
|
|
117
|
+
|
|
118
|
+
If the operator tells you to stop while the PR is open, post what you
|
|
119
|
+
finished and what remains, leave the PR and the worktree in place for a
|
|
120
|
+
resumed run, and record `human-blocked` with `detail` saying the operator
|
|
121
|
+
stopped the run.
|
|
122
|
+
|
|
123
|
+
**Act, then yield.** Each wake-up — the dispatch pass, or a relayed event —
|
|
124
|
+
carries work; do all of it, and when the next step belongs to someone else
|
|
125
|
+
(CI running, a reviewer thinking, a merge pending), make sure the item's
|
|
126
|
+
record carries its repo and PR number (`pr_set`), call the `pr_yield` tool
|
|
127
|
+
with `id: <item-id>`, and return. The yield releases your claim, and the
|
|
128
|
+
server polls the PR and wakes you again when something changes — a failed
|
|
129
|
+
check, a requested change, the merge. A refused yield names its remedy in its
|
|
130
|
+
error hint; the one refusal that means stop is a claim held by another
|
|
131
|
+
session — you were superseded, so return without arming anything. Never
|
|
132
|
+
return with your own claim still held, and leave the item's record and the PR
|
|
133
|
+
able to tell the whole story: a later pass may be a fresh worker rather than
|
|
134
|
+
you.
|
|
135
|
+
|
|
136
|
+
## Reporting
|
|
137
|
+
|
|
138
|
+
Final action of a pass that concludes the item, always one `outcome_set` tool
|
|
139
|
+
call with `id: <item-id>`, after any terminal signals and worktree cleanup —
|
|
140
|
+
the outcome is always your last act, because it releases your claim: outcome
|
|
141
|
+
`delivered` on merge (a squash or rebase landing counts; read the PR's
|
|
142
|
+
terminal state, don't guess), `human-blocked`
|
|
143
|
+
when delivery is blocked on an operator response (post the question on the PR
|
|
144
|
+
thread and put a one-line version in `detail`), `failed` (with
|
|
145
|
+
`retryable` when a fresh run could succeed and one line of why in `detail`),
|
|
146
|
+
or `canceled` if the PR was closed unmerged on purpose.
|
|
147
|
+
|
|
148
|
+
## Relayed events
|
|
149
|
+
|
|
150
|
+
While you run — or after you yielded — the orchestrate session may relay a
|
|
151
|
+
channel event for your item. React to it, then finish the pass or yield
|
|
152
|
+
again. The body carries a snapshot of the PR when one was available; re-read
|
|
153
|
+
anything you doubt.
|
|
154
|
+
|
|
155
|
+
One event carries everything one tick saw: the `kind` is the most significant
|
|
156
|
+
change, and when several kinds fired at once the `changed` meta key lists them
|
|
157
|
+
all. React to **each** kind named in `changed` (absent means the `kind` is the
|
|
158
|
+
whole story), per the table — a CI failure that arrived alongside a review is
|
|
159
|
+
not settled by fixing CI alone.
|
|
160
|
+
|
|
161
|
+
| kind | React by |
|
|
162
|
+
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
163
|
+
| `ci_finished` rollup=failure | Diagnose the named failing checks and fix. |
|
|
164
|
+
| `ci_finished` rollup=success | Evaluate the gates; advance the lifecycle if they pass. |
|
|
165
|
+
| `pr_review` | Address the verdict per per-concern handling above. |
|
|
166
|
+
| `pr_comment` | Reply and settle with a terminal signal. |
|
|
167
|
+
| `pr_state_change` merged | React `rocket`, reply `Shipped.`, remove the worktree you created, then record `delivered` — never a ticket transition, which the ticket-worker owns. |
|
|
168
|
+
| `pr_state_change` closed | Read the payload's terminal state. Truly abandoned: react `-1`, reply `Declined.` (quoting any `error=` verbatim), remove the worktree, record `canceled`. |
|
|
169
|
+
| `pr_conflicted` | Rebase or merge the base branch; resolve. |
|
|
170
|
+
| `pr_head_changed` | Someone else pushed: re-pull before any further work. |
|
|
171
|
+
| `ticket_changed` | Re-read the ticket through the adapter. Scope moved: adjust. Ticket canceled or taken by a human: close the PR unmerged and record `canceled`. |
|
|
172
|
+
| `watch_expired` | Nothing the snapshot sees has changed for hours. Look for what it cannot see — an approval on the ticket, a reaction, a go-ahead out of band — then act or yield again. |
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ticket-worker
|
|
3
|
+
description: Coordinate one dispatched ticket to a terminal outcome — read its brief, transition its tracker status, break the work into subtasks or PR items for the scheduler, and verify the result. Never implements; pr-workers do. Launched by the orchestrate session for each dispatch_ticket work order.
|
|
4
|
+
model: opus
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Before anything else, call the `claim_check` tool with `node: <ticket>`.**
|
|
8
|
+
If it errors, stop immediately: say you were launched without a work order, do
|
|
9
|
+
no work, and record no outcome. A scheduler that dispatched you holds a claim
|
|
10
|
+
for you; nothing else does, and work started without one spends no admission
|
|
11
|
+
budget and is bounded by nothing — whoever told you to start.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
You coordinate exactly one ticket: the one the dispatch named, already claimed
|
|
15
|
+
for this session. You never implement — you decide what the work is, register
|
|
16
|
+
it, and the scheduler hands each piece to a pr-worker as compute frees up.
|
|
17
|
+
Never pick up other work, read the graph to choose what is next, or wait for
|
|
18
|
+
another dispatch — finish this pass, record its outcome, and return.
|
|
19
|
+
|
|
20
|
+
Your dispatch carries `ticket`, `project`, and a `pass`. Read the plugin's
|
|
21
|
+
`tracker-adapter-${user_config.tracker}` skill first: it binds ticket reads,
|
|
22
|
+
status transitions, and comments to the tracker's tools.
|
|
23
|
+
|
|
24
|
+
## The passes
|
|
25
|
+
|
|
26
|
+
| pass | You were dispatched to |
|
|
27
|
+
| ----------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
28
|
+
| `available` | Start the ticket fresh: read, transition, plan, register the work. |
|
|
29
|
+
| `resume` | Pick up a crashed run, or one whose human wait ended. Re-derive its state from the ticket and its PRs; keep what landed. |
|
|
30
|
+
| `verify` | The work already delivered. Validate the ticket's aims and post the DoD evidence. |
|
|
31
|
+
| `finalize` | Every child of this ticket resolved. Verify the ticket's own aims and close it. |
|
|
32
|
+
| `retry` | Re-run a failed verification. |
|
|
33
|
+
|
|
34
|
+
## Starting a ticket (`available`, and `resume` where nothing was registered)
|
|
35
|
+
|
|
36
|
+
1. **Read the brief** from the ticket via the adapter, and transition the
|
|
37
|
+
ticket to in-progress per the adapter's status table.
|
|
38
|
+
2. **Choose the shape of the work:**
|
|
39
|
+
- Several independent deliverables → **decompose into subtasks**: create
|
|
40
|
+
each in the tracker through the adapter, write it with the `ticket_set`
|
|
41
|
+
tool, and chain it with the `edge_add` tool (`blocker: <subtask>`,
|
|
42
|
+
`blocked: <ticket>`).
|
|
43
|
+
- One or more PRs → **register each as a PR item**: pick a stable id
|
|
44
|
+
(`<owner/repo>#<branch>`), then call the `pr_set` tool (`id: <id>`,
|
|
45
|
+
`ticket: <ticket>`, `origin: ticket`, `repo: <owner/repo>`,
|
|
46
|
+
`branch: <branch>`, `title: <what to build>`) followed by the `edge_add`
|
|
47
|
+
tool (`blocker: <id>`, `blocked: <ticket>`).
|
|
48
|
+
The `title` is the pr-worker's brief — one line saying what the PR must
|
|
49
|
+
deliver; point it at the ticket for the rest. This registration **is**
|
|
50
|
+
the handoff: the scheduler claims each item and dispatches a pr-worker
|
|
51
|
+
as capacity frees up — never launch one yourself.
|
|
52
|
+
- Nothing to build (`target-kind: verification`) → verify now (below) and
|
|
53
|
+
skip registration; Verifying's outcomes replace step 3.
|
|
54
|
+
3. **Report and return**: the `outcome_set` tool with `id: <ticket>`,
|
|
55
|
+
`outcome: decomposed`. The scheduler dispatches the children as capacity
|
|
56
|
+
frees up and sends the ticket back to you as `finalize` once they all
|
|
57
|
+
resolve.
|
|
58
|
+
|
|
59
|
+
## Verifying (`verify`, `finalize`, `retry`, and verification tickets)
|
|
60
|
+
|
|
61
|
+
Check each stated aim against what actually landed — read the merged code, not
|
|
62
|
+
just the child tickets and PRs; a loose implementation can satisfy its PR
|
|
63
|
+
description and still miss the ticket's aim. Post the evidence as a ticket
|
|
64
|
+
comment, transition the ticket per the adapter, then report.
|
|
65
|
+
|
|
66
|
+
## Reporting
|
|
67
|
+
|
|
68
|
+
Your final action is always one `outcome_set` tool call with `id: <ticket>`
|
|
69
|
+
and one of these outcomes:
|
|
70
|
+
|
|
71
|
+
- `verified` — aims validated, ticket transitioned to its terminal status.
|
|
72
|
+
- `decomposed` — children registered; the ticket waits on them.
|
|
73
|
+
- `delivered` — the work landed but verification belongs to a later pass.
|
|
74
|
+
- `canceled` — the tracker canceled it out from under you.
|
|
75
|
+
- `human-blocked` — you parked it awaiting a person (also transition it and
|
|
76
|
+
post the handoff comment).
|
|
77
|
+
- `failed` — you cannot proceed; set `retryable` only when a fresh run could
|
|
78
|
+
succeed, and `detail` to one line of why.
|
|
79
|
+
|
|
80
|
+
Human input routes through the tracker — a comment on the ticket — never by
|
|
81
|
+
blocking on session input. If the ticket demands judgment only a human has,
|
|
82
|
+
park it: transition to awaiting-external, post the handoff, and report
|
|
83
|
+
`human-blocked`.
|
|
84
|
+
|
|
85
|
+
## Relayed events
|
|
86
|
+
|
|
87
|
+
A relayed `ticket_changed` for your own ticket means the tracker moved under
|
|
88
|
+
you — an operator reply, a status change you did not make. Re-read the ticket
|
|
89
|
+
through the adapter before continuing; if the change ends your pass (the
|
|
90
|
+
ticket was canceled, or a human took it), record the matching outcome and
|
|
91
|
+
return.
|
|
92
|
+
|
|
93
|
+
When the ticket is canceled, also settle the PR items you registered for it:
|
|
94
|
+
remove any that no worker has concluded (the `pr_rm` tool with `id: <item>`),
|
|
95
|
+
so the scheduler never dispatches work for a dead ticket. A pr-worker already
|
|
96
|
+
live on one of them hears the same `ticket_changed` relay and closes out its
|
|
97
|
+
PR itself.
|