You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(mdd): add global ops scope, collision guard, and ops list command
- /mdd ops now asks global vs project scope as first question
- Global saves to ~/.claude/ops/ — reusable across all projects
- Note shown: global ops cannot access project-local .env vars
- Collision guard: if a global op exists with the same slug, creating
a project op with that name is a hard stop (no silent shadowing)
- runop and update-op check project-local first, then global;
announce which scope the runbook was found in
- /mdd ops list shows unified view of all global + project runbooks
with last-run status, grouped by scope
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
(b) Global — ~/.claude/ops/<slug>.md (reusable across all projects)
1885
+
1886
+
Note: Global ops cannot access project-local .env variables or
1887
+
project-specific paths. Use ~/.env globals only.
1888
+
```
1889
+
1890
+
**Step 2 — Derive slug:**
1891
+
Strip `ops` from the start of arguments. Use the remainder as the description.
1892
+
Derive a slug: lowercase, hyphens, drop filler words (e.g., "deploy swarmk to dokploy" → `swarmk-dokploy`, "update cloudflare dns" → `cloudflare-dns`).
1893
+
1894
+
**Step 3 — Collision check:**
1895
+
- If scope is **project**: check whether `~/.claude/ops/<slug>.md` exists.
1896
+
- If global op exists with that slug → **hard stop**:
1897
+
*"A global runbook named `<slug>` already exists (`~/.claude/ops/<slug>.md`). Project ops cannot share a name with a global op — use a different name, or run `/mdd runop <slug>` to execute the global one."*
1898
+
- If scope is **global**: check whether `~/.claude/ops/` exists, create it if not (`mkdir -p ~/.claude/ops`).
1899
+
1900
+
**Step 4 — Check target location:**
1901
+
- Target path: `.mdd/ops/<slug>.md` (project) or `~/.claude/ops/<slug>.md` (global)
1902
+
-**Does not exist** → proceed to Phase OP2 (create)
1903
+
-**Exists** → tell the user: *"Runbook `<slug>` already exists. Use `/mdd update-op <slug>` to edit it or `/mdd runop <slug>` to execute it."* Stop.
1884
1904
1885
1905
### Phase OP2 — Ask questions
1886
1906
@@ -1995,8 +2015,10 @@ Triggered when arguments start with `runop`. Executes an existing ops runbook wi
1995
2015
### Phase RO1 — Load runbook
1996
2016
1997
2017
1. Parse `<slug>` from arguments — hard stop *"Slug required. Usage: /mdd runop <slug>"* if missing.
1998
-
2. Read `.mdd/ops/<slug>.md` — hard stop if not found:
1999
-
*"No runbook found for `<slug>`. Run `/mdd ops <description>` to create one."*
2018
+
2. Locate the runbook (project-local first, then global):
- Check `~/.claude/ops/<slug>.md` → found: announce *"Running global runbook: `<slug>`"*
2021
+
- Neither found → hard stop: *"No runbook found for `<slug>` (checked project and global). Run `/mdd ops <description>` to create one, or `/mdd ops list` to see all available runbooks."*
2000
2022
3. Parse all frontmatter fields: regions (sorted by `deploy_order`), services, `deployment_strategy`.
2001
2023
2002
2024
### Phase RO2 — Pre-flight health check (all regions)
@@ -2114,7 +2136,10 @@ Triggered when arguments start with `update-op`. Updates an existing ops runbook
2114
2136
### Phase UO1 — Load
2115
2137
2116
2138
1. Parse `<slug>` — hard stop *"Slug required. Usage: /mdd update-op <slug>"* if missing.
2117
-
2. Read `.mdd/ops/<slug>.md` — hard stop if not found: *"No runbook found for `<slug>`."*
2139
+
2. Locate runbook (project-local first, then global):
0 commit comments