create-agentic-pdlc 2.3.0 → 2.4.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 (53) hide show
  1. package/.agentic-pdlc/metrics/raw/2026-W22.jsonl +114 -0
  2. package/.github/ISSUE_TEMPLATE/bug.md +53 -0
  3. package/.github/ISSUE_TEMPLATE/feature.md +54 -0
  4. package/.github/ISSUE_TEMPLATE/task.md +33 -0
  5. package/.github/workflows/add-to-board.yml +1 -1
  6. package/.github/workflows/agent-trigger.yml +4 -4
  7. package/.github/workflows/agentic-metrics.yml +150 -27
  8. package/.github/workflows/ci.yml +1 -1
  9. package/.github/workflows/npm-publish.yml +2 -2
  10. package/.github/workflows/pdlc-health-check.yml +1 -1
  11. package/.github/workflows/pdlc-stage-gate.yml +2 -2
  12. package/.github/workflows/project-automation.yml +51 -12
  13. package/.github/workflows/qa-agent.yml +22 -11
  14. package/.github/workflows/qa-gate.yml +51 -0
  15. package/AGENTS.md +50 -8
  16. package/CLAUDE.md +2 -0
  17. package/SETUP.md +2 -1
  18. package/adapters/claude-code/skill.md +32 -11
  19. package/adapters/hooks/pdlc-stage-gate.sh +3 -8
  20. package/bin/cli.js +23 -2
  21. package/docs/pdlc.md +5 -5
  22. package/docs/superpowers/plans/2026-05-28-jules-label-pat-split.md +240 -0
  23. package/docs/superpowers/plans/2026-05-29-agentic-pulse-rework-taxonomy.md +474 -0
  24. package/docs/superpowers/plans/2026-05-29-qa-gate-enforcement.md +354 -0
  25. package/docs/superpowers/specs/2026-05-29-agentic-pulse-rework-taxonomy-design.md +122 -0
  26. package/package.json +1 -1
  27. package/templates/.github/ISSUE_TEMPLATE/bug.md +53 -0
  28. package/templates/.github/ISSUE_TEMPLATE/feature.md +54 -0
  29. package/templates/.github/ISSUE_TEMPLATE/task.md +33 -0
  30. package/templates/.github/workflows/add-to-board.yml +4 -4
  31. package/templates/.github/workflows/agent-trigger.yml +22 -13
  32. package/{.agentic-pdlc/templates → templates}/.github/workflows/agentic-metrics.yml +150 -27
  33. package/templates/.github/workflows/ci.yml +1 -1
  34. package/templates/.github/workflows/pdlc-health-check.yml +1 -1
  35. package/templates/.github/workflows/pdlc-stage-gate.yml +2 -2
  36. package/templates/.github/workflows/project-automation.yml +71 -32
  37. package/templates/.github/workflows/qa-agent.yml +32 -18
  38. package/templates/.github/workflows/qa-gate.yml +51 -0
  39. package/templates/AGENTS.md +57 -29
  40. package/templates/docs/pdlc.md +4 -4
  41. package/.agentic-pdlc/templates/.github/CODEOWNERS +0 -5
  42. package/.agentic-pdlc/templates/.github/copilot-instructions.md +0 -12
  43. package/.agentic-pdlc/templates/.github/workflows/add-to-board.yml +0 -38
  44. package/.agentic-pdlc/templates/.github/workflows/agent-trigger.yml +0 -146
  45. package/.agentic-pdlc/templates/.github/workflows/auto-approve.yml +0 -16
  46. package/.agentic-pdlc/templates/.github/workflows/ci.yml +0 -54
  47. package/.agentic-pdlc/templates/.github/workflows/pdlc-health-check.yml +0 -121
  48. package/.agentic-pdlc/templates/.github/workflows/pdlc-stage-gate.yml +0 -51
  49. package/.agentic-pdlc/templates/.github/workflows/project-automation.yml +0 -274
  50. package/.agentic-pdlc/templates/.github/workflows/protect-workflows.yml +0 -21
  51. package/.agentic-pdlc/templates/.github/workflows/qa-agent.yml +0 -128
  52. package/.agentic-pdlc/templates/AGENTS.md +0 -104
  53. package/.agentic-pdlc/templates/docs/pdlc.md +0 -123
@@ -31,7 +31,7 @@ jobs:
31
31
  steps:
32
32
  - name: Detect Label and Move Issue
33
33
  if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
34
- uses: actions/github-script@v7
34
+ uses: actions/github-script@v8
35
35
  with:
36
36
  github-token: ${{ env.PROJECT_TOKEN }}
37
37
  script: |
@@ -51,9 +51,6 @@ jobs:
51
51
  } else if (labelName === 'stage:development') {
52
52
  targetStatusId = process.env.STATUS_DEVELOPMENT;
53
53
  stageName = 'Development';
54
- } else if (labelName === 'stage:testing') {
55
- targetStatusId = process.env.STATUS_TESTING;
56
- stageName = 'Testing';
57
54
  }
58
55
 
59
56
  if (!targetStatusId) {
@@ -83,6 +80,42 @@ jobs:
83
80
  await moveItem(node_id, targetStatusId);
84
81
  console.log(`Issue #${number} moved to ${stageName}`);
85
82
 
83
+ # human-approved on issue → qa:approved on linked open PRs
84
+ handle-human-approved:
85
+ name: human-approved → qa:approved on linked PRs
86
+ if: github.event_name == 'issues' && github.event.action == 'labeled' && github.event.label.name == 'human-approved'
87
+ runs-on: ubuntu-latest
88
+ permissions:
89
+ issues: write
90
+ pull-requests: write
91
+ steps:
92
+ - name: Add qa:approved to linked open PRs
93
+ uses: actions/github-script@v8
94
+ with:
95
+ github-token: ${{ secrets.GITHUB_TOKEN }}
96
+ script: |
97
+ const { owner, repo } = context.repo;
98
+ const issueNumber = context.payload.issue.number;
99
+ const pattern = new RegExp(`(?:Closes?|Fixes?|Resolves?)\\s+#${issueNumber}\\b`, 'i');
100
+
101
+ const prs = await github.paginate(github.rest.pulls.list, {
102
+ owner, repo, state: 'open', per_page: 100
103
+ });
104
+
105
+ const linked = prs.filter(pr => pattern.test(pr.body ?? ''));
106
+
107
+ if (linked.length === 0) {
108
+ console.log(`No open PRs linking issue #${issueNumber}. Exiting.`);
109
+ return;
110
+ }
111
+
112
+ for (const pr of linked) {
113
+ await github.rest.issues.addLabels({
114
+ owner, repo, issue_number: pr.number, labels: ['qa:approved']
115
+ }).catch(() => {});
116
+ console.log(`PR #${pr.number} → qa:approved`);
117
+ }
118
+
86
119
  # OPTIONAL: Uncomment to enable architecture-violation → Idea
87
120
  # move-violation-to-board:
88
121
  # name: architecture-violation → 💡 Idea
@@ -91,7 +124,7 @@ jobs:
91
124
  # steps:
92
125
  # - name: Move issue to Idea
93
126
  # if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
94
- # uses: actions/github-script@v7
127
+ # uses: actions/github-script@v8
95
128
  # with:
96
129
  # github-token: ${{ env.PROJECT_TOKEN }}
97
130
  # script: |
@@ -121,7 +154,7 @@ jobs:
121
154
  steps:
122
155
  - name: Move linked issue to Testing
123
156
  if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
124
- uses: actions/github-script@v7
157
+ uses: actions/github-script@v8
125
158
  with:
126
159
  github-token: ${{ env.PROJECT_TOKEN }}
127
160
  script: |
@@ -152,7 +185,7 @@ jobs:
152
185
  });
153
186
  };
154
187
 
155
- const stageLabelsToRemove = ['stage:development', 'stage:brainstorming', 'stage:detailing', 'stage:approval', 'jules', 'agent:working'];
188
+ const stageLabelsToRemove = ['stage:development', 'stage:brainstorming', 'stage:detailing', 'jules'];
156
189
 
157
190
  if (linkedIssues.length > 0) {
158
191
  for (const n of linkedIssues) {
@@ -181,7 +214,7 @@ jobs:
181
214
  steps:
182
215
  - name: Move linked issue to Code Review / PR
183
216
  if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
184
- uses: actions/github-script@v7
217
+ uses: actions/github-script@v8
185
218
  with:
186
219
  github-token: ${{ env.PROJECT_TOKEN }}
187
220
  script: |
@@ -215,6 +248,9 @@ jobs:
215
248
  for (const n of linkedIssues) {
216
249
  const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number: n });
217
250
  await moveItem(issue.node_id);
251
+ if (issue.labels?.some(l => l.name === 'stage:testing')) {
252
+ await github.rest.issues.removeLabel({ owner, repo, issue_number: n, name: 'stage:testing' }).catch(() => {});
253
+ }
218
254
  console.log(`Issue #${n} → Code Review / PR`);
219
255
  }
220
256
  } else {
@@ -232,7 +268,7 @@ jobs:
232
268
  steps:
233
269
  - name: Swap PR labels
234
270
  if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
235
- uses: actions/github-script@v7
271
+ uses: actions/github-script@v8
236
272
  with:
237
273
  github-token: ${{ env.PROJECT_TOKEN }}
238
274
  script: |
@@ -251,7 +287,7 @@ jobs:
251
287
  steps:
252
288
  - name: Move issue to Production
253
289
  if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
254
- uses: actions/github-script@v7
290
+ uses: actions/github-script@v8
255
291
  with:
256
292
  github-token: ${{ env.PROJECT_TOKEN }}
257
293
  script: |
@@ -279,6 +315,9 @@ jobs:
279
315
  for (const n of linkedIssues) {
280
316
  const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number: n });
281
317
  await moveItem(issue.node_id);
318
+ if (issue.labels?.some(l => l.name === 'stage:approval')) {
319
+ await github.rest.issues.removeLabel({ owner, repo, issue_number: n, name: 'stage:approval' }).catch(() => {});
320
+ }
282
321
  console.log(`Issue #${n} → Production`);
283
322
  }
284
323
  } else {
@@ -291,7 +330,7 @@ jobs:
291
330
  runs-on: ubuntu-latest
292
331
  steps:
293
332
  - name: Remove transient labels
294
- uses: actions/github-script@v7
333
+ uses: actions/github-script@v8
295
334
  with:
296
335
  github-token: ${{ secrets.GITHUB_TOKEN }}
297
336
  script: |
@@ -300,7 +339,7 @@ jobs:
300
339
  const toRemove = [
301
340
  'stage:brainstorming', 'stage:detailing',
302
341
  'stage:approval', 'stage:development', 'stage:testing',
303
- 'agent:working', 'qa:needs-work', 'pr:in-review', 'jules'
342
+ 'qa:needs-work', 'pr:in-review', 'jules'
304
343
  ];
305
344
  for (const label of toRemove) {
306
345
  await github.rest.issues.removeLabel({ owner, repo, issue_number, name: label }).catch(() => {});
@@ -19,7 +19,7 @@ jobs:
19
19
  STATUS_FIELD_ID: "PVTSSF_lAHODpFFL84BXg7hzhStRHI"
20
20
  STATUS_CODE_REVIEW_PR: "86ca9720"
21
21
  steps:
22
- - uses: actions/checkout@v4
22
+ - uses: actions/checkout@v5.0.1
23
23
  with:
24
24
  fetch-depth: 0
25
25
 
@@ -34,7 +34,7 @@ jobs:
34
34
  HEAD="${{ github.event.pull_request.head.sha }}"
35
35
 
36
36
  # Get PR diff (truncated to 8000 chars to stay within context limits)
37
- DIFF=$(git diff "$BASE" "$HEAD" | head -c 64000)
37
+ DIFF=$(git diff "$BASE" "$HEAD" | head -c 8000)
38
38
 
39
39
  # Extract linked issues from PR body
40
40
  PR_BODY=$(gh pr view "$PR_NUMBER" --json body --jq '.body // ""')
@@ -53,20 +53,30 @@ jobs:
53
53
  AC_CONTEXT="No linked issue found. Evaluate if the PR description is self-contained."
54
54
  fi
55
55
 
56
- # Serialize prompt as JSON string and call GitHub Models API (30s timeout)
56
+ # Serialize prompt as JSON string and call GitHub Models API (3 attempts, 20s backoff)
57
57
  PROMPT_JSON=$(printf '%s' "You are a senior QA engineer. Review whether this PR diff satisfies the Acceptance Criteria below.\n\nACCEPTANCE CRITERIA:\n${AC_CONTEXT}\n\nPR DIFF:\n${DIFF}\n\nFirst line of your response must be exactly one word: PASS or FAIL. Second line: brief explanation (max 3 sentences)." | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')
58
58
 
59
- RESPONSE=$(curl -sf -X POST \
60
- "https://models.github.ai/inference/chat/completions" \
61
- -H "Authorization: Bearer ${GITHUB_TOKEN}" \
62
- -H "Content-Type: application/json" \
63
- -d "{\"model\":\"gpt-4o-mini\",\"messages\":[{\"role\":\"user\",\"content\":${PROMPT_JSON}}]}" \
64
- --max-time 30 || echo "API_ERROR")
59
+ RESPONSE="API_ERROR"
60
+ for attempt in 1 2 3; do
61
+ RESULT=$(curl -s -X POST \
62
+ "https://models.github.ai/inference/chat/completions" \
63
+ -H "Authorization: Bearer ${GITHUB_TOKEN}" \
64
+ -H "Content-Type: application/json" \
65
+ -d "{\"model\":\"gpt-4o-mini\",\"messages\":[{\"role\":\"user\",\"content\":${PROMPT_JSON}}]}" \
66
+ -w "\n__HTTP_STATUS__:%{http_code}" \
67
+ --max-time 45 2>/dev/null)
68
+ HTTP_STATUS=$(echo "$RESULT" | grep -o '__HTTP_STATUS__:[0-9]*' | cut -d: -f2)
69
+ BODY=$(echo "$RESULT" | sed 's/__HTTP_STATUS__:[0-9]*$//')
70
+ echo "Attempt $attempt: HTTP $HTTP_STATUS"
71
+ if [ "$HTTP_STATUS" = "200" ]; then RESPONSE="$BODY"; break; fi
72
+ [ $attempt -lt 3 ] && sleep 20
73
+ done
65
74
 
66
75
  if [ "$RESPONSE" = "API_ERROR" ]; then
67
76
  GH_TOKEN="$PROJECT_TOKEN" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
68
77
  gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not reach GitHub Models API. Manual review required."
69
- exit 0
78
+ # exit 1 marks this check as failed; qa-gate.yml enforces the merge block via infra:qa-broken label
79
+ exit 1
70
80
  fi
71
81
 
72
82
  VERDICT=$(echo "$RESPONSE" | python3 -c 'import json,sys,re; d=json.load(sys.stdin); t=d.get("choices",[{}])[0].get("message",{}).get("content","").strip(); first=t.split("\n")[0].upper() if t else ""; print("FAIL" if re.search(r"\bFAIL\b",first) else "PASS" if re.search(r"\bPASS\b",first) else "API_ERROR")')
@@ -81,11 +91,12 @@ jobs:
81
91
  else
82
92
  GH_TOKEN="$PROJECT_TOKEN" gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/labels" --method POST -f 'labels[]=infra:qa-broken'
83
93
  gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not parse GitHub Models response. Manual review required."
94
+ exit 1
84
95
  fi
85
96
 
86
97
  - name: Move board card to Code Review on qa:approved
87
98
  if: ${{ env.PROJECT_TOKEN != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
88
- uses: actions/github-script@v7
99
+ uses: actions/github-script@v8
89
100
  with:
90
101
  github-token: ${{ env.PROJECT_TOKEN }}
91
102
  script: |
@@ -0,0 +1,51 @@
1
+ name: QA Gate
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, reopened, labeled, unlabeled]
6
+
7
+ permissions:
8
+ pull-requests: read
9
+
10
+ jobs:
11
+ qa-gate:
12
+ name: QA Gate
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Check QA status label
16
+ env:
17
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
18
+ run: |
19
+ set -e
20
+ PR_NUMBER="${{ github.event.pull_request.number }}"
21
+ REPO="${{ github.repository }}"
22
+
23
+ PR_LABELS=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json labels --jq '.labels[].name')
24
+
25
+ if echo "$PR_LABELS" | grep -qx "hotfix"; then
26
+ echo "✅ QA Gate: hotfix label — bypassed."
27
+ exit 0
28
+ fi
29
+
30
+ if echo "$PR_LABELS" | grep -qx "human-approved"; then
31
+ echo "✅ QA Gate: human-approved label — manual QA sign-off, bypassed."
32
+ exit 0
33
+ fi
34
+
35
+ if echo "$PR_LABELS" | grep -qx "qa:approved"; then
36
+ echo "✅ QA Gate: qa:approved — merge allowed."
37
+ exit 0
38
+ fi
39
+
40
+ if echo "$PR_LABELS" | grep -qx "infra:qa-broken"; then
41
+ echo "❌ QA Gate: infra:qa-broken — GitHub Models API unreachable. Manual QA review required before merge."
42
+ exit 1
43
+ fi
44
+
45
+ if echo "$PR_LABELS" | grep -qx "qa:needs-work"; then
46
+ echo "❌ QA Gate: qa:needs-work — acceptance criteria not fully met. Fix required before merge."
47
+ exit 1
48
+ fi
49
+
50
+ echo "❌ QA Gate: no QA label found — AC Coverage Verification has not completed. Wait for the check to finish."
51
+ exit 1
package/AGENTS.md CHANGED
@@ -27,14 +27,55 @@ Always start from the current `main` HEAD. Never work over stale snapshots.
27
27
  ## Mandatory Workflow
28
28
 
29
29
  0. **Identity**: Always prefix your GitHub comments with `🤖 **Agent:** ` to distinguish yourself.
30
- 1. **Initial State**: When beginning work on a new issue, your very first action must be to apply the `stage:brainstorming` label using the GitHub CLI (`gh issue edit <N> --add-label "stage:brainstorming"`).
31
- 2. Read the issue entirely understand its type (US/BUG/TASK/SPIKE) and the Acceptance Criteria.
32
- 3. Read `docs/pdlc.md` understand the PDLC and the Definition of Done in this project.
33
- 4. Read all files mentioned in the issue's technical context.
34
- 5. Implement the **minimum viable change** that satisfies the ACsdo not refactor beyond scope.
35
- 6. Run tests: `echo "No tests/build needed."`
36
- 7. Run typecheck: `echo "No typecheck needed."`
37
- 8. Create a Pull Request with `Closes #N` in the body automation moves the board.
30
+ 1. **Stage Check**: Before applying any label or taking any action, run `gh issue view <N> --json labels,title` to determine the issue's current stage. State: *"Issue #N [title] is currently at `<stage>`. Requesting confirmation to advance to `<next>`."* Wait for an explicit stage-advancement signal in this conversation turn. A prioritization signal ("work on X", "tackle X next") does **not** count as confirmation — only an explicit signal counts (e.g. "start brainstorming", "yes advance", "go"). **Exceptions — skip this step and proceed directly**:
31
+ - `spec:approved` begin implementation (gate already passed)
32
+ - `stage:development` or `stage:testing` issue is owned by automation; do not intervene unless explicitly asked to fix a specific problem
33
+ - `stage:approval` spec already written; wait for PM to add `spec:approved` before doing anything
34
+ 2. **Initial State**: Apply the `stage:brainstorming` label using the GitHub CLI (`gh issue edit <N> --add-label "stage:brainstorming"`). **Exception pre-spec'd issue**: if the issue body already contains all required spec sections (`## Problem`, `## Solution`, `## Acceptance Criteria`, `## Edge Cases`, `## Out of Scope`, `## Files to Modify`) all present and non-empty — apply `stage:approval` directly in a single call instead, skipping `stage:brainstorming` and `stage:detailing`.
35
+ 3. Read the issue entirely — understand its type (US/BUG/TASK/SPIKE) and the Acceptance Criteria.
36
+ 4. Read `docs/pdlc.md` understand the PDLC and the Definition of Done in this project.
37
+ 5. Read all files mentioned in the issue's technical context.
38
+ 6. Implement the **minimum viable change** that satisfies the ACs — do not refactor beyond scope.
39
+ 7. Run tests: `echo "No tests/build needed."`
40
+ 8. Run typecheck: `echo "No typecheck needed."`
41
+ 9. Create a Pull Request with `Closes #N` in the body — automation moves the board.
42
+
43
+ ## Spec Format
44
+
45
+ When writing or rewriting an issue body during detailing, include ALL sections below. Omitting any section blocks `stage:approval`.
46
+
47
+ ```
48
+ ## Problem
49
+ [1-3 sentences. What fails. Who affected. Measured impact.]
50
+
51
+ ## Sprint Goal / Success Metrics
52
+ | Metric | Baseline | Target | When |
53
+ |--------|----------|--------|------|
54
+
55
+ ## Solution
56
+ [Behavioral description of what is built. No implementation details.]
57
+
58
+ ## Acceptance Criteria
59
+ **AC1 — [name]**
60
+ - Given [precondition]
61
+ - When [action]
62
+ - Then [outcome]
63
+
64
+ ## Edge Cases
65
+ - EC1: [condition] → [expected behavior]
66
+
67
+ ## Out of Scope
68
+ - [item] — reason
69
+
70
+ ## Non-Functional Requirements
71
+ - Performance: [metric with number]
72
+ - Security: [constraint]
73
+ - Reliability: [constraint]
74
+ > For pure docs/markdown issues with zero runtime behavior, include the NFRs section and state "N/A".
75
+
76
+ ## Files to Modify
77
+ - `path/to/file` — what changes
78
+ ```
38
79
 
39
80
  ## What NOT to do
40
81
 
@@ -50,3 +91,4 @@ Always start from the current `main` HEAD. Never work over stale snapshots.
50
91
  - **Lint/Types:** `echo "No tests/build needed."`
51
92
  - **Typecheck:** `echo "No typecheck needed."`
52
93
  - **Build:** `echo "No tests/build needed."`
94
+ - **Canonical secret name:** `PROJECT_TOKEN` (not `PROJECT_PAT`) — use this in all workflow files, both live and templates
package/CLAUDE.md CHANGED
@@ -33,6 +33,8 @@ The PreToolUse hook will block `gh pr create` automatically if this rule is viol
33
33
 
34
34
  **Detailing is fully autonomous.** Write the complete spec, add it to the issue, advance to `stage:approval` — no confirmation needed. Then **stop and wait** for human to add `spec:approved` before any implementation.
35
35
 
36
+ **Spec destination: the issue body.** Write spec content to the issue body using `gh issue edit <N> --body "..."` — not to a file. A file is acceptable as optional reference only. Automation checks the issue body for `## Acceptance Criteria` and `## Files to Modify` to advance the stage; content that exists only in a file is invisible to it.
37
+
36
38
  ## Stage Transition Rules (non-negotiable)
37
39
 
38
40
  MUST apply `stage:brainstorming` label immediately on starting work — before
package/SETUP.md CHANGED
@@ -63,7 +63,7 @@ npx create-agentic-pdlc
63
63
  The CLI will:
64
64
  1. Ask you which AI Agent you use (Claude Code, Cursor, etc.).
65
65
  2. Copy the system instructions pointing to our interactive Setup Mode.
66
- 3. Automatically download the base templates to `.agentic-pdlc/templates/`.
66
+ 3. Automatically install the base templates into your project.
67
67
 
68
68
  Once the CLI finishes, it will instruct you to open your AI agent and run the **Setup Mode**. Your AI agent will then ask you the required project variables interactively and generate `AGENTS.md`, `docs/pdlc.md`, and the GitHub Actions for you!
69
69
 
@@ -169,6 +169,7 @@ The issue appears in your GitHub notifications automatically — zero extra setu
169
169
  ```bash
170
170
  cp .agentic-pdlc/templates/.github/workflows/agentic-metrics.yml .github/workflows/agentic-metrics.yml
171
171
  ```
172
+ > If the file is missing, re-run `npx create-agentic-pdlc` to update your installed templates.
172
173
 
173
174
  2. Commit and push. The first pulse runs next Sunday, or trigger it manually:
174
175
  ```bash
@@ -106,21 +106,21 @@ If `AGENTS.md` and `docs/pdlc.md` are present, you are in **Execution Mode**.
106
106
 
107
107
  Reading the issue title and body for type inference is exempt from the initial label requirement: it is metadata already present in the request, not code reading or skill invocation.
108
108
 
109
- 1. Check if issue already has a `type:*` label (`type:us`, `type:task`, `type:bug`, `type:spike`) → if yes, skip to Section 0.1.
109
+ 1. Check if issue already has a `type:*` label (`type:feature`, `type:task`, `type:bug`, `type:spike`) → if yes, skip to Section 0.1.
110
110
  2. Read issue title + body (metadata only — no code reading at this step).
111
111
  3. Classify using these rules:
112
112
  - `type:task` — operational change, config, rename, docs update, non-functional (no user-facing behavior change)
113
113
  - `type:bug` — something broken that should work
114
114
  - `type:spike` — research/evaluation spike, never reaches Development
115
- - `type:us` — new feature, behavioral change, anything product-facing
115
+ - `type:feature` — new feature, behavioral change, anything product-facing
116
116
  4. Confidence ≥ 85% → add inferred label: `gh issue edit <N> --add-label "type:<inferred>"`
117
- 5. Confidence < 85% → default to `type:us`: `gh issue edit <N> --add-label "type:us"`
117
+ 5. Confidence < 85% → default to `type:feature`: `gh issue edit <N> --add-label "type:feature"`
118
118
 
119
119
  **Type drives the PDLC flow:**
120
120
 
121
121
  | Type | Flow |
122
122
  |---|---|
123
- | `type:us` | brainstorming → Gate 1 → detailing → approval |
123
+ | `type:feature` | brainstorming → Gate 1 → detailing → approval |
124
124
  | `type:task` | brainstorming → Gate 1 → detailing → approval |
125
125
  | `type:bug` | brainstorming → Gate 1 → detailing → approval |
126
126
  | `type:spike` | brainstorming → Gate 1 → detailing → conclusion comment (never reaches Development) |
@@ -157,18 +157,39 @@ When asked to work on a feature, you will:
157
157
  - Stop and wait for the human PM's explicit approval (Gate 1).
158
158
 
159
159
  ### 2. Creating the Spec
160
- Once approved, you will detail the solution directly into the GitHub Issue body. Focus on precise Acceptance Criteria.
161
- **IMPORTANT:** You must always rewrite the full issue body to include both the user story and the Acceptance Criteria. Do not simply append the ACs to the existing text. Use this format:
160
+ Once approved, detail the solution directly into the GitHub Issue body. Always rewrite the full issue body — never append only ACs to existing text. Include ALL sections below. Omitting any section blocks `stage:approval`. Use this format:
162
161
 
163
162
  ```
164
- **As** [user],
165
- **I want** [action],
166
- **so that** [benefit].
163
+ ## Problem
164
+ [1-3 sentences. What fails. Who affected. Measured impact.]
167
165
 
168
- ---
166
+ ## Sprint Goal / Success Metrics
167
+ | Metric | Baseline | Target | When |
168
+ |--------|----------|--------|------|
169
+
170
+ ## Solution
171
+ [Behavioral description of what is built. No implementation details.]
169
172
 
170
173
  ## Acceptance Criteria
171
- ...
174
+ **AC1 — [name]**
175
+ - Given [precondition]
176
+ - When [action]
177
+ - Then [outcome]
178
+
179
+ ## Edge Cases
180
+ - EC1: [condition] → [expected behavior]
181
+
182
+ ## Out of Scope
183
+ - [item] — reason
184
+
185
+ ## Non-Functional Requirements
186
+ - Performance: [metric with number]
187
+ - Security: [constraint]
188
+ - Reliability: [constraint]
189
+ > For pure docs/markdown issues with zero runtime behavior, include the NFRs section and state "N/A".
190
+
191
+ ## Files to Modify
192
+ - `path/to/file` — what changes
172
193
  ```
173
194
 
174
195
  ### 3. Handoff
@@ -26,19 +26,14 @@ fi
26
26
 
27
27
  LABELS=$(gh issue view "$ISSUE_NUM" --json labels --jq '[.labels[].name] | join(" ")' 2>/dev/null || echo "")
28
28
 
29
- if echo "$LABELS" | grep -qw "spec:approved"; then
30
- echo "✅ PDLC: Issue #$ISSUE_NUM spec approved by PM — gate passed."
31
- exit 0
32
- fi
33
-
34
- if echo "$LABELS" | grep -qw "stage:development"; then
35
- echo "✅ PDLC: Issue #$ISSUE_NUM in development (spec already approved) — gate passed."
29
+ if echo "$LABELS" | grep -qw "spec:approved" || echo "$LABELS" | grep -qw "stage:approval" || echo "$LABELS" | grep -qw "stage:development" || echo "$LABELS" | grep -qw "stage:testing" || echo "$LABELS" | grep -qw "human-approved"; then
30
+ echo "✅ PDLC: Issue #$ISSUE_NUM approved — gate passed."
36
31
  exit 0
37
32
  fi
38
33
 
39
34
  STAGE=$(echo "$LABELS" | tr ' ' '\n' | grep "^stage:" | head -1 || echo "none")
40
35
  echo "❌ PDLC Stage Gate: Issue #$ISSUE_NUM is not approved."
41
36
  echo " Current stage: $STAGE"
42
- echo " Required: spec:approved (set by human PM) or stage:development label on the issue."
37
+ echo " Required: stage:approval OR spec:approved OR stage:development OR stage:testing OR human-approved label on the issue."
43
38
  echo " Emergency bypass: rename branch to hotfix/<issue-number>-<description>."
44
39
  exit 1
package/bin/cli.js CHANGED
@@ -41,10 +41,10 @@ const i18n = {
41
41
  invalid_repo: t('❌ Invalid repository URL. Expected format: https://github.com/OWNER/REPO', '❌ URL de repositório inválida. Formato esperado: https://github.com/OWNER/REPO', '❌ URL de repositorio inválida. Formato esperado: https://github.com/OWNER/REPO'),
42
42
  ask_org: t('Does this repository belong to a personal User account (e.g., github.com/rafaeltcosta86) or an Organization (e.g., github.com/google-labs)? (user/org): ', 'Esse repositório pertence a um Usuário pessoal (ex: github.com/rafaeltcosta86) ou a uma Organização (ex: github.com/google-labs)? (user/org): ', '¿Este repositorio pertenece a un Usuario personal (ej: github.com/rafaeltcosta86) o a una Organización (ej: github.com/google-labs)? (user/org): '),
43
43
  starting_setup: t('Starting automated repository setup...', 'Iniciando o setup automatizado do repositório...', 'Iniciando la configuración automatizada del repositorio...'),
44
- creating_labels: t('[1/2] Creating repository labels...', '[1/2] Criando labels no repositório...', '[1/2] Creando etiquetas (labels) en el repositorio...'),
44
+ creating_labels: t('[1/3] Creating repository labels...', '[1/3] Criando labels no repositório...', '[1/3] Creando etiquetas (labels) en el repositorio...'),
45
45
  label_ok: t('✅ Label created: ', '✅ Label criada: ', '✅ Etiqueta creada: '),
46
46
  label_warn: t('⚠️ Failed to create label (might already exist): ', '⚠️ Falha ao criar label (talvez já exista): ', '⚠️ Fallo al crear etiqueta (quizás ya exista): '),
47
- creating_project: t('[2/2] Creating Project V2 Board...', '[2/2] Criando Project V2 Board...', '[2/2] Creando Project V2 Board...'),
47
+ creating_project: t('[2/3] Creating Project V2 Board...', '[2/3] Criando Project V2 Board...', '[2/3] Creando Project V2 Board...'),
48
48
  project_ok: t('✅ Project created (ID: ', '✅ Projeto criado (ID: ', '✅ Proyecto creado (ID: '),
49
49
  project_err: t('❌ Failed to create project. Error: ', '❌ Falha ao criar o projeto. Erro: ', '❌ Fallo al crear el proyecto. Error: '),
50
50
  link_project_ok: t('✅ Project linked to repository.', '✅ Projeto vinculado ao repositório.', '✅ Proyecto vinculado al repositorio.'),
@@ -72,6 +72,9 @@ const i18n = {
72
72
  update_qa_ask: t(' Activate? Uses GITHUB_TOKEN — no extra secrets needed. (Y/n): ', ' Ativar? Usa GITHUB_TOKEN — nenhum secret extra necessário. (S/n): ', ' ¿Activar? Usa GITHUB_TOKEN — sin secrets adicionales. (S/n): '),
73
73
  update_sentinel_header: t('— Sentinel (architecture audit via Gemini Code Assist) —', '— Sentinel (auditoria de arquitetura via Gemini Code Assist) —', '— Sentinel (auditoría de arquitectura via Gemini Code Assist) —'),
74
74
  update_sentinel_ask: t(' Activate? Requires Gemini Code Assist CI job. (Y/n): ', ' Ativar? Requer CI job do Gemini Code Assist. (S/n): ', ' ¿Activar? Requiere CI job de Gemini Code Assist. (S/n): '),
75
+ configuring_protection: t('[3/3] Configuring branch protection...', '[3/3] Configurando proteção de branch...', '[3/3] Configurando protección de rama...'),
76
+ protection_ok: t('✅ Branch protection set — required checks: PDLC Stage Gate, QA Gate.', '✅ Proteção de branch configurada — checks obrigatórios: PDLC Stage Gate, QA Gate.', '✅ Protección de rama configurada — checks requeridos: PDLC Stage Gate, QA Gate.'),
77
+ protection_warn: t('⚠️ Branch protection could not be set automatically.\n Set required checks manually: Settings → Branches → main → Required status checks.\n Required: "PDLC Stage Gate" and "QA Gate"', '⚠️ Proteção de branch não pôde ser configurada automaticamente.\n Configure manualmente: Settings → Branches → main → Required status checks.\n Obrigatórios: "PDLC Stage Gate" e "QA Gate"', '⚠️ No se pudo configurar la protección de rama automáticamente.\n Configúralo en: Settings → Branches → main → Required status checks.\n Requeridos: "PDLC Stage Gate" y "QA Gate"'),
75
78
  };
76
79
 
77
80
  const cyan = '\x1b[36m';
@@ -355,6 +358,24 @@ async function runSetup() {
355
358
  console.log(`\n${yellow}ℹ️ Org repo detected — PROJECT_PAT will require manual setup for security.${reset}`);
356
359
  }
357
360
 
361
+ // Branch protection — require PDLC Stage Gate + QA Gate on default branch
362
+ console.log(`\n${cyan}${i18n.configuring_protection}${reset}`);
363
+ try {
364
+ const defaultBranch = execFileSync('gh', ['api', `repos/${repo}`, '--jq', '.default_branch'],
365
+ { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8' }).trim() || 'main';
366
+ const protectionPayload = JSON.stringify({
367
+ required_status_checks: { strict: false, contexts: ['PDLC Stage Gate', 'QA Gate'] },
368
+ enforce_admins: false,
369
+ required_pull_request_reviews: null,
370
+ restrictions: null
371
+ });
372
+ execFileSync('gh', ['api', `repos/${repo}/branches/${defaultBranch}/protection`, '--method', 'PUT', '--input', '-'],
373
+ { input: protectionPayload, stdio: ['pipe', 'ignore', 'pipe'] });
374
+ console.log(` ${green}${i18n.protection_ok}${reset}`);
375
+ } catch (_) {
376
+ console.log(` ${yellow}${i18n.protection_warn}${reset}`);
377
+ }
378
+
358
379
  console.log(`\n${yellow}${i18n.scaffolding}${reset}`);
359
380
 
360
381
  // We copy the templates folder so the agent has the real text logic to replace and rename
package/docs/pdlc.md CHANGED
@@ -53,7 +53,7 @@ REPO = {{REPO_OWNER}}/{{REPO_NAME}}
53
53
  ```
54
54
  [icon] [PREFIX]: [short description, imperative tense]
55
55
 
56
- 👤 US: user story
56
+ feat: new feature or behavioral change
57
57
  🐛 BUG: bug
58
58
  🔧 TASK: operational task
59
59
  🔬 SPIKE: exploration/evaluation spike
@@ -69,7 +69,7 @@ REPO = {{REPO_OWNER}}/{{REPO_NAME}}
69
69
  | `spec:approved` | Issue | Green | Gate 2 — agent is cleared to implement |
70
70
  | `pr:in-review` | PR | Yellow | Awaiting code review |
71
71
  | `pr:approved` | PR | Green | Code review approved |
72
- | `type:us` | Issue | Blue | New feature or behavioral change — full flow |
72
+ | `type:feature` | Issue | Blue | New feature or behavioral change — full flow |
73
73
  | `type:task` | Issue | Yellow | Operational/non-functional change — full flow |
74
74
  | `type:bug` | Issue | Red | Something broken — full flow |
75
75
  | `type:spike` | Issue | Gray | Research/evaluation — never reaches Development |
@@ -90,12 +90,12 @@ The `type:*` label is the authoritative signal — set automatically by the agen
90
90
 
91
91
  | Label | Flow |
92
92
  |---|---|
93
- | `type:us` | brainstorming → Gate 1 → detailing → approval |
93
+ | `type:feature` | brainstorming → Gate 1 → detailing → approval |
94
94
  | `type:task` | brainstorming → Gate 1 → detailing → approval |
95
95
  | `type:bug` | brainstorming → Gate 1 → detailing → approval |
96
96
  | `type:spike` | brainstorming → Gate 1 → detailing → conclusion comment (never reaches Development) |
97
97
 
98
- If no `type:*` label present and agent confidence < 85%, defaults to `type:us` (safe fallback — never skips gates by omission).
98
+ If no `type:*` label present and agent confidence < 85%, defaults to `type:feature` (safe fallback — never skips gates by omission).
99
99
 
100
100
  ## Bypass Mechanism
101
101
 
@@ -103,7 +103,7 @@ Agents MUST NOT skip any stage. The ONLY authorized bypasses are:
103
103
 
104
104
  | Mechanism | Who authorizes | What it bypasses |
105
105
  |---|---|---|
106
- | `human-approved` label on issue | PM (human) only | All stage gates |
106
+ | `human-approved` label on issue | PM (human) only | All stage gates — automation adds `qa:approved` to linked PRs, moving card to Code Review / PR. `pdlc-stage-gate` accepts `stage:testing` as a valid post-gate state. |
107
107
  | Branch prefix `hotfix/` | PM (human) only | PR gate only |
108
108
 
109
109
  Agents MUST NOT self-authorize a bypass. Stop and ask the PM explicitly.