allye-pi 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +363 -0
- package/docs/install-pi.md +174 -0
- package/package.json +50 -0
- package/packages/allye-pi/src/index.ts +911 -0
- package/packages/allye-pi/tsconfig.json +13 -0
- package/skills/agent-runtime/SKILL.md +124 -0
- package/skills/agent-runtime/references/herdr.md +154 -0
- package/skills/board-progression/SKILL.md +214 -0
- package/skills/branch-landing/SKILL.md +88 -0
- package/skills/delivery/SKILL.md +187 -0
- package/skills/execution/SKILL.md +390 -0
- package/skills/handover-protocol/SKILL.md +74 -0
- package/skills/handover-protocol/references/correction.md +32 -0
- package/skills/handover-protocol/references/discovery-to-planning.md +44 -0
- package/skills/handover-protocol/references/execution-report.md +42 -0
- package/skills/handover-protocol/references/planning-to-technical.md +42 -0
- package/skills/handover-protocol/references/story-execution.md +74 -0
- package/skills/handover-protocol/references/technical-to-orchestration.md +45 -0
- package/skills/memory-protocol/SKILL.md +323 -0
- package/skills/orchestrator/SKILL.md +247 -0
- package/skills/product-planning/SKILL.md +255 -0
- package/skills/review/SKILL.md +165 -0
- package/skills/sandbox/SKILL.md +62 -0
- package/skills/setup/SKILL.md +225 -0
- package/skills/tdd-workflow/SKILL.md +144 -0
- package/skills/technical-planning/SKILL.md +352 -0
- package/skills/tools-quickref/SKILL.md +303 -0
- package/skills/using-allye/SKILL.md +191 -0
- package/skills/verification-loop/SKILL.md +93 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"allowImportingTsExtensions": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"types": ["node"]
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*.ts"]
|
|
13
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-runtime
|
|
3
|
+
description: Contract for driving an external agent runtime — spawning real agent processes in panes, dispatching work to them, and collecting results. Use when the session hook reported a runtime and work is about to be dispatched in parallel.
|
|
4
|
+
version: "1.0"
|
|
5
|
+
category: methodology
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Agent Runtime
|
|
9
|
+
|
|
10
|
+
An **agent runtime** owns real agent processes the human can watch, attach to, and take
|
|
11
|
+
over. This skill defines what the plugin needs from one, so the Orchestrator can drive
|
|
12
|
+
any runtime that satisfies the contract rather than one specific tool.
|
|
13
|
+
|
|
14
|
+
Load this only when the session hook reported a runtime. Without one, dispatch falls back
|
|
15
|
+
to the manual handover and the dispatched-subagent modes, both of which work unchanged.
|
|
16
|
+
|
|
17
|
+
Concrete commands for the runtimes we implement live in `references/`. This file is the
|
|
18
|
+
contract; the reference is the implementation.
|
|
19
|
+
|
|
20
|
+
<!-- adapted from ogulcancelik/herdr SKILL.md (Apache-2.0) — the primitive vocabulary and the safety rules -->
|
|
21
|
+
|
|
22
|
+
## The five primitives
|
|
23
|
+
|
|
24
|
+
### 1. detect
|
|
25
|
+
|
|
26
|
+
Answer two questions, not one: does the tool exist, and **is this session running inside
|
|
27
|
+
it**. A binary on `PATH` says nothing about the second.
|
|
28
|
+
|
|
29
|
+
A runtime that fails any part of detection is **absent**, never **broken**. A version
|
|
30
|
+
mismatch, an unreachable server, a missing environment variable — each means fall back to
|
|
31
|
+
asking the user manual-or-automatic. A degraded runtime must never block delivery.
|
|
32
|
+
|
|
33
|
+
### 2. spawn
|
|
34
|
+
|
|
35
|
+
Produce an isolated execution location and return a **stable identifier** for it. The
|
|
36
|
+
location must be a shell at an interactive prompt with nothing running in the foreground,
|
|
37
|
+
and creating it must not steal the human's focus.
|
|
38
|
+
|
|
39
|
+
<HARD-GATE>
|
|
40
|
+
**Wait for the shell; do not merely inspect it.** A pane created a moment ago is often
|
|
41
|
+
still running the shell's startup — a banner, a version manager, a greeting. Dispatching
|
|
42
|
+
into it fails. Poll for a bare shell with a bound, and treat a pane still busy after the
|
|
43
|
+
bound as a problem to report rather than one to keep waiting on.
|
|
44
|
+
</HARD-GATE>
|
|
45
|
+
|
|
46
|
+
### 3. dispatch
|
|
47
|
+
|
|
48
|
+
Deliver the briefing and **confirm it was accepted**.
|
|
49
|
+
|
|
50
|
+
<HARD-GATE>
|
|
51
|
+
Confirmation is part of the primitive, not an optional check. Sending text to an agent
|
|
52
|
+
that is idle can leave it sitting in the input box unsubmitted — the agent looks dispatched
|
|
53
|
+
and is not. After dispatching, read the agent's state back. If it has not moved to a
|
|
54
|
+
working state, submit explicitly and read it again.
|
|
55
|
+
</HARD-GATE>
|
|
56
|
+
|
|
57
|
+
### 4. wait
|
|
58
|
+
|
|
59
|
+
Block until the agent's lifecycle state settles. **Always with a timeout** — an unbounded
|
|
60
|
+
wait on a stalled agent hangs the whole delivery.
|
|
61
|
+
|
|
62
|
+
<HARD-GATE>
|
|
63
|
+
A settled state does not prove completion. "Idle" can mean finished, or an API error
|
|
64
|
+
mid-turn, or a question sitting unanswered on screen. An "unknown" state proves nothing at
|
|
65
|
+
all.
|
|
66
|
+
|
|
67
|
+
Runtime state is **evidence**. The verdict comes from `collect`.
|
|
68
|
+
</HARD-GATE>
|
|
69
|
+
|
|
70
|
+
**`wait` is not how the Orchestrator blocks — it is how the runtime's lifecycle becomes an
|
|
71
|
+
event in whatever system the Orchestrator actually lives in.** Run it as a background job
|
|
72
|
+
of the host harness so its completion arrives as a notification. Polling the agent's state
|
|
73
|
+
by hand works and is wrong: it makes every check an arbitrary interruption, and a finished
|
|
74
|
+
agent sits unnoticed until the next one. **A dispatch without a wait registered is a story
|
|
75
|
+
nobody is listening for**, so registering it is the closing step of `dispatch`, not a
|
|
76
|
+
separate thing to remember.
|
|
77
|
+
|
|
78
|
+
A future runtime satisfies this primitive only if its wait can be bridged that way.
|
|
79
|
+
|
|
80
|
+
### 5. collect
|
|
81
|
+
|
|
82
|
+
Read the result **from Allye**:
|
|
83
|
+
|
|
84
|
+
- `work_children(id: "{story uuid}")` — the real status of every task
|
|
85
|
+
- `memory_search("Review {STORY-KEY}")` — the review findings
|
|
86
|
+
- `memory_search("Implementation {TASK-KEY}")` — what was done and why
|
|
87
|
+
|
|
88
|
+
The terminal is for human observation and for diagnosing a stuck agent. It is never the
|
|
89
|
+
source of the result, for three reasons that hold regardless of what the terminal can show:
|
|
90
|
+
|
|
91
|
+
- A record in Allye is structured and machine-readable; a transcript is prose to be parsed.
|
|
92
|
+
- The Orchestrator can read it from a pane it never created, and after that pane is closed.
|
|
93
|
+
- It works identically for every runtime, including those with no output-read primitive at
|
|
94
|
+
all — which is most of the category.
|
|
95
|
+
|
|
96
|
+
There is also a documented failure mode where full-screen agents render on the terminal's
|
|
97
|
+
alternate screen and those rows never reach scrollback, making a long report unrecoverable.
|
|
98
|
+
**Treat that as a caveat, not the reason.** It did not reproduce in testing on 2026-07-26,
|
|
99
|
+
and a design justified by a failure that does not reproduce is one experiment away from
|
|
100
|
+
being abandoned for the wrong reason.
|
|
101
|
+
|
|
102
|
+
An agent that has settled but left no trace in Allye has produced an **incomplete report**.
|
|
103
|
+
Treat it the way §5 of `orchestrator` already treats one: ask for more, do not wave it
|
|
104
|
+
through.
|
|
105
|
+
|
|
106
|
+
## The obligation on the dispatched side
|
|
107
|
+
|
|
108
|
+
The contract closes only because the dispatched agent carries the other half:
|
|
109
|
+
|
|
110
|
+
> **Before settling, leave a durable trace in Allye.** Executor: task statuses advanced,
|
|
111
|
+
> plus an implementation memory. Reviewer: a memory holding the findings.
|
|
112
|
+
|
|
113
|
+
This is already what `execution` and `review` do. Here it becomes load-bearing rather than
|
|
114
|
+
good practice — it is the entire result channel.
|
|
115
|
+
|
|
116
|
+
## Teardown
|
|
117
|
+
|
|
118
|
+
Destroy only what you created, and only after the work it held is merged and verified.
|
|
119
|
+
Never close a pane, tab, workspace, or session the plugin did not create. Never stop the
|
|
120
|
+
runtime's server.
|
|
121
|
+
|
|
122
|
+
## Implementations
|
|
123
|
+
|
|
124
|
+
- Herdr — `references/herdr.md`
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Runtime implementation: Herdr
|
|
2
|
+
|
|
3
|
+
Herdr is a terminal multiplexer that recognizes coding agents inside panes and exposes
|
|
4
|
+
them over a CLI. Its mental model: `workspace (w1) → tab (w1:t1) → pane (w1:p1)`, with an
|
|
5
|
+
**agent** being a recognized process inside a pane. A pane exists whether or not it holds
|
|
6
|
+
an agent, and starting an agent never creates or moves layout — topology is the caller's job.
|
|
7
|
+
|
|
8
|
+
Agent names must match `[a-z][a-z0-9_-]{0,31}` and be unique among live agents. Use
|
|
9
|
+
`story-beac-1716`, never `BEAC-1716`.
|
|
10
|
+
|
|
11
|
+
## detect
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
[ "${HERDR_ENV:-}" = "1" ] || exit 1 # not inside a pane
|
|
15
|
+
command -v herdr >/dev/null || exit 1
|
|
16
|
+
herdr status | grep -q 'compatible: yes' || exit 1
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The session hook already runs this and reports the result. Re-run it only if a dispatch
|
|
20
|
+
fails in a way that suggests the server went away.
|
|
21
|
+
|
|
22
|
+
Caller context is injected into every managed pane: `$HERDR_PANE_ID`, `$HERDR_TAB_ID`,
|
|
23
|
+
`$HERDR_WORKSPACE_ID`.
|
|
24
|
+
|
|
25
|
+
## spawn
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
herdr pane layout --pane "$HERDR_PANE_ID"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Read the pane's dimensions from `.result.layout.area`. **Split a wide pane to the right and
|
|
32
|
+
a narrow or tall one down.** Repeated splits in one direction produce columns too narrow to
|
|
33
|
+
read.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
herdr pane split --current --direction right --cwd "$CWD" --no-focus
|
|
37
|
+
# new pane id: .result.pane.pane_id
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`--no-focus` keeps the human where they were. **Wait** for the pane to reach a bare shell —
|
|
41
|
+
a pane created a second ago is usually still running the shell's startup, and `agent start`
|
|
42
|
+
fails with `agent_pane_busy`:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
for _ in $(seq 1 10); do
|
|
46
|
+
FG=$(herdr pane process-info --pane "$PANE" | jq -r '.result.process_info.foreground_processes[0].name')
|
|
47
|
+
case "$FG" in zsh|bash|sh|fish) break;; esac
|
|
48
|
+
sleep 3
|
|
49
|
+
done
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Bounded, not infinite. A pane still busy after thirty seconds is a problem to report.
|
|
53
|
+
|
|
54
|
+
## dispatch
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
herdr agent start {name} --kind {kind} --pane {pane_id} --timeout 120000 -- {native args}
|
|
58
|
+
herdr agent prompt {name} "$(cat {briefing file})"
|
|
59
|
+
herdr agent get {name} | jq -r '.result.agent.agent_status'
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The third command is mandatory, not diagnostic — and **expect to need the fourth.**
|
|
63
|
+
Prompting an idle agent left the text unsubmitted in every observed dispatch, so treat this
|
|
64
|
+
as a two-step operation rather than a rare branch. When the status does not read `working`:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
herdr agent send-keys {name} enter
|
|
68
|
+
herdr agent get {name} | jq -r '.result.agent.agent_status'
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`--kind` accepts, among others: `claude`, `codex`, `opencode`, `pi`, `gemini`, `cursor`,
|
|
72
|
+
`copilot`, `amp`, `droid`. Native arguments pass verbatim after `--`.
|
|
73
|
+
|
|
74
|
+
Named failure: `agent_prompt_stalled`, returned when no lifecycle change is observed within
|
|
75
|
+
five seconds of prompting a non-working agent.
|
|
76
|
+
|
|
77
|
+
## wait
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
herdr agent wait {name} --timeout 3600000
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Run it as a background job of your own harness**, so its exit arrives as a notification
|
|
84
|
+
rather than something you have to remember to check. That bridge is the point of the
|
|
85
|
+
primitive — see the contract's §4. Do not poll `agent get` in a loop: the wait is
|
|
86
|
+
server-side and event-driven, and polling turns every check into an arbitrary interruption
|
|
87
|
+
while leaving a finished agent unnoticed between them.
|
|
88
|
+
|
|
89
|
+
Across all panes at once:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
herdr agent list | jq -r '.result.agents[] | "\(.pane_id)\t\(.agent)\t\(.agent_status)\t\(.cwd)"'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`herdr agent read` returns **plain text, not JSON** — piping it to `jq` fails.
|
|
96
|
+
|
|
97
|
+
To understand why a pane was classified as it was:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
herdr agent explain {name} --json --verbose
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## collect
|
|
104
|
+
|
|
105
|
+
Read from Allye — see the contract. The terminal is diagnostic only:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
herdr agent read {name} --source recent-unwrapped --lines 200
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Sources are `visible`, `recent`, `recent-unwrapped`, and `detection`. Prefer
|
|
112
|
+
`recent-unwrapped` for transcripts. If raising `--lines` reveals nothing more, the agent is
|
|
113
|
+
rendering on the alternate screen and the rows are gone — this is expected, and is why the
|
|
114
|
+
result channel is Allye.
|
|
115
|
+
|
|
116
|
+
## answering a blocked agent
|
|
117
|
+
|
|
118
|
+
A `blocked` state means Herdr recognized an approval or question UI. Read the pane before
|
|
119
|
+
answering — the question may be one whose options are all wrong:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
herdr agent read {name} --source recent-unwrapped --lines 120
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
If a selection UI is open and your answer is not one of its options, **dismiss it first**.
|
|
126
|
+
Sending a prompt into an open menu risks the text being read as menu navigation:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
herdr agent send-keys {name} esc
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Then dispatch normally, including the submit confirmation — a freshly dismissed menu leaves
|
|
133
|
+
the agent idle, which is exactly the state where a prompt lands unsubmitted.
|
|
134
|
+
|
|
135
|
+
## teardown
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
herdr pane close {pane_id}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Only panes the plugin created, and only after §7.1's merge gates have passed.
|
|
142
|
+
|
|
143
|
+
## Safety rules — never widened
|
|
144
|
+
|
|
145
|
+
- Never run bare `herdr` for discovery; it launches or attaches the TUI. Discover with
|
|
146
|
+
`herdr agent`, `herdr pane`, `herdr workspace` — a group name with no subcommand prints
|
|
147
|
+
its help.
|
|
148
|
+
- Never probe a mutating command by omitting its arguments. `herdr workspace create` is
|
|
149
|
+
valid with defaults and will execute.
|
|
150
|
+
- Never run `herdr server stop`. Never kill the main Herdr process.
|
|
151
|
+
- Never close a workspace, tab, pane, or session the plugin did not create.
|
|
152
|
+
- Always pass `--timeout`. Omitting it allows an indefinite wait.
|
|
153
|
+
- Parse identifiers out of JSON responses. Never derive them from sidebar order or from
|
|
154
|
+
the examples above.
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: board-progression
|
|
3
|
+
description: Rules for moving work items between statuses in Allye boards. Covers work_status_next, work_status_done, and status categories.
|
|
4
|
+
version: "1.2"
|
|
5
|
+
category: methodology
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Board Progression
|
|
9
|
+
|
|
10
|
+
How to move work items between statuses on Allye boards, correctly.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. Status Categories vs. Status Names
|
|
15
|
+
|
|
16
|
+
The MCP client can only **confirm** 4 status categories — `work_statuses()` (`work_items.py`) groups every status under a hardcoded `category_order`:
|
|
17
|
+
|
|
18
|
+
| Category (confirmed) | Meaning |
|
|
19
|
+
|----------|---------|
|
|
20
|
+
| `proposed` | Not yet started (backlog/todo-like) |
|
|
21
|
+
| `in_progress` | Actively being worked on |
|
|
22
|
+
| `done` | Completed and verified |
|
|
23
|
+
| `cancelled` | Will not be done |
|
|
24
|
+
|
|
25
|
+
That's the only taxonomy the MCP client source guarantees. Specific status **names** are team-configurable `WorkflowStatus` records mapped onto those 4 categories via board columns — not enumerable or guaranteed from the client code alone, and a given team's board may use different names or skip some of them.
|
|
26
|
+
|
|
27
|
+
### The team's pipeline is data. Read it.
|
|
28
|
+
|
|
29
|
+
Allye is multi-tenant. Four presets ship — Solo, Startup, Standard, Enterprise — and every
|
|
30
|
+
team customises from there, so **there is no status list to memorise and no ordering to
|
|
31
|
+
assume.** A skill that names a status has guessed about somebody else's board.
|
|
32
|
+
|
|
33
|
+
Only three things are stable enough to build a rule on:
|
|
34
|
+
|
|
35
|
+
| Stable | Why |
|
|
36
|
+
|---|---|
|
|
37
|
+
| The four categories: `proposed`, `in_progress`, `done`, `cancelled` | A schema enum. Every status maps to exactly one. |
|
|
38
|
+
| The three pipelines: `product`, `engineering`, `shared` | A schema enum. `product` carries epics and features; `engineering` carries stories and below; `shared` holds the terminal states. |
|
|
39
|
+
| The board's own ordering | Whatever it is, it is what `work_status_next` walks. |
|
|
40
|
+
|
|
41
|
+
Discover the rest:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
work_statuses() → every status the team has, grouped by category, in position order
|
|
45
|
+
board_columns() → the columns of a specific board
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Two things `work_statuses()` does not tell you today**, and planning around them is the
|
|
49
|
+
difference between a working transition and a surprised one:
|
|
50
|
+
|
|
51
|
+
- **`position`, `pipeline`, and `description` are not returned.** They exist on the record —
|
|
52
|
+
the seed writes all three — but the MCP formatter emits only name, key, id, and colour.
|
|
53
|
+
- **`board_columns()` returns names and ids only** — no status-to-column mapping and no
|
|
54
|
+
ordering. The visible subset a given board shows cannot be reconstructed from it.
|
|
55
|
+
|
|
56
|
+
Together these mean **you cannot reliably predict the next status.** So do not:
|
|
57
|
+
|
|
58
|
+
<HARD-GATE>
|
|
59
|
+
Move one status at a time, then **read back** the status you actually landed on. Never
|
|
60
|
+
assume a transition took you where you expected, and never chain several moves on a
|
|
61
|
+
prediction. One extra read per transition costs nothing next to a cascade that silently
|
|
62
|
+
skipped four gates.
|
|
63
|
+
</HARD-GATE>
|
|
64
|
+
|
|
65
|
+
For reference only, these are the eighteen statuses the presets seed — **an example of one
|
|
66
|
+
tenant's configuration, not a list to code against**: `idea`, `researching`, `designing`,
|
|
67
|
+
`specifying`, `backlog`, `todo`, `in_progress`, `code_review`, `security_scan`, `qa_testing`,
|
|
68
|
+
`doc_review`, `deploy_staging`, `qa_staging`, `deploy_preprod`, `qa_preprod`, `deploy_prod`,
|
|
69
|
+
`done`, `cancelled`.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 2. How `work_status_next` Works
|
|
74
|
+
|
|
75
|
+
`work_status_next` moves a work item to the **next logical status** in the board progression.
|
|
76
|
+
|
|
77
|
+
### Resolution logic
|
|
78
|
+
|
|
79
|
+
1. Collects all visible statuses from non-archived boards
|
|
80
|
+
2. Orders them by: `board.position → column.position → BoardColumnStatus.position`
|
|
81
|
+
3. Deduplicates: first occurrence wins
|
|
82
|
+
4. Finds the current status in this ordered list
|
|
83
|
+
5. Moves to the next status in the list
|
|
84
|
+
|
|
85
|
+
### Edge cases
|
|
86
|
+
|
|
87
|
+
| Situation | Behavior |
|
|
88
|
+
|-----------|----------|
|
|
89
|
+
| Current status is NOT in any visible board | Moves to the **first** status in the list |
|
|
90
|
+
| Current status is the **last** in the list | Returns an **error** — cannot move forward |
|
|
91
|
+
| Item has no status set | Moves to the **first** status in the list |
|
|
92
|
+
|
|
93
|
+
### When to use
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
work_status_next(id: "{work item uuid}")
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Use it for **forward progression**, one status at a time, as each step's work actually finishes — how progression differs by pipeline and item type is in §5.
|
|
100
|
+
|
|
101
|
+
### When NOT to use
|
|
102
|
+
|
|
103
|
+
- Don't use to skip statuses (e.g., backlog → done)
|
|
104
|
+
- Don't use to go backward — there is no `work_status_prev`
|
|
105
|
+
- Don't call repeatedly to "fast forward" through multiple statuses without doing the actual work
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 3. How `work_status_done` Works
|
|
110
|
+
|
|
111
|
+
`work_status_done` moves a work item directly to the "done" status, regardless of its current position.
|
|
112
|
+
|
|
113
|
+
### Resolution logic
|
|
114
|
+
|
|
115
|
+
1. Looks for a status mapped to a column with `is_done_column = true`
|
|
116
|
+
2. Fallback: picks the first status with `category === "done"`
|
|
117
|
+
3. Sets `completed_at = now()` on the work item
|
|
118
|
+
|
|
119
|
+
### When to use
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
work_status_done(id: "{work item uuid}")
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Use this when work is **fully complete and verified**:
|
|
126
|
+
- All acceptance criteria are met
|
|
127
|
+
- Tests pass
|
|
128
|
+
- Review is approved (if applicable)
|
|
129
|
+
|
|
130
|
+
<HARD-GATE>
|
|
131
|
+
Do NOT call work_status_done unless the work is genuinely complete.
|
|
132
|
+
"Almost done" is not done. "Tests are mostly passing" is not done.
|
|
133
|
+
Verify all acceptance criteria before marking an item as done.
|
|
134
|
+
</HARD-GATE>
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 3.1 Where an agent's authority ends
|
|
139
|
+
|
|
140
|
+
> **An agent drives everything that is verification. It stops at the first gate that changes
|
|
141
|
+
> the world outside the repository.**
|
|
142
|
+
|
|
143
|
+
Deploying does that. Verifying does not. The rule survives renaming because it describes what
|
|
144
|
+
a gate *is*, not what it is called — which is the only kind of rule that works when every
|
|
145
|
+
team configures its own statuses.
|
|
146
|
+
|
|
147
|
+
In practice, on the seeded presets: reviewing, scanning, testing, and updating docs are all
|
|
148
|
+
verification and all satisfiable by an agent. Every deploy stage, and any validation
|
|
149
|
+
performed in a deployed environment, is not.
|
|
150
|
+
|
|
151
|
+
<HARD-GATE>
|
|
152
|
+
`work_status_done` is **not** the exit from a pipeline an agent cannot finish. Calling it
|
|
153
|
+
from four statuses away records "done" for work that never passed the gates in between.
|
|
154
|
+
|
|
155
|
+
Use it only when the item's next status **is** the done status. Otherwise stop at the last
|
|
156
|
+
gate you satisfied and say plainly which gate is next and who owns it.
|
|
157
|
+
</HARD-GATE>
|
|
158
|
+
|
|
159
|
+
An unrecognised status is treated as a stop, not a pass. Ask once who satisfies it, record
|
|
160
|
+
the answer in the team's delivery configuration, and never ask again.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 4. Checking Available Statuses
|
|
165
|
+
|
|
166
|
+
Before moving items, understand what statuses exist:
|
|
167
|
+
|
|
168
|
+
### List all statuses
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
work_statuses()
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Returns all available statuses with their categories and names.
|
|
175
|
+
|
|
176
|
+
### View board columns
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
board_columns()
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Returns the board's columns for the given `board_id` — each rendered as `- {column name} (ID: {column id})`. Note: this tool's text output does not surface which statuses map to which column, nor an explicit ordering field (`boards.py`'s `board_columns` action only formats `name` and `id` per column) — that richer structure may exist in the underlying API but isn't exposed here. Use it to confirm which columns exist on a board; pair it with `work_statuses()` for status names/categories.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## 5. Progression Patterns by Item Type
|
|
187
|
+
|
|
188
|
+
Progression differs by pipeline, not only by type. **Epics and features live on the `product`
|
|
189
|
+
pipeline; stories, bugs, hotfixes, tasks, spikes, and subtasks live on `engineering`.** A
|
|
190
|
+
cascade from task to epic therefore crosses pipelines, and the statuses available on each side
|
|
191
|
+
are different sets.
|
|
192
|
+
|
|
193
|
+
What holds regardless of the team's configuration:
|
|
194
|
+
|
|
195
|
+
- **Parents move because children moved.** A story advances when its tasks do; a feature when
|
|
196
|
+
its stories do; an epic when its features do. Never the other way round.
|
|
197
|
+
- **A parent never reaches the done category while any child is outside it.** This is the one
|
|
198
|
+
rule that failed in practice: a story closed with seven of fifteen tasks still mid-pipeline,
|
|
199
|
+
because closing it was the only exit the flow offered. Stopping is the exit.
|
|
200
|
+
- **The Executor advances a task only to the first review gate.** The move past that is the
|
|
201
|
+
Orchestrator's, after review clears — see `orchestrator` §6.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## 6. Common Mistakes
|
|
206
|
+
|
|
207
|
+
| Mistake | Why it's wrong | Do this instead |
|
|
208
|
+
|---------|---------------|-----------------|
|
|
209
|
+
| Moving story to done before all tasks are done | Misrepresents progress | Check `work_children` first — all tasks must be done |
|
|
210
|
+
| Marking a task done as soon as its own tests pass | Done requires review approval, not just green tests | `work_status_next` once, to the first review gate, and stop; the Orchestrator carries it from there — see §3.1 |
|
|
211
|
+
| Skipping statuses with repeated `work_status_next` | Loses tracking fidelity | Only advance when the work for that status is actually complete |
|
|
212
|
+
| Moving to in_progress without planning | No tasks = no accountability | Run Technical Planning first, create tasks, then advance |
|
|
213
|
+
| Forgetting to check board structure | Different teams may have different progressions | Always check `board_columns` if unsure about available statuses |
|
|
214
|
+
| Moving a cancelled item to done | Contradictory | Cancelled items stay cancelled |
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: branch-landing
|
|
3
|
+
description: Decide and execute what happens to a branch once its work is done — merge, open a pull request, or leave it — then tear down the worktree and pane without losing anything. Use when a story's implementation is complete, or when another skill needs the teardown sequence.
|
|
4
|
+
version: "1.0"
|
|
5
|
+
category: methodology
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Branch Landing
|
|
9
|
+
|
|
10
|
+
Code that is written and reviewed is not yet delivered. It sits on a branch, and something has to decide what happens to it. This skill is that decision and the sequence that carries it out.
|
|
11
|
+
|
|
12
|
+
## 1. A branch does not land ahead of its story
|
|
13
|
+
|
|
14
|
+
<HARD-GATE>
|
|
15
|
+
Before anything else, check where the story actually is.
|
|
16
|
+
|
|
17
|
+
If the story is parked at a pipeline gate — waiting on QA, a scan, a deploy, anything the team satisfies outside this session (see `board-progression` §3.1) — **the branch waits with it.** Do not merge, do not open a pull request, do not remove the worktree.
|
|
18
|
+
|
|
19
|
+
Landing code whose story never passed its gates is the same defect as closing a story to tidy the board, one layer down. Say which gate the story waits at, and stop.
|
|
20
|
+
</HARD-GATE>
|
|
21
|
+
|
|
22
|
+
The work item is the authority on whether the work is done. The branch follows it; it never leads.
|
|
23
|
+
|
|
24
|
+
## 2. Ask how the work should land
|
|
25
|
+
|
|
26
|
+
Teams integrate differently and the plugin has no basis to guess. Ask once, with a recommendation so accepting takes a word:
|
|
27
|
+
|
|
28
|
+
| Option | What happens | When it fits |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| **Pull request** | Push the branch, open a PR against the base, leave everything standing | Any team that reviews before merging, or where CI runs on the PR |
|
|
31
|
+
| **Merge locally** | Merge into the base in the main checkout, then tear down | Solo work, or a change already reviewed by the two axes |
|
|
32
|
+
| **Leave it** | Push for safety, change nothing else | The human wants to look first, or the work is paused |
|
|
33
|
+
|
|
34
|
+
The base branch is per-repo and comes from the `Allye Delivery Configuration` Core Document — **never assumed.** Repos with a git-flow layout branch from `develop`; repos releasing from trunk branch from `main`.
|
|
35
|
+
|
|
36
|
+
**Nothing merges into the base branch without the human choosing it in this conversation.** A merge is not reversible in the way an unmerged branch is, and no amount of green review substitutes for being asked.
|
|
37
|
+
|
|
38
|
+
## 3. The sequence, when merging locally
|
|
39
|
+
|
|
40
|
+
Every step is a gate. One story at a time; do not batch.
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
1. GATE: git -C <worktree> status --porcelain must be EMPTY
|
|
44
|
+
dirty → STOP, escalate. Do not merge, do not remove.
|
|
45
|
+
2. git push -u origin <branch>
|
|
46
|
+
3. In the MAIN checkout, on the base: git merge --no-ff <branch>
|
|
47
|
+
4. Conflicts in shared wiring files are expected when parallel work
|
|
48
|
+
touched the same composition root. Resolve by CONSOLIDATING into one
|
|
49
|
+
instance — never by picking a side.
|
|
50
|
+
5. Rebuild, typecheck, run tests BEFORE committing the merge
|
|
51
|
+
6. git worktree remove <path> ← without --force
|
|
52
|
+
7. Close the runtime pane ← only after step 6
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### The three locks
|
|
56
|
+
|
|
57
|
+
Each exists because it prevents one specific way work disappears. They look skippable right up until they are not.
|
|
58
|
+
|
|
59
|
+
| Lock | What it prevents |
|
|
60
|
+
|---|---|
|
|
61
|
+
| **Push before removal** (2) | The branch exists on the remote before anything is destroyed. After this, no local accident loses the work. |
|
|
62
|
+
| **`worktree remove` without `--force`** (6) | Git refuses a dirty worktree. That refusal is the last safety net; bypassing it by reflex is how uncommitted work vanishes. |
|
|
63
|
+
| **Pane closes last** (7) | While the pane lives, the session's reasoning is inspectable. Close it before a validated merge and the *why* is gone, even though the *what* survives in the diff. |
|
|
64
|
+
|
|
65
|
+
### When merging is not the choice
|
|
66
|
+
|
|
67
|
+
**Pull request:** push, open the PR against the base, and stop. Worktree and pane stay — review feedback arrives there. Record the PR reference on the story so the next session finds it.
|
|
68
|
+
|
|
69
|
+
**Leave it:** push, and change nothing else. Say plainly what is standing: branch, worktree, pane.
|
|
70
|
+
|
|
71
|
+
## 4. Never
|
|
72
|
+
|
|
73
|
+
- **Never merge into the base branch unasked.** §2.
|
|
74
|
+
- **Never force-push.** A force-push rewrites what step 2 exists to protect.
|
|
75
|
+
- **Never delete a branch.** Merged branches are cheap and are the record of how something was built. Removing a worktree is not deleting its branch, and should not become it.
|
|
76
|
+
- **Never destroy what you did not create.** A worktree or pane that predates this session belongs to someone else.
|
|
77
|
+
|
|
78
|
+
## 5. Abandoned work
|
|
79
|
+
|
|
80
|
+
A story that failed, was cancelled, or stalled gets **no cleanup at all**. Worktree, branch, and pane all stay.
|
|
81
|
+
|
|
82
|
+
Visible litter costs far less than deleted work, and an abandoned branch is often the only record of an approach that was tried and rejected — which is worth more than the disk it occupies.
|
|
83
|
+
|
|
84
|
+
## 6. Record where it landed
|
|
85
|
+
|
|
86
|
+
Once the work has landed, the branch may be the only durable trace outside the diff. Carry the reference into the delivery memory (`memory_save`, `sector: "knowledge"`): the branch name, the merge commit or PR reference, and the base it landed on.
|
|
87
|
+
|
|
88
|
+
A memory that says a story was delivered, without saying where the code went, is a memory that sends the next reader searching.
|