create-agentic-pdlc 2.2.1 → 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 (59) hide show
  1. package/.agentic-pdlc/SETUP_PROMPT.md +3 -4
  2. package/.agentic-pdlc/metrics/raw/2026-W18.jsonl +2 -0
  3. package/.agentic-pdlc/metrics/raw/2026-W21.jsonl +68 -0
  4. package/.agentic-pdlc/metrics/raw/2026-W22.jsonl +114 -0
  5. package/.agentic-setup-prompt.md +3 -4
  6. package/.agentic-setup.md +3 -4
  7. package/.github/ISSUE_TEMPLATE/bug.md +53 -0
  8. package/.github/ISSUE_TEMPLATE/feature.md +54 -0
  9. package/.github/ISSUE_TEMPLATE/task.md +33 -0
  10. package/.github/workflows/add-to-board.yml +1 -1
  11. package/.github/workflows/agent-trigger.yml +4 -4
  12. package/.github/workflows/agentic-metrics.yml +171 -38
  13. package/.github/workflows/ci.yml +1 -1
  14. package/.github/workflows/npm-publish.yml +2 -2
  15. package/.github/workflows/pdlc-health-check.yml +1 -3
  16. package/.github/workflows/pdlc-stage-gate.yml +2 -2
  17. package/.github/workflows/project-automation.yml +79 -16
  18. package/.github/workflows/qa-agent.yml +26 -15
  19. package/.github/workflows/qa-gate.yml +51 -0
  20. package/AGENTS.md +50 -8
  21. package/CLAUDE.md +53 -3
  22. package/SETUP.md +4 -1
  23. package/adapters/claude-code/skill.md +44 -20
  24. package/adapters/hooks/pdlc-stage-gate.sh +2 -7
  25. package/bin/cli.js +41 -9
  26. package/docs/flow.md +8 -21
  27. package/docs/pdlc.md +24 -16
  28. package/docs/superpowers/plans/2026-05-28-jules-label-pat-split.md +240 -0
  29. package/docs/superpowers/plans/2026-05-29-agentic-pulse-rework-taxonomy.md +474 -0
  30. package/docs/superpowers/plans/2026-05-29-qa-gate-enforcement.md +354 -0
  31. package/docs/superpowers/specs/2026-05-29-agentic-pulse-rework-taxonomy-design.md +122 -0
  32. package/package.json +1 -1
  33. package/templates/.github/ISSUE_TEMPLATE/bug.md +53 -0
  34. package/templates/.github/ISSUE_TEMPLATE/feature.md +54 -0
  35. package/templates/.github/ISSUE_TEMPLATE/task.md +33 -0
  36. package/templates/.github/workflows/add-to-board.yml +4 -4
  37. package/templates/.github/workflows/agent-trigger.yml +24 -15
  38. package/{.agentic-pdlc/templates → templates}/.github/workflows/agentic-metrics.yml +166 -36
  39. package/templates/.github/workflows/ci.yml +15 -1
  40. package/templates/.github/workflows/pdlc-health-check.yml +1 -3
  41. package/templates/.github/workflows/pdlc-stage-gate.yml +2 -2
  42. package/templates/.github/workflows/project-automation.yml +93 -36
  43. package/templates/.github/workflows/qa-agent.yml +33 -17
  44. package/templates/.github/workflows/qa-gate.yml +51 -0
  45. package/templates/AGENTS.md +74 -23
  46. package/templates/docs/pdlc.md +24 -16
  47. package/.agentic-pdlc/templates/.github/CODEOWNERS +0 -5
  48. package/.agentic-pdlc/templates/.github/copilot-instructions.md +0 -12
  49. package/.agentic-pdlc/templates/.github/workflows/add-to-board.yml +0 -38
  50. package/.agentic-pdlc/templates/.github/workflows/agent-trigger.yml +0 -146
  51. package/.agentic-pdlc/templates/.github/workflows/auto-approve.yml +0 -16
  52. package/.agentic-pdlc/templates/.github/workflows/ci.yml +0 -40
  53. package/.agentic-pdlc/templates/.github/workflows/pdlc-health-check.yml +0 -123
  54. package/.agentic-pdlc/templates/.github/workflows/pdlc-stage-gate.yml +0 -51
  55. package/.agentic-pdlc/templates/.github/workflows/project-automation.yml +0 -278
  56. package/.agentic-pdlc/templates/.github/workflows/protect-workflows.yml +0 -21
  57. package/.agentic-pdlc/templates/.github/workflows/qa-agent.yml +0 -128
  58. package/.agentic-pdlc/templates/AGENTS.md +0 -81
  59. package/.agentic-pdlc/templates/docs/pdlc.md +0 -115
@@ -1,278 +0,0 @@
1
- name: PDLC Board Automation
2
-
3
- on:
4
- pull_request:
5
- types: [opened, reopened, closed, labeled]
6
- pull_request_review:
7
- types: [submitted]
8
- issues:
9
- types: [labeled]
10
-
11
- env:
12
- PROJECT_ID: "{{PROJECT_ID}}"
13
- STATUS_FIELD_ID: "{{STATUS_FIELD_ID}}"
14
- STATUS_IDEA: "{{ID_IDEA}}"
15
- STATUS_EXPLORATION: "{{ID_EXPLORATION}}"
16
- STATUS_BRAINSTORMING: "{{ID_BRAINSTORMING}}"
17
- STATUS_DETAILING: "{{ID_DETAILING}}"
18
- STATUS_APPROVAL: "{{ID_APPROVAL}}"
19
- STATUS_DEVELOPMENT: "{{ID_DEVELOPMENT}}"
20
- STATUS_TESTING: "{{ID_TESTING}}"
21
- STATUS_CODE_REVIEW_PR: "{{ID_CODE_REVIEW_PR}}"
22
- STATUS_PRODUCTION: "{{ID_PRODUCTION}}"
23
-
24
- jobs:
25
- # Issue Labeled → Move Upstream
26
- move-card-on-label:
27
- name: Upstream Label → Move Card
28
- if: github.event_name == 'issues' && github.event.action == 'labeled'
29
- runs-on: ubuntu-latest
30
- env:
31
- PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
32
- steps:
33
- - name: Detect Label and Move Issue
34
- if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
35
- uses: actions/github-script@v7
36
- with:
37
- github-token: ${{ env.PROJECT_PAT }}
38
- script: |
39
- const labelName = context.payload.label.name;
40
- let targetStatusId = null;
41
- let stageName = null;
42
-
43
- if (labelName === 'stage:exploration') {
44
- targetStatusId = process.env.STATUS_EXPLORATION;
45
- stageName = 'Exploration';
46
- } else if (labelName === 'stage:brainstorming') {
47
- targetStatusId = process.env.STATUS_BRAINSTORMING;
48
- stageName = 'Brainstorming';
49
- } else if (labelName === 'stage:detailing') {
50
- targetStatusId = process.env.STATUS_DETAILING;
51
- stageName = 'Detailing';
52
- } else if (labelName === 'stage:approval') {
53
- targetStatusId = process.env.STATUS_APPROVAL;
54
- stageName = 'Approval';
55
- } else if (labelName === 'stage:development') {
56
- targetStatusId = process.env.STATUS_DEVELOPMENT;
57
- stageName = 'Development';
58
- } else if (labelName === 'stage:testing') {
59
- targetStatusId = process.env.STATUS_TESTING;
60
- stageName = 'Testing';
61
- }
62
-
63
- if (!targetStatusId) {
64
- console.log('No stage PDLC label found. Skipping.');
65
- return;
66
- }
67
-
68
- const { issue: { number, node_id } } = context.payload;
69
-
70
- const moveItem = async (nodeId, statusId) => {
71
- const { addProjectV2ItemById: { item } } = await github.graphql(`
72
- mutation($p: ID!, $c: ID!) {
73
- addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
74
- }`, { p: process.env.PROJECT_ID, c: nodeId });
75
-
76
- await github.graphql(`
77
- mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
78
- updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
79
- projectV2Item { id }
80
- }
81
- }`, {
82
- p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
83
- v: { singleSelectOptionId: statusId }
84
- });
85
- };
86
-
87
- await moveItem(node_id, targetStatusId);
88
- console.log(`Issue #${number} moved to ${stageName}`);
89
-
90
- # OPTIONAL: Uncomment to enable architecture-violation → Idea
91
- # move-violation-to-board:
92
- # name: architecture-violation → 💡 Idea
93
- # if: github.event_name == 'issues' && github.event.action == 'labeled' && github.event.label.name == 'architecture-violation'
94
- # runs-on: ubuntu-latest
95
- # steps:
96
- # - name: Move issue to Idea
97
- # if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
98
- # uses: actions/github-script@v7
99
- # with:
100
- # github-token: ${{ env.PROJECT_PAT }}
101
- # script: |
102
- # const { issue: { number, node_id } } = context.payload;
103
- # const { addProjectV2ItemById: { item } } = await github.graphql(`
104
- # mutation($p: ID!, $c: ID!) {
105
- # addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
106
- # }`, { p: process.env.PROJECT_ID, c: node_id });
107
- # await github.graphql(`
108
- # mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
109
- # updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
110
- # projectV2Item { id }
111
- # }
112
- # }`, {
113
- # p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
114
- # v: { singleSelectOptionId: process.env.STATUS_IDEA }
115
- # });
116
- # console.log(`Issue #${number} moved to Idea`);
117
-
118
- # PR Opened → Move linked issue to Testing (Variant B — QA Agent enabled)
119
- move-card-on-pr-open:
120
- name: Open PR → Testing
121
- if: github.event_name == 'pull_request' && (github.event.action == 'opened' || github.event.action == 'reopened')
122
- runs-on: ubuntu-latest
123
- env:
124
- PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
125
- steps:
126
- - name: Move linked issue to Testing
127
- if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
128
- uses: actions/github-script@v7
129
- with:
130
- github-token: ${{ env.PROJECT_PAT }}
131
- script: |
132
- const prNumber = context.payload.pull_request.number;
133
- const { owner, repo } = context.repo;
134
-
135
- const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
136
- const body = pr.body ?? '';
137
-
138
- // Extract issues linked via "Closes #N", "Fixes #N", "Resolves #N"
139
- const linkedIssues = [...body.matchAll(/(?:Closes?|Fixes?|Resolves?)\s+#(\d+)/gi)]
140
- .map(m => parseInt(m[1]));
141
-
142
- const moveItem = async (nodeId) => {
143
- const { addProjectV2ItemById: { item } } = await github.graphql(`
144
- mutation($p: ID!, $c: ID!) {
145
- addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
146
- }`, { p: process.env.PROJECT_ID, c: nodeId });
147
-
148
- await github.graphql(`
149
- mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
150
- updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
151
- projectV2Item { id }
152
- }
153
- }`, {
154
- p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
155
- v: { singleSelectOptionId: process.env.STATUS_TESTING }
156
- });
157
- };
158
-
159
- if (linkedIssues.length > 0) {
160
- for (const n of linkedIssues) {
161
- const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number: n });
162
- await moveItem(issue.node_id);
163
- console.log(`Issue #${n} → Testing`);
164
- }
165
- } else {
166
- await moveItem(pr.node_id);
167
- console.log(`PR #${prNumber} → Testing (no linked issue)`);
168
- }
169
-
170
- await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: ['pr:in-review'] }).catch(() => {});
171
-
172
- # QA Approved → Move linked issue to Code Review / PR
173
- move-card-on-qa-pass:
174
- name: qa:approved → Code Review / PR
175
- if: github.event_name == 'pull_request' && github.event.action == 'labeled' && github.event.label.name == 'qa:approved'
176
- runs-on: ubuntu-latest
177
- env:
178
- PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
179
- steps:
180
- - name: Move linked issue to Code Review / PR
181
- if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
182
- uses: actions/github-script@v7
183
- with:
184
- github-token: ${{ env.PROJECT_PAT }}
185
- script: |
186
- const prNumber = context.payload.pull_request.number;
187
- const { owner, repo } = context.repo;
188
- const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
189
- const body = pr.body ?? '';
190
- const linkedIssues = [...body.matchAll(/(?:Closes?|Fixes?|Resolves?)\s+#(\d+)/gi)].map(m => parseInt(m[1]));
191
- const moveItem = async (nodeId) => {
192
- const { addProjectV2ItemById: { item } } = await github.graphql(`
193
- mutation($p: ID!, $c: ID!) {
194
- addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
195
- }`, { p: process.env.PROJECT_ID, c: nodeId });
196
- await github.graphql(`
197
- mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
198
- updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
199
- projectV2Item { id }
200
- }
201
- }`, {
202
- p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
203
- v: { singleSelectOptionId: process.env.STATUS_CODE_REVIEW_PR }
204
- });
205
- };
206
- if (linkedIssues.length > 0) {
207
- for (const n of linkedIssues) {
208
- const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number: n });
209
- await moveItem(issue.node_id);
210
- console.log(`Issue #${n} → Code Review / PR`);
211
- }
212
- } else {
213
- await moveItem(pr.node_id);
214
- console.log(`PR #${prNumber} → Code Review / PR (no linked issue)`);
215
- }
216
-
217
- # Review Approved → Add Label
218
- move-card-on-review-approved:
219
- name: Approved PR → Add Label
220
- if: github.event_name == 'pull_request_review' && github.event.review.state == 'approved'
221
- runs-on: ubuntu-latest
222
- env:
223
- PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
224
- steps:
225
- - name: Swap PR labels
226
- if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
227
- uses: actions/github-script@v7
228
- with:
229
- github-token: ${{ env.PROJECT_PAT }}
230
- script: |
231
- const prNumber = context.payload.pull_request.number;
232
- const { owner, repo } = context.repo;
233
- try { await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name: 'pr:in-review' }); } catch {}
234
- await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: ['pr:approved'] }).catch(() => {});
235
-
236
- # PR Merged → Production
237
- move-card-on-pr-merge:
238
- name: Merged PR → Production
239
- if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true
240
- runs-on: ubuntu-latest
241
- env:
242
- PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
243
- steps:
244
- - name: Move issue to Production
245
- if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
246
- uses: actions/github-script@v7
247
- with:
248
- github-token: ${{ env.PROJECT_PAT }}
249
- script: |
250
- const prNumber = context.payload.pull_request.number;
251
- const { owner, repo } = context.repo;
252
- const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
253
- const body = pr.body ?? '';
254
- const linkedIssues = [...body.matchAll(/(?:Closes?|Fixes?|Resolves?)\s+#(\d+)/gi)].map(m => parseInt(m[1]));
255
-
256
- const moveItem = async (nodeId) => {
257
- const { addProjectV2ItemById: { item } } = await github.graphql(`
258
- mutation($p: ID!, $c: ID!) {
259
- addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
260
- }`, { p: process.env.PROJECT_ID, c: nodeId });
261
- await github.graphql(`
262
- mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
263
- updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
264
- projectV2Item { id }
265
- }
266
- }`, { p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
267
- v: { singleSelectOptionId: process.env.STATUS_PRODUCTION } });
268
- };
269
-
270
- if (linkedIssues.length > 0) {
271
- for (const n of linkedIssues) {
272
- const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number: n });
273
- await moveItem(issue.node_id);
274
- console.log(`Issue #${n} → Production`);
275
- }
276
- } else {
277
- await moveItem(pr.node_id);
278
- }
@@ -1,21 +0,0 @@
1
- name: Protect Workflows
2
-
3
- on:
4
- pull_request:
5
- types: [opened, synchronize, reopened, labeled]
6
- paths:
7
- - '.github/**'
8
-
9
- jobs:
10
- block-unauthorized-edits:
11
- name: Protect .github directory
12
- runs-on: ubuntu-latest
13
- steps:
14
- - name: Check for Human Approval
15
- if: ${{ !contains(github.event.pull_request.labels.*.name, 'human-approved') }}
16
- run: |
17
- echo "🚨 Modifications in the .github/ directory detected."
18
- echo "As a security measure, this repository blocks workflow edits by default."
19
- echo "If you are an AI Agent, do not add the approval label yourself."
20
- echo "If you are the human owner, please add the 'human-approved' label to this PR to allow merging."
21
- exit 1
@@ -1,128 +0,0 @@
1
- name: AI QA Agent
2
- on:
3
- pull_request:
4
- types: [opened, synchronize, reopened]
5
-
6
- permissions:
7
- pull-requests: write
8
- contents: read
9
- issues: read
10
- models: read
11
-
12
- jobs:
13
- qa:
14
- name: AC Coverage Verification (GitHub Models)
15
- runs-on: ubuntu-latest
16
- env:
17
- PROJECT_PAT: ${{ secrets.PROJECT_PAT }}
18
- PROJECT_ID: "{{PROJECT_ID}}"
19
- STATUS_FIELD_ID: "{{STATUS_FIELD_ID}}"
20
- STATUS_CODE_REVIEW_PR: "{{ID_CODE_REVIEW_PR}}"
21
- steps:
22
- - uses: actions/checkout@v4
23
- with:
24
- fetch-depth: 0
25
-
26
- - name: Verify AC Coverage via GitHub Models
27
- env:
28
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29
- run: |
30
- set -e
31
-
32
- PR_NUMBER="${{ github.event.pull_request.number }}"
33
- BASE="${{ github.event.pull_request.base.sha }}"
34
- HEAD="${{ github.event.pull_request.head.sha }}"
35
-
36
- # Get PR diff (truncated to 8000 chars to stay within context limits)
37
- DIFF=$(git diff "$BASE" "$HEAD" | head -c 64000)
38
-
39
- # Extract linked issues from PR body
40
- PR_BODY=$(gh pr view "$PR_NUMBER" --json body --jq '.body // ""')
41
- ISSUE_NUMS=$(echo "$PR_BODY" | grep -oiE '(Closes?|Fixes?|Resolves?)\s+#([0-9]+)' | grep -oE '[0-9]+' || true)
42
-
43
- # Build acceptance criteria context
44
- AC_CONTEXT=""
45
- if [ -n "$ISSUE_NUMS" ]; then
46
- for NUM in $ISSUE_NUMS; do
47
- ISSUE_BODY=$(gh issue view "$NUM" --json body --jq '.body // ""' 2>/dev/null || echo "")
48
- AC_CONTEXT="${AC_CONTEXT}\\n\\n--- Issue #${NUM} ---\\n${ISSUE_BODY}"
49
- done
50
- fi
51
-
52
- if [ -z "$AC_CONTEXT" ]; then
53
- AC_CONTEXT="No linked issue found. Evaluate if the PR description is self-contained."
54
- fi
55
-
56
- # Serialize prompt as JSON string and call GitHub Models API (30s timeout)
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
-
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")
65
-
66
- if [ "$RESPONSE" = "API_ERROR" ]; then
67
- gh pr edit "$PR_NUMBER" --add-label "infra:qa-broken"
68
- gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not reach GitHub Models API. Manual review required."
69
- exit 0
70
- fi
71
-
72
- 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")')
73
- EXPLANATION=$(echo "$RESPONSE" | python3 -c 'import json,sys; d=json.load(sys.stdin); t=d.get("choices",[{}])[0].get("message",{}).get("content","").strip(); lines=t.split("\n",1); print(lines[1].strip() if len(lines)>1 else "")')
74
-
75
- if echo "$VERDICT" | grep -q "^PASS"; then
76
- gh pr edit "$PR_NUMBER" --add-label "qa:approved"
77
- gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** AC coverage verified. ${EXPLANATION}"
78
- elif echo "$VERDICT" | grep -q "^FAIL"; then
79
- gh pr edit "$PR_NUMBER" --add-label "qa:needs-work"
80
- gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** AC coverage insufficient. ${EXPLANATION}"
81
- else
82
- gh pr edit "$PR_NUMBER" --add-label "infra:qa-broken"
83
- gh pr comment "$PR_NUMBER" --body "🤖 **QA Agent:** Could not parse GitHub Models response. Manual review required."
84
- fi
85
-
86
- - name: Move board card to Code Review on qa:approved
87
- if: ${{ env.PROJECT_PAT != '' && env.PROJECT_ID != '{{PROJECT_ID}}' }}
88
- uses: actions/github-script@v7
89
- with:
90
- github-token: ${{ env.PROJECT_PAT }}
91
- script: |
92
- const prNumber = context.payload.pull_request.number;
93
- const { owner, repo } = context.repo;
94
-
95
- const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
96
- if (!pr.labels.some(l => l.name === 'qa:approved')) {
97
- console.log('qa:approved not on PR — skipping board move');
98
- return;
99
- }
100
-
101
- const body = pr.body ?? '';
102
- const linkedIssues = [...body.matchAll(/(?:Closes?|Fixes?|Resolves?)\s+#(\d+)/gi)]
103
- .map(m => parseInt(m[1]));
104
-
105
- const moveItem = async (nodeId) => {
106
- const { addProjectV2ItemById: { item } } = await github.graphql(`
107
- mutation($p: ID!, $c: ID!) {
108
- addProjectV2ItemById(input: {projectId: $p, contentId: $c}) { item { id } }
109
- }`, { p: process.env.PROJECT_ID, c: nodeId });
110
- await github.graphql(`
111
- mutation($p: ID!, $i: ID!, $f: ID!, $v: ProjectV2FieldValue!) {
112
- updateProjectV2ItemFieldValue(input: {projectId: $p, itemId: $i, fieldId: $f, value: $v}) {
113
- projectV2Item { id }
114
- }
115
- }`, { p: process.env.PROJECT_ID, i: item.id, f: process.env.STATUS_FIELD_ID,
116
- v: { singleSelectOptionId: process.env.STATUS_CODE_REVIEW_PR } });
117
- };
118
-
119
- if (linkedIssues.length > 0) {
120
- for (const n of linkedIssues) {
121
- const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number: n });
122
- await moveItem(issue.node_id);
123
- console.log(`Issue #${n} → Code Review / PR`);
124
- }
125
- } else {
126
- await moveItem(pr.node_id);
127
- console.log(`PR #${prNumber} → Code Review / PR (no linked issue)`);
128
- }
@@ -1,81 +0,0 @@
1
- # {{PROJECT_NAME}} — AI Agent Instructions
2
-
3
- This template is the contract between the project and any external AI agent
4
- (Claude Code, Cursor, Copilot, Jules, Codex, Sweep, etc.). Read this before committing any change.
5
-
6
- ## Project Overview
7
-
8
- {{PROJECT_DESCRIPTION}}
9
-
10
- **Structure:**
11
- {{PROJECT_STRUCTURE}}
12
-
13
- ## Before Any Change
14
-
15
- ```bash
16
- git fetch origin && git checkout main && git pull
17
- ```
18
-
19
- Always start from the current `main` HEAD. Never work over stale snapshots.
20
-
21
- ## Invariants / Non-negotiable business rules
22
-
23
- {{INVARIANTS}}
24
- <!-- Examples:
25
- 1. **Human-in-the-Loop** — No external side-effect actions without explicit human approval.
26
- 2. **Immutable Audit-Log** — It's strictly forbidden to UPDATE/DELETE on audit_log; INSERT only.
27
- 3. **Credential Isolation** — Decryption occurs only in a specific service.
28
- -->
29
-
30
- ## Mandatory Workflow
31
-
32
- 0. **Identity**: Always prefix your GitHub comments with `🤖 **Agent:** ` to distinguish yourself.
33
- 1. **Initial State**: When beginning work on a new issue, your very first action must be to apply the `stage:exploration` label using the GitHub CLI (`gh issue edit <N> --add-label "stage:exploration"`).
34
- 2. Read the issue entirely — understand its type (US/BUG/TASK/SPIKE) and the Acceptance Criteria.
35
- 3. Read `docs/pdlc.md` — understand the PDLC and the Definition of Done in this project.
36
- 4. Read all files mentioned in the issue's technical context.
37
- 5. Implement the **minimum viable change** that satisfies the ACs — do not refactor beyond scope.
38
- 6. Run tests: `{{TEST_COMMAND}}`
39
- 7. Run typecheck (if applicable): `{{TYPECHECK_COMMAND}}`
40
- 8. Create a Pull Request with `Closes #N` in the body — automation moves the board.
41
-
42
- ### Spec format (Upstream Agents)
43
-
44
- When detailing a solution in an issue body, you must **always** include both the user story and the acceptance criteria. Never append only the ACs to an existing text; rewrite the full issue body in this standard format:
45
-
46
- ```
47
- **As** [user],
48
- **I want** [action],
49
- **so that** [benefit].
50
-
51
- ---
52
-
53
- ## Acceptance Criteria
54
-
55
- **AC1 — ...**
56
- - Given ...
57
- - When ...
58
- - Then ...
59
-
60
- **AC2 — ...**
61
- ...
62
-
63
- ## Files to modify
64
- - `path/to/file.ts` — what changes
65
- ```
66
-
67
- ## What NOT to do
68
-
69
- - Never commit directly to `main`.
70
- - Never open a PR without passing the tests.
71
- - Never implement beyond the immediate scope of the issue.
72
- - Never create future-proofing abstractions for hypothetical features.
73
- {{EXTRA_DONT}}
74
-
75
- ## Project Standards
76
-
77
- - **Tests:** `{{TEST_COMMAND}}`
78
- - **Lint/Types:** `{{LINT_COMMAND}}`
79
- - **Typecheck:** `{{TYPECHECK_COMMAND}}`
80
- - **Build:** `{{BUILD_COMMAND}}`
81
- {{EXTRA_PATTERNS}}
@@ -1,115 +0,0 @@
1
- # PDLC — {{PROJECT_NAME}}
2
-
3
- ## Board Columns
4
-
5
- | Column | Meaning | Who moves the card |
6
- |---|---|---|
7
- | 💡 Idea — don't move manually to Exploration | Backlog — tell agent: "work on issue #XX" | Don't move manually |
8
- | 🔍 Exploration | Claude is analyzing code and context | Label `stage:exploration` |
9
- | 🧠 Brainstorming | Claude proposed approaches, awaiting PM gate | Label `stage:brainstorming` |
10
- | 📐 Detail Solution | Claude is writing the technical spec | Label `stage:detailing` |
11
- | ✅ Approval | Spec ready, awaiting `spec:approved` label | Label `spec:approved` |
12
- | ⚙️ Development | Agent implementing the spec | Label `stage:development` |
13
- | 🧪 Testing | CI pipeline or AI QA Agent running (Variant B) | GitHub Actions / QA Agent |
14
- | 👁 Code Review / PR | PR opened (Variant A) or QA passed (Variant B) | GitHub Actions |
15
- | 🚀 Ready for Production | Merged | GitHub Actions |
16
-
17
- <!--
18
- Adapt columns as needed. The functional baseline is:
19
- 💡 Idea → ⚙️ Development → 👁 Code Review / PR → 🚀 Ready for Production
20
- -->
21
-
22
- ## Workflow Variants (QA Agent)
23
-
24
- - **Variant A (Default):** PRs bypass the `Testing` column and land directly in `Code Review / PR`.
25
- - **Variant B (QA Agent Enabled):** PRs land in the `Testing` column first. An AI QA agent verifies the PR, adding `qa:pass` or `qa:fail`. Only after a `qa:pass` is the issue moved to `Code Review / PR`.
26
-
27
- ## Board Identifiers (GitHub Projects)
28
-
29
- ```
30
- PROJECT_ID = {{PROJECT_ID}}
31
- STATUS_FIELD = {{STATUS_FIELD_ID}}
32
- REPO = {{REPO_OWNER}}/{{REPO_NAME}}
33
- ```
34
-
35
- ## Column Option IDs
36
-
37
- | Column | Option ID |
38
- |---|---|
39
- | 💡 Idea | `{{ID_IDEA}}` |
40
- | 🔍 Exploration | `{{ID_EXPLORATION}}` |
41
- | 🧠 Brainstorming | `{{ID_BRAINSTORMING}}` |
42
- | 📐 Detail Solution | `{{ID_DETAIL}}` |
43
- | ✅ Approval | `{{ID_APPROVAL}}` |
44
- | ⚙️ Development | `{{ID_DEVELOPMENT}}` |
45
- | 🧪 Testing | `{{ID_TESTING}}` |
46
- | 👁 Code Review / PR | `{{ID_CODE_REVIEW_PR}}` |
47
- | 🚀 Ready for Production | `{{ID_READY_FOR_PRODUCTION}}` |
48
-
49
- ## Agent × Phase Mapping
50
-
51
- | Phase | Responsible |
52
- |---|---|
53
- | 💡 → 📐 (upstream) | Claude (or ideation agent) in conversational session |
54
- | ⚙️ → 🔀 (downstream) | {{IMPLEMENTATION_AGENT}} (e.g. Jules `@google-labs-jules`) |
55
- | 👁 Code Review / PR | Human (you) |
56
- | Automatic transitions | GitHub Actions |
57
-
58
- ## Issue Title Conventions
59
-
60
- ```
61
- [icon] [PREFIX]: [short description, imperative tense]
62
-
63
- 👤 US: user story
64
- 🐛 BUG: bug
65
- 🔧 TASK: operational task
66
- 🔬 SPIKE: exploration/evaluation spike
67
- ```
68
-
69
- ## Labels
70
-
71
- | Label | Entity | Color | Meaning |
72
- |---|---|---|---|
73
- | `stage:exploration` | Issue | Purple | Issue is being evaluated |
74
- | `stage:brainstorming` | Issue | Pink | Proposed approaches awaiting PM gate |
75
- | `stage:detailing` | Issue | Blue | Technical spec is being written |
76
- | `stage:development` | Issue | Orange | Agent is implementing the spec |
77
- | `spec:approved` | Issue | Green | Gate 2 — agent is cleared to implement |
78
- | `pr:in-review` | PR | Yellow | Awaiting code review |
79
- | `pr:approved` | PR | Green | Code review approved |
80
- | `type:us` | Issue | Blue | New feature or behavioral change — full flow |
81
- | `type:task` | Issue | Yellow | Operational/non-functional change — skips brainstorming |
82
- | `type:bug` | Issue | Red | Something broken — skips brainstorming |
83
- | `type:spike` | Issue | Gray | Research/evaluation — never reaches Development |
84
-
85
- ## Approval Gates
86
-
87
- **Gate 1 — PM/Ideation (Brainstorming):**
88
- You comment on the issue approving one of the approaches proposed by the ideation agent.
89
- Format: *"Approved — proceed with option X."*
90
-
91
- **Gate 2 — Tech Lead (Spec):**
92
- You add the `spec:approved` label to the issue after reviewing the technical spec in the body.
93
- This triggers the implementation agent via `agent-trigger.yml`.
94
-
95
- ## Shortcuts by Type
96
-
97
- The `type:*` label is the authoritative signal — set automatically by the agent via type inference (see `adapters/claude-code/skill.md`). Title prefixes (`🔧 TASK:`, `👤 US:`) are hints for humans; the label drives the flow.
98
-
99
- | Label | Flow |
100
- |---|---|
101
- | `type:us` | Full flow — exploration → brainstorming → Gate 1 → detailing → approval |
102
- | `type:task` | Skips brainstorming — exploration → detailing → approval |
103
- | `type:bug` | Skips brainstorming — exploration → detailing → approval |
104
- | `type:spike` | Skips brainstorming — exploration → detailing → conclusion comment (never reaches Development) |
105
-
106
- If no `type:*` label present and agent confidence < 85%, defaults to `type:us` (safe fallback — never skips gates by omission).
107
-
108
- ## Definition of Done
109
-
110
- An issue is truly done when:
111
- - [ ] All Acceptance Criteria described in the body are implemented
112
- - [ ] Tests passing: `{{TEST_COMMAND}}`
113
- - [ ] No invariant violations (CI green)
114
- - [ ] Associated PR explicitly contains `Closes #N`
115
- - [ ] Basic manual smoke test executed after deploy (when applicable)