@orderful/droid 0.44.0 → 0.44.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @orderful/droid
2
2
 
3
+ ## 0.44.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#258](https://github.com/Orderful/droid/pull/258) [`2e19bbd`](https://github.com/Orderful/droid/commit/2e19bbda7146847836ccda028e1c6bf802a5215e) Thanks [@frytyler](https://github.com/frytyler)! - Add lock/unlock commands to release tool. Requires branch-lock.yml GitHub Action deployed to target repos.
8
+
3
9
  ## 0.44.0
4
10
 
5
11
  ### Minor Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "droid-release",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Release ceremony automation — create release PRs, check status, notify Slack.",
5
5
  "author": {
6
6
  "name": "Orderful",
@@ -1,6 +1,6 @@
1
1
  name: release
2
2
  description: "Release ceremony automation — create release PRs, check status, notify Slack."
3
- version: 0.1.0
3
+ version: 0.2.0
4
4
  status: alpha
5
5
 
6
6
  includes:
@@ -18,4 +18,4 @@ config_schema:
18
18
  slack_channel:
19
19
  type: string
20
20
  description: "Slack channel for release notifications"
21
- default: "#release-management"
21
+ default: "#release_management"
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: release
3
- description: "Release ceremony automation"
4
- argument-hint: "[start [repo] | status | complete [repo]]"
3
+ description: "Release ceremony automation and branch locking"
4
+ argument-hint: "[start [repo] [--no-lock] | merge [repo] | lock [repo] | unlock [repo] | status | complete [repo]]"
5
5
  ---
6
6
 
7
7
  # /release
@@ -12,17 +12,25 @@ argument-hint: "[start [repo] | status | complete [repo]]"
12
12
 
13
13
  ## Examples
14
14
 
15
- - `/release start` → Create release PR for current repo
15
+ - `/release start` → Create release PR + auto-lock branch
16
16
  - `/release start orderful-workspace` → Create release PR for a specific repo
17
- - `/release status` → Check CI state across release repos
18
- - `/release complete` → Post "release complete" to Slack
17
+ - `/release start --no-lock` → Create release PR without locking
18
+ - `/release merge` → Merge release PR (checks must be green)
19
+ - `/release lock` → Manually lock the release branch
20
+ - `/release unlock` → Unlock the release branch
21
+ - `/release status` → Check CI and lock state across release repos
22
+ - `/release complete` → Post "release complete" to Slack, auto-unlock if locked
19
23
 
20
24
  ## Quick Reference
21
25
 
22
26
  ```
23
- /release start [repo] # Create release PR + notify Slack
24
- /release status # CI state across repos
25
- /release complete [repo] # Notify Slack, close out release
27
+ /release start [repo] # Create release PR + auto-lock + notify Slack
28
+ /release start --no-lock # Create release PR without locking
29
+ /release merge [repo] # Merge release PR (checks must pass)
30
+ /release lock [repo] # Manually lock release branch
31
+ /release unlock [repo] # Unlock release branch
32
+ /release status # CI + lock state across repos
33
+ /release complete [repo] # Notify Slack + auto-unlock
26
34
  ```
27
35
 
28
36
  See the **release skill** for complete documentation.
@@ -1,20 +1,21 @@
1
1
  ---
2
2
  name: release
3
- description: "Release ceremony automation for dev-to-master releases. Use when starting a release, merging a release, checking release status, or completing a release. User prompts like 'start a release', 'merge the release', 'release status', 'release complete'."
4
- argument-hint: "[start [repo] | merge [repo] | status | complete [repo]]"
3
+ description: "Release ceremony automation for dev-to-master releases. Use when starting a release, merging a release, locking a branch, checking release status, or completing a release. User prompts like 'start a release', 'merge the release', 'lock dev', 'release status', 'unlock the branch'."
4
+ argument-hint: "[start [repo] | merge [repo] | lock [repo] | unlock [repo] | status | complete [repo]]"
5
5
  allowed-tools: [Read, Write, Glob, Grep, Bash, Edit]
6
6
  ---
7
7
 
8
8
  # Release Skill
9
9
 
10
- Automate dev → master release ceremonies: create release PRs, notify Slack, and track status.
10
+ Automate dev → master release ceremonies: create release PRs, lock branches during CI, notify Slack, and track status.
11
11
 
12
12
  ## When to Use
13
13
 
14
14
  - User wants to start a release (create PR from dev → master)
15
- - User asks about release status (open PRs, CI checks)
15
+ - User wants to lock or unlock a branch during a release
16
+ - User asks about release status (open PRs, lock state, CI checks)
16
17
  - User says "release complete" or wants to close out a release
17
- - Natural language like "start a release", "what's the release status?"
18
+ - Natural language like "start a release", "lock dev", "what's the release status?"
18
19
 
19
20
  ## When NOT to Use
20
21
 
@@ -26,6 +27,7 @@ Automate dev → master release ceremonies: create release PRs, notify Slack, an
26
27
 
27
28
  1. **`gh` CLI** — authenticated with access to target repos
28
29
  2. **Slack integration** — `droid integrations slack post` configured (optional, falls back to terminal)
30
+ 3. **`branch-lock.yml`** — GitHub Action deployed to target repo (required for auto-lock on start + lock/unlock commands)
29
31
 
30
32
  ## Configuration
31
33
 
@@ -37,7 +39,7 @@ droid config --get repos
37
39
  ```
38
40
 
39
41
  - **Repos:** Filter `repos` array for entries with `release_branch` set — these are release repos
40
- - **Slack channel:** From `tools.release.slack_channel` (default: `#release-management`)
42
+ - **Slack channel:** From `tools.release.slack_channel` (default: `#release_management`)
41
43
  - **Repo detection:** Match cwd against repo paths, or ask user if ambiguous
42
44
 
43
45
  If no repos have `release_branch` set, tell user:
@@ -47,10 +49,12 @@ If no repos have `release_branch` set, tell user:
47
49
 
48
50
  | Command | Action |
49
51
  |---------|--------|
50
- | `/release start [repo]` | Create release PR + notify Slack |
52
+ | `/release start [repo] [--no-lock]` | Create release PR + auto-lock branch + notify Slack |
51
53
  | `/release merge [repo]` | Merge release PR (only if checks pass) + notify Slack |
52
- | `/release status` | Check open release PRs + CI state |
53
- | `/release complete [repo]` | Post completion to Slack |
54
+ | `/release lock [repo]` | Lock release branch (confirms first) |
55
+ | `/release unlock [repo]` | Unlock release branch |
56
+ | `/release status` | Check open release PRs + CI state + lock state |
57
+ | `/release complete [repo]` | Post completion to Slack + auto-unlock |
54
58
 
55
59
  See `references/workflows.md` for detailed step-by-step procedures and exact `gh` commands.
56
60
 
@@ -69,6 +73,8 @@ See `references/templates.md` for Slack message and PR body templates.
69
73
  |-------|--------|
70
74
  | No release repos configured | Suggest `droid repos add` with release branch |
71
75
  | `gh` CLI not authenticated | Suggest `gh auth login` |
76
+ | `branch-lock.yml` not found in repo | Tell user to add the `branch-lock.yml` workflow to the repo |
72
77
  | Slack not configured | Print message to terminal, suggest `droid integrations setup slack` |
78
+ | Branch already locked | Warn user, offer to unlock first |
73
79
  | Release PR already exists | Show existing PR, ask if user wants to proceed |
74
80
  | CI checks failing | Show status, do not auto-merge |
@@ -6,20 +6,23 @@ Slack mrkdwn and PR body templates for release notifications.
6
6
 
7
7
  All Slack messages are posted via `droid integrations slack post`. Format as Slack mrkdwn (not GitHub markdown).
8
8
 
9
- ### Release Started
9
+ ### Release Open for Review
10
10
 
11
11
  ```
12
- :rocket: *Release started — {repo_name}*
12
+ :rocket: *Release open for review — {repo_name}*
13
13
 
14
14
  *Risk:* {risk_emoji} {risk_level}
15
15
  *PR:* <{pr_url}|#{pr_number}>
16
16
  *Branch:* `{release_branch}` → `{production_branch}`
17
+ :lock: `{release_branch}` is locked — no merges until release completes
17
18
 
18
19
  {pr_summary}
19
20
 
20
21
  Posted with :droid:
21
22
  ```
22
23
 
24
+ If `--no-lock` was used, omit the lock line.
25
+
23
26
  Risk emojis:
24
27
  - Low Risk: `:large_green_circle:`
25
28
  - High Risk: `:warning:`
@@ -37,6 +40,26 @@ Monitoring deployment :eyes:
37
40
  Posted with :droid:
38
41
  ```
39
42
 
43
+ ### Branch Locked
44
+
45
+ ```
46
+ :lock: *Branch locked — {repo_name}*
47
+
48
+ `{branch}` is now read-only. No merges until unlocked.
49
+
50
+ Posted with :droid:
51
+ ```
52
+
53
+ ### Branch Unlocked
54
+
55
+ ```
56
+ :unlock: *Branch unlocked — {repo_name}*
57
+
58
+ `{branch}` is open for merges.
59
+
60
+ Posted with :droid:
61
+ ```
62
+
40
63
  ### Release Complete
41
64
 
42
65
  ```
@@ -48,6 +71,11 @@ Posted with :droid:
48
71
  Posted with :droid:
49
72
  ```
50
73
 
74
+ If auto-unlocked, append:
75
+ ```
76
+ :unlock: Auto-unlocked `{release_branch}`
77
+ ```
78
+
51
79
  ---
52
80
 
53
81
  ## Release PR Body
@@ -81,14 +109,17 @@ Where `{pr_list}` is a bulleted list of merged PRs:
81
109
 
82
110
  When Slack is not configured, print a plain-text version to terminal:
83
111
 
84
- ### Release Started (terminal)
112
+ ### Release Open for Review (terminal)
85
113
  ```
86
- Release started — {repo_name}
114
+ Release open for review — {repo_name}
87
115
  Risk: {risk_level}
88
116
  PR: {pr_url}
89
117
  Branch: {release_branch} -> {production_branch}
118
+ Lock: {release_branch} locked (no merges until release completes)
90
119
  ```
91
120
 
121
+ If `--no-lock` was used, omit the Lock line.
122
+
92
123
  ### Release Merged (terminal)
93
124
  ```
94
125
  Release merged — {repo_name}
@@ -97,6 +128,18 @@ Release merged — {repo_name}
97
128
  Monitoring deployment...
98
129
  ```
99
130
 
131
+ ### Branch Locked (terminal)
132
+ ```
133
+ Branch locked — {repo_name}
134
+ {branch} is now read-only
135
+ ```
136
+
137
+ ### Branch Unlocked (terminal)
138
+ ```
139
+ Branch unlocked — {repo_name}
140
+ {branch} is open for merges
141
+ ```
142
+
100
143
  ### Release Complete (terminal)
101
144
  ```
102
145
  Release complete — {repo_name}
@@ -7,8 +7,8 @@ Detailed step-by-step procedures for each `/release` subcommand. All commands us
7
7
  ```bash
8
8
  # 1. Read config
9
9
  SLACK_CHANNEL=$(droid config --get tools.release.slack_channel)
10
- # Default to #release-management if not set
11
- SLACK_CHANNEL="${SLACK_CHANNEL:-#release-management}"
10
+ # Default to #release_management if not set
11
+ SLACK_CHANNEL="${SLACK_CHANNEL:-#release_management}"
12
12
 
13
13
  # 2. Get repos and filter for release repos (those with release_branch set)
14
14
  droid config --get repos
@@ -25,9 +25,11 @@ git -C {repo_path} remote get-url origin
25
25
 
26
26
  ---
27
27
 
28
- ## `/release start [repo]`
28
+ ## `/release start [repo] [--no-lock]`
29
29
 
30
- Create a release PR and notify Slack.
30
+ Create a release PR, auto-lock the release branch, and notify Slack.
31
+
32
+ **Auto-lock is on by default.** The branch is locked immediately after the PR is created to prevent blind merges during CI. Pass `--no-lock` (or natural language like "start without locking") to skip.
31
33
 
32
34
  ### Steps
33
35
 
@@ -64,7 +66,22 @@ Create a release PR and notify Slack.
64
66
  ```
65
67
  See `templates.md` for the PR body template.
66
68
 
67
- 6. **Post to Slack:**
69
+ 6. **Auto-lock branch** (unless `--no-lock`):
70
+ ```bash
71
+ gh workflow run branch-lock.yml \
72
+ -f action=lock \
73
+ -f branch={release_branch} \
74
+ --repo {owner}/{repo}
75
+ ```
76
+ Verify lock applied:
77
+ ```bash
78
+ sleep 5
79
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled'
80
+ ```
81
+ If `branch-lock.yml` is not found in the repo, warn but don't fail:
82
+ "Could not auto-lock — `branch-lock.yml` not found in `{repo_name}`. Use `/release lock` manually after adding the workflow."
83
+
84
+ 7. **Post to Slack:**
68
85
  ```bash
69
86
  node -e 'process.stdout.write(JSON.stringify({
70
87
  channel: "{slack_channel}",
@@ -72,9 +89,9 @@ Create a release PR and notify Slack.
72
89
  unfurl_links: false
73
90
  }))' | droid integrations slack post
74
91
  ```
75
- See `templates.md` for the Slack message template (release started).
92
+ See `templates.md` for the Slack message template (release open for review — includes lock status).
76
93
 
77
- 7. **Confirm to user** — show PR URL and Slack post confirmation.
94
+ 8. **Confirm to user** — show PR URL, lock status, and Slack post confirmation.
78
95
 
79
96
  ---
80
97
 
@@ -112,6 +129,81 @@ Merge the release PR if all checks are green, then notify Slack.
112
129
 
113
130
  ---
114
131
 
132
+ ## `/release lock [repo]`
133
+
134
+ Manually lock the release branch. Use when you need to lock outside of `/release start` (which auto-locks).
135
+
136
+ ### Steps
137
+
138
+ 1. **Detect repo** — match cwd or ask user
139
+
140
+ 2. **Check current lock state:**
141
+ ```bash
142
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled // false'
143
+ ```
144
+ If already locked, warn: "Branch `{release_branch}` is already locked. Unlock first?"
145
+
146
+ 3. **Confirm with user** — use AskUserQuestion:
147
+ "Lock `{release_branch}` on `{repo_name}`? No one will be able to merge until unlocked."
148
+
149
+ 4. **Trigger the lock Action:**
150
+ ```bash
151
+ gh workflow run branch-lock.yml \
152
+ -f action=lock \
153
+ -f branch={release_branch} \
154
+ --repo {owner}/{repo}
155
+ ```
156
+
157
+ 5. **Verify lock applied** (wait a few seconds, then check):
158
+ ```bash
159
+ sleep 5
160
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled'
161
+ ```
162
+ If still not locked, check the workflow run status:
163
+ ```bash
164
+ gh run list --workflow=branch-lock.yml --limit 1 --json status,conclusion --repo {owner}/{repo}
165
+ ```
166
+
167
+ 6. **Post to Slack** — lock notification (see `templates.md`).
168
+
169
+ 7. **Confirm to user** — "Locked `{release_branch}` on `{repo_name}`."
170
+
171
+ ---
172
+
173
+ ## `/release unlock [repo]`
174
+
175
+ Unlock the release branch.
176
+
177
+ ### Steps
178
+
179
+ 1. **Detect repo** — match cwd or ask user
180
+
181
+ 2. **Check current lock state:**
182
+ ```bash
183
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled // false'
184
+ ```
185
+ If not locked, inform: "Branch `{release_branch}` is not currently locked."
186
+
187
+ 3. **Trigger the unlock Action:**
188
+ ```bash
189
+ gh workflow run branch-lock.yml \
190
+ -f action=unlock \
191
+ -f branch={release_branch} \
192
+ --repo {owner}/{repo}
193
+ ```
194
+
195
+ 4. **Verify unlock applied:**
196
+ ```bash
197
+ sleep 5
198
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled'
199
+ ```
200
+
201
+ 5. **Post to Slack** — unlock notification (see `templates.md`).
202
+
203
+ 6. **Confirm to user** — "Unlocked `{release_branch}` on `{repo_name}`."
204
+
205
+ ---
206
+
115
207
  ## `/release status`
116
208
 
117
209
  Check release status across all configured release repos.
@@ -127,11 +219,17 @@ Check release status across all configured release repos.
127
219
  gh pr list --search "[RELEASE]" --state open --json number,title,url,statusCheckRollup --repo {owner}/{repo}
128
220
  ```
129
221
 
222
+ **Lock state:**
223
+ ```bash
224
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled // false'
225
+ ```
226
+
130
227
  3. **Format and display** as a summary:
131
228
 
132
229
  ```
133
230
  {repo_name}
134
231
  Release PR: #{number} — {CI status} (green/pending/failing)
232
+ Branch lock: {release_branch} — locked/unlocked
135
233
  ```
136
234
 
137
235
  If no open release PR: "No active release"
@@ -141,7 +239,7 @@ Check release status across all configured release repos.
141
239
 
142
240
  ## `/release complete [repo]`
143
241
 
144
- Close out a release — notify Slack.
242
+ Close out a release — notify Slack and auto-unlock.
145
243
 
146
244
  ### Steps
147
245
 
@@ -161,6 +259,20 @@ Close out a release — notify Slack.
161
259
 
162
260
  3. **Post to Slack** — release complete notification (see `templates.md`).
163
261
 
164
- 4. **Confirm to user:**
262
+ 4. **Auto-unlock if locked:**
263
+ ```bash
264
+ LOCKED=$(gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled // false')
265
+ ```
266
+ If locked, trigger unlock:
267
+ ```bash
268
+ gh workflow run branch-lock.yml \
269
+ -f action=unlock \
270
+ -f branch={release_branch} \
271
+ --repo {owner}/{repo}
272
+ ```
273
+ Post unlock notification to Slack as well.
274
+
275
+ 5. **Confirm to user:**
165
276
  - "Release complete for `{repo_name}`"
277
+ - "Auto-unlocked `{release_branch}`" (if was locked)
166
278
  - Show Slack message confirmation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orderful/droid",
3
- "version": "0.44.0",
3
+ "version": "0.44.1",
4
4
  "description": "AI workflow toolkit for sharing skills, commands, and agents across the team",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "droid-release",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Release ceremony automation — create release PRs, check status, notify Slack.",
5
5
  "author": {
6
6
  "name": "Orderful",
@@ -1,6 +1,6 @@
1
1
  name: release
2
2
  description: "Release ceremony automation — create release PRs, check status, notify Slack."
3
- version: 0.1.0
3
+ version: 0.2.0
4
4
  status: alpha
5
5
 
6
6
  includes:
@@ -18,4 +18,4 @@ config_schema:
18
18
  slack_channel:
19
19
  type: string
20
20
  description: "Slack channel for release notifications"
21
- default: "#release-management"
21
+ default: "#release_management"
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: release
3
- description: "Release ceremony automation"
4
- argument-hint: "[start [repo] | status | complete [repo]]"
3
+ description: "Release ceremony automation and branch locking"
4
+ argument-hint: "[start [repo] [--no-lock] | merge [repo] | lock [repo] | unlock [repo] | status | complete [repo]]"
5
5
  ---
6
6
 
7
7
  # /release
@@ -12,17 +12,25 @@ argument-hint: "[start [repo] | status | complete [repo]]"
12
12
 
13
13
  ## Examples
14
14
 
15
- - `/release start` → Create release PR for current repo
15
+ - `/release start` → Create release PR + auto-lock branch
16
16
  - `/release start orderful-workspace` → Create release PR for a specific repo
17
- - `/release status` → Check CI state across release repos
18
- - `/release complete` → Post "release complete" to Slack
17
+ - `/release start --no-lock` → Create release PR without locking
18
+ - `/release merge` → Merge release PR (checks must be green)
19
+ - `/release lock` → Manually lock the release branch
20
+ - `/release unlock` → Unlock the release branch
21
+ - `/release status` → Check CI and lock state across release repos
22
+ - `/release complete` → Post "release complete" to Slack, auto-unlock if locked
19
23
 
20
24
  ## Quick Reference
21
25
 
22
26
  ```
23
- /release start [repo] # Create release PR + notify Slack
24
- /release status # CI state across repos
25
- /release complete [repo] # Notify Slack, close out release
27
+ /release start [repo] # Create release PR + auto-lock + notify Slack
28
+ /release start --no-lock # Create release PR without locking
29
+ /release merge [repo] # Merge release PR (checks must pass)
30
+ /release lock [repo] # Manually lock release branch
31
+ /release unlock [repo] # Unlock release branch
32
+ /release status # CI + lock state across repos
33
+ /release complete [repo] # Notify Slack + auto-unlock
26
34
  ```
27
35
 
28
36
  See the **release skill** for complete documentation.
@@ -1,20 +1,21 @@
1
1
  ---
2
2
  name: release
3
- description: "Release ceremony automation for dev-to-master releases. Use when starting a release, merging a release, checking release status, or completing a release. User prompts like 'start a release', 'merge the release', 'release status', 'release complete'."
4
- argument-hint: "[start [repo] | merge [repo] | status | complete [repo]]"
3
+ description: "Release ceremony automation for dev-to-master releases. Use when starting a release, merging a release, locking a branch, checking release status, or completing a release. User prompts like 'start a release', 'merge the release', 'lock dev', 'release status', 'unlock the branch'."
4
+ argument-hint: "[start [repo] | merge [repo] | lock [repo] | unlock [repo] | status | complete [repo]]"
5
5
  allowed-tools: [Read, Write, Glob, Grep, Bash, Edit]
6
6
  ---
7
7
 
8
8
  # Release Skill
9
9
 
10
- Automate dev → master release ceremonies: create release PRs, notify Slack, and track status.
10
+ Automate dev → master release ceremonies: create release PRs, lock branches during CI, notify Slack, and track status.
11
11
 
12
12
  ## When to Use
13
13
 
14
14
  - User wants to start a release (create PR from dev → master)
15
- - User asks about release status (open PRs, CI checks)
15
+ - User wants to lock or unlock a branch during a release
16
+ - User asks about release status (open PRs, lock state, CI checks)
16
17
  - User says "release complete" or wants to close out a release
17
- - Natural language like "start a release", "what's the release status?"
18
+ - Natural language like "start a release", "lock dev", "what's the release status?"
18
19
 
19
20
  ## When NOT to Use
20
21
 
@@ -26,6 +27,7 @@ Automate dev → master release ceremonies: create release PRs, notify Slack, an
26
27
 
27
28
  1. **`gh` CLI** — authenticated with access to target repos
28
29
  2. **Slack integration** — `droid integrations slack post` configured (optional, falls back to terminal)
30
+ 3. **`branch-lock.yml`** — GitHub Action deployed to target repo (required for auto-lock on start + lock/unlock commands)
29
31
 
30
32
  ## Configuration
31
33
 
@@ -37,7 +39,7 @@ droid config --get repos
37
39
  ```
38
40
 
39
41
  - **Repos:** Filter `repos` array for entries with `release_branch` set — these are release repos
40
- - **Slack channel:** From `tools.release.slack_channel` (default: `#release-management`)
42
+ - **Slack channel:** From `tools.release.slack_channel` (default: `#release_management`)
41
43
  - **Repo detection:** Match cwd against repo paths, or ask user if ambiguous
42
44
 
43
45
  If no repos have `release_branch` set, tell user:
@@ -47,10 +49,12 @@ If no repos have `release_branch` set, tell user:
47
49
 
48
50
  | Command | Action |
49
51
  |---------|--------|
50
- | `/release start [repo]` | Create release PR + notify Slack |
52
+ | `/release start [repo] [--no-lock]` | Create release PR + auto-lock branch + notify Slack |
51
53
  | `/release merge [repo]` | Merge release PR (only if checks pass) + notify Slack |
52
- | `/release status` | Check open release PRs + CI state |
53
- | `/release complete [repo]` | Post completion to Slack |
54
+ | `/release lock [repo]` | Lock release branch (confirms first) |
55
+ | `/release unlock [repo]` | Unlock release branch |
56
+ | `/release status` | Check open release PRs + CI state + lock state |
57
+ | `/release complete [repo]` | Post completion to Slack + auto-unlock |
54
58
 
55
59
  See `references/workflows.md` for detailed step-by-step procedures and exact `gh` commands.
56
60
 
@@ -69,6 +73,8 @@ See `references/templates.md` for Slack message and PR body templates.
69
73
  |-------|--------|
70
74
  | No release repos configured | Suggest `droid repos add` with release branch |
71
75
  | `gh` CLI not authenticated | Suggest `gh auth login` |
76
+ | `branch-lock.yml` not found in repo | Tell user to add the `branch-lock.yml` workflow to the repo |
72
77
  | Slack not configured | Print message to terminal, suggest `droid integrations setup slack` |
78
+ | Branch already locked | Warn user, offer to unlock first |
73
79
  | Release PR already exists | Show existing PR, ask if user wants to proceed |
74
80
  | CI checks failing | Show status, do not auto-merge |
@@ -6,20 +6,23 @@ Slack mrkdwn and PR body templates for release notifications.
6
6
 
7
7
  All Slack messages are posted via `droid integrations slack post`. Format as Slack mrkdwn (not GitHub markdown).
8
8
 
9
- ### Release Started
9
+ ### Release Open for Review
10
10
 
11
11
  ```
12
- :rocket: *Release started — {repo_name}*
12
+ :rocket: *Release open for review — {repo_name}*
13
13
 
14
14
  *Risk:* {risk_emoji} {risk_level}
15
15
  *PR:* <{pr_url}|#{pr_number}>
16
16
  *Branch:* `{release_branch}` → `{production_branch}`
17
+ :lock: `{release_branch}` is locked — no merges until release completes
17
18
 
18
19
  {pr_summary}
19
20
 
20
21
  Posted with :droid:
21
22
  ```
22
23
 
24
+ If `--no-lock` was used, omit the lock line.
25
+
23
26
  Risk emojis:
24
27
  - Low Risk: `:large_green_circle:`
25
28
  - High Risk: `:warning:`
@@ -37,6 +40,26 @@ Monitoring deployment :eyes:
37
40
  Posted with :droid:
38
41
  ```
39
42
 
43
+ ### Branch Locked
44
+
45
+ ```
46
+ :lock: *Branch locked — {repo_name}*
47
+
48
+ `{branch}` is now read-only. No merges until unlocked.
49
+
50
+ Posted with :droid:
51
+ ```
52
+
53
+ ### Branch Unlocked
54
+
55
+ ```
56
+ :unlock: *Branch unlocked — {repo_name}*
57
+
58
+ `{branch}` is open for merges.
59
+
60
+ Posted with :droid:
61
+ ```
62
+
40
63
  ### Release Complete
41
64
 
42
65
  ```
@@ -48,6 +71,11 @@ Posted with :droid:
48
71
  Posted with :droid:
49
72
  ```
50
73
 
74
+ If auto-unlocked, append:
75
+ ```
76
+ :unlock: Auto-unlocked `{release_branch}`
77
+ ```
78
+
51
79
  ---
52
80
 
53
81
  ## Release PR Body
@@ -81,14 +109,17 @@ Where `{pr_list}` is a bulleted list of merged PRs:
81
109
 
82
110
  When Slack is not configured, print a plain-text version to terminal:
83
111
 
84
- ### Release Started (terminal)
112
+ ### Release Open for Review (terminal)
85
113
  ```
86
- Release started — {repo_name}
114
+ Release open for review — {repo_name}
87
115
  Risk: {risk_level}
88
116
  PR: {pr_url}
89
117
  Branch: {release_branch} -> {production_branch}
118
+ Lock: {release_branch} locked (no merges until release completes)
90
119
  ```
91
120
 
121
+ If `--no-lock` was used, omit the Lock line.
122
+
92
123
  ### Release Merged (terminal)
93
124
  ```
94
125
  Release merged — {repo_name}
@@ -97,6 +128,18 @@ Release merged — {repo_name}
97
128
  Monitoring deployment...
98
129
  ```
99
130
 
131
+ ### Branch Locked (terminal)
132
+ ```
133
+ Branch locked — {repo_name}
134
+ {branch} is now read-only
135
+ ```
136
+
137
+ ### Branch Unlocked (terminal)
138
+ ```
139
+ Branch unlocked — {repo_name}
140
+ {branch} is open for merges
141
+ ```
142
+
100
143
  ### Release Complete (terminal)
101
144
  ```
102
145
  Release complete — {repo_name}
@@ -7,8 +7,8 @@ Detailed step-by-step procedures for each `/release` subcommand. All commands us
7
7
  ```bash
8
8
  # 1. Read config
9
9
  SLACK_CHANNEL=$(droid config --get tools.release.slack_channel)
10
- # Default to #release-management if not set
11
- SLACK_CHANNEL="${SLACK_CHANNEL:-#release-management}"
10
+ # Default to #release_management if not set
11
+ SLACK_CHANNEL="${SLACK_CHANNEL:-#release_management}"
12
12
 
13
13
  # 2. Get repos and filter for release repos (those with release_branch set)
14
14
  droid config --get repos
@@ -25,9 +25,11 @@ git -C {repo_path} remote get-url origin
25
25
 
26
26
  ---
27
27
 
28
- ## `/release start [repo]`
28
+ ## `/release start [repo] [--no-lock]`
29
29
 
30
- Create a release PR and notify Slack.
30
+ Create a release PR, auto-lock the release branch, and notify Slack.
31
+
32
+ **Auto-lock is on by default.** The branch is locked immediately after the PR is created to prevent blind merges during CI. Pass `--no-lock` (or natural language like "start without locking") to skip.
31
33
 
32
34
  ### Steps
33
35
 
@@ -64,7 +66,22 @@ Create a release PR and notify Slack.
64
66
  ```
65
67
  See `templates.md` for the PR body template.
66
68
 
67
- 6. **Post to Slack:**
69
+ 6. **Auto-lock branch** (unless `--no-lock`):
70
+ ```bash
71
+ gh workflow run branch-lock.yml \
72
+ -f action=lock \
73
+ -f branch={release_branch} \
74
+ --repo {owner}/{repo}
75
+ ```
76
+ Verify lock applied:
77
+ ```bash
78
+ sleep 5
79
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled'
80
+ ```
81
+ If `branch-lock.yml` is not found in the repo, warn but don't fail:
82
+ "Could not auto-lock — `branch-lock.yml` not found in `{repo_name}`. Use `/release lock` manually after adding the workflow."
83
+
84
+ 7. **Post to Slack:**
68
85
  ```bash
69
86
  node -e 'process.stdout.write(JSON.stringify({
70
87
  channel: "{slack_channel}",
@@ -72,9 +89,9 @@ Create a release PR and notify Slack.
72
89
  unfurl_links: false
73
90
  }))' | droid integrations slack post
74
91
  ```
75
- See `templates.md` for the Slack message template (release started).
92
+ See `templates.md` for the Slack message template (release open for review — includes lock status).
76
93
 
77
- 7. **Confirm to user** — show PR URL and Slack post confirmation.
94
+ 8. **Confirm to user** — show PR URL, lock status, and Slack post confirmation.
78
95
 
79
96
  ---
80
97
 
@@ -112,6 +129,81 @@ Merge the release PR if all checks are green, then notify Slack.
112
129
 
113
130
  ---
114
131
 
132
+ ## `/release lock [repo]`
133
+
134
+ Manually lock the release branch. Use when you need to lock outside of `/release start` (which auto-locks).
135
+
136
+ ### Steps
137
+
138
+ 1. **Detect repo** — match cwd or ask user
139
+
140
+ 2. **Check current lock state:**
141
+ ```bash
142
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled // false'
143
+ ```
144
+ If already locked, warn: "Branch `{release_branch}` is already locked. Unlock first?"
145
+
146
+ 3. **Confirm with user** — use AskUserQuestion:
147
+ "Lock `{release_branch}` on `{repo_name}`? No one will be able to merge until unlocked."
148
+
149
+ 4. **Trigger the lock Action:**
150
+ ```bash
151
+ gh workflow run branch-lock.yml \
152
+ -f action=lock \
153
+ -f branch={release_branch} \
154
+ --repo {owner}/{repo}
155
+ ```
156
+
157
+ 5. **Verify lock applied** (wait a few seconds, then check):
158
+ ```bash
159
+ sleep 5
160
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled'
161
+ ```
162
+ If still not locked, check the workflow run status:
163
+ ```bash
164
+ gh run list --workflow=branch-lock.yml --limit 1 --json status,conclusion --repo {owner}/{repo}
165
+ ```
166
+
167
+ 6. **Post to Slack** — lock notification (see `templates.md`).
168
+
169
+ 7. **Confirm to user** — "Locked `{release_branch}` on `{repo_name}`."
170
+
171
+ ---
172
+
173
+ ## `/release unlock [repo]`
174
+
175
+ Unlock the release branch.
176
+
177
+ ### Steps
178
+
179
+ 1. **Detect repo** — match cwd or ask user
180
+
181
+ 2. **Check current lock state:**
182
+ ```bash
183
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled // false'
184
+ ```
185
+ If not locked, inform: "Branch `{release_branch}` is not currently locked."
186
+
187
+ 3. **Trigger the unlock Action:**
188
+ ```bash
189
+ gh workflow run branch-lock.yml \
190
+ -f action=unlock \
191
+ -f branch={release_branch} \
192
+ --repo {owner}/{repo}
193
+ ```
194
+
195
+ 4. **Verify unlock applied:**
196
+ ```bash
197
+ sleep 5
198
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled'
199
+ ```
200
+
201
+ 5. **Post to Slack** — unlock notification (see `templates.md`).
202
+
203
+ 6. **Confirm to user** — "Unlocked `{release_branch}` on `{repo_name}`."
204
+
205
+ ---
206
+
115
207
  ## `/release status`
116
208
 
117
209
  Check release status across all configured release repos.
@@ -127,11 +219,17 @@ Check release status across all configured release repos.
127
219
  gh pr list --search "[RELEASE]" --state open --json number,title,url,statusCheckRollup --repo {owner}/{repo}
128
220
  ```
129
221
 
222
+ **Lock state:**
223
+ ```bash
224
+ gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled // false'
225
+ ```
226
+
130
227
  3. **Format and display** as a summary:
131
228
 
132
229
  ```
133
230
  {repo_name}
134
231
  Release PR: #{number} — {CI status} (green/pending/failing)
232
+ Branch lock: {release_branch} — locked/unlocked
135
233
  ```
136
234
 
137
235
  If no open release PR: "No active release"
@@ -141,7 +239,7 @@ Check release status across all configured release repos.
141
239
 
142
240
  ## `/release complete [repo]`
143
241
 
144
- Close out a release — notify Slack.
242
+ Close out a release — notify Slack and auto-unlock.
145
243
 
146
244
  ### Steps
147
245
 
@@ -161,6 +259,20 @@ Close out a release — notify Slack.
161
259
 
162
260
  3. **Post to Slack** — release complete notification (see `templates.md`).
163
261
 
164
- 4. **Confirm to user:**
262
+ 4. **Auto-unlock if locked:**
263
+ ```bash
264
+ LOCKED=$(gh api repos/{owner}/{repo}/branches/{release_branch}/protection --jq '.lock_branch.enabled // false')
265
+ ```
266
+ If locked, trigger unlock:
267
+ ```bash
268
+ gh workflow run branch-lock.yml \
269
+ -f action=unlock \
270
+ -f branch={release_branch} \
271
+ --repo {owner}/{repo}
272
+ ```
273
+ Post unlock notification to Slack as well.
274
+
275
+ 5. **Confirm to user:**
165
276
  - "Release complete for `{repo_name}`"
277
+ - "Auto-unlocked `{release_branch}`" (if was locked)
166
278
  - Show Slack message confirmation