forge-workflow 0.0.4 → 0.0.5

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.
Files changed (209) hide show
  1. package/.claude/commands/dev.md +340 -340
  2. package/.claude/commands/plan.md +521 -521
  3. package/.claude/commands/premerge.md +176 -176
  4. package/.claude/commands/research.md +42 -42
  5. package/.claude/commands/review.md +442 -442
  6. package/.claude/commands/rollback.md +721 -721
  7. package/.claude/commands/ship.md +164 -164
  8. package/.claude/commands/sonarcloud.md +152 -152
  9. package/.claude/commands/status.md +48 -48
  10. package/.claude/commands/validate.md +282 -282
  11. package/.claude/commands/verify.md +221 -221
  12. package/.claude/rules/greptile-review-process.md +285 -285
  13. package/.claude/rules/workflow.md +105 -105
  14. package/.claude/scripts/greptile-resolve.sh +526 -526
  15. package/.claude/scripts/load-env.sh +32 -32
  16. package/.cline/workflows/dev.md +337 -337
  17. package/.cline/workflows/plan.md +518 -518
  18. package/.cline/workflows/premerge.md +173 -173
  19. package/.cline/workflows/research.md +39 -39
  20. package/.cline/workflows/review.md +439 -439
  21. package/.cline/workflows/rollback.md +718 -718
  22. package/.cline/workflows/ship.md +161 -161
  23. package/.cline/workflows/sonarcloud.md +146 -146
  24. package/.cline/workflows/status.md +45 -45
  25. package/.cline/workflows/validate.md +279 -279
  26. package/.cline/workflows/verify.md +218 -218
  27. package/.codex/config.toml +11 -11
  28. package/.codex/skills/dev/SKILL.md +340 -340
  29. package/.codex/skills/plan/SKILL.md +521 -521
  30. package/.codex/skills/premerge/SKILL.md +176 -176
  31. package/.codex/skills/research/SKILL.md +42 -42
  32. package/.codex/skills/review/SKILL.md +442 -442
  33. package/.codex/skills/rollback/SKILL.md +721 -721
  34. package/.codex/skills/ship/SKILL.md +164 -164
  35. package/.codex/skills/sonarcloud/SKILL.md +149 -149
  36. package/.codex/skills/status/SKILL.md +48 -48
  37. package/.codex/skills/validate/SKILL.md +282 -282
  38. package/.codex/skills/verify/SKILL.md +221 -221
  39. package/.cursor/commands/dev.md +337 -337
  40. package/.cursor/commands/plan.md +518 -518
  41. package/.cursor/commands/premerge.md +173 -173
  42. package/.cursor/commands/research.md +39 -39
  43. package/.cursor/commands/review.md +439 -439
  44. package/.cursor/commands/rollback.md +718 -718
  45. package/.cursor/commands/ship.md +161 -161
  46. package/.cursor/commands/sonarcloud.md +146 -146
  47. package/.cursor/commands/status.md +45 -45
  48. package/.cursor/commands/validate.md +279 -279
  49. package/.cursor/commands/verify.md +218 -218
  50. package/.cursor/rules/permissions-guidance.mdc +37 -37
  51. package/.forge/hooks/check-tdd.js +240 -240
  52. package/.github/PLUGIN_TEMPLATE.json +32 -32
  53. package/.github/prompts/dev.prompt.md +342 -342
  54. package/.github/prompts/plan.prompt.md +523 -523
  55. package/.github/prompts/premerge.prompt.md +178 -178
  56. package/.github/prompts/research.prompt.md +44 -44
  57. package/.github/prompts/review.prompt.md +444 -444
  58. package/.github/prompts/rollback.prompt.md +723 -723
  59. package/.github/prompts/ship.prompt.md +166 -166
  60. package/.github/prompts/sonarcloud.prompt.md +151 -151
  61. package/.github/prompts/status.prompt.md +50 -50
  62. package/.github/prompts/validate.prompt.md +284 -284
  63. package/.github/prompts/verify.prompt.md +223 -223
  64. package/.github/workflows/beads-to-github.yml +56 -0
  65. package/.github/workflows/github-to-beads.yml +97 -0
  66. package/.kilocode/workflows/dev.md +341 -341
  67. package/.kilocode/workflows/plan.md +522 -522
  68. package/.kilocode/workflows/premerge.md +177 -177
  69. package/.kilocode/workflows/research.md +43 -43
  70. package/.kilocode/workflows/review.md +443 -443
  71. package/.kilocode/workflows/rollback.md +722 -722
  72. package/.kilocode/workflows/ship.md +165 -165
  73. package/.kilocode/workflows/sonarcloud.md +150 -150
  74. package/.kilocode/workflows/status.md +49 -49
  75. package/.kilocode/workflows/validate.md +283 -283
  76. package/.kilocode/workflows/verify.md +222 -222
  77. package/.mcp.json.example +12 -12
  78. package/.opencode/commands/dev.md +340 -340
  79. package/.opencode/commands/plan.md +521 -521
  80. package/.opencode/commands/premerge.md +176 -176
  81. package/.opencode/commands/research.md +42 -42
  82. package/.opencode/commands/review.md +442 -442
  83. package/.opencode/commands/rollback.md +721 -721
  84. package/.opencode/commands/ship.md +164 -164
  85. package/.opencode/commands/sonarcloud.md +149 -149
  86. package/.opencode/commands/status.md +48 -48
  87. package/.opencode/commands/validate.md +282 -282
  88. package/.opencode/commands/verify.md +221 -221
  89. package/.roo/commands/dev.md +341 -341
  90. package/.roo/commands/plan.md +522 -522
  91. package/.roo/commands/premerge.md +177 -177
  92. package/.roo/commands/research.md +43 -43
  93. package/.roo/commands/review.md +443 -443
  94. package/.roo/commands/rollback.md +722 -722
  95. package/.roo/commands/ship.md +165 -165
  96. package/.roo/commands/sonarcloud.md +150 -150
  97. package/.roo/commands/status.md +49 -49
  98. package/.roo/commands/validate.md +283 -283
  99. package/.roo/commands/verify.md +222 -222
  100. package/AGENTS.md +175 -175
  101. package/CLAUDE.md +100 -100
  102. package/README.md +429 -416
  103. package/bin/forge-cmd.js +313 -313
  104. package/bin/forge-preflight.js +309 -309
  105. package/bin/forge.js +4596 -4303
  106. package/docs/AGENT_INSTALL_PROMPT.md +342 -342
  107. package/docs/BEADS_GITHUB_SYNC.md +251 -251
  108. package/docs/ENHANCED_ONBOARDING.md +602 -602
  109. package/docs/EXAMPLES.md +482 -482
  110. package/docs/GREPTILE_SETUP.md +400 -400
  111. package/docs/MANUAL_REVIEW_GUIDE.md +106 -106
  112. package/docs/ROADMAP.md +359 -359
  113. package/docs/SETUP.md +663 -631
  114. package/docs/TOOLCHAIN.md +630 -630
  115. package/docs/VALIDATION.md +363 -363
  116. package/install.sh +40 -1056
  117. package/lefthook.yml +39 -39
  118. package/lib/agents/README.md +198 -198
  119. package/lib/agents/claude.plugin.json +28 -28
  120. package/lib/agents/cline.plugin.json +22 -22
  121. package/lib/agents/codex.plugin.json +19 -19
  122. package/lib/agents/copilot.plugin.json +24 -24
  123. package/lib/agents/cursor.plugin.json +25 -25
  124. package/lib/agents/kilocode.plugin.json +22 -22
  125. package/lib/agents/opencode.plugin.json +20 -20
  126. package/lib/agents/roo.plugin.json +23 -23
  127. package/lib/agents-config.js +2112 -2112
  128. package/lib/beads-health-check.js +143 -0
  129. package/lib/beads-setup.js +341 -0
  130. package/lib/beads-sync-scaffold.js +260 -0
  131. package/lib/commands/dev.js +513 -513
  132. package/lib/commands/plan.js +692 -692
  133. package/lib/commands/recommend.js +119 -119
  134. package/lib/commands/ship.js +377 -377
  135. package/lib/commands/status.js +378 -378
  136. package/lib/commands/validate.js +602 -602
  137. package/lib/context-merge.js +359 -359
  138. package/lib/dep-guard/analyzer.js +294 -294
  139. package/lib/dep-guard/behavior-detector.js +98 -98
  140. package/lib/dep-guard/contract-detector.js +162 -162
  141. package/lib/dep-guard/import-detector.js +498 -498
  142. package/lib/dep-guard/path-utils.js +13 -13
  143. package/lib/dep-guard/rubric.js +120 -120
  144. package/lib/dep-guard/task-parser.js +318 -318
  145. package/lib/detect-agent.js +191 -191
  146. package/lib/detect-worktree.js +47 -47
  147. package/lib/file-hash.js +26 -26
  148. package/lib/husky-migration.js +450 -0
  149. package/lib/lefthook-check.js +65 -0
  150. package/lib/pat-setup.js +207 -0
  151. package/lib/plugin-catalog.js +350 -350
  152. package/lib/plugin-manager.js +166 -166
  153. package/lib/plugin-recommender.js +141 -141
  154. package/lib/project-discovery.js +491 -491
  155. package/lib/setup-action-log.js +139 -139
  156. package/lib/setup-summary-renderer.js +106 -106
  157. package/lib/setup-utils.js +96 -0
  158. package/lib/setup.js +192 -192
  159. package/lib/smart-merge.js +64 -0
  160. package/lib/symlink-utils.js +81 -0
  161. package/lib/workflow-profiles.js +197 -197
  162. package/package.json +131 -128
  163. package/scripts/beads-context.sh +291 -0
  164. package/scripts/beads-context.test.js +563 -0
  165. package/scripts/behavioral-judge.sh +378 -0
  166. package/scripts/benchmark.js +85 -0
  167. package/scripts/branch-protection.js +183 -0
  168. package/scripts/check-agents.js +172 -0
  169. package/scripts/commitlint.js +42 -0
  170. package/scripts/conflict-detect.sh +323 -0
  171. package/scripts/dep-guard-analyze.js +71 -0
  172. package/scripts/dep-guard.sh +811 -0
  173. package/scripts/eval_win.py +249 -0
  174. package/scripts/file-index.sh +399 -0
  175. package/scripts/github-beads-sync/comment.mjs +64 -0
  176. package/scripts/github-beads-sync/config.mjs +148 -0
  177. package/scripts/github-beads-sync/github-api.mjs +131 -0
  178. package/scripts/github-beads-sync/index.mjs +332 -0
  179. package/scripts/github-beads-sync/label-mapper.mjs +54 -0
  180. package/scripts/github-beads-sync/mapping.mjs +78 -0
  181. package/scripts/github-beads-sync/reverse-sync-cli.mjs +31 -0
  182. package/scripts/github-beads-sync/reverse-sync.mjs +138 -0
  183. package/scripts/github-beads-sync/run-bd.mjs +159 -0
  184. package/scripts/github-beads-sync/sanitize.mjs +121 -0
  185. package/scripts/github-beads-sync.config.json +26 -0
  186. package/scripts/improve-command.js +375 -0
  187. package/scripts/lib/eval-runner.js +229 -0
  188. package/scripts/lib/eval-schema.js +135 -0
  189. package/scripts/lib/eval-storage.js +78 -0
  190. package/scripts/lib/grading.js +203 -0
  191. package/scripts/lib/transcript-parser.js +63 -0
  192. package/scripts/lint.js +47 -0
  193. package/scripts/migrate-to-bun-test.js +412 -0
  194. package/scripts/run-command-eval.js +236 -0
  195. package/scripts/smart-status.sh +782 -0
  196. package/scripts/sync-commands.js +571 -0
  197. package/scripts/sync-utils.sh +460 -0
  198. package/scripts/test-dashboard.js +123 -0
  199. package/scripts/test.js +44 -0
  200. package/scripts/validate.sh +94 -0
  201. package/skills/parallel-deep-research/SKILL.md +108 -108
  202. package/skills/parallel-deep-research/evals/README.md +27 -27
  203. package/skills/parallel-deep-research/evals/evals.json +62 -62
  204. package/skills/sonarcloud-analysis/SKILL.md +171 -171
  205. package/skills/sonarcloud-analysis/evals/README.md +27 -27
  206. package/skills/sonarcloud-analysis/evals/evals.json +50 -50
  207. package/skills/sonarcloud-analysis/references/api-reference.md +466 -466
  208. package/.cursor/hooks/state/continual-learning-index.json +0 -19
  209. package/.cursor/hooks/state/continual-learning.json +0 -8
@@ -1,251 +1,251 @@
1
- # GitHub <-> Beads Issue Sync
2
-
3
- Automatic synchronization between GitHub Issues and Beads issue tracking.
4
-
5
- **GitHub Issues** = human/team/public interface.
6
- **Beads** = AI agent engine (`bd ready`, `bd close`).
7
-
8
- Neither side needs to know about the other. Contributors file issues on GitHub; AI agents pick up work via Beads. Status changes propagate automatically.
9
-
10
- ---
11
-
12
- ## Architecture
13
-
14
- ### Phase 1: GitHub -> Beads (CI-driven)
15
-
16
- ```mermaid
17
- sequenceDiagram
18
- participant U as User
19
- participant GH as GitHub Issues
20
- participant WF as GitHub Actions
21
- participant BD as Beads CLI
22
- participant Repo as .beads/ + mapping
23
-
24
- U->>GH: Opens issue #42
25
- GH->>WF: issues.opened trigger
26
- WF->>WF: Guard checks (bot? skip label? no-beads?)
27
- WF->>WF: Idempotency check (existing bot comment?)
28
- WF->>BD: bd create --title "..." --type bug --priority 1
29
- BD->>Repo: Write .beads/issues.jsonl
30
- WF->>Repo: Write .github/beads-mapping.json {"42": "forge-abc"}
31
- WF->>GH: Post bot comment <!-- beads-sync:42 -->
32
- WF->>Repo: git commit + push
33
-
34
- U->>GH: Closes issue #42
35
- GH->>WF: issues.closed trigger
36
- WF->>Repo: Read mapping: "42" -> "forge-abc"
37
- WF->>BD: bd close forge-abc --reason "Closed via GitHub #42"
38
- WF->>Repo: git commit + push
39
- ```
40
-
41
- ### Phase 2: Beads -> GitHub (push-triggered)
42
-
43
- ```mermaid
44
- sequenceDiagram
45
- participant AI as AI Agent
46
- participant BD as Beads CLI
47
- participant Repo as .beads/
48
- participant WF as GitHub Actions
49
- participant GH as GitHub Issues
50
-
51
- AI->>BD: bd close forge-abc
52
- BD->>Repo: Update issues.jsonl
53
- AI->>Repo: git push
54
- Repo->>WF: push trigger (paths: .beads/**)
55
- WF->>WF: Guard: skip if commit msg starts with "chore(beads):"
56
- WF->>Repo: Diff issues.jsonl for closed transitions
57
- WF->>GH: gh api PATCH /issues/42 state=closed
58
- ```
59
-
60
- ### Loop Prevention
61
-
62
- Three guards prevent infinite ping-pong:
63
-
64
- 1. **Bot detection** -- workflows skip events from `github-actions[bot]`
65
- 2. **Commit message prefix** -- Phase 2 workflow skips commits starting with `chore(beads):`
66
- 3. **Opt-out label** -- `skip-beads-sync` label on any issue disables sync entirely
67
-
68
- ---
69
-
70
- ## Setup
71
-
72
- ### Via Forge Setup (recommended)
73
-
74
- ```bash
75
- bunx forge setup
76
- # During interactive prompts:
77
- # "Enable GitHub <-> Beads sync? (y/n)" -> y
78
- ```
79
-
80
- This scaffolds:
81
- - `.github/workflows/github-to-beads.yml`
82
- - `.github/workflows/beads-to-github.yml` (Phase 2)
83
- - `.github/beads-mapping.json`
84
- - `scripts/github-beads-sync/` (Node modules)
85
- - `scripts/github-beads-sync.config.json`
86
-
87
- ### Manual Setup
88
-
89
- 1. Copy workflow files from `templates/` into `.github/workflows/`
90
- 2. Copy `scripts/github-beads-sync/` and `scripts/github-beads-sync.config.json`
91
- 3. Create `.github/beads-mapping.json` with `{}`
92
- 4. Ensure Beads is initialized: `bd init`
93
- 5. Commit and push to enable the workflows
94
-
95
- ---
96
-
97
- ## Configuration Reference
98
-
99
- All settings live in `scripts/github-beads-sync.config.json`.
100
-
101
- ### Label and Type Mapping
102
-
103
- | Field | Type | Default | Description |
104
- |-------|------|---------|-------------|
105
- | `labelToType` | `object` | `{"bug":"bug", "enhancement":"feature", "documentation":"task", "question":"task"}` | Maps GitHub labels to Beads issue types. First matching label wins. |
106
- | `labelToPriority` | `object` | `{"P0":0, "critical":0, "P1":1, "high":1, "P2":2, "medium":2, "P3":3, "low":3, "P4":4, "backlog":4}` | Maps GitHub labels to Beads priority levels (0-4). First matching label wins. |
107
- | `defaultType` | `string` | `"task"` | Beads type when no label matches `labelToType`. |
108
- | `defaultPriority` | `number` | `2` | Beads priority when no label matches `labelToPriority`. |
109
- | `mapAssignee` | `boolean` | `true` | Whether to copy GitHub assignee to Beads issue on creation. |
110
-
111
- ### Security Gates (Public Repos)
112
-
113
- | Field | Type | Default | Description |
114
- |-------|------|---------|-------------|
115
- | `publicRepoGate` | `string` | `"none"` | Access control for public repos. See [Security](#security) section. |
116
- | `gateLabelName` | `string` | `"beads-track"` | Required label when `publicRepoGate` is `"label"`. |
117
- | `gateAssociations` | `string[]` | `["MEMBER", "COLLABORATOR", "OWNER"]` | Allowed author associations when `publicRepoGate` is `"author_association"`. |
118
-
119
- ### Example: Custom Configuration
120
-
121
- ```json
122
- {
123
- "labelToType": {
124
- "bug": "bug",
125
- "feature": "feature",
126
- "chore": "chore",
127
- "spike": "task"
128
- },
129
- "labelToPriority": {
130
- "urgent": 0,
131
- "important": 1,
132
- "normal": 2,
133
- "nice-to-have": 3
134
- },
135
- "defaultType": "task",
136
- "defaultPriority": 2,
137
- "mapAssignee": true,
138
- "publicRepoGate": "author_association",
139
- "gateAssociations": ["MEMBER", "COLLABORATOR", "OWNER"]
140
- }
141
- ```
142
-
143
- ---
144
-
145
- ## Security
146
-
147
- ### Public Repo Gate
148
-
149
- On public repos, anyone can open an issue -- which triggers a commit to your default branch via the sync workflow. The `publicRepoGate` setting controls who can trigger sync:
150
-
151
- | Value | Behavior | Recommended For |
152
- |-------|----------|-----------------|
153
- | `"none"` | All issues sync (default). | Private repos, trusted teams. |
154
- | `"author_association"` | Only issues from authors in `gateAssociations` sync. | Public repos with known contributors. |
155
- | `"label"` | Only issues with the `gateLabelName` label sync. A maintainer must add the label. | Public repos accepting external issues. |
156
-
157
- ### Input Sanitization
158
-
159
- - Issue titles and bodies are **never interpolated in shell commands**. The sync scripts use Node `execFile` with array arguments (no shell).
160
- - Workflow files pass event data via `env:` blocks, never via `${{ }}` in `run:` blocks (prevents GitHub Actions injection).
161
- - Only title, URL, mapped type, and priority are stored in Beads -- raw issue body is not committed.
162
-
163
- ### SHA-Pinned Actions
164
-
165
- All third-party actions in the workflow files are pinned to full commit SHAs, not tags. This prevents supply-chain attacks via tag mutation.
166
-
167
- ```yaml
168
- # Good: SHA-pinned
169
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
170
-
171
- # Bad: tag-only (never used)
172
- - uses: actions/checkout@v4
173
- ```
174
-
175
- ---
176
-
177
- ## Opt-Out
178
-
179
- Two ways to prevent an issue from syncing:
180
-
181
- 1. **Label**: Add `skip-beads-sync` to the GitHub issue. The workflow checks labels before processing.
182
- 2. **Body keyword**: Include `no-beads` anywhere in the issue body. Useful for quick one-off exclusions.
183
-
184
- Both are checked at the `issues.opened` trigger. If added after creation, they prevent close-sync but not the already-created Beads issue.
185
-
186
- ---
187
-
188
- ## Troubleshooting
189
-
190
- ### Sync not triggering
191
-
192
- - **Check workflow is enabled**: Go to Actions tab in GitHub, verify `github-to-beads` workflow exists and is active.
193
- - **Check branch**: Workflows must exist on the default branch (usually `main` or `master`).
194
- - **Check permissions**: The workflow needs `contents: write` and `issues: write` permissions.
195
-
196
- ### Duplicate Beads issues
197
-
198
- - The workflow checks for an existing `<!-- beads-sync:N -->` bot comment before creating. If the comment was deleted, a duplicate may be created.
199
- - Fix: Check `.github/beads-mapping.json` for the existing mapping and manually remove the duplicate Beads issue with `bd delete`.
200
-
201
- ### Loop detection firing incorrectly
202
-
203
- - If legitimate commits starting with `chore(beads):` are being skipped by the Phase 2 workflow, rename the commit prefix in the workflow file.
204
- - The bot-actor check uses `github.actor` -- ensure your CI bot user matches the expected name.
205
-
206
- ### Mapping file conflicts
207
-
208
- - If two issues are created simultaneously, the `git push` for the second may fail due to a stale mapping file.
209
- - The workflow retries with `git pull --rebase` up to 3 times. If it still fails, the workflow run will show as failed -- re-run it manually.
210
-
211
- ### `bd` command not found in CI
212
-
213
- - The workflow installs Beads fresh each run: `bun add -g @beads/bd`.
214
- - If this fails, check that the workflow uses a runner with Node/Bun available.
215
-
216
- ---
217
-
218
- ## Fork Behavior
219
-
220
- Sync does **not** work in forks. The `GITHUB_TOKEN` provided to forked repo workflows is scoped to the fork and cannot write to the upstream repo's `.beads/` directory or post comments on upstream issues.
221
-
222
- When a fork PR uses `Closes #N`, GitHub closes the issue on the **upstream** repo on merge. This triggers the upstream's `issues.closed` workflow, which handles the Beads close normally.
223
-
224
- ---
225
-
226
- ## GitHub Projects Integration
227
-
228
- This plugin creates well-labeled GitHub issues but does **not** manage GitHub Projects boards. Use GitHub's built-in automation instead:
229
-
230
- ### Setting Up Auto-Add to Project
231
-
232
- 1. Go to your GitHub Project (Projects tab on your profile or org)
233
- 2. Click the `...` menu, then **Workflows**
234
- 3. Enable **"Auto-add to project"**
235
- 4. Set the filter, for example: `is:issue is:open label:bug,enhancement`
236
- 5. All matching issues (including those created by the sync) will auto-appear on your board
237
-
238
- ### Recommended Project Views
239
-
240
- - **Board view**: Columns for `Open`, `In Progress`, `Done` -- map to Beads statuses
241
- - **Table view**: Add `Labels`, `Assignees`, `Priority` fields for triage
242
- - **Filter by label**: Use the labels mapped in your config to create focused views
243
-
244
- This approach is more flexible than automating board placement -- you control the filters and views entirely within GitHub's UI.
245
-
246
- ---
247
-
248
- ## Related Documentation
249
-
250
- - [Design doc](plans/2026-03-21-github-beads-sync-design.md) -- full design decisions, OWASP analysis, and edge cases
251
- - [Toolchain reference](TOOLCHAIN.md) -- Beads CLI commands, installation, and troubleshooting
1
+ # GitHub <-> Beads Issue Sync
2
+
3
+ Automatic synchronization between GitHub Issues and Beads issue tracking.
4
+
5
+ **GitHub Issues** = human/team/public interface.
6
+ **Beads** = AI agent engine (`bd ready`, `bd close`).
7
+
8
+ Neither side needs to know about the other. Contributors file issues on GitHub; AI agents pick up work via Beads. Status changes propagate automatically.
9
+
10
+ ---
11
+
12
+ ## Architecture
13
+
14
+ ### Phase 1: GitHub -> Beads (CI-driven)
15
+
16
+ ```mermaid
17
+ sequenceDiagram
18
+ participant U as User
19
+ participant GH as GitHub Issues
20
+ participant WF as GitHub Actions
21
+ participant BD as Beads CLI
22
+ participant Repo as .beads/ + mapping
23
+
24
+ U->>GH: Opens issue #42
25
+ GH->>WF: issues.opened trigger
26
+ WF->>WF: Guard checks (bot? skip label? no-beads?)
27
+ WF->>WF: Idempotency check (existing bot comment?)
28
+ WF->>BD: bd create --title "..." --type bug --priority 1
29
+ BD->>Repo: Write .beads/issues.jsonl
30
+ WF->>Repo: Write .github/beads-mapping.json {"42": "forge-abc"}
31
+ WF->>GH: Post bot comment <!-- beads-sync:42 -->
32
+ WF->>Repo: git commit + push
33
+
34
+ U->>GH: Closes issue #42
35
+ GH->>WF: issues.closed trigger
36
+ WF->>Repo: Read mapping: "42" -> "forge-abc"
37
+ WF->>BD: bd close forge-abc --reason "Closed via GitHub #42"
38
+ WF->>Repo: git commit + push
39
+ ```
40
+
41
+ ### Phase 2: Beads -> GitHub (push-triggered)
42
+
43
+ ```mermaid
44
+ sequenceDiagram
45
+ participant AI as AI Agent
46
+ participant BD as Beads CLI
47
+ participant Repo as .beads/
48
+ participant WF as GitHub Actions
49
+ participant GH as GitHub Issues
50
+
51
+ AI->>BD: bd close forge-abc
52
+ BD->>Repo: Update issues.jsonl
53
+ AI->>Repo: git push
54
+ Repo->>WF: push trigger (paths: .beads/**)
55
+ WF->>WF: Guard: skip if commit msg starts with "chore(beads):"
56
+ WF->>Repo: Diff issues.jsonl for closed transitions
57
+ WF->>GH: gh api PATCH /issues/42 state=closed
58
+ ```
59
+
60
+ ### Loop Prevention
61
+
62
+ Three guards prevent infinite ping-pong:
63
+
64
+ 1. **Bot detection** -- workflows skip events from `github-actions[bot]`
65
+ 2. **Commit message prefix** -- Phase 2 workflow skips commits starting with `chore(beads):`
66
+ 3. **Opt-out label** -- `skip-beads-sync` label on any issue disables sync entirely
67
+
68
+ ---
69
+
70
+ ## Setup
71
+
72
+ ### Via Forge Setup (recommended)
73
+
74
+ ```bash
75
+ bunx forge setup
76
+ # During interactive prompts:
77
+ # "Enable GitHub <-> Beads sync? (y/n)" -> y
78
+ ```
79
+
80
+ This scaffolds:
81
+ - `.github/workflows/github-to-beads.yml`
82
+ - `.github/workflows/beads-to-github.yml` (Phase 2)
83
+ - `.github/beads-mapping.json`
84
+ - `scripts/github-beads-sync/` (Node modules)
85
+ - `scripts/github-beads-sync.config.json`
86
+
87
+ ### Manual Setup
88
+
89
+ 1. Copy workflow files from `templates/` into `.github/workflows/`
90
+ 2. Copy `scripts/github-beads-sync/` and `scripts/github-beads-sync.config.json`
91
+ 3. Create `.github/beads-mapping.json` with `{}`
92
+ 4. Ensure Beads is initialized: `bd init`
93
+ 5. Commit and push to enable the workflows
94
+
95
+ ---
96
+
97
+ ## Configuration Reference
98
+
99
+ All settings live in `scripts/github-beads-sync.config.json`.
100
+
101
+ ### Label and Type Mapping
102
+
103
+ | Field | Type | Default | Description |
104
+ |-------|------|---------|-------------|
105
+ | `labelToType` | `object` | `{"bug":"bug", "enhancement":"feature", "documentation":"task", "question":"task"}` | Maps GitHub labels to Beads issue types. First matching label wins. |
106
+ | `labelToPriority` | `object` | `{"P0":0, "critical":0, "P1":1, "high":1, "P2":2, "medium":2, "P3":3, "low":3, "P4":4, "backlog":4}` | Maps GitHub labels to Beads priority levels (0-4). First matching label wins. |
107
+ | `defaultType` | `string` | `"task"` | Beads type when no label matches `labelToType`. |
108
+ | `defaultPriority` | `number` | `2` | Beads priority when no label matches `labelToPriority`. |
109
+ | `mapAssignee` | `boolean` | `true` | Whether to copy GitHub assignee to Beads issue on creation. |
110
+
111
+ ### Security Gates (Public Repos)
112
+
113
+ | Field | Type | Default | Description |
114
+ |-------|------|---------|-------------|
115
+ | `publicRepoGate` | `string` | `"none"` | Access control for public repos. See [Security](#security) section. |
116
+ | `gateLabelName` | `string` | `"beads-track"` | Required label when `publicRepoGate` is `"label"`. |
117
+ | `gateAssociations` | `string[]` | `["MEMBER", "COLLABORATOR", "OWNER"]` | Allowed author associations when `publicRepoGate` is `"author_association"`. |
118
+
119
+ ### Example: Custom Configuration
120
+
121
+ ```json
122
+ {
123
+ "labelToType": {
124
+ "bug": "bug",
125
+ "feature": "feature",
126
+ "chore": "chore",
127
+ "spike": "task"
128
+ },
129
+ "labelToPriority": {
130
+ "urgent": 0,
131
+ "important": 1,
132
+ "normal": 2,
133
+ "nice-to-have": 3
134
+ },
135
+ "defaultType": "task",
136
+ "defaultPriority": 2,
137
+ "mapAssignee": true,
138
+ "publicRepoGate": "author_association",
139
+ "gateAssociations": ["MEMBER", "COLLABORATOR", "OWNER"]
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Security
146
+
147
+ ### Public Repo Gate
148
+
149
+ On public repos, anyone can open an issue -- which triggers a commit to your default branch via the sync workflow. The `publicRepoGate` setting controls who can trigger sync:
150
+
151
+ | Value | Behavior | Recommended For |
152
+ |-------|----------|-----------------|
153
+ | `"none"` | All issues sync (default). | Private repos, trusted teams. |
154
+ | `"author_association"` | Only issues from authors in `gateAssociations` sync. | Public repos with known contributors. |
155
+ | `"label"` | Only issues with the `gateLabelName` label sync. A maintainer must add the label. | Public repos accepting external issues. |
156
+
157
+ ### Input Sanitization
158
+
159
+ - Issue titles and bodies are **never interpolated in shell commands**. The sync scripts use Node `execFile` with array arguments (no shell).
160
+ - Workflow files pass event data via `env:` blocks, never via `${{ }}` in `run:` blocks (prevents GitHub Actions injection).
161
+ - Only title, URL, mapped type, and priority are stored in Beads -- raw issue body is not committed.
162
+
163
+ ### SHA-Pinned Actions
164
+
165
+ All third-party actions in the workflow files are pinned to full commit SHAs, not tags. This prevents supply-chain attacks via tag mutation.
166
+
167
+ ```yaml
168
+ # Good: SHA-pinned
169
+ - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
170
+
171
+ # Bad: tag-only (never used)
172
+ - uses: actions/checkout@v4
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Opt-Out
178
+
179
+ Two ways to prevent an issue from syncing:
180
+
181
+ 1. **Label**: Add `skip-beads-sync` to the GitHub issue. The workflow checks labels before processing.
182
+ 2. **Body keyword**: Include `no-beads` anywhere in the issue body. Useful for quick one-off exclusions.
183
+
184
+ Both are checked at the `issues.opened` trigger. If added after creation, they prevent close-sync but not the already-created Beads issue.
185
+
186
+ ---
187
+
188
+ ## Troubleshooting
189
+
190
+ ### Sync not triggering
191
+
192
+ - **Check workflow is enabled**: Go to Actions tab in GitHub, verify `github-to-beads` workflow exists and is active.
193
+ - **Check branch**: Workflows must exist on the default branch (usually `main` or `master`).
194
+ - **Check permissions**: The workflow needs `contents: write` and `issues: write` permissions.
195
+
196
+ ### Duplicate Beads issues
197
+
198
+ - The workflow checks for an existing `<!-- beads-sync:N -->` bot comment before creating. If the comment was deleted, a duplicate may be created.
199
+ - Fix: Check `.github/beads-mapping.json` for the existing mapping and manually remove the duplicate Beads issue with `bd delete`.
200
+
201
+ ### Loop detection firing incorrectly
202
+
203
+ - If legitimate commits starting with `chore(beads):` are being skipped by the Phase 2 workflow, rename the commit prefix in the workflow file.
204
+ - The bot-actor check uses `github.actor` -- ensure your CI bot user matches the expected name.
205
+
206
+ ### Mapping file conflicts
207
+
208
+ - If two issues are created simultaneously, the `git push` for the second may fail due to a stale mapping file.
209
+ - The workflow retries with `git pull --rebase` up to 3 times. If it still fails, the workflow run will show as failed -- re-run it manually.
210
+
211
+ ### `bd` command not found in CI
212
+
213
+ - The workflow installs Beads fresh each run: `bun add -g @beads/bd`.
214
+ - If this fails, check that the workflow uses a runner with Node/Bun available.
215
+
216
+ ---
217
+
218
+ ## Fork Behavior
219
+
220
+ Sync does **not** work in forks. The `GITHUB_TOKEN` provided to forked repo workflows is scoped to the fork and cannot write to the upstream repo's `.beads/` directory or post comments on upstream issues.
221
+
222
+ When a fork PR uses `Closes #N`, GitHub closes the issue on the **upstream** repo on merge. This triggers the upstream's `issues.closed` workflow, which handles the Beads close normally.
223
+
224
+ ---
225
+
226
+ ## GitHub Projects Integration
227
+
228
+ This plugin creates well-labeled GitHub issues but does **not** manage GitHub Projects boards. Use GitHub's built-in automation instead:
229
+
230
+ ### Setting Up Auto-Add to Project
231
+
232
+ 1. Go to your GitHub Project (Projects tab on your profile or org)
233
+ 2. Click the `...` menu, then **Workflows**
234
+ 3. Enable **"Auto-add to project"**
235
+ 4. Set the filter, for example: `is:issue is:open label:bug,enhancement`
236
+ 5. All matching issues (including those created by the sync) will auto-appear on your board
237
+
238
+ ### Recommended Project Views
239
+
240
+ - **Board view**: Columns for `Open`, `In Progress`, `Done` -- map to Beads statuses
241
+ - **Table view**: Add `Labels`, `Assignees`, `Priority` fields for triage
242
+ - **Filter by label**: Use the labels mapped in your config to create focused views
243
+
244
+ This approach is more flexible than automating board placement -- you control the filters and views entirely within GitHub's UI.
245
+
246
+ ---
247
+
248
+ ## Related Documentation
249
+
250
+ - [Design doc](plans/2026-03-21-github-beads-sync-design.md) -- full design decisions, OWASP analysis, and edge cases
251
+ - [Toolchain reference](TOOLCHAIN.md) -- Beads CLI commands, installation, and troubleshooting