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.
@@ -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.