chief-clancy 0.7.3 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/bundle/clancy-once.js +94 -45
- package/package.json +1 -1
- package/src/roles/planner/workflows/approve-plan.md +98 -43
- package/src/roles/planner/workflows/plan.md +7 -6
- package/src/roles/setup/workflows/init.md +68 -0
- package/src/roles/setup/workflows/scaffold.md +30 -0
- package/src/roles/setup/workflows/settings.md +62 -0
- package/src/roles/strategist/workflows/approve-brief.md +70 -6
- package/src/roles/strategist/workflows/brief.md +136 -0
- package/src/templates/.env.example.github +10 -0
- package/src/templates/.env.example.jira +10 -0
- package/src/templates/.env.example.linear +10 -0
package/package.json
CHANGED
|
@@ -314,25 +314,29 @@ Could not update plan comment. The plan is still promoted to the description.
|
|
|
314
314
|
|
|
315
315
|
---
|
|
316
316
|
|
|
317
|
-
## Step 6 — Post-approval transition
|
|
317
|
+
## Step 6 — Post-approval label transition
|
|
318
318
|
|
|
319
|
-
Transition the ticket from the planning queue to the implementation queue. This is **best-effort** — warn on failure, continue.
|
|
319
|
+
Transition the ticket from the planning queue to the implementation queue via pipeline labels. This is **best-effort** — warn on failure, continue.
|
|
320
320
|
|
|
321
|
-
|
|
321
|
+
**Crash safety:** Add the new label BEFORE removing the old one. A ticket briefly has two labels (harmless) rather than zero labels (ticket lost).
|
|
322
322
|
|
|
323
|
-
|
|
323
|
+
Read `CLANCY_LABEL_BUILD` from `.clancy/.env` (default: `clancy:build`). Read `CLANCY_LABEL_PLAN` from `.clancy/.env` (default: `clancy:plan`, falls back to `CLANCY_PLAN_LABEL`).
|
|
324
|
+
|
|
325
|
+
### GitHub
|
|
326
|
+
|
|
327
|
+
1. **Add build label** (ensure it exists first):
|
|
324
328
|
```bash
|
|
329
|
+
# Ensure label exists (ignore 422 = already exists)
|
|
325
330
|
curl -s \
|
|
326
331
|
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
|
327
332
|
-H "Accept: application/vnd.github+json" \
|
|
328
333
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
329
|
-
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
334
|
+
-H "Content-Type: application/json" \
|
|
335
|
+
-X POST \
|
|
336
|
+
"https://api.github.com/repos/$GITHUB_REPO/labels" \
|
|
337
|
+
-d '{"name": "$CLANCY_LABEL_BUILD", "color": "0075ca"}'
|
|
333
338
|
|
|
334
|
-
|
|
335
|
-
```bash
|
|
339
|
+
# Add to issue
|
|
336
340
|
curl -s \
|
|
337
341
|
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
|
338
342
|
-H "Accept: application/vnd.github+json" \
|
|
@@ -340,38 +344,68 @@ Transition the ticket from the planning queue to the implementation queue. This
|
|
|
340
344
|
-H "Content-Type: application/json" \
|
|
341
345
|
-X POST \
|
|
342
346
|
"https://api.github.com/repos/$GITHUB_REPO/issues/$ISSUE_NUMBER/labels" \
|
|
343
|
-
-d '{"labels": ["$
|
|
347
|
+
-d '{"labels": ["$CLANCY_LABEL_BUILD"]}'
|
|
344
348
|
```
|
|
345
|
-
|
|
349
|
+
|
|
350
|
+
2. **Remove plan label:**
|
|
346
351
|
```bash
|
|
347
352
|
curl -s \
|
|
348
353
|
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
|
349
354
|
-H "Accept: application/vnd.github+json" \
|
|
355
|
+
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
356
|
+
-X DELETE \
|
|
357
|
+
"https://api.github.com/repos/$GITHUB_REPO/issues/$ISSUE_NUMBER/labels/$(echo $CLANCY_LABEL_PLAN | jq -Rr @uri)"
|
|
358
|
+
```
|
|
359
|
+
Ignore 404 (label not on issue).
|
|
360
|
+
|
|
361
|
+
### Jira
|
|
362
|
+
|
|
363
|
+
1. **Add build label** (Jira auto-creates labels):
|
|
364
|
+
```bash
|
|
365
|
+
# Fetch current labels
|
|
366
|
+
CURRENT_LABELS=$(curl -s \
|
|
367
|
+
-u "$JIRA_USER:$JIRA_API_TOKEN" \
|
|
368
|
+
-H "Accept: application/json" \
|
|
369
|
+
"$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY?fields=labels" | jq -r '.fields.labels')
|
|
370
|
+
|
|
371
|
+
# Add build label
|
|
372
|
+
UPDATED_LABELS=$(echo "$CURRENT_LABELS" | jq --arg build "$CLANCY_LABEL_BUILD" '. + [$build] | unique')
|
|
373
|
+
|
|
374
|
+
curl -s \
|
|
375
|
+
-u "$JIRA_USER:$JIRA_API_TOKEN" \
|
|
376
|
+
-X PUT \
|
|
350
377
|
-H "Content-Type: application/json" \
|
|
351
|
-
|
|
352
|
-
"
|
|
353
|
-
-d '{"name": "$CLANCY_LABEL", "color": "0075ca"}'
|
|
378
|
+
"$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY" \
|
|
379
|
+
-d "{\"fields\": {\"labels\": $UPDATED_LABELS}}"
|
|
354
380
|
```
|
|
355
|
-
If 403 (no admin access) or 422 (invalid name): warn, continue without label.
|
|
356
381
|
|
|
357
|
-
|
|
382
|
+
2. **Remove plan label:**
|
|
383
|
+
```bash
|
|
384
|
+
# Re-fetch labels (may have changed), remove plan label
|
|
385
|
+
CURRENT_LABELS=$(curl -s \
|
|
386
|
+
-u "$JIRA_USER:$JIRA_API_TOKEN" \
|
|
387
|
+
-H "Accept: application/json" \
|
|
388
|
+
"$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY?fields=labels" | jq -r '.fields.labels')
|
|
358
389
|
|
|
359
|
-
|
|
390
|
+
UPDATED_LABELS=$(echo "$CURRENT_LABELS" | jq --arg plan "$CLANCY_LABEL_PLAN" '[.[] | select(. != $plan)]')
|
|
360
391
|
|
|
361
|
-
|
|
392
|
+
curl -s \
|
|
393
|
+
-u "$JIRA_USER:$JIRA_API_TOKEN" \
|
|
394
|
+
-X PUT \
|
|
395
|
+
-H "Content-Type: application/json" \
|
|
396
|
+
"$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY" \
|
|
397
|
+
-d "{\"fields\": {\"labels\": $UPDATED_LABELS}}"
|
|
398
|
+
```
|
|
362
399
|
|
|
363
|
-
|
|
400
|
+
3. **Status transition** (only if `CLANCY_STATUS_PLANNED` is set — skip if unset):
|
|
364
401
|
```bash
|
|
402
|
+
# Fetch transitions
|
|
365
403
|
curl -s \
|
|
366
404
|
-u "$JIRA_USER:$JIRA_API_TOKEN" \
|
|
367
405
|
-H "Accept: application/json" \
|
|
368
406
|
"$JIRA_BASE_URL/rest/api/3/issue/$TICKET_KEY/transitions"
|
|
369
|
-
```
|
|
370
407
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
3. **Execute transition:**
|
|
374
|
-
```bash
|
|
408
|
+
# Find matching transition and execute
|
|
375
409
|
curl -s \
|
|
376
410
|
-u "$JIRA_USER:$JIRA_API_TOKEN" \
|
|
377
411
|
-X POST \
|
|
@@ -385,23 +419,50 @@ On failure:
|
|
|
385
419
|
Could not transition ticket. Move it manually to your implementation queue.
|
|
386
420
|
```
|
|
387
421
|
|
|
388
|
-
### Linear
|
|
422
|
+
### Linear
|
|
423
|
+
|
|
424
|
+
1. **Add build label** (ensure it exists, then add):
|
|
425
|
+
```graphql
|
|
426
|
+
# Ensure label exists — check team labels, workspace labels, create if missing
|
|
427
|
+
mutation {
|
|
428
|
+
issueLabelCreate(input: {
|
|
429
|
+
teamId: "$LINEAR_TEAM_ID"
|
|
430
|
+
name: "$CLANCY_LABEL_BUILD"
|
|
431
|
+
color: "#0075ca"
|
|
432
|
+
}) { success issueLabel { id } }
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
# Fetch current label IDs on the issue, add build label ID
|
|
436
|
+
mutation {
|
|
437
|
+
issueUpdate(
|
|
438
|
+
id: "$ISSUE_UUID"
|
|
439
|
+
input: { labelIds: [...currentLabelIds, buildLabelId] }
|
|
440
|
+
) { success }
|
|
441
|
+
}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
2. **Remove plan label:**
|
|
445
|
+
```graphql
|
|
446
|
+
# Fetch current label IDs, filter out plan label ID
|
|
447
|
+
mutation {
|
|
448
|
+
issueUpdate(
|
|
449
|
+
id: "$ISSUE_UUID"
|
|
450
|
+
input: { labelIds: [currentLabelIds without planLabelId] }
|
|
451
|
+
) { success }
|
|
452
|
+
}
|
|
453
|
+
```
|
|
389
454
|
|
|
390
|
-
|
|
455
|
+
3. **State transition** (always):
|
|
391
456
|
```graphql
|
|
457
|
+
# Resolve "unstarted" state
|
|
392
458
|
query {
|
|
393
459
|
workflowStates(filter: {
|
|
394
460
|
team: { id: { eq: "$LINEAR_TEAM_ID" } }
|
|
395
461
|
type: { eq: "unstarted" }
|
|
396
|
-
}) {
|
|
397
|
-
nodes { id name }
|
|
398
|
-
}
|
|
462
|
+
}) { nodes { id name } }
|
|
399
463
|
}
|
|
400
|
-
```
|
|
401
|
-
Use `nodes[0].id` as the target state. If nodes is empty: warn `No 'unstarted' state found for team.` Skip transition.
|
|
402
464
|
|
|
403
|
-
|
|
404
|
-
```graphql
|
|
465
|
+
# Transition
|
|
405
466
|
mutation {
|
|
406
467
|
issueUpdate(
|
|
407
468
|
id: "$ISSUE_UUID"
|
|
@@ -409,6 +470,7 @@ Could not transition ticket. Move it manually to your implementation queue.
|
|
|
409
470
|
) { success }
|
|
410
471
|
}
|
|
411
472
|
```
|
|
473
|
+
If no `unstarted` state found: warn, skip transition.
|
|
412
474
|
|
|
413
475
|
On failure:
|
|
414
476
|
```
|
|
@@ -421,20 +483,13 @@ Could not transition ticket. Move it manually to your implementation queue.
|
|
|
421
483
|
|
|
422
484
|
On success, display a board-specific message:
|
|
423
485
|
|
|
424
|
-
**GitHub
|
|
486
|
+
**GitHub:**
|
|
425
487
|
```
|
|
426
|
-
Plan promoted. Label swapped: {
|
|
488
|
+
Plan promoted. Label swapped: {CLANCY_LABEL_PLAN} → {CLANCY_LABEL_BUILD}. Ready for /clancy:once.
|
|
427
489
|
|
|
428
490
|
"Book 'em, Lou." — The ticket is ready for /clancy:once.
|
|
429
491
|
```
|
|
430
492
|
|
|
431
|
-
**GitHub (without CLANCY_LABEL):**
|
|
432
|
-
```
|
|
433
|
-
Plan promoted. Label removed: {plan_label}. Add your implementation label manually, or run /clancy:once.
|
|
434
|
-
|
|
435
|
-
"Book 'em, Lou."
|
|
436
|
-
```
|
|
437
|
-
|
|
438
493
|
**Jira (with transition):**
|
|
439
494
|
```
|
|
440
495
|
Plan promoted. Ticket transitioned to {CLANCY_STATUS_PLANNED}.
|
|
@@ -136,9 +136,9 @@ Then skip to Step 3b with this single ticket.
|
|
|
136
136
|
Build the JQL using planning-specific env vars:
|
|
137
137
|
- `CLANCY_PLAN_STATUS` defaults to `Backlog` if not set
|
|
138
138
|
- Sprint clause: include `AND sprint in openSprints()` if `CLANCY_JQL_SPRINT` is set
|
|
139
|
-
- Label clause: include `AND labels = "$CLANCY_LABEL"` if `CLANCY_LABEL` is set
|
|
139
|
+
- Label clause: include `AND labels = "$CLANCY_LABEL_PLAN"` if `CLANCY_LABEL_PLAN` is set (falls back to `CLANCY_PLAN_LABEL` if `CLANCY_LABEL_PLAN` is not set). If neither is set, include `AND labels = "$CLANCY_LABEL"` if `CLANCY_LABEL` is set.
|
|
140
140
|
|
|
141
|
-
Full JQL: `project=$JIRA_PROJECT_KEY [AND sprint in openSprints()] [AND labels = "$
|
|
141
|
+
Full JQL: `project=$JIRA_PROJECT_KEY [AND sprint in openSprints()] [AND labels = "$CLANCY_LABEL_PLAN"] AND assignee=currentUser() AND status="$CLANCY_PLAN_STATUS" ORDER BY priority ASC`
|
|
142
142
|
|
|
143
143
|
```bash
|
|
144
144
|
RESPONSE=$(curl -s \
|
|
@@ -164,16 +164,16 @@ Then fetch issues:
|
|
|
164
164
|
RESPONSE=$(curl -s \
|
|
165
165
|
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
|
166
166
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
167
|
-
"https://api.github.com/repos/$GITHUB_REPO/issues?state=open&assignee=$GITHUB_USERNAME&labels=$
|
|
167
|
+
"https://api.github.com/repos/$GITHUB_REPO/issues?state=open&assignee=$GITHUB_USERNAME&labels=$CLANCY_LABEL_PLAN&per_page=<N>")
|
|
168
168
|
```
|
|
169
169
|
|
|
170
|
-
- `
|
|
170
|
+
- `CLANCY_LABEL_PLAN` is the pipeline label for the planning queue (default: `clancy:plan`). Falls back to `CLANCY_PLAN_LABEL` if `CLANCY_LABEL_PLAN` is not set. If neither is set, defaults to `needs-refinement`.
|
|
171
171
|
- Filter out PRs (entries with `pull_request` key)
|
|
172
172
|
- For each issue, fetch comments: `GET /repos/$GITHUB_REPO/issues/{number}/comments`
|
|
173
173
|
|
|
174
174
|
#### Linear
|
|
175
175
|
|
|
176
|
-
Build the filter using `CLANCY_PLAN_STATE_TYPE` (defaults to `backlog` if not set):
|
|
176
|
+
Build the filter using `CLANCY_PLAN_STATE_TYPE` (defaults to `backlog` if not set). If `CLANCY_LABEL_PLAN` is set (falls back to `CLANCY_PLAN_LABEL`), add a label filter to the query:
|
|
177
177
|
|
|
178
178
|
```graphql
|
|
179
179
|
query {
|
|
@@ -182,6 +182,7 @@ query {
|
|
|
182
182
|
filter: {
|
|
183
183
|
state: { type: { eq: "$CLANCY_PLAN_STATE_TYPE" } }
|
|
184
184
|
team: { id: { eq: "$LINEAR_TEAM_ID" } }
|
|
185
|
+
labels: { name: { eq: "$CLANCY_LABEL_PLAN" } } # Only if CLANCY_LABEL_PLAN is set
|
|
185
186
|
}
|
|
186
187
|
first: $N
|
|
187
188
|
orderBy: priority
|
|
@@ -214,7 +215,7 @@ If no tickets found:
|
|
|
214
215
|
|
|
215
216
|
Then display board-specific guidance:
|
|
216
217
|
|
|
217
|
-
- **GitHub:** `For GitHub: planning uses the "$
|
|
218
|
+
- **GitHub:** `For GitHub: planning uses the "$CLANCY_LABEL_PLAN" label (default: clancy:plan, fallback: $CLANCY_PLAN_LABEL or needs-refinement). Apply that label to issues you want planned.`
|
|
218
219
|
- **Jira:** `Check that CLANCY_PLAN_STATUS (currently: "$CLANCY_PLAN_STATUS") matches a status in your Jira project, and that tickets in that status are assigned to you.`
|
|
219
220
|
- **Linear:** `Check that CLANCY_PLAN_STATE_TYPE (currently: "$CLANCY_PLAN_STATE_TYPE") is a valid Linear state type (backlog, unstarted, started, completed, canceled, triage), and that tickets in that state are assigned to you in team $LINEAR_TEAM_ID.`
|
|
220
221
|
|
|
@@ -592,6 +592,74 @@ Note: as more roles are added in future versions, they appear as additional numb
|
|
|
592
592
|
|
|
593
593
|
---
|
|
594
594
|
|
|
595
|
+
## Step 4c-2 — Pipeline labels (conditional)
|
|
596
|
+
|
|
597
|
+
Only ask this if any optional role was enabled in Step 4c. If neither Planner nor Strategist was selected, skip this section entirely. If `CLANCY_LABEL` or `CLANCY_PLAN_LABEL` are already set in `.clancy/.env`, show:
|
|
598
|
+
|
|
599
|
+
```
|
|
600
|
+
Note: CLANCY_LABEL and CLANCY_PLAN_LABEL are deprecated.
|
|
601
|
+
Use CLANCY_LABEL_BUILD and CLANCY_LABEL_PLAN instead.
|
|
602
|
+
Your existing values will continue to work as fallbacks.
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
**If the user enabled Strategist (or both Strategist + Planner):**
|
|
606
|
+
|
|
607
|
+
Output:
|
|
608
|
+
|
|
609
|
+
```
|
|
610
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
611
|
+
Pipeline Labels
|
|
612
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
613
|
+
|
|
614
|
+
Clancy uses labels to move tickets through pipeline stages:
|
|
615
|
+
brief → plan → build
|
|
616
|
+
|
|
617
|
+
Each label marks which queue a ticket belongs to.
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
Then ask each label in order:
|
|
621
|
+
|
|
622
|
+
```
|
|
623
|
+
What label marks tickets that have been briefed (awaiting approval)?
|
|
624
|
+
[clancy:brief]
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
If a value is entered: store as `CLANCY_LABEL_BRIEF` in `.clancy/.env`. Wrap in double quotes.
|
|
628
|
+
If enter is pressed: use default — store `CLANCY_LABEL_BRIEF="clancy:brief"` in `.clancy/.env`.
|
|
629
|
+
|
|
630
|
+
```
|
|
631
|
+
What label marks tickets that need planning?
|
|
632
|
+
[clancy:plan]
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
If a value is entered: store as `CLANCY_LABEL_PLAN` in `.clancy/.env`. Wrap in double quotes.
|
|
636
|
+
If enter is pressed: use default — store `CLANCY_LABEL_PLAN="clancy:plan"` in `.clancy/.env`.
|
|
637
|
+
|
|
638
|
+
```
|
|
639
|
+
What label marks tickets ready to build?
|
|
640
|
+
[clancy:build]
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
If a value is entered: store as `CLANCY_LABEL_BUILD` in `.clancy/.env`. Wrap in double quotes.
|
|
644
|
+
If enter is pressed: use default — store `CLANCY_LABEL_BUILD="clancy:build"` in `.clancy/.env`.
|
|
645
|
+
|
|
646
|
+
**If the user enabled Planner only (no Strategist):**
|
|
647
|
+
|
|
648
|
+
Skip `CLANCY_LABEL_BRIEF` (no `/clancy:brief` command). Ask only:
|
|
649
|
+
|
|
650
|
+
```
|
|
651
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
652
|
+
Pipeline Labels
|
|
653
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
654
|
+
|
|
655
|
+
Clancy uses labels to move tickets through pipeline stages:
|
|
656
|
+
plan → build
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
Then ask `CLANCY_LABEL_PLAN` and `CLANCY_LABEL_BUILD` using the same prompts and defaults as above.
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
595
663
|
## Step 4d (if Planner role selected): Planning queue config
|
|
596
664
|
|
|
597
665
|
Only ask this if the user selected Planner in Step 4c above (or if re-running init and `CLANCY_ROLES` already includes `planner`).
|
|
@@ -396,6 +396,16 @@ MAX_ITERATIONS=5
|
|
|
396
396
|
# CLANCY_GIT_PLATFORM=gitlab # override auto-detection (github/gitlab/bitbucket)
|
|
397
397
|
# CLANCY_GIT_API_URL=https://gitlab.example.com/api/v4 # self-hosted git API base URL
|
|
398
398
|
|
|
399
|
+
# ─── Optional: Pipeline labels ────────────────────────────────────────────────
|
|
400
|
+
# Labels that control ticket flow through pipeline stages.
|
|
401
|
+
# CLANCY_LABEL_BRIEF marks tickets that have been briefed (awaiting approval).
|
|
402
|
+
# CLANCY_LABEL_PLAN marks tickets that need planning.
|
|
403
|
+
# CLANCY_LABEL_BUILD marks tickets ready for implementation.
|
|
404
|
+
# Deprecated: CLANCY_LABEL (use CLANCY_LABEL_BUILD), CLANCY_PLAN_LABEL (use CLANCY_LABEL_PLAN)
|
|
405
|
+
# CLANCY_LABEL_BRIEF="clancy:brief"
|
|
406
|
+
# CLANCY_LABEL_PLAN="clancy:plan"
|
|
407
|
+
# CLANCY_LABEL_BUILD="clancy:build"
|
|
408
|
+
|
|
399
409
|
# ─── Optional: Rework loop ──────────────────────────────────────────────────
|
|
400
410
|
# PR-based rework is automatic — when a reviewer leaves inline comments or
|
|
401
411
|
# a conversation comment prefixed with "Rework:", Clancy picks it up on the
|
|
@@ -502,6 +512,16 @@ MAX_ITERATIONS=20
|
|
|
502
512
|
# PLAYWRIGHT_STORYBOOK_PORT=6006
|
|
503
513
|
# PLAYWRIGHT_STARTUP_WAIT=15
|
|
504
514
|
|
|
515
|
+
# ─── Optional: Pipeline labels ────────────────────────────────────────────────
|
|
516
|
+
# Labels that control ticket flow through pipeline stages.
|
|
517
|
+
# CLANCY_LABEL_BRIEF marks tickets that have been briefed (awaiting approval).
|
|
518
|
+
# CLANCY_LABEL_PLAN marks tickets that need planning.
|
|
519
|
+
# CLANCY_LABEL_BUILD marks tickets ready for implementation.
|
|
520
|
+
# Deprecated: CLANCY_LABEL (use CLANCY_LABEL_BUILD), CLANCY_PLAN_LABEL (use CLANCY_LABEL_PLAN)
|
|
521
|
+
# CLANCY_LABEL_BRIEF="clancy:brief"
|
|
522
|
+
# CLANCY_LABEL_PLAN="clancy:plan"
|
|
523
|
+
# CLANCY_LABEL_BUILD="clancy:build"
|
|
524
|
+
|
|
505
525
|
# ─── Optional: Rework loop ──────────────────────────────────────────────────
|
|
506
526
|
# PR-based rework is automatic — when a reviewer leaves inline comments or
|
|
507
527
|
# a conversation comment prefixed with "Rework:", Clancy picks it up on the
|
|
@@ -636,6 +656,16 @@ MAX_ITERATIONS=20
|
|
|
636
656
|
# CLANCY_GIT_PLATFORM=gitlab # override auto-detection (github/gitlab/bitbucket)
|
|
637
657
|
# CLANCY_GIT_API_URL=https://gitlab.example.com/api/v4 # self-hosted git API base URL
|
|
638
658
|
|
|
659
|
+
# ─── Optional: Pipeline labels ────────────────────────────────────────────────
|
|
660
|
+
# Labels that control ticket flow through pipeline stages.
|
|
661
|
+
# CLANCY_LABEL_BRIEF marks tickets that have been briefed (awaiting approval).
|
|
662
|
+
# CLANCY_LABEL_PLAN marks tickets that need planning.
|
|
663
|
+
# CLANCY_LABEL_BUILD marks tickets ready for implementation.
|
|
664
|
+
# Deprecated: CLANCY_LABEL (use CLANCY_LABEL_BUILD), CLANCY_PLAN_LABEL (use CLANCY_LABEL_PLAN)
|
|
665
|
+
# CLANCY_LABEL_BRIEF="clancy:brief"
|
|
666
|
+
# CLANCY_LABEL_PLAN="clancy:plan"
|
|
667
|
+
# CLANCY_LABEL_BUILD="clancy:build"
|
|
668
|
+
|
|
639
669
|
# ─── Optional: Reliable autonomous mode ───────────────────────────────────────
|
|
640
670
|
# Max self-healing attempts after verification failure (default: 2, range 0-5)
|
|
641
671
|
# CLANCY_FIX_RETRIES=2
|
|
@@ -86,6 +86,14 @@ Strategist
|
|
|
86
86
|
[T2] Issue type {CLANCY_BRIEF_ISSUE_TYPE:-Task}
|
|
87
87
|
[T3] Component {CLANCY_COMPONENT if set, else "off"}
|
|
88
88
|
|
|
89
|
+
{If Planner or Strategist enabled:}
|
|
90
|
+
Pipeline Labels
|
|
91
|
+
[L1] Brief label {CLANCY_LABEL_BRIEF if set, else "clancy:brief"} (Strategist only)
|
|
92
|
+
[L2] Plan label {CLANCY_LABEL_PLAN if set, else "clancy:plan"}
|
|
93
|
+
[L3] Build label {CLANCY_LABEL_BUILD if set, else "clancy:build"}
|
|
94
|
+
{If CLANCY_LABEL or CLANCY_PLAN_LABEL set:}
|
|
95
|
+
⚠ CLANCY_LABEL and CLANCY_PLAN_LABEL are deprecated. Use CLANCY_LABEL_BUILD and CLANCY_LABEL_PLAN.
|
|
96
|
+
|
|
89
97
|
{If Planner enabled:}
|
|
90
98
|
Planner
|
|
91
99
|
{If Jira:}
|
|
@@ -539,6 +547,60 @@ If [2]: remove `CLANCY_COMPONENT` from `.clancy/.env`.
|
|
|
539
547
|
|
|
540
548
|
---
|
|
541
549
|
|
|
550
|
+
### [L1] Brief label
|
|
551
|
+
|
|
552
|
+
Only shown when Strategist is enabled.
|
|
553
|
+
|
|
554
|
+
```
|
|
555
|
+
Brief label — current: {value or "clancy:brief"}
|
|
556
|
+
Label applied to tickets after /clancy:brief. Removed when the brief is approved.
|
|
557
|
+
|
|
558
|
+
[1] clancy:brief (default)
|
|
559
|
+
[2] Enter a different value
|
|
560
|
+
[3] Cancel
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
If [1]: remove `CLANCY_LABEL_BRIEF` from `.clancy/.env` (uses default).
|
|
564
|
+
If [2]: prompt `What label should /clancy:brief apply?` then write `CLANCY_LABEL_BRIEF=<value>` to `.clancy/.env`. Wrap in double quotes.
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
### [L2] Plan label
|
|
569
|
+
|
|
570
|
+
Only shown when Planner or Strategist is enabled.
|
|
571
|
+
|
|
572
|
+
```
|
|
573
|
+
Plan label — current: {value or "clancy:plan"}
|
|
574
|
+
Label applied to tickets that need planning. Removed when the plan is approved.
|
|
575
|
+
|
|
576
|
+
[1] clancy:plan (default)
|
|
577
|
+
[2] Enter a different value
|
|
578
|
+
[3] Cancel
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
If [1]: remove `CLANCY_LABEL_PLAN` from `.clancy/.env` (uses default).
|
|
582
|
+
If [2]: prompt `What label should mark tickets needing planning?` then write `CLANCY_LABEL_PLAN=<value>` to `.clancy/.env`. Wrap in double quotes.
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
### [L3] Build label
|
|
587
|
+
|
|
588
|
+
Only shown when Planner or Strategist is enabled.
|
|
589
|
+
|
|
590
|
+
```
|
|
591
|
+
Build label — current: {value or "clancy:build"}
|
|
592
|
+
Label applied to tickets ready for implementation. Used by /clancy:once and /clancy:run to filter the queue.
|
|
593
|
+
|
|
594
|
+
[1] clancy:build (default)
|
|
595
|
+
[2] Enter a different value
|
|
596
|
+
[3] Cancel
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
If [1]: remove `CLANCY_LABEL_BUILD` from `.clancy/.env` (uses default).
|
|
600
|
+
If [2]: prompt `What label should mark tickets ready to build?` then write `CLANCY_LABEL_BUILD=<value>` to `.clancy/.env`. Wrap in double quotes.
|
|
601
|
+
|
|
602
|
+
---
|
|
603
|
+
|
|
542
604
|
### [P1] Plan queue status (Jira only)
|
|
543
605
|
|
|
544
606
|
```
|
|
@@ -218,13 +218,19 @@ Platform-specific pre-creation lookups.
|
|
|
218
218
|
|
|
219
219
|
### GitHub
|
|
220
220
|
|
|
221
|
+
**Pipeline label for children:** Determine the pipeline label based on planner role and flags:
|
|
222
|
+
- `--skip-plan` flag → `CLANCY_LABEL_BUILD` (default: `clancy:build`)
|
|
223
|
+
- Planner role enabled (`CLANCY_ROLES` includes `planner`) → `CLANCY_LABEL_PLAN` (default: `clancy:plan`)
|
|
224
|
+
- Planner role NOT enabled → `CLANCY_LABEL_BUILD` (default: `clancy:build`)
|
|
225
|
+
|
|
221
226
|
**Labels to apply per ticket:**
|
|
222
|
-
- `
|
|
223
|
-
- `CLANCY_LABEL` (if set) — Clancy identifier
|
|
227
|
+
- The pipeline label determined above (`CLANCY_LABEL_PLAN` or `CLANCY_LABEL_BUILD`) — replaces `CLANCY_LABEL` on children
|
|
224
228
|
- `component:{CLANCY_COMPONENT}` (if `CLANCY_COMPONENT` set)
|
|
225
229
|
- `size:{S|M|L}` — from decomposition table
|
|
226
230
|
- `clancy:afk` or `clancy:hitl` — from Mode column
|
|
227
231
|
|
|
232
|
+
Note: `CLANCY_LABEL` is NOT applied to child tickets when pipeline labels are active. The pipeline label (`clancy:plan` or `clancy:build`) serves as the queue identifier.
|
|
233
|
+
|
|
228
234
|
**Label pre-creation:** For each unique label, attempt to create it on the repo. If it already exists, GitHub returns 422 — ignore that error. If 403 (no admin access), note the label as unavailable.
|
|
229
235
|
|
|
230
236
|
```bash
|
|
@@ -266,7 +272,9 @@ Set CLANCY_BRIEF_ISSUE_TYPE in .clancy/.env.
|
|
|
266
272
|
```
|
|
267
273
|
Stop.
|
|
268
274
|
|
|
269
|
-
**
|
|
275
|
+
**Pipeline label for children:** Same logic as GitHub — determine the pipeline label from `--skip-plan` flag and planner role.
|
|
276
|
+
|
|
277
|
+
**Labels:** Jira auto-creates labels — no pre-creation needed. Apply: the pipeline label (`CLANCY_LABEL_PLAN` or `CLANCY_LABEL_BUILD`), `clancy:afk` or `clancy:hitl`. `CLANCY_LABEL` is NOT applied to children when pipeline labels are active.
|
|
270
278
|
|
|
271
279
|
**Components:** If `CLANCY_COMPONENT` is set, it maps to the Jira `components` field.
|
|
272
280
|
|
|
@@ -297,7 +305,9 @@ query {
|
|
|
297
305
|
}
|
|
298
306
|
```
|
|
299
307
|
|
|
300
|
-
|
|
308
|
+
**Pipeline label for children:** Same logic as GitHub/Jira — determine the pipeline label from `--skip-plan` flag and planner role.
|
|
309
|
+
|
|
310
|
+
For each required label (the pipeline label, `component:{CLANCY_COMPONENT}`, `clancy:afk`, `clancy:hitl`): search by exact name. `CLANCY_LABEL` is NOT applied to children when pipeline labels are active. If not found in team labels, check workspace labels:
|
|
301
311
|
|
|
302
312
|
```graphql
|
|
303
313
|
query {
|
|
@@ -370,7 +380,7 @@ curl -s \
|
|
|
370
380
|
-d '{
|
|
371
381
|
"title": "{ticket title}",
|
|
372
382
|
"body": "Epic: #{parent_number}\n\n## {Title}\n\n{Description}\n\n---\n\n**Parent:** #{parent_number}\n**Brief:** {slug}\n**Size:** {S|M|L}\n\n### Dependencies\n\n{Depends on #NN lines or None}\n\n---\n\n*Created by Clancy from strategic brief.*",
|
|
373
|
-
"labels": ["{
|
|
383
|
+
"labels": ["{PIPELINE_LABEL}", "size:{size}", "clancy:{mode}", ...],
|
|
374
384
|
"assignees": ["{resolved_username}"]
|
|
375
385
|
}'
|
|
376
386
|
```
|
|
@@ -412,7 +422,7 @@ curl -s \
|
|
|
412
422
|
},
|
|
413
423
|
"issuetype": { "name": "{CLANCY_BRIEF_ISSUE_TYPE or Task}" },
|
|
414
424
|
"parent": { "key": "{PARENT_KEY}" },
|
|
415
|
-
"labels": ["{
|
|
425
|
+
"labels": ["{PIPELINE_LABEL}", "clancy:{mode}"]
|
|
416
426
|
}
|
|
417
427
|
}'
|
|
418
428
|
```
|
|
@@ -631,6 +641,60 @@ Created by Clancy on {YYYY-MM-DD}.
|
|
|
631
641
|
|
|
632
642
|
---
|
|
633
643
|
|
|
644
|
+
## Step 11a — Remove brief label from parent
|
|
645
|
+
|
|
646
|
+
Only if a parent ticket exists AND all tickets were created successfully. Remove `CLANCY_LABEL_BRIEF` from the parent ticket. Best-effort — warn on failure, never stop.
|
|
647
|
+
|
|
648
|
+
Read `CLANCY_LABEL_BRIEF` from `.clancy/.env`. Default: `clancy:brief`.
|
|
649
|
+
|
|
650
|
+
### GitHub
|
|
651
|
+
|
|
652
|
+
```bash
|
|
653
|
+
curl -s \
|
|
654
|
+
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
|
655
|
+
-H "Accept: application/vnd.github+json" \
|
|
656
|
+
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
657
|
+
-X DELETE \
|
|
658
|
+
"https://api.github.com/repos/$GITHUB_REPO/issues/$PARENT_NUMBER/labels/$(echo $CLANCY_LABEL_BRIEF | jq -Rr @uri)"
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
Ignore 404 (label may not be present on the parent).
|
|
662
|
+
|
|
663
|
+
### Jira
|
|
664
|
+
|
|
665
|
+
```bash
|
|
666
|
+
CURRENT_LABELS=$(curl -s \
|
|
667
|
+
-u "$JIRA_USER:$JIRA_API_TOKEN" \
|
|
668
|
+
-H "Accept: application/json" \
|
|
669
|
+
"$JIRA_BASE_URL/rest/api/3/issue/$PARENT_KEY?fields=labels" | jq -r '.fields.labels')
|
|
670
|
+
|
|
671
|
+
UPDATED_LABELS=$(echo "$CURRENT_LABELS" | jq --arg brief "$CLANCY_LABEL_BRIEF" '[.[] | select(. != $brief)]')
|
|
672
|
+
|
|
673
|
+
curl -s \
|
|
674
|
+
-u "$JIRA_USER:$JIRA_API_TOKEN" \
|
|
675
|
+
-X PUT \
|
|
676
|
+
-H "Content-Type: application/json" \
|
|
677
|
+
"$JIRA_BASE_URL/rest/api/3/issue/$PARENT_KEY" \
|
|
678
|
+
-d "{\"fields\": {\"labels\": $UPDATED_LABELS}}"
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Linear
|
|
682
|
+
|
|
683
|
+
```bash
|
|
684
|
+
# Fetch current label IDs on the parent, remove the brief label ID, issueUpdate
|
|
685
|
+
# Use the same pattern as brief.md Step 10a — query labels, filter, update
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### On failure
|
|
689
|
+
|
|
690
|
+
```
|
|
691
|
+
⚠️ Could not remove brief label from {PARENT_KEY}. Remove it manually if needed.
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
Continue — do not stop.
|
|
695
|
+
|
|
696
|
+
---
|
|
697
|
+
|
|
634
698
|
## Step 12 — Display summary
|
|
635
699
|
|
|
636
700
|
Show the final result:
|