chief-clancy 0.5.12 → 0.7.0

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 (102) hide show
  1. package/README.md +15 -8
  2. package/dist/bundle/clancy-afk.js +6 -2
  3. package/dist/bundle/clancy-once.js +71 -48
  4. package/dist/installer/hook-installer/hook-installer.d.ts +2 -0
  5. package/dist/installer/hook-installer/hook-installer.d.ts.map +1 -1
  6. package/dist/installer/hook-installer/hook-installer.js +36 -1
  7. package/dist/installer/hook-installer/hook-installer.js.map +1 -1
  8. package/dist/installer/install.js +16 -1
  9. package/dist/installer/install.js.map +1 -1
  10. package/dist/schemas/env.d.ts +36 -0
  11. package/dist/schemas/env.d.ts.map +1 -1
  12. package/dist/schemas/env.js +11 -0
  13. package/dist/schemas/env.js.map +1 -1
  14. package/dist/schemas/github-issues.d.ts +6 -0
  15. package/dist/schemas/github-issues.d.ts.map +1 -1
  16. package/dist/schemas/github-issues.js +3 -0
  17. package/dist/schemas/github-issues.js.map +1 -1
  18. package/dist/schemas/jira.d.ts +21 -0
  19. package/dist/schemas/jira.d.ts.map +1 -1
  20. package/dist/schemas/jira.js +18 -0
  21. package/dist/schemas/jira.js.map +1 -1
  22. package/dist/schemas/linear.d.ts +41 -0
  23. package/dist/schemas/linear.d.ts.map +1 -1
  24. package/dist/schemas/linear.js +34 -0
  25. package/dist/schemas/linear.js.map +1 -1
  26. package/dist/scripts/afk/afk.d.ts.map +1 -1
  27. package/dist/scripts/afk/afk.js +28 -0
  28. package/dist/scripts/afk/afk.js.map +1 -1
  29. package/dist/scripts/afk/report/report.d.ts +47 -0
  30. package/dist/scripts/afk/report/report.d.ts.map +1 -0
  31. package/dist/scripts/afk/report/report.js +194 -0
  32. package/dist/scripts/afk/report/report.js.map +1 -0
  33. package/dist/scripts/board/github/github.d.ts +33 -3
  34. package/dist/scripts/board/github/github.d.ts.map +1 -1
  35. package/dist/scripts/board/github/github.js +112 -27
  36. package/dist/scripts/board/github/github.js.map +1 -1
  37. package/dist/scripts/board/jira/jira.d.ts +36 -4
  38. package/dist/scripts/board/jira/jira.d.ts.map +1 -1
  39. package/dist/scripts/board/jira/jira.js +138 -65
  40. package/dist/scripts/board/jira/jira.js.map +1 -1
  41. package/dist/scripts/board/linear/linear.d.ts +32 -5
  42. package/dist/scripts/board/linear/linear.d.ts.map +1 -1
  43. package/dist/scripts/board/linear/linear.js +135 -17
  44. package/dist/scripts/board/linear/linear.js.map +1 -1
  45. package/dist/scripts/once/board-ops/board-ops.d.ts.map +1 -1
  46. package/dist/scripts/once/board-ops/board-ops.js +1 -1
  47. package/dist/scripts/once/board-ops/board-ops.js.map +1 -1
  48. package/dist/scripts/once/cost/cost.d.ts +10 -0
  49. package/dist/scripts/once/cost/cost.d.ts.map +1 -0
  50. package/dist/scripts/once/cost/cost.js +23 -0
  51. package/dist/scripts/once/cost/cost.js.map +1 -0
  52. package/dist/scripts/once/deliver/deliver.d.ts.map +1 -1
  53. package/dist/scripts/once/deliver/deliver.js +18 -1
  54. package/dist/scripts/once/deliver/deliver.js.map +1 -1
  55. package/dist/scripts/once/fetch-ticket/fetch-ticket.d.ts +19 -1
  56. package/dist/scripts/once/fetch-ticket/fetch-ticket.d.ts.map +1 -1
  57. package/dist/scripts/once/fetch-ticket/fetch-ticket.js +93 -29
  58. package/dist/scripts/once/fetch-ticket/fetch-ticket.js.map +1 -1
  59. package/dist/scripts/once/lock/lock.d.ts +17 -0
  60. package/dist/scripts/once/lock/lock.d.ts.map +1 -0
  61. package/dist/scripts/once/lock/lock.js +70 -0
  62. package/dist/scripts/once/lock/lock.js.map +1 -0
  63. package/dist/scripts/once/once.d.ts.map +1 -1
  64. package/dist/scripts/once/once.js +100 -4
  65. package/dist/scripts/once/once.js.map +1 -1
  66. package/dist/scripts/once/resume/resume.d.ts +24 -0
  67. package/dist/scripts/once/resume/resume.d.ts.map +1 -0
  68. package/dist/scripts/once/resume/resume.js +159 -0
  69. package/dist/scripts/once/resume/resume.js.map +1 -0
  70. package/dist/scripts/shared/format/format.d.ts.map +1 -1
  71. package/dist/scripts/shared/format/format.js +6 -1
  72. package/dist/scripts/shared/format/format.js.map +1 -1
  73. package/dist/scripts/shared/progress/progress.d.ts +18 -2
  74. package/dist/scripts/shared/progress/progress.d.ts.map +1 -1
  75. package/dist/scripts/shared/progress/progress.js +31 -4
  76. package/dist/scripts/shared/progress/progress.js.map +1 -1
  77. package/dist/scripts/shared/pull-request/pr-body/pr-body.d.ts +2 -1
  78. package/dist/scripts/shared/pull-request/pr-body/pr-body.d.ts.map +1 -1
  79. package/dist/scripts/shared/pull-request/pr-body/pr-body.js +10 -1
  80. package/dist/scripts/shared/pull-request/pr-body/pr-body.js.map +1 -1
  81. package/dist/types/remote.d.ts +1 -1
  82. package/dist/types/remote.d.ts.map +1 -1
  83. package/hooks/clancy-branch-guard.js +129 -0
  84. package/hooks/clancy-check-update.js +43 -0
  85. package/hooks/clancy-context-monitor.js +134 -46
  86. package/hooks/clancy-post-compact.js +53 -0
  87. package/hooks/package.json +3 -0
  88. package/package.json +3 -2
  89. package/src/agents/devils-advocate.md +53 -0
  90. package/src/agents/verification-gate.md +128 -0
  91. package/src/roles/planner/workflows/approve-plan.md +2 -2
  92. package/src/roles/reviewer/workflows/logs.md +9 -6
  93. package/src/roles/setup/commands/help.md +7 -0
  94. package/src/roles/setup/workflows/init.md +111 -6
  95. package/src/roles/setup/workflows/scaffold.md +57 -0
  96. package/src/roles/setup/workflows/settings.md +145 -0
  97. package/src/roles/setup/workflows/update.md +18 -0
  98. package/src/roles/strategist/commands/approve-brief.md +20 -0
  99. package/src/roles/strategist/commands/brief.md +27 -0
  100. package/src/roles/strategist/workflows/approve-brief.md +763 -0
  101. package/src/roles/strategist/workflows/brief.md +732 -0
  102. package/src/templates/CLAUDE.md +8 -1
@@ -0,0 +1,732 @@
1
+ # Clancy Brief Workflow
2
+
3
+ ## Overview
4
+
5
+ Research an idea, interrogate it thoroughly, and generate a structured strategic brief with vertical-slice ticket decomposition. Briefs are saved locally and optionally posted as comments on the source ticket. Does not create tickets — that is `/clancy:approve-brief`.
6
+
7
+ ---
8
+
9
+ ## Step 1 — Preflight checks
10
+
11
+ 1. Check `.clancy/` exists and `.clancy/.env` is present. If not:
12
+ ```
13
+ .clancy/ not found. Run /clancy:init to set up Clancy first.
14
+ ```
15
+ Stop.
16
+
17
+ 2. Source `.clancy/.env` and check board credentials are present.
18
+
19
+ 3. Check `CLANCY_ROLES` includes `strategist` (or env var is unset, which indicates a global install where all roles are available). If `CLANCY_ROLES` is set but does not include `strategist`:
20
+ ```
21
+ The Strategist role is not enabled. Add "strategist" to CLANCY_ROLES in .clancy/.env or run /clancy:settings.
22
+ ```
23
+ Stop.
24
+
25
+ 4. Branch freshness check — run `git fetch origin` and compare the current HEAD with `origin/$CLANCY_BASE_BRANCH` (defaults to `main`). If the local branch is behind:
26
+ ```
27
+ ⚠️ Your local branch is behind origin/{CLANCY_BASE_BRANCH} by {N} commit(s).
28
+
29
+ [1] Pull latest
30
+ [2] Continue anyway
31
+ [3] Abort
32
+ ```
33
+ - [1] runs `git pull origin $CLANCY_BASE_BRANCH` and continues
34
+ - [2] continues without pulling
35
+ - [3] stops
36
+
37
+ ---
38
+
39
+ ## Step 2 — Parse arguments
40
+
41
+ Parse the arguments passed to the command. Arguments can appear in any order.
42
+
43
+ ### Flags
44
+
45
+ - **`--list`** — show brief inventory and stop (no brief generated)
46
+ - **`--fresh`** — discard any existing brief and start over from scratch
47
+ - **`--research`** — force web research agent (adds 1 web agent to the research phase)
48
+ - **`--afk`** — use AI-grill instead of human grill (no interactive questions)
49
+ - **`--epic {KEY}`** — hint for `/clancy:approve-brief` later. Stored in the brief's metadata. Ignored if the input is a board ticket (the source ticket is the parent).
50
+
51
+ ### Input modes
52
+
53
+ - **No input (no flags that consume arguments):** Interactive mode — prompt `What's the idea?` and parse the response. If the response looks like a ticket reference (`#42`, `PROJ-123`, `ENG-42`), switch to board ticket mode. Otherwise treat as inline text.
54
+ - **Ticket key** (`PROJ-123`, `#42`, `ENG-42`): Board ticket mode — fetch the ticket from the board API. Validate format per platform:
55
+ - `#N` — valid for GitHub only. If board is Jira or Linear: `The #N format is for GitHub Issues. Use a ticket key like PROJ-123.` Stop.
56
+ - `PROJ-123` / `ENG-42` (letters-dash-number) — valid for Jira and Linear. If board is GitHub: `Use #N format for GitHub Issues (e.g. #42).` Stop.
57
+ - **Quoted string or unquoted non-matching text** (e.g. `"Add dark mode"`): Inline text mode — use the text directly as the idea.
58
+ - **`--from {path}`** — From file mode. Cannot be combined with a ticket reference (error if both present: `Cannot use both a ticket reference and --from. Use one or the other.`). Validate:
59
+ - File does not exist: `File not found: {path}` Stop.
60
+ - File is empty: `File is empty: {path}` Stop.
61
+ - File > 50KB: Warn `Large file ({size}KB). Clancy will use the first ~50KB for context.` Truncate internally, continue.
62
+ - **Bare positive integer** (e.g. `/clancy:brief 3`): Batch mode or ambiguous.
63
+ - Board is GitHub and value could be an issue: Ambiguous — ask: `Did you mean issue #3 or batch 3 tickets? [1] Brief issue #3 [2] Brief 3 tickets from queue`
64
+ - Board is Jira or Linear: Batch mode (N tickets from queue). Implies `--afk` (AI-grill for all).
65
+
66
+ If N > 10: `Maximum batch size is 10. Briefing 10 tickets.`
67
+
68
+ ### --list flag handling
69
+
70
+ If `--list` is present (with or without other arguments), jump to Step 11 (Brief Inventory) and stop.
71
+
72
+ ---
73
+
74
+ ## Step 3 — Gather idea (mode-specific)
75
+
76
+ ### Board ticket mode
77
+
78
+ Fetch the source ticket from the board API.
79
+
80
+ #### GitHub — Fetch specific issue
81
+
82
+ ```bash
83
+ RESPONSE=$(curl -s \
84
+ -H "Authorization: Bearer $GITHUB_TOKEN" \
85
+ -H "X-GitHub-Api-Version: 2022-11-28" \
86
+ "https://api.github.com/repos/$GITHUB_REPO/issues/$ISSUE_NUMBER")
87
+ ```
88
+
89
+ Validate the response:
90
+ - If `pull_request` field is present and non-null: `#N is a pull request, not an issue.` Stop.
91
+ - If `state` is `closed`: warn `#N is closed. Brief it anyway? [y/N]`
92
+ - If `body` is null/empty: warn `No issue description — briefing from title only.`
93
+ - Extract: `title`, `body`, `labels`, `milestone`.
94
+
95
+ Fetch comments for existing brief detection:
96
+ ```bash
97
+ COMMENTS=$(curl -s \
98
+ -H "Authorization: Bearer $GITHUB_TOKEN" \
99
+ -H "X-GitHub-Api-Version: 2022-11-28" \
100
+ "https://api.github.com/repos/$GITHUB_REPO/issues/$ISSUE_NUMBER/comments?per_page=100")
101
+ ```
102
+
103
+ #### Jira — Fetch specific ticket
104
+
105
+ ```bash
106
+ RESPONSE=$(curl -s \
107
+ -u "$JIRA_USER:$JIRA_API_TOKEN" \
108
+ -H "Accept: application/json" \
109
+ "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY?fields=summary,description,status,issuetype,parent,customfield_10014,components,priority,comment,project")
110
+ ```
111
+
112
+ Validate the response:
113
+ - If `fields.status.statusCategory.key` is `done`: warn `{KEY} is Done. Brief it anyway? [y/N]`
114
+ - If `fields.status.statusCategory.key` is `indeterminate`: warn `{KEY} is In Progress — briefing anyway.`
115
+ - If `fields.issuetype.name` is `Epic`: note `{KEY} is an Epic — child tickets will be created under it.`
116
+ - Extract: `summary`, `description` (ADF → plain text via `extractAdfText()`), status, existing comments from `comment.comments[]`.
117
+
118
+ #### Linear — Fetch specific issue
119
+
120
+ ```graphql
121
+ query {
122
+ issues(filter: { identifier: { eq: "$IDENTIFIER" } }) {
123
+ nodes {
124
+ id identifier title description
125
+ state { id name type }
126
+ parent { id identifier title }
127
+ children { nodes { id identifier title state { type } } }
128
+ team { id key name }
129
+ labels { nodes { id name } }
130
+ priority estimate
131
+ }
132
+ }
133
+ }
134
+ ```
135
+
136
+ Validate the response:
137
+ - If `nodes` is empty: `Issue {KEY} not found on Linear.` Stop.
138
+ - If `state.type` is `completed` or `canceled`: warn `{KEY} is {state.name}. Brief it anyway? [y/N]`
139
+ - If `state.type` is `started`: warn `{KEY} is In Progress — briefing anyway.`
140
+ - If `parent` is present: warn `{KEY} is a sub-issue of {parent.identifier}. Creating children will produce a 3-level hierarchy. Continue? [Y/n]`
141
+ - If `team.id` differs from `LINEAR_TEAM_ID`: warn `{KEY} belongs to team "{team.name}", but LINEAR_TEAM_ID is different. Continue? [Y/n]`
142
+
143
+ #### All platforms — error handling
144
+
145
+ If the API call fails:
146
+ - 404: `{KEY} not found — check the ticket key.` Stop.
147
+ - 401: `Auth failed — check credentials in .clancy/.env` Stop.
148
+ - 403: `Permission denied — check token scopes.` Stop.
149
+ - 5xx / timeout: `Server error. Try again in a few minutes.` Stop.
150
+ - Network error: `Could not reach {platform} — check network connection.` Stop.
151
+
152
+ ### Inline text mode
153
+
154
+ Use the provided text directly. No API call.
155
+
156
+ ### From file mode
157
+
158
+ Read the file content. Slug derived from filename (strip extension, strip date prefix if present).
159
+
160
+ ### Batch mode
161
+
162
+ Fetch N issues from the planning queue (same labels/statuses as `/clancy:plan`):
163
+
164
+ #### GitHub batch fetch
165
+ ```bash
166
+ GITHUB_USERNAME=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/user | jq -r '.login')
167
+
168
+ RESPONSE=$(curl -s \
169
+ -H "Authorization: Bearer $GITHUB_TOKEN" \
170
+ -H "X-GitHub-Api-Version: 2022-11-28" \
171
+ "https://api.github.com/repos/$GITHUB_REPO/issues?state=open&assignee=$GITHUB_USERNAME&labels=$CLANCY_PLAN_LABEL&per_page=$N")
172
+ ```
173
+
174
+ Filter out PRs (entries with `pull_request` key).
175
+
176
+ #### Jira batch fetch
177
+ ```bash
178
+ RESPONSE=$(curl -s \
179
+ -u "$JIRA_USER:$JIRA_API_TOKEN" \
180
+ -X POST \
181
+ -H "Content-Type: application/json" \
182
+ -H "Accept: application/json" \
183
+ "$JIRA_BASE_URL/rest/api/3/search/jql" \
184
+ -d '{"jql": "project=$JIRA_PROJECT_KEY AND assignee=currentUser() AND status=\"$CLANCY_PLAN_STATUS\" ORDER BY priority ASC", "maxResults": <N>, "fields": ["summary", "description", "status", "issuetype", "parent", "comment"]}')
185
+ ```
186
+
187
+ `CLANCY_PLAN_STATUS` defaults to `Backlog`.
188
+
189
+ #### Linear batch fetch
190
+ ```graphql
191
+ query {
192
+ viewer {
193
+ assignedIssues(
194
+ filter: {
195
+ state: { type: { eq: "unstarted" } }
196
+ team: { id: { eq: "$LINEAR_TEAM_ID" } }
197
+ }
198
+ first: $N
199
+ orderBy: priority
200
+ ) {
201
+ nodes {
202
+ id identifier title description
203
+ state { id name type }
204
+ parent { id identifier title }
205
+ children { nodes { id identifier title state { type } } }
206
+ team { id key }
207
+ }
208
+ }
209
+ }
210
+ }
211
+ ```
212
+
213
+ If no tickets found:
214
+ ```
215
+ No tickets in the planning queue. Check your queue label/status configuration.
216
+ ```
217
+ Stop.
218
+
219
+ For batch mode, process each ticket sequentially through Steps 4-10. Skip tickets that already have a brief (check `.clancy/briefs/`). Batch mode always uses AI-grill (no human interaction per ticket).
220
+
221
+ ---
222
+
223
+ ## Step 4 — Grill phase
224
+
225
+ The grill phase is the most critical part of the brief workflow. Its purpose is to walk every branch of the design tree, resolving ambiguity upfront rather than encoding it into vague tickets.
226
+
227
+ ### Mode detection
228
+
229
+ ```
230
+ --afk flag passed? -> AI-GRILL
231
+ CLANCY_MODE=afk in env? -> AI-GRILL
232
+ Batch mode (N tickets)? -> AI-GRILL
233
+ Otherwise -> HUMAN GRILL
234
+ ```
235
+
236
+ The `--afk` flag takes precedence over `CLANCY_MODE`.
237
+
238
+ ### Human grill
239
+
240
+ Interview the user RELENTLESSLY about every aspect of the idea until you reach a shared understanding.
241
+
242
+ **Core principle** (from Matt Pocock's "grill me" skill):
243
+
244
+ > "Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one by one. If a question can be answered by exploring the codebase, explore the codebase instead."
245
+
246
+ **Rules:**
247
+
248
+ 1. Be RELENTLESS. Do not accept vague answers. If the user says "it should be fast", ask "what's the latency budget? 100ms? 500ms? Per-request or p99?" If they say "just pick something", explain the trade-offs and make them choose.
249
+
250
+ 2. For each question, **provide your recommended answer** based on codebase context, board context, or best practices. The user can agree, disagree, or ask for more detail. This speeds up the grill — the user confirms or overrides rather than researching from scratch.
251
+
252
+ 3. Walk each branch of the design tree to its CONCLUSION before moving to the next. Don't jump between topics — follow each thread until it's fully resolved.
253
+
254
+ 4. Explore the codebase instead of asking when the answer is in the code. Don't ask "do you have an auth module?" — check. Then ask informed follow-ups: "I see `src/auth/sso-provider.ts` uses SAML. Should the new feature use the same provider?"
255
+
256
+ 5. This is a TWO-WAY conversation. The user can ask questions back at any time:
257
+ - "What does the codebase currently use?" → explore and answer
258
+ - "What do other projects typically do?" → web research
259
+ - "Are there related tickets?" → board query
260
+ - "What would you recommend?" → give an informed opinion with trade-offs, then let the user decide
261
+
262
+ 6. Answers spawn follow-up questions (multi-round): "We want SSO" → "SAML or OIDC?" → "OIDC" → "Which provider? No OIDC client in codebase yet."
263
+
264
+ 7. Do NOT generate the brief until the grill is complete. The goal is ZERO AMBIGUITY before a single ticket is written. Push back if the user tries to rush: "We still have open questions about X and Y. Let's resolve those first."
265
+
266
+ 8. Stop when you reach a SHARED UNDERSTANDING — both sides agree they understand the full scope, constraints, and decisions. Not just "no more questions" but genuine mutual comprehension.
267
+
268
+ 9. The resolved answers feed into the `## Discovery` section of the brief.
269
+
270
+ **Question categories:**
271
+ - **Scope:** What's in and what's out?
272
+ - **Users:** Who uses this? What are the personas?
273
+ - **Constraints:** Performance budget? Browser support? Auth?
274
+ - **Edge cases:** What happens when X is empty / fails / times out?
275
+ - **Dependencies:** Does this depend on other in-flight work?
276
+ - **Existing code:** How does this interact with `{module}`?
277
+ - **Data:** What's the data model? Volume? Retention?
278
+ - **Security:** Who can access this? What's the auth boundary?
279
+ - **Observability:** How will you know if this breaks?
280
+
281
+ Typical: 5-20 clarifying questions over 2-5 rounds.
282
+
283
+ ### AI-grill
284
+
285
+ Same relentless energy as the human grill, but directed at the strategist itself via a devil's advocate agent.
286
+
287
+ 1. Generate 10-15 clarifying questions using the same categories as the human grill (scope, users, constraints, edge cases, dependencies, existing code, data, security, observability).
288
+
289
+ 2. Spawn the devil's advocate agent via the Agent tool, passing:
290
+ - The idea text (ticket title + description, or inline text, or file content)
291
+ - The 10-15 generated questions
292
+ - The path to the agent prompt: `src/agents/devils-advocate.md`
293
+
294
+ 3. The devil's advocate agent answers each question by INTERROGATING ITS SOURCES:
295
+ - **Codebase:** explore affected areas, read `.clancy/docs/`, check existing patterns. Don't assume — look.
296
+ - **Board:** parent ticket, related tickets, existing children. Check for conflicting requirements.
297
+ - **Web:** when the question involves external technology, patterns, or third-party integrations. Same trigger as Step 6: `--research` flag forces it, otherwise judgement-based.
298
+
299
+ 4. The agent CHALLENGES ITS OWN ANSWERS. If the codebase says one thing but the ticket description says another, flag the conflict. If a question can be partially answered, answer the part it can and flag the rest. Do NOT accept vague self-answers — if the codebase doesn't clearly support a decision, don't guess.
300
+
301
+ 5. Answers may spawn SELF-FOLLOW-UPS within the same pass: "Should this support SSO?" → checks codebase → finds `src/auth/sso-provider.ts` → "SSO exists, but it's SAML. Should the new feature use SAML or add OIDC?" → checks ticket description → no mention → checks web → "OIDC is the modern standard" → resolves as OIDC with caveat. All resolved in one pass.
302
+
303
+ 6. Single pass — no multi-round loop with the human. But the agent must be thorough enough in one pass that a second would add nothing.
304
+
305
+ 7. The agent NEVER asks the human questions (that defeats `--afk` mode). Unresolvable questions go to `## Open Questions` for the PO to address during brief review.
306
+
307
+ 8. Classify each question:
308
+ - **Answerable** (>80% confidence, or technical decision with clear codebase precedent) → `## Discovery` with source tag
309
+ - **Conflicting evidence** (codebase says X, ticket says Y) → `## Open Questions` with conflict noted
310
+ - **Not answerable** (business decision, ambiguous requirements, no codebase precedent, involves money/legal/compliance/security policy) → `## Open Questions` for PO
311
+
312
+ Typical: 10-15 questions, 8-12 resolved, 2-4 open.
313
+
314
+ ### Output from both modes
315
+
316
+ Both grill modes produce a `## Discovery` section and an `## Open Questions` section. Each Q&A in Discovery includes a source tag:
317
+
318
+ ```
319
+ ## Discovery
320
+
321
+ Q: Should we support system preference detection?
322
+ A: Yes — the codebase already uses `prefers-color-scheme` in
323
+ `src/styles/media.ts`. (Source: codebase)
324
+
325
+ Q: Should dark mode persist across sessions?
326
+ A: Yes, store in localStorage. User confirmed. (Source: human)
327
+
328
+ Q: What's the industry standard for dark mode colour contrast?
329
+ A: WCAG AA requires 4.5:1 ratio for normal text. (Source: web)
330
+
331
+ ## Open Questions
332
+ - [ ] Should dark mode apply to emails/PDFs or just the web UI?
333
+ - [ ] Should portal users see all org data or only their team's?
334
+ (No RBAC policy found in codebase or ticket — needs PO input)
335
+ ```
336
+
337
+ Source tags: `(Source: human)`, `(Source: codebase)`, `(Source: board)`, `(Source: web)`
338
+
339
+ ---
340
+
341
+ ## Step 5 — Auto-detect existing brief
342
+
343
+ Scan `.clancy/briefs/` for an existing brief matching this idea:
344
+ - **Board ticket:** match by ticket key in the `**Source:**` line
345
+ - **Inline text / file:** match by slug in the filename
346
+
347
+ | Condition | Behaviour |
348
+ |---|---|
349
+ | No existing brief | Continue to Step 6 (fresh brief) |
350
+ | Existing brief + `--fresh` flag | Delete old file, continue to Step 6 |
351
+ | Existing brief + feedback found | Revise: read existing brief + all feedback, generate revised brief with `### Changes From Previous Brief` section |
352
+ | Existing brief + no feedback + no `--fresh` | Stop: `Already briefed. Add feedback to revise, or use --fresh to start over.` |
353
+
354
+ ### Feedback detection (3 sources, checked in order)
355
+
356
+ 1. **Local brief file** — check for `## Feedback` section appended to `.clancy/briefs/{date}-{slug}.md`
357
+ 2. **Companion file** — check for `.clancy/briefs/{date}-{slug}.feedback.md`
358
+ 3. **Board comments** (board-sourced only) — find the most recent `Clancy Strategic Brief` comment on the source ticket. Collect all comments posted AFTER it.
359
+
360
+ Board comment feedback filtering per platform:
361
+ - **GitHub:** comments where `created_at` > brief comment's `created_at` AND `user.login` != resolved username (via `GET /user`)
362
+ - **Jira:** comments where created timestamp > brief comment timestamp AND `author.accountId` != brief comment's `author.accountId`
363
+ - **Linear:** all comments posted after the brief comment are treated as feedback (Linear personal keys don't easily expose viewer ID)
364
+
365
+ Merge order: local `## Feedback` section first, then `.feedback.md` file, then board comments (chronological). All passed to generation step as additional context.
366
+
367
+ ### Edge cases
368
+
369
+ - **Board comment exists but local file is missing:** Re-download the brief from the board comment into `.clancy/briefs/`. Then check for feedback normally.
370
+ - **Local file exists but board comment was deleted:** Use local feedback only. No board feedback to read.
371
+ - **Multiple brief comments on same ticket:** Use the MOST RECENT (latest timestamp) as the reference point for feedback detection.
372
+
373
+ ---
374
+
375
+ ## Step 6 — Relevance check
376
+
377
+ Read `.clancy/docs/STACK.md` and `ARCHITECTURE.md` (if they exist). Compare the idea's domain against the codebase technology stack.
378
+
379
+ If the idea is clearly irrelevant (targets a platform or technology completely outside the codebase):
380
+ ```
381
+ Skipping — this idea targets {platform}, but this codebase is {stack}.
382
+ ```
383
+ Log: `YYYY-MM-DD HH:MM | BRIEF | {slug} | SKIPPED — not relevant ({reason})`
384
+ Stop.
385
+
386
+ If the idea mentions a technology not listed in STACK.md, flag it as a concern but do NOT skip — include a note in the brief's Technical Considerations section.
387
+
388
+ ---
389
+
390
+ ## Step 7 — Research (adaptive agents)
391
+
392
+ Assess complexity from the idea title + description:
393
+
394
+ | Complexity | Agents | Trigger |
395
+ |---|---|---|
396
+ | Narrow (single feature, few files) | 1 codebase agent | Simple scope |
397
+ | Moderate (multi-component, clear boundary) | 2 codebase agents | Medium scope |
398
+ | Broad (cross-cutting, multiple subsystems) | 3 codebase agents | Large scope |
399
+
400
+ Web research agent (adds 1 to the count above, max 4 total):
401
+ - `--research` flag → always add web agent
402
+ - Idea involves new/external technology → add web agent (judgement-based)
403
+ - Internal refactor → no web agent
404
+
405
+ ### What agents explore
406
+
407
+ - `.clancy/docs/` — STACK.md, ARCHITECTURE.md, CONVENTIONS.md, TESTING.md, DESIGN-SYSTEM.md
408
+ - Affected code areas via Glob + Read
409
+ - Board for duplicates/related tickets (text-match against title):
410
+ - **GitHub:** `GET /repos/$GITHUB_REPO/issues?state=open&per_page=30` and text-match
411
+ - **Jira:** `POST /rest/api/3/search/jql` with `summary ~ "keywords"`
412
+ - **Linear:** `issues(filter: ...)` by text search
413
+ - Existing children of the source ticket (board-sourced only):
414
+ - **GitHub:** scan open issues for `Epic: #{parent}` in body
415
+ - **Jira:** `POST /rest/api/3/search/jql` with `parent = {KEY}`
416
+ - **Linear:** already included in the fetch response (`children.nodes`)
417
+ - Web research (if triggered)
418
+
419
+ Display per-agent progress:
420
+ ```
421
+ Researching...
422
+ Agent 1: Codebase structure ✅
423
+ Agent 2: Testing patterns ✅
424
+ Agent 3: Web research ✅ (3 sources)
425
+ ```
426
+
427
+ ---
428
+
429
+ ## Step 8 — Generate brief
430
+
431
+ Using all gathered context (idea, grill output, research findings), generate the brief in this exact template:
432
+
433
+ ```markdown
434
+ # Clancy Strategic Brief
435
+
436
+ **Source:** {source — see below}
437
+ **Date:** {YYYY-MM-DD}
438
+ **Status:** Draft
439
+
440
+ ---
441
+
442
+ ## Problem Statement
443
+ {2-4 sentences: what problem does this solve and why does it matter?}
444
+
445
+ ## Goals
446
+ - {Specific, measurable goal}
447
+ - {Specific, measurable goal}
448
+
449
+ ## Non-Goals
450
+ - {What is explicitly out of scope}
451
+ - {What is explicitly out of scope}
452
+
453
+ ## Discovery
454
+ {Q&A pairs from the grill phase, each with source tag — see Step 4 output format}
455
+
456
+ ## Background Research
457
+ {Findings from codebase exploration and web research. Include file paths, patterns found, and external references.}
458
+
459
+ ## Related Existing Work
460
+ {Existing tickets, PRs, or code that overlaps with this idea. If the source ticket has children, list them here. "None found" if clean.}
461
+
462
+ ## User Stories
463
+ - As a {persona}, I want to {action} so that {outcome}.
464
+ - As a {persona}, I want to {action} so that {outcome}.
465
+ - As a {persona}, I want to {action} so that {outcome}.
466
+
467
+ ## Technical Considerations
468
+ - {Architectural decisions, patterns to follow, constraints}
469
+ - {Integration points, migration needs, backwards compatibility}
470
+ - {Performance, security, accessibility considerations}
471
+
472
+ ## Ticket Decomposition
473
+
474
+ | # | Title | Description | Size | Deps | Mode |
475
+ |---|-------|-------------|------|------|------|
476
+ | 1 | {Vertical slice title} | {1-2 sentences} | S | — | AFK |
477
+ | 2 | {Vertical slice title} | {1-2 sentences} | M | #1 | AFK |
478
+ | 3 | {Vertical slice title} | {1-2 sentences} | M | #1 | HITL |
479
+
480
+ ## Open Questions
481
+ - [ ] {Unresolved question from grill phase — with reason}
482
+ - [ ] {Unresolved question — needs PO input}
483
+
484
+ ## Success Criteria
485
+ - [ ] {Specific, testable criterion for the entire initiative}
486
+ - [ ] {Specific, testable criterion}
487
+
488
+ ## Risks
489
+ - {Specific risk and mitigation strategy}
490
+ - {Specific risk and mitigation strategy}
491
+
492
+ ---
493
+ *Generated by [Clancy](https://github.com/Pushedskydiver/clancy). To request changes: comment on the source ticket or add a ## Feedback section to the brief file, then re-run `/clancy:brief` to revise. To approve: `/clancy:approve-brief`. To start over: `/clancy:brief --fresh`.*
494
+ ```
495
+
496
+ ### Source field format
497
+
498
+ - **Board ticket:** `[{KEY}] {Title}` (e.g. `[#50] Redesign settings page`, `[PROJ-200] Add customer portal`, `[ENG-42] Add real-time notifications`)
499
+ - **Inline text:** `"{text}"` (e.g. `"Add dark mode support"`)
500
+ - **From file:** `{path}` (e.g. `docs/rfcs/auth-rework.md`)
501
+
502
+ ### Ticket Decomposition rules
503
+
504
+ 1. **Max 10 tickets.** If the idea needs more, note "Consider splitting this initiative into multiple briefs."
505
+ 2. **Vertical slices only.** Each ticket must cut through all layers needed to deliver one thin, working piece of functionality end-to-end. If a ticket title mentions only one layer (e.g. "Set up database schema", "Create React components"), restructure it into a slice that delivers observable behaviour.
506
+ 3. **Dependencies** reference other tickets in the table by `#N` (e.g. `#1`, `#1, #3`). Use `—` for no dependencies.
507
+ 4. **Size:** S (< 1 hour, few files), M (1-4 hours, moderate), L (4+ hours, significant).
508
+ 5. **Mode:**
509
+ - `AFK` — ticket can be implemented autonomously by `/clancy:once` or `/clancy:run`
510
+ - `HITL` — ticket requires human judgement, approval, or input (design decisions, credentials, external service setup, UX review, ambiguous requirements)
511
+ 6. Every ticket must trace to at least one user story.
512
+
513
+ ### User Story rules
514
+
515
+ - Write 3-8 user stories per brief (more = scope too large)
516
+ - Each story must be testable (implies acceptance criteria)
517
+ - Use the format: `As a {persona}, I want to {action} so that {outcome}.`
518
+
519
+ ### Re-brief revision
520
+
521
+ If revising from feedback (Step 5), prepend a section before Problem Statement:
522
+
523
+ ```markdown
524
+ ### Changes From Previous Brief
525
+ {What feedback was addressed and how the brief changed}
526
+ ```
527
+
528
+ ---
529
+
530
+ ## Step 9 — Save locally
531
+
532
+ Write to `.clancy/briefs/{YYYY-MM-DD}-{slug}.md`.
533
+
534
+ **Slug generation:**
535
+ - **Board ticket:** derive from title — lowercase, replace non-alphanumeric with hyphens, trim, truncate to 50 chars. E.g. `add-customer-portal`.
536
+ - **Inline text:** derive from the text — same rules.
537
+ - **From file:** derive from filename — strip extension, strip date prefix if present.
538
+
539
+ **Slug collision:** If file already exists, append `-2`, `-3`, etc.
540
+
541
+ **Create `.clancy/briefs/` directory** if it does not exist.
542
+
543
+ ---
544
+
545
+ ## Step 10 — Post to board
546
+
547
+ Only for board-sourced briefs (ticket key was provided). Inline text and file briefs are local only.
548
+
549
+ ### GitHub — POST comment
550
+
551
+ ```bash
552
+ curl -s \
553
+ -H "Authorization: Bearer $GITHUB_TOKEN" \
554
+ -H "X-GitHub-Api-Version: 2022-11-28" \
555
+ -X POST \
556
+ "https://api.github.com/repos/$GITHUB_REPO/issues/$ISSUE_NUMBER/comments" \
557
+ -d '{"body": "<full brief markdown>"}'
558
+ ```
559
+
560
+ GitHub accepts Markdown directly.
561
+
562
+ ### Jira — POST comment
563
+
564
+ ```bash
565
+ curl -s \
566
+ -u "$JIRA_USER:$JIRA_API_TOKEN" \
567
+ -X POST \
568
+ -H "Content-Type: application/json" \
569
+ -H "Accept: application/json" \
570
+ "$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY/comment" \
571
+ -d '<ADF JSON body>'
572
+ ```
573
+
574
+ Construct ADF (Atlassian Document Format) JSON for the comment body:
575
+ - `## Heading` → `heading` node (level 2)
576
+ - `### Heading` → `heading` node (level 3)
577
+ - `- bullet` → `bulletList > listItem > paragraph`
578
+ - `| table |` → `table > tableRow > tableCell`
579
+ - `**bold**` → marks: `[{ "type": "strong" }]`
580
+ - `` `code` `` → marks: `[{ "type": "code" }]`
581
+
582
+ If ADF construction is too complex for a particular element, fall back to wrapping that section in a `codeBlock` node.
583
+
584
+ Comment marker heading: `## Clancy Strategic Brief` (H2 ADF heading node).
585
+
586
+ ### Linear — commentCreate mutation
587
+
588
+ ```bash
589
+ curl -s \
590
+ -X POST \
591
+ -H "Content-Type: application/json" \
592
+ -H "Authorization: $LINEAR_API_KEY" \
593
+ "https://api.linear.app/graphql" \
594
+ -d '{"query": "mutation { commentCreate(input: { issueId: \"$ISSUE_ID\", body: \"<full brief markdown>\" }) { success } }"}'
595
+ ```
596
+
597
+ Linear accepts Markdown directly. Comment marker heading: `# Clancy Strategic Brief`.
598
+
599
+ Note: Linear personal API keys do NOT use `Bearer` prefix.
600
+
601
+ ### On failure (any platform)
602
+
603
+ ```
604
+ ⚠️ Failed to post brief comment on {KEY}. Brief saved locally at .clancy/briefs/{file}. Paste it manually.
605
+ ```
606
+
607
+ Continue — do not stop. The local file is the source of truth.
608
+
609
+ ---
610
+
611
+ ## Step 11 — Brief inventory (`--list`)
612
+
613
+ If `--list` flag is present, display an inventory of all briefs and stop.
614
+
615
+ Scan `.clancy/briefs/` for all `.md` files. For each file:
616
+ - Parse date from filename prefix (`YYYY-MM-DD-slug.md`)
617
+ - Parse `**Source:**` line
618
+ - Parse Status (check for `.approved` marker file)
619
+ - Parse ticket count from decomposition table (`?` if unparseable)
620
+ - Calculate age (today - date)
621
+ - Check stale: unapproved + age > 7 days
622
+
623
+ Sort by date (newest first). Display:
624
+
625
+ ```
626
+ Clancy — Briefs
627
+ ================================================================
628
+
629
+ [1] dark-mode-support 2026-03-14 Draft 3 tickets Source: #50
630
+ [2] customer-portal 2026-03-13 Approved 8 tickets Source: PROJ-200 ✅
631
+ [3] real-time-notifications 2026-03-12 Draft 4 tickets Source: ENG-42
632
+ [4] auth-rework 2026-03-05 Draft 6 tickets Source: file STALE (9 days)
633
+
634
+ 3 unapproved drafts. 1 stale (>7 days).
635
+
636
+ To approve: /clancy:approve-brief <slug or index>
637
+ To review stale briefs: open the file and add ## Feedback, or delete it.
638
+ ```
639
+
640
+ If `.clancy/briefs/` does not exist or is empty:
641
+ ```
642
+ No briefs found. Run /clancy:brief to create one.
643
+ ```
644
+
645
+ Stop.
646
+
647
+ ---
648
+
649
+ ## Step 12 — Display
650
+
651
+ Print the full brief to stdout, followed by the sign-off:
652
+
653
+ ```
654
+ "I'm going to need to ask you some questions, and I want them answered immediately."
655
+ ```
656
+
657
+ ### Next steps (board-sourced)
658
+
659
+ ```
660
+ Next steps:
661
+ To request changes:
662
+ • Comment on {KEY} on your board, then re-run /clancy:brief {KEY} to revise
663
+ • Or add a ## Feedback section to the brief file and re-run
664
+ To approve: /clancy:approve-brief {KEY}
665
+ To start over: /clancy:brief --fresh {KEY}
666
+ ```
667
+
668
+ ### Next steps (inline text / from file)
669
+
670
+ ```
671
+ Next steps:
672
+ To request changes:
673
+ • Add a ## Feedback section to:
674
+ .clancy/briefs/{date}-{slug}.md
675
+ • Or create a companion file:
676
+ .clancy/briefs/{date}-{slug}.feedback.md
677
+ Then re-run /clancy:brief to revise.
678
+ To approve: /clancy:approve-brief {slug}
679
+ To attach to a parent: /clancy:approve-brief {slug} --epic {KEY}
680
+ To start over: /clancy:brief --fresh
681
+ ```
682
+
683
+ ---
684
+
685
+ ## Step 13 — Log
686
+
687
+ Append to `.clancy/progress.txt`:
688
+
689
+ | Outcome | Log entry |
690
+ |---|---|
691
+ | Brief generated | `YYYY-MM-DD HH:MM \| BRIEF \| {slug} \| {N} proposed tickets` |
692
+ | Brief revised (from feedback) | `YYYY-MM-DD HH:MM \| BRIEF \| {slug} \| REVISED - {N} proposed tickets` |
693
+ | Brief skipped (not relevant) | `YYYY-MM-DD HH:MM \| BRIEF \| {slug} \| SKIPPED - not relevant ({reason})` |
694
+ | Brief skipped (ticket Done) | `YYYY-MM-DD HH:MM \| BRIEF \| {slug} \| SKIPPED - ticket is Done` |
695
+ | Brief skipped (not found) | `YYYY-MM-DD HH:MM \| BRIEF \| {slug} \| SKIPPED - ticket not found` |
696
+ | Already briefed (no feedback) | (nothing logged) |
697
+ | `--list` display | (nothing logged) |
698
+ | Auth/network failure | (nothing logged) |
699
+
700
+ ---
701
+
702
+ ## Step 14 — Batch summary
703
+
704
+ After all tickets in a batch are processed, display:
705
+
706
+ ```
707
+ Briefed {M} of {N} tickets. {K} skipped.
708
+
709
+ ✅ [{KEY1}] {Title} — 4 tickets proposed
710
+ ✅ [{KEY2}] {Title} — 6 tickets proposed
711
+ ⏭️ [{KEY3}] {Title} — already briefed
712
+ ⏭️ [{KEY4}] {Title} — not relevant
713
+
714
+ Briefs saved to .clancy/briefs/. Run /clancy:approve-brief to create tickets.
715
+ ```
716
+
717
+ ---
718
+
719
+ ## Notes
720
+
721
+ - This command does NOT create tickets — it generates briefs only. Ticket creation is `/clancy:approve-brief`.
722
+ - Briefs are saved locally in `.clancy/briefs/` and optionally posted as comments on the source ticket.
723
+ - The grill phase is the most important part — do not skip or rush it. Zero ambiguity is the goal.
724
+ - Re-running without `--fresh` auto-detects feedback: if feedback exists, revises; if no feedback, stops with guidance.
725
+ - The `--fresh` flag discards the existing brief entirely and generates a new one from scratch.
726
+ - The `--list` flag is an inventory display only — no brief generated, no API calls beyond the local filesystem.
727
+ - Batch mode (`/clancy:brief 3`) implies AI-grill — each ticket is briefed autonomously.
728
+ - All board API calls are best-effort — if a comment fails to post, print the brief and warn. The local file is the source of truth.
729
+ - The `## Clancy Strategic Brief` marker in comments is used by both `/clancy:brief` (to detect existing briefs) and `/clancy:approve-brief` (to find the brief).
730
+ - Jira uses ADF for comments (with `codeBlock` fallback). GitHub and Linear accept Markdown directly.
731
+ - Linear personal API keys do NOT use `Bearer` prefix.
732
+ - Jira uses the new `POST /rest/api/3/search/jql` endpoint (old GET `/search` removed Aug 2025).