Skip to content

Commit 7043033

Browse files
lapc506claude
andauthored
feat(implement): make OpenSpec mandatory when configured (Phase 0) (#13)
* feat(implement): make OpenSpec mandatory when configured (Phase 0) Introduces a new Phase 0 in /make-no-mistakes:implement that runs BEFORE Phase 1 (Setup). When linear-setup.json has openspec.changesPath configured, every issue MUST have a corresponding OpenSpec change (proposal.md + design.md + tasks.md) before implementation begins. Previously, step 4b in Phase 2 read OpenSpec context only "if found", which made the spec-first discipline silently skippable. Since OpenSpec was officially adopted at Dojo Coding on 2026-03-30 (Slack thread C0AE5MKAX7B), that gap re-introduces exactly the failure mode adoption was meant to prevent: implementations diverging from intent because nobody wrote the intent down. Behavior change: - When openspec.changesPath is set AND the issue is non-trivial (>2 files, architectural decisions, or reviewer-flagged risk), the implementer STOPS and creates the OpenSpec change as the first commit on the implementation branch. - Trivial issues (typo fixes, dependency bumps, single-line changes) may opt out with a one-line PR note. - Repos without openspec.changesPath are unaffected — Phase 0 is skipped entirely, preserving back-compat. Bumps version to 1.4.1 across plugin.json, marketplace.json, and package.json. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(implement): use \$CHANGES_PATH in step 4a + renumber phases sequentially Greptile re-review on PR #13 caught two real defects in the new Phase 0/Phase 1 text: 1. Phase 1 step 4a's git add command used an undefined placeholder "{changes-path}" — the variable established in Phase 0 step 1 is "\$CHANGES_PATH" (set via jq from linear-setup.json). An agent running the step verbatim would stage nothing, producing an empty first commit and silently breaking the spec-first guarantee the entire phase enforces. Step 4a now re-exports CHANGES_PATH inside the worktree (the parent shell's variable doesn't survive the cd into a fresh worktree) and uses "\$CHANGES_PATH/{change-slug}/" in the git add. 2. The original document restarted step numbering at 4 in Phase 2, colliding with Phase 1's existing step 4 + 4a. Cross-phase references like "step 4" became ambiguous. Renumbered the entire chain so steps run sequentially across all four phases: - Phase 1: 1, 2, 3, 4, 4a - Phase 2: 5, 6, 7 - Phase 3: 8, 9, 10, 11, 12 - Phase 4: 13, 14, 15, 16, 17 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(implement): make step 4a's source path explicit via git worktree list Greptile re-review on PR #13 caught a P1 ambiguity in step 4a: Phase 0 drafts spec files in the main working tree at {main-tree}/\$CHANGES_PATH/ {change-slug}/, but Phase 1 step 3 cd's into a freshly created worktree that does NOT carry over uncommitted files. The previous wording said "move/copy if not already there" without naming the source path — an agent inside the worktree could resolve it incorrectly and end up running git add on a non-existent path, producing a silently empty docs(openspec) commit and defeating the spec-first guarantee. Step 4a now: 1. Re-exports \$CHANGES_PATH inside the worktree (the parent shell's variable doesn't survive the cd). 2. Computes \$MAIN_TREE via git worktree list --porcelain (first entry is always the primary tree, regardless of which worktree we're currently in). 3. Skips the copy when the directory already exists in the worktree (idempotent on retry). 4. Copies "\$MAIN_TREE/\$CHANGES_PATH/{change-slug}" into the worktree before git add — explicit, unambiguous, agent-runnable verbatim. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(implement): bind {change-slug} as $CHANGE_SLUG + define naming rule Greptile round-4 caught the same class of defect as round 2 but for a different placeholder: {change-slug} was a bare template literal in the step 4a bash block, sitting next to a properly bound \$CHANGES_PATH. An agent running the block verbatim would execute git add "\$CHANGES_PATH/{change-slug}/" which stages a literal path containing the brace string — staging nothing — and produces a silently empty docs(openspec) commit. Two paired fixes: 1. Phase 0 step 3 now states the slug naming convention explicitly: {issue-id-lowercase}-{short-kebab-description} (lowercase ASCII + hyphens, e.g. doj-3946-atomic-primitives-sprint). Same shape as the implementation branch so agents and humans converge on the same directory name across runs. 2. Step 4a bash block now binds CHANGE_SLUG="<change-slug>" at the top (placeholder agents/humans MUST replace before running) and uses "\$CHANGE_SLUG" in every file path expression. mkdir/cp/git add/git commit all reference the bound variable, so verbatim execution produces a non-empty commit even if the surrounding text is unread. Documentation-template uses of {change-slug} elsewhere in the file are left intact — they refer to the literal directory name in prose, not shell variables, and agents reading prose interpret them correctly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 8785187 commit 7043033

4 files changed

Lines changed: 77 additions & 28 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
33
"name": "make-no-mistakes",
4-
"version": "1.4.0",
4+
"version": "1.6.0",
55
"description": "The disciplined dev lifecycle — implement issues, review PRs, sync releases, test E2E, manage sessions, and stash secrets via OS-native prompts. One plugin to make no mistakes.",
66
"owner": {
77
"name": "Luis Andres Pena Castillo",
@@ -11,7 +11,7 @@
1111
{
1212
"name": "make-no-mistakes",
1313
"description": "Dev lifecycle orchestrator: disciplined Linear issue execution with worktree isolation, PR review with Greptile gating, team release sync, E2E test generation and execution, test suite previewer, security pentesting, MoSCoW + RICE prioritization, cross-platform secret stash via OS-native GUI prompts (zenity / kdialog / osascript / Get-Credential), and session management. 18 commands, 6 auto-activating skills, 2 specialized agents.",
14-
"version": "1.4.0",
14+
"version": "1.6.0",
1515
"author": {
1616
"name": "Luis Andres Pena Castillo",
1717
"email": "lapc506@users.noreply.github.com"

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "make-no-mistakes",
3-
"version": "1.5.0",
3+
"version": "1.6.0",
44
"description": "The disciplined dev lifecycle — implement issues, review PRs, sync releases, test E2E, manage sessions, stash secrets, and enforce manifest-driven tool-call hooks. One plugin to make no mistakes.",
55
"author": {
66
"name": "Luis Andres Pena Castillo",

commands/implement.md

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,37 @@ If any check fails, STOP and resolve before proceeding.
181181

182182
For EACH issue in the sequence, follow this exact workflow. No shortcuts. No exceptions.
183183

184+
### Phase 0: OpenSpec Context (MANDATORY when configured)
185+
186+
Run this BEFORE Phase 1 (Setup). If `linear-setup.json` has `openspec.changesPath`:
187+
188+
1. **Resolve the configured changes directory** and check for an existing OpenSpec change that references this issue. The grep MUST use the configured path — projects may set `openspec.changesPath` to anything (e.g., `specs/changes/`) and a hardcoded `openspec/changes/` would silently miss every existing spec there:
189+
```bash
190+
CHANGES_PATH=$(jq -r '.openspec.changesPath' linear-setup.json)
191+
grep -r "{issue-id}" "$CHANGES_PATH"/*/proposal.md 2>/dev/null
192+
```
193+
In all references below, `<changes>` denotes that resolved `$CHANGES_PATH` value, NOT the literal string `openspec/changes/`.
194+
195+
2. **If found**: Read ALL three artifacts as primary implementation context:
196+
- `<changes>/{change-slug}/proposal.md` — intent, domain, scope
197+
- `<changes>/{change-slug}/design.md` — architectural decisions, rejected alternatives, pre-launch checklist
198+
- `<changes>/{change-slug}/tasks.md` — atomic task list with file paths and commit messages
199+
200+
These three files are the CONTRACT. The Linear issue is the WHAT; OpenSpec is the HOW. Do not deviate from the spec without going back to it first.
201+
202+
3. **If MISSING and the issue is non-trivial** (touches >2 files OR involves architectural decisions OR has reviewer-flagged risk): STOP and prepare the OpenSpec change BEFORE proceeding.
203+
- Use `/superpowers:brainstorming` if the design needs more thinking
204+
- Use `/make-no-mistakes:premortem` if the change is load-bearing in production
205+
- **Compute the change slug deterministically** so every later step (and any restart) targets the same directory. The slug MUST follow the same shape as the implementation branch: `{issue-id-lowercase}-{short-kebab-description}` (e.g., `doj-3946-atomic-primitives-sprint`). Lowercase only, ASCII alphanumerics + hyphens, no leading/trailing hyphens, no other separators.
206+
- **Draft the three artifacts** in `<changes>/<change-slug>/`: proposal.md (intent + scope + out-of-scope), design.md (decisions + rationale), tasks.md (atomic checklist with commit messages). Leave them uncommitted on disk — the implementation branch does not exist yet.
207+
- **Defer the commit to Phase 1 step 4a** (below). Phase 1 creates the branch and worktree; the OpenSpec files are then committed as the very first commit on that branch.
208+
209+
4. **If MISSING but the issue is trivial** (typo fix, dependency bump, single-line change): proceed to Phase 1 without OpenSpec. Add a one-line note to the PR description explaining why OpenSpec was skipped.
210+
211+
5. **If `openspec.changesPath` is not configured** in `linear-setup.json`: skip this phase entirely. The project hasn't adopted OpenSpec yet.
212+
213+
**Why mandatory**: per the adoption decision (Slack 2026-03-30, channel C0AE5MKAX7B), OpenSpec is the durable persistence of design decisions. A skill that makes it optional re-introduces the failure mode it was adopted to prevent — implementations diverging from intent because nobody wrote the intent down.
214+
184215
### Phase 1: Setup
185216

186217
1. **Claim the issue in Linear:**
@@ -209,24 +240,42 @@ For EACH issue in the sequence, follow this exact workflow. No shortcuts. No exc
209240
- Create sub-issues in Linear for each PR if decomposing.
210241
- Comment the decomposition plan on the parent issue.
211242

212-
### Phase 2: Implement
243+
4a. **Commit the OpenSpec change as the first commit** (only if Phase 0 step 3 drafted artifacts because none existed):
244+
- Phase 0 wrote the artifacts to the **main working tree** at `{main-tree}/$CHANGES_PATH/<change-slug>/`. Phase 1 step 3 created a fresh worktree from `{baseBranch}`, which does NOT carry over those uncommitted files. Copy them into the current worktree explicitly. The `CHANGE_SLUG` value MUST match the slug Phase 0 step 3 chose (same `{issue-id-lowercase}-{short-kebab-description}` rule):
245+
```bash
246+
# Inside the new worktree (Phase 1 step 3 cd'd here).
247+
CHANGES_PATH=$(jq -r '.openspec.changesPath' linear-setup.json)
248+
# Bind the slug Phase 0 step 3 produced. Replace the placeholder before
249+
# running — never leave it as a literal "<change-slug>" string.
250+
CHANGE_SLUG="<change-slug>" # e.g. doj-3946-atomic-primitives-sprint
251+
# Resolve the main working tree's filesystem path from git's worktree
252+
# registry — first row of `git worktree list --porcelain` is always the
253+
# primary tree, regardless of which worktree we're currently in.
254+
MAIN_TREE=$(git worktree list --porcelain | awk '/^worktree/ {print $2; exit}')
255+
# Skip the copy if the worktree already has the directory (e.g. an
256+
# earlier run already staged it, or the spec was committed previously).
257+
if [ ! -d "$CHANGES_PATH/$CHANGE_SLUG" ]; then
258+
mkdir -p "$CHANGES_PATH"
259+
cp -r "$MAIN_TREE/$CHANGES_PATH/$CHANGE_SLUG" "$CHANGES_PATH/"
260+
fi
261+
git add "$CHANGES_PATH/$CHANGE_SLUG/"
262+
git commit -m "docs(openspec): $CHANGE_SLUG"
263+
```
264+
- The `docs(openspec)` commit MUST be commit #1 on the branch — reviewers and future agents read the spec before the diff.
265+
- If Phase 0 found an existing change (step 2), skip this entire step — the spec is already on `{baseBranch}` and inherited by the new worktree.
213266

214-
4. **Implement in the worktree.** Follow all project conventions from CLAUDE.md.
267+
### Phase 2: Implement
215268

216-
4b. **Check for OpenSpec context:**
217-
- If `linear-setup.json` has `openspec.changesPath`, check if an OpenSpec change exists that references this issue
218-
- Look in `openspec/changes/*/proposal.md` for the issue ID
219-
- If found, read ALL artifacts (proposal.md, design.md, tasks.md) as implementation context
220-
- This provides richer context than the Linear issue description alone
269+
5. **Implement in the worktree.** Follow all project conventions from CLAUDE.md. If Phase 0 produced an OpenSpec change, treat its `tasks.md` as the authoritative checklist — work through it in order and do not improvise file paths or commit messages outside the spec.
221270

222-
5. **If multiple approaches exist:**
271+
6. **If multiple approaches exist:**
223272
- Dispatch one sub-agent per approach via Mode A (each gets its own worktree automatically)
224273
- Run all approaches in parallel with `run_in_background: true`
225274
- Each approach may discover new issues — document them in its final report
226275
- Synthesize the best parts of multiple solutions if needed
227276
- Close losing sub-agent branches/PRs after synthesis
228277

229-
6. **Write tests:**
278+
7. **Write tests:**
230279
- Model E2E test cases with Slack MCP first (plan them in a test channel or thread)
231280
- Split test cases: some for **Playwright**, others for **Chrome DevTools MCP**
232281
- Browser ALWAYS in focus. **NEVER headless.** Both Playwright and Chrome DevTools MCP.
@@ -238,33 +287,33 @@ For EACH issue in the sequence, follow this exact workflow. No shortcuts. No exc
238287

239288
### Phase 3: PR + Review Loop
240289

241-
7. **Create the PR:**
290+
8. **Create the PR:**
242291
```bash
243292
gh pr create --base {baseBranch} --title "{issue-id}: {concise title}" --body "..."
244293
```
245294
- Link the Linear issue in the PR body
246295
- Add "Created by Claude Code on behalf of @{user}"
247296

248-
8. **Tag ALL reviewers:**
297+
9. **Tag ALL reviewers:**
249298
- Comment `@greptile review` on the PR
250299
- Wait for automated reviews from **Greptile**, **CodeRabbit**, and **Graphite**
251300
- All three reviewers are configured in the project — check all of them
252301

253-
9. **Fix reviewer feedback:**
254-
- Address ALL insights from Greptile, CodeRabbit, AND Graphite
255-
- Commit fixes to the same branch
256-
- Re-tag: `@greptile review` again if needed
257-
- Target: Greptile confidence **≥ 3/5**, CodeRabbit no critical issues, Graphite no blockers
258-
- If a reviewer doesn't respond within 5 minutes, proceed but note it to the user
302+
10. **Fix reviewer feedback:**
303+
- Address ALL insights from Greptile, CodeRabbit, AND Graphite
304+
- Commit fixes to the same branch
305+
- Re-tag: `@greptile review` again if needed
306+
- Target: Greptile confidence **≥ 3/5**, CodeRabbit no critical issues, Graphite no blockers
307+
- If a reviewer doesn't respond within 5 minutes, proceed but note it to the user
259308
260-
10. **Verify CI:**
309+
11. **Verify CI:**
261310
```bash
262311
gh pr checks {pr-number} --watch
263312
```
264313
- ALL checks must pass before proceeding
265314
- If CI fails, fix and push — do not skip
266315
267-
11. **Check merge conflicts:**
316+
12. **Check merge conflicts:**
268317
```bash
269318
gh pr view {pr-number} --json mergeable
270319
```
@@ -273,30 +322,30 @@ For EACH issue in the sequence, follow this exact workflow. No shortcuts. No exc
273322
274323
### Phase 4: Merge + Cleanup
275324
276-
12. **Merge the PR:**
325+
13. **Merge the PR:**
277326
```bash
278327
gh pr merge {pr-number} --squash --delete-branch
279328
```
280329
281-
13. **Update Linear:**
330+
14. **Update Linear:**
282331
- Set status to **Done**
283332
- Comment: "Merged via PR #{pr-number}"
284333
285-
14. **Clean up worktrees:**
334+
15. **Clean up worktrees:**
286335
```bash
287336
git worktree remove .claude/worktrees/{issue-id} --force
288337
# Verify ALL worktrees for this issue are removed
289338
git worktree list
290339
git worktree prune
291340
```
292341
293-
15. **Sync before next issue:**
342+
16. **Sync before next issue:**
294343
```bash
295344
git checkout {baseBranch}
296345
git pull origin {baseBranch} --rebase
297346
```
298347
299-
16. **Repeat** from Phase 1 for the next issue.
348+
17. **Repeat** from Phase 1 for the next issue.
300349
301350
## Chain Merge Strategy
302351

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@lapc506/make-no-mistakes",
3-
"version": "1.5.0",
3+
"version": "1.6.0",
44
"description": "The disciplined dev lifecycle — implement issues, review PRs, sync releases, test E2E, manage sessions, stash secrets, and enforce manifest-driven tool-call hooks (no SSH+DB, no manual prod, no minified build, no secret leaks, Slack format). OpenCode + Claude Code plugin.",
55
"type": "module",
66
"main": "./dist/index.js",

0 commit comments

Comments
 (0)