create-agentic-pdlc 2.2.0 → 2.3.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.
- package/.agentic-pdlc/SETUP_PROMPT.md +3 -4
- package/.agentic-pdlc/metrics/raw/2026-W18.jsonl +2 -0
- package/.agentic-pdlc/metrics/raw/2026-W21.jsonl +68 -0
- package/.agentic-pdlc/templates/.github/workflows/agent-trigger.yml +2 -2
- package/.agentic-pdlc/templates/.github/workflows/agentic-metrics.yml +16 -9
- package/.agentic-pdlc/templates/.github/workflows/ci.yml +14 -0
- package/.agentic-pdlc/templates/.github/workflows/pdlc-health-check.yml +0 -2
- package/.agentic-pdlc/templates/.github/workflows/project-automation.yml +1 -5
- package/.agentic-pdlc/templates/.github/workflows/qa-agent.yml +4 -4
- package/.agentic-pdlc/templates/AGENTS.md +24 -1
- package/.agentic-pdlc/templates/docs/pdlc.md +21 -13
- package/.agentic-setup-prompt.md +3 -4
- package/.agentic-setup.md +3 -4
- package/.github/workflows/agentic-metrics.yml +21 -11
- package/.github/workflows/pdlc-health-check.yml +0 -2
- package/.github/workflows/project-automation.yml +31 -7
- package/.github/workflows/qa-agent.yml +4 -4
- package/AGENTS.md +1 -1
- package/CLAUDE.md +51 -3
- package/SETUP.md +2 -0
- package/adapters/claude-code/skill.md +35 -22
- package/adapters/hooks/pdlc-stage-gate.sh +3 -3
- package/bin/cli.js +103 -13
- package/docs/flow.md +8 -21
- package/docs/pdlc.md +21 -13
- package/package.json +1 -1
- package/templates/.github/workflows/agent-trigger.yml +2 -2
- package/templates/.github/workflows/ci.yml +14 -0
- package/templates/.github/workflows/pdlc-health-check.yml +0 -2
- package/templates/.github/workflows/project-automation.yml +24 -6
- package/templates/.github/workflows/qa-agent.yml +6 -4
- package/templates/AGENTS.md +25 -2
- package/templates/docs/pdlc.md +21 -13
package/CLAUDE.md
CHANGED
|
@@ -1,9 +1,57 @@
|
|
|
1
|
+
# agentic-pdlc
|
|
2
|
+
|
|
3
|
+
**What it is:** npm CLI (`npx create-agentic-pdlc`) that installs a PDLC workflow for AI agent projects. Stack: Markdown + GitHub Actions YAML only — never complex Node/Python/Bash scripts.
|
|
4
|
+
|
|
5
|
+
**Workflow:** `stage:brainstorming` → `stage:detailing` → `spec:approved` → `stage:development` → PR → merge. Labels move the board automatically.
|
|
6
|
+
|
|
7
|
+
## Session Startup
|
|
8
|
+
|
|
9
|
+
Read: `AGENTS.md` (mandatory contract), `docs/pdlc.md` (board + labels — only when operating on the board).
|
|
10
|
+
Run: `gh issue list --state open --label "stage:development" --json number,title --jq '.[] | "#\(.number) \(.title)"'`
|
|
11
|
+
|
|
1
12
|
# PDLC Stage Gate
|
|
2
13
|
|
|
3
14
|
NEVER run `gh pr create` unless one of these is true:
|
|
4
|
-
- The linked issue has label `
|
|
15
|
+
- The linked issue has label `spec:approved`
|
|
5
16
|
- The branch name starts with `hotfix/`
|
|
6
17
|
|
|
7
|
-
|
|
18
|
+
NEVER edit files, create branches, or commit unless the linked issue has label `spec:approved` (set by human PM only) or the branch name starts with `hotfix/`.
|
|
19
|
+
|
|
20
|
+
Advance stages first: `brainstorming` → `detailing` → `approval` → (human adds `spec:approved`) → `development`
|
|
21
|
+
|
|
22
|
+
The PreToolUse hook will block `gh pr create` automatically if this rule is violated.
|
|
23
|
+
|
|
24
|
+
## Human-in-the-Loop
|
|
25
|
+
|
|
26
|
+
| Transition | Gate |
|
|
27
|
+
|---|---|
|
|
28
|
+
| → `stage:brainstorming` | Autonomous — apply immediately |
|
|
29
|
+
| → `stage:detailing` | Ask user — present problem summary + options, wait for choice |
|
|
30
|
+
| → `stage:approval` | **Autonomous** — agent completes spec end-to-end, advances without asking |
|
|
31
|
+
| `spec:approved` | **Human PM only** — agent waits; never adds this label |
|
|
32
|
+
| → `stage:development` | Human applies `spec:approved` label — that IS the gate |
|
|
33
|
+
|
|
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
|
+
|
|
36
|
+
## Stage Transition Rules (non-negotiable)
|
|
37
|
+
|
|
38
|
+
MUST apply `stage:brainstorming` label immediately on starting work — before
|
|
39
|
+
reading any code, before invoking any skill. Then read context and present
|
|
40
|
+
problem summary + 2–3 solution options in a single message.
|
|
41
|
+
|
|
42
|
+
MUST NOT add `stage:detailing` label until the user has explicitly selected
|
|
43
|
+
an approach in the current conversation turn. Work done in a prior
|
|
44
|
+
planning session does NOT count as confirmation.
|
|
45
|
+
|
|
46
|
+
MUST NOT add `spec:approved` or any approval-trigger label under any
|
|
47
|
+
circumstances — these are set by the PM (human) only, after reviewing the spec
|
|
48
|
+
in the issue body. Adding them triggers irreversible automation (Jules dispatch,
|
|
49
|
+
board move).
|
|
50
|
+
|
|
51
|
+
MUST NOT add or remove `stage:development`, `spec:approved`, or `qa:*` labels —
|
|
52
|
+
these are owned by GitHub Actions automation and the PM. The agent is responsible
|
|
53
|
+
for applying `stage:brainstorming`, `stage:detailing`, and `stage:approval` as
|
|
54
|
+
part of the prescribed workflow above.
|
|
8
55
|
|
|
9
|
-
|
|
56
|
+
Each stage transition requires a fresh explicit signal from the user in the same
|
|
57
|
+
session where the transition happens. These rules have no exceptions.
|
package/SETUP.md
CHANGED
|
@@ -12,6 +12,8 @@ Estimated time: 2-3 hours (including GitHub Projects setup).
|
|
|
12
12
|
- GitHub Projects enabled on your account/organization
|
|
13
13
|
- Implementation agent connected to the repository (e.g., Jules: github.com/google-labs/jules)
|
|
14
14
|
|
|
15
|
+
> **Jules users:** After installing the Jules GitHub App at [github.com/settings/installations](https://github.com/settings/installations), set `JULES_ENABLED=true` at **repo → Settings → Variables → Actions** to enable Jules dispatch. If this variable is absent, agent comments are silently skipped — no false "dispatched" messages.
|
|
16
|
+
|
|
15
17
|
---
|
|
16
18
|
|
|
17
19
|
## Step 1 — Create the GitHub Project Board
|
|
@@ -25,7 +25,7 @@ If any of these files are missing, you are in **Setup Mode**. Do not proceed wit
|
|
|
25
25
|
1. **Language Detection:** Analyze the user's previous prompts and preferred language. Conduct this entire Setup Mode and ask all your interactive questions in that same language.
|
|
26
26
|
2. Acknowledge that the framework is not yet set up.
|
|
27
27
|
3. **Pre-filled Context:** Before asking any questions, read the following files if they exist:
|
|
28
|
-
- `.agentic-pdlc/cli-context.json` — written by the CLI. Contains `projectName`, `repoOwner`, `repoName
|
|
28
|
+
- `.agentic-pdlc/cli-context.json` — written by the CLI. Contains `projectName`, `repoOwner`, `repoName`, `projectNumber`, `isOrg`, `boardUrl`, and `patAutoSet` (boolean). Use these values directly and skip the corresponding questions. Honor `patAutoSet` in Step 7 and `boardUrl` in Step 10.
|
|
29
29
|
- `.agentic-pdlc/templates/docs/pdlc.md` — the CLI pre-fills PROJECT_ID, STATUS_FIELD_ID, REPO_OWNER, REPO_NAME, and all 9 column option IDs. If none of the values still contain `{{...}}` placeholders, skip the entire Board IDs question group.
|
|
30
30
|
- `.agentic-pdlc/templates/.github/workflows/project-automation.yml` — the CLI also pre-fills all ID placeholders here. When writing the workflow file, the remaining `{{...}}` placeholders are only non-ID ones (project name, commands, etc.).
|
|
31
31
|
4. Interactively ask the user only for the **missing values**, **one group at a time**:
|
|
@@ -48,25 +48,39 @@ If any of these files are missing, you are in **Setup Mode**. Do not proceed wit
|
|
|
48
48
|
- a) **No** — *No autonomous implementation agent.*
|
|
49
49
|
- b) **@google-labs-jules** — *Jules (recommended if you don't have one).*
|
|
50
50
|
- c) **Other** — *Enter the agent's handle.*
|
|
51
|
+
|
|
52
|
+
When writing `agent-trigger.yml`, set `{{IMPLEMENTATION_AGENT_LABEL}}` as follows:
|
|
53
|
+
- Jules (`@google-labs-jules`): use `jules` — this is the native label the Jules GitHub App watches. **Do NOT use `agent:jules`** — Jules does not watch that label and the trigger will silently fail.
|
|
54
|
+
- Other agents: use the handle without `@`, lowercase (e.g. `@my-agent` → `my-agent`).
|
|
51
55
|
5. Generate and write the missing files replacing the `{{SCREAMING_SNAKE_CASE}}` placeholders using the templates in `.agentic-pdlc/templates/`.
|
|
52
56
|
6. Offer to run the `gh` commands for labels (`spec:approved`, `pr:in-review`, `pr:approved`, `architecture-violation`).
|
|
53
|
-
7.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
7. **`PROJECT_PAT` secret (required for board automation):**
|
|
58
|
+
|
|
59
|
+
Read `patAutoSet` from `.agentic-pdlc/cli-context.json`:
|
|
60
|
+
|
|
61
|
+
**If `patAutoSet === true`:** The CLI already configured this secret automatically. Print `✅ PROJECT_PAT is configured.` and continue to Step 8 — do not ask the user anything.
|
|
62
|
+
|
|
63
|
+
**If `patAutoSet === false` (org repo):** Show the block below and wait for the user to reply "done" or "secret set" before continuing:
|
|
64
|
+
|
|
65
|
+
> Your repo is in an organization. For security, `PROJECT_PAT` must be a dedicated PAT (not your personal OAuth token). Without it, all board card movements in CI will silently skip — no error surfaced.
|
|
66
|
+
>
|
|
67
|
+
> 1. Open: **github.com/settings/tokens** → *Generate new token (classic)*
|
|
68
|
+
> 2. Name: `PROJECT_PAT — <repo-name>`
|
|
69
|
+
> 3. Select scopes: ✅ `repo` + ✅ `project`
|
|
70
|
+
> 4. Copy the token, then run:
|
|
71
|
+
> ```
|
|
72
|
+
> gh secret set PROJECT_PAT --body "<your-token>" --repo <owner>/<repo>
|
|
73
|
+
> ```
|
|
74
|
+
> 5. Reply **"done"** when finished.
|
|
62
75
|
8. **IMPORTANT:** Delete the setup prompt file by running exactly:
|
|
63
76
|
```
|
|
64
77
|
rm -f .agentic-setup.md .agentic-setup-prompt.md .agentic-pdlc/SETUP_PROMPT.md
|
|
65
78
|
```
|
|
66
79
|
**Do NOT run `git add` or any other git command.** These files were never committed and do not exist in the git index. This command must run **before** the commit step.
|
|
67
80
|
9. Commit everything with the message: `chore: setup agentic-pdlc framework`.
|
|
68
|
-
10. Conclude Setup Mode. Read `
|
|
69
|
-
|
|
81
|
+
10. Conclude Setup Mode. Read `boardUrl` from `.agentic-pdlc/cli-context.json` and show the user exactly this (do not reconstruct the URL — `boardUrl` already includes the correct `users/` or `orgs/` path segment and `?layout=board`):
|
|
82
|
+
|
|
83
|
+
`🎉 Setup complete! Your board: <boardUrl>`
|
|
70
84
|
|
|
71
85
|
---
|
|
72
86
|
|
|
@@ -88,9 +102,9 @@ If `AGENTS.md` and `docs/pdlc.md` are present, you are in **Execution Mode**.
|
|
|
88
102
|
|
|
89
103
|
### 0. [FIRST] Issue Type Identification
|
|
90
104
|
|
|
91
|
-
**Run before anything else — before
|
|
105
|
+
**Run before anything else — before reading code.**
|
|
92
106
|
|
|
93
|
-
Reading the issue title and body for type inference is exempt from the
|
|
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.
|
|
94
108
|
|
|
95
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.
|
|
96
110
|
2. Read issue title + body (metadata only — no code reading at this step).
|
|
@@ -106,10 +120,10 @@ Reading the issue title and body for type inference is exempt from the `stage:ex
|
|
|
106
120
|
|
|
107
121
|
| Type | Flow |
|
|
108
122
|
|---|---|
|
|
109
|
-
| `type:us` |
|
|
110
|
-
| `type:task` |
|
|
111
|
-
| `type:bug` |
|
|
112
|
-
| `type:spike` |
|
|
123
|
+
| `type:us` | brainstorming → Gate 1 → detailing → approval |
|
|
124
|
+
| `type:task` | brainstorming → Gate 1 → detailing → approval |
|
|
125
|
+
| `type:bug` | brainstorming → Gate 1 → detailing → approval |
|
|
126
|
+
| `type:spike` | brainstorming → Gate 1 → detailing → conclusion comment (never reaches Development) |
|
|
113
127
|
|
|
114
128
|
### 0.1 Board Labels — Mandatory at Every State Transition
|
|
115
129
|
|
|
@@ -117,11 +131,10 @@ These label commands are non-negotiable. They run **before** the activity they a
|
|
|
117
131
|
|
|
118
132
|
| When | Command |
|
|
119
133
|
|---|---|
|
|
120
|
-
| Before reading any code / invoking any skill | `gh issue edit <N> --add-label "stage:
|
|
121
|
-
| Before presenting architecture approaches | `gh issue edit <N> --add-label "stage:brainstorming" --remove-label "stage:exploration"` |
|
|
134
|
+
| Before reading any code / invoking any skill | `gh issue edit <N> --add-label "stage:brainstorming"` |
|
|
122
135
|
| Before writing the technical spec | `gh issue edit <N> --add-label "stage:detailing" --remove-label "stage:brainstorming"` |
|
|
123
136
|
|
|
124
|
-
No investigation, no skill invocation, no code reading happens before `stage:
|
|
137
|
+
No investigation, no skill invocation, no code reading happens before `stage:brainstorming` is applied. No spec writing starts before `stage:detailing` is set (and `stage:brainstorming` removed).
|
|
125
138
|
|
|
126
139
|
### 0.1 PR Stage Gate — Non-Negotiable
|
|
127
140
|
|
|
@@ -137,7 +150,7 @@ git checkout -b hotfix/<N>-<description>
|
|
|
137
150
|
```
|
|
138
151
|
|
|
139
152
|
### 1. Daily Upstream Loop
|
|
140
|
-
Your job is to move issues from "💡 Idea
|
|
153
|
+
Your job is to move issues from "💡 Idea" to "📐 Detail Solution".
|
|
141
154
|
When asked to work on a feature, you will:
|
|
142
155
|
- Explore the code context.
|
|
143
156
|
- Present architectural approaches (Brainstorming).
|
|
@@ -26,8 +26,8 @@ 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 "
|
|
30
|
-
echo "✅ PDLC: Issue #$ISSUE_NUM approved — gate passed."
|
|
29
|
+
if echo "$LABELS" | grep -qw "spec:approved"; then
|
|
30
|
+
echo "✅ PDLC: Issue #$ISSUE_NUM spec approved by PM — gate passed."
|
|
31
31
|
exit 0
|
|
32
32
|
fi
|
|
33
33
|
|
|
@@ -39,6 +39,6 @@ fi
|
|
|
39
39
|
STAGE=$(echo "$LABELS" | tr ' ' '\n' | grep "^stage:" | head -1 || echo "none")
|
|
40
40
|
echo "❌ PDLC Stage Gate: Issue #$ISSUE_NUM is not approved."
|
|
41
41
|
echo " Current stage: $STAGE"
|
|
42
|
-
echo " Required:
|
|
42
|
+
echo " Required: spec:approved (set by human PM) or stage:development label on the issue."
|
|
43
43
|
echo " Emergency bypass: rename branch to hotfix/<issue-number>-<description>."
|
|
44
44
|
exit 1
|
package/bin/cli.js
CHANGED
|
@@ -84,6 +84,11 @@ console.log(`${cyan}============================================================
|
|
|
84
84
|
console.log(`${cyan}${i18n.welcome}${reset}`);
|
|
85
85
|
console.log(`${cyan}================================================================${reset}\n`);
|
|
86
86
|
|
|
87
|
+
function buildBoardUrl(repoOwner, projectNumber, isOrg) {
|
|
88
|
+
const segment = isOrg ? 'orgs' : 'users';
|
|
89
|
+
return `https://github.com/${segment}/${repoOwner}/projects/${projectNumber}/views/1?layout=board`;
|
|
90
|
+
}
|
|
91
|
+
|
|
87
92
|
// Helper function to recursively copy directories
|
|
88
93
|
function copyDirSync(src, dest) {
|
|
89
94
|
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
|
|
@@ -121,6 +126,43 @@ async function runSetup() {
|
|
|
121
126
|
process.exit(1);
|
|
122
127
|
}
|
|
123
128
|
|
|
129
|
+
function getScopes() {
|
|
130
|
+
try {
|
|
131
|
+
const out = execFileSync('gh', ['api', 'user', '-i'], { stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf8' });
|
|
132
|
+
const line = out.split('\n').find(l => l.toLowerCase().startsWith('x-oauth-scopes:'));
|
|
133
|
+
return line ? line.split(':').slice(1).join(':').split(',').map(s => s.trim()) : [];
|
|
134
|
+
} catch (e) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const scopesBefore = getScopes();
|
|
140
|
+
if (scopesBefore.length > 0 && !scopesBefore.includes('project')) {
|
|
141
|
+
console.log(`${yellow}⚠️ Token missing 'project' scope — required for GitHub Projects board.${reset}`);
|
|
142
|
+
console.log(`${yellow} Refreshing token now (browser may open)...${reset}\n`);
|
|
143
|
+
try {
|
|
144
|
+
execSync('gh auth refresh -h github.com -s project', { stdio: 'inherit' });
|
|
145
|
+
} catch (e) {
|
|
146
|
+
console.log(`${red}❌ Token refresh failed. Run manually: gh auth refresh -h github.com -s project${reset}`);
|
|
147
|
+
rl.close();
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
const scopesAfter = getScopes();
|
|
151
|
+
if (scopesAfter.length > 0 && !scopesAfter.includes('project')) {
|
|
152
|
+
console.log(`\n${red}❌ 'project' scope still missing after refresh.${reset}`);
|
|
153
|
+
console.log(`${yellow} Active scopes: ${scopesAfter.join(', ')}${reset}`);
|
|
154
|
+
console.log(`${yellow} Note: gh uses OAuth tokens — visible at github.com/settings/applications, not /settings/tokens${reset}`);
|
|
155
|
+
console.log(`${yellow} Try manually: gh auth refresh -h github.com -s project${reset}`);
|
|
156
|
+
rl.close();
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
if (scopesAfter.length > 0) {
|
|
160
|
+
console.log(`\n${green}✅ Token refreshed. Active scopes: ${scopesAfter.join(', ')}${reset}\n`);
|
|
161
|
+
} else {
|
|
162
|
+
console.log(`\n${green}✅ Token refreshed with 'project' scope.${reset}\n`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
124
166
|
const agentAnswer = await askQuestion(i18n.ask_agent);
|
|
125
167
|
const agent = agentAnswer.trim().toLowerCase();
|
|
126
168
|
if (!['claude', 'cursor', 'copilot'].includes(agent)) {
|
|
@@ -185,26 +227,36 @@ async function runSetup() {
|
|
|
185
227
|
}
|
|
186
228
|
}
|
|
187
229
|
|
|
230
|
+
const defaultLabels = [
|
|
231
|
+
'bug', 'documentation', 'duplicate', 'enhancement',
|
|
232
|
+
'good first issue', 'help wanted', 'invalid', 'question', 'wontfix'
|
|
233
|
+
];
|
|
234
|
+
for (const label of defaultLabels) {
|
|
235
|
+
try {
|
|
236
|
+
execFileSync('gh', ['label', 'delete', label, '--repo', repo, '--yes'], { stdio: 'ignore' });
|
|
237
|
+
} catch (_) {}
|
|
238
|
+
}
|
|
239
|
+
|
|
188
240
|
// Project V2
|
|
189
241
|
console.log(`\n${cyan}${i18n.creating_project}${reset}`);
|
|
190
242
|
let ownerId, projectId, projectNumber;
|
|
191
243
|
try {
|
|
192
244
|
if (isOrg) {
|
|
193
|
-
const orgOutput = execFileSync('gh', ['api', 'graphql', '-f', 'query=query($login: String!) { organization(login: $login) { id } }', '-f', `login=${repoOwner}`, '--jq', '.data.organization.id']).toString().trim();
|
|
245
|
+
const orgOutput = execFileSync('gh', ['api', 'graphql', '-f', 'query=query($login: String!) { organization(login: $login) { id } }', '-f', `login=${repoOwner}`, '--jq', '.data.organization.id'], { stdio: ['ignore', 'pipe', 'pipe'] }).toString().trim();
|
|
194
246
|
ownerId = orgOutput;
|
|
195
247
|
} else {
|
|
196
|
-
const userOutput = execFileSync('gh', ['api', 'graphql', '-f', 'query={ viewer { id } }', '--jq', '.data.viewer.id']).toString().trim();
|
|
248
|
+
const userOutput = execFileSync('gh', ['api', 'graphql', '-f', 'query={ viewer { id } }', '--jq', '.data.viewer.id'], { stdio: ['ignore', 'pipe', 'pipe'] }).toString().trim();
|
|
197
249
|
ownerId = userOutput;
|
|
198
250
|
}
|
|
199
251
|
|
|
200
|
-
const projectCreateRaw = execFileSync('gh', ['api', 'graphql', '-f', 'query=mutation($owner: ID!, $title: String!) { createProjectV2(input: {ownerId: $owner, title: $title}) { projectV2 { id number } } }', '-f', `owner=${ownerId}`, '-f', `title=${boardName}`]).toString().trim();
|
|
201
|
-
const projectCreateResponse = JSON.parse(projectCreateRaw);
|
|
202
|
-
if (projectCreateResponse
|
|
252
|
+
const projectCreateRaw = execFileSync('gh', ['api', 'graphql', '-f', 'query=mutation($owner: ID!, $title: String!) { createProjectV2(input: {ownerId: $owner, title: $title}) { projectV2 { id number } } }', '-f', `owner=${ownerId}`, '-f', `title=${boardName}`], { stdio: ['ignore', 'pipe', 'pipe'] }).toString().trim();
|
|
253
|
+
const projectCreateResponse = projectCreateRaw ? JSON.parse(projectCreateRaw) : null;
|
|
254
|
+
if (projectCreateResponse?.errors) {
|
|
203
255
|
throw new Error(projectCreateResponse.errors.map(e => e.message).join('; '));
|
|
204
256
|
}
|
|
205
|
-
const projectCreateData = projectCreateResponse
|
|
206
|
-
projectId = projectCreateData
|
|
207
|
-
projectNumber = projectCreateData
|
|
257
|
+
const projectCreateData = projectCreateResponse?.data?.createProjectV2?.projectV2;
|
|
258
|
+
projectId = projectCreateData?.id;
|
|
259
|
+
projectNumber = projectCreateData?.number;
|
|
208
260
|
|
|
209
261
|
console.log(` ${i18n.project_ok}${projectId})`);
|
|
210
262
|
|
|
@@ -217,7 +269,14 @@ async function runSetup() {
|
|
|
217
269
|
}
|
|
218
270
|
|
|
219
271
|
} catch (err) {
|
|
220
|
-
|
|
272
|
+
const isScopeError = (err.message || '').includes("required scopes") || (err.stderr || '').toString().includes("required scopes");
|
|
273
|
+
if (isScopeError) {
|
|
274
|
+
console.log(` ${red}❌ Token missing 'project' scope.${reset}`);
|
|
275
|
+
console.log(` ${yellow}Fix: gh auth refresh -s project${reset}`);
|
|
276
|
+
console.log(` ${yellow}Then re-run: npx create-agentic-pdlc${reset}`);
|
|
277
|
+
} else {
|
|
278
|
+
console.log(` ${i18n.project_err}${err.message}`);
|
|
279
|
+
}
|
|
221
280
|
}
|
|
222
281
|
|
|
223
282
|
let statusFieldId;
|
|
@@ -231,7 +290,7 @@ async function runSetup() {
|
|
|
231
290
|
|
|
232
291
|
if (statusFieldId) {
|
|
233
292
|
const columns = [
|
|
234
|
-
{ name: "💡 Idea", description: "
|
|
293
|
+
{ name: "💡 Idea - No move to Exploration directly", description: "Just tell your agent to work on issue #XX", color: "GRAY" },
|
|
235
294
|
{ name: "🔍 Exploration", description: "AI is analyzing code and context", color: "PURPLE" },
|
|
236
295
|
{ name: "🧠 Brainstorming", description: "AI proposed approaches and trade-offs", color: "PINK" },
|
|
237
296
|
{ name: "📐 Detail Solution", description: "AI is writing the technical spec", color: "BLUE" },
|
|
@@ -265,7 +324,8 @@ async function runSetup() {
|
|
|
265
324
|
|
|
266
325
|
const updateOutput = execFileSync('gh', ['api', 'graphql', '--input', '-'], { input: queryPayload }).toString().trim();
|
|
267
326
|
const jsonResponse = updateOutput ? JSON.parse(updateOutput) : null;
|
|
268
|
-
const returnedOptions = jsonResponse?.data?.updateProjectV2Field?.projectV2Field?.options ||
|
|
327
|
+
const returnedOptions = jsonResponse?.data?.updateProjectV2Field?.projectV2Field?.options ||
|
|
328
|
+
jsonResponse?.data?.updateProjectV2SingleSelectField?.projectV2SingleSelectField?.options || [];
|
|
269
329
|
|
|
270
330
|
for (const opt of returnedOptions) {
|
|
271
331
|
optionMap[opt.name] = opt.id;
|
|
@@ -278,6 +338,23 @@ async function runSetup() {
|
|
|
278
338
|
}
|
|
279
339
|
}
|
|
280
340
|
|
|
341
|
+
// Auto-provision PROJECT_PAT for personal repos
|
|
342
|
+
let patAutoSet = false;
|
|
343
|
+
if (projectId && !isOrg) {
|
|
344
|
+
try {
|
|
345
|
+
const tokenOut = execFileSync('gh', ['auth', 'token'], { stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf8' }).trim();
|
|
346
|
+
if (tokenOut) {
|
|
347
|
+
execFileSync('gh', ['secret', 'set', 'PROJECT_PAT', '--body', tokenOut, '--repo', repo], { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
348
|
+
patAutoSet = true;
|
|
349
|
+
console.log(`\n${green}✅ PROJECT_PAT secret set automatically (uses your gh OAuth token).${reset}`);
|
|
350
|
+
}
|
|
351
|
+
} catch (err) {
|
|
352
|
+
console.log(`\n${yellow}⚠️ Could not auto-set PROJECT_PAT. Agent will guide manual setup.${reset}`);
|
|
353
|
+
}
|
|
354
|
+
} else if (projectId && isOrg) {
|
|
355
|
+
console.log(`\n${yellow}ℹ️ Org repo detected — PROJECT_PAT will require manual setup for security.${reset}`);
|
|
356
|
+
}
|
|
357
|
+
|
|
281
358
|
console.log(`\n${yellow}${i18n.scaffolding}${reset}`);
|
|
282
359
|
|
|
283
360
|
// We copy the templates folder so the agent has the real text logic to replace and rename
|
|
@@ -311,7 +388,11 @@ async function runSetup() {
|
|
|
311
388
|
}
|
|
312
389
|
|
|
313
390
|
fs.writeFileSync(pdlcDest, pdlcContent);
|
|
314
|
-
|
|
391
|
+
if (projectId && statusFieldId && Object.keys(optionMap).length > 0) {
|
|
392
|
+
console.log(`${i18n.pdlc_prefilled}`);
|
|
393
|
+
} else {
|
|
394
|
+
console.log(`${yellow}⚠️ pdlc.md copied — Project IDs not filled (board creation failed). Re-run after fixing token.${reset}`);
|
|
395
|
+
}
|
|
315
396
|
}
|
|
316
397
|
|
|
317
398
|
// Pre-fill project-automation.yml with the same IDs so the agent doesn't need to map them
|
|
@@ -338,7 +419,16 @@ async function runSetup() {
|
|
|
338
419
|
// Write CLI context for the agent to consume in Setup Mode
|
|
339
420
|
try {
|
|
340
421
|
const cliContextPath = path.join(targetDir, '.agentic-pdlc', 'cli-context.json');
|
|
341
|
-
|
|
422
|
+
const boardUrl = projectNumber ? buildBoardUrl(repoOwner, projectNumber, isOrg) : null;
|
|
423
|
+
fs.writeFileSync(cliContextPath, JSON.stringify({
|
|
424
|
+
projectName,
|
|
425
|
+
repoOwner,
|
|
426
|
+
repoName,
|
|
427
|
+
projectNumber,
|
|
428
|
+
isOrg,
|
|
429
|
+
boardUrl,
|
|
430
|
+
patAutoSet
|
|
431
|
+
}, null, 2));
|
|
342
432
|
} catch (err) {
|
|
343
433
|
// Non-fatal — agent will ask for the values instead
|
|
344
434
|
}
|
package/docs/flow.md
CHANGED
|
@@ -5,8 +5,7 @@ This document describes the full lifecycle of a card on the agentic-pdlc board
|
|
|
5
5
|
```mermaid
|
|
6
6
|
stateDiagram-v2
|
|
7
7
|
direction LR
|
|
8
|
-
Idea -->
|
|
9
|
-
Exploration --> Brainstorming : stage:brainstorming
|
|
8
|
+
Idea --> Brainstorming : stage:brainstorming
|
|
10
9
|
Brainstorming --> Detailing : Gate 1 (PM)
|
|
11
10
|
Detailing --> Approval : stage:approval
|
|
12
11
|
Approval --> Development : Gate 2 (spec:approved)
|
|
@@ -23,7 +22,7 @@ stateDiagram-v2
|
|
|
23
22
|
|------|---------------|
|
|
24
23
|
| **PM** (human) | Selects issues for the sprint, approves brainstorm (Gate 1), approves spec (Gate 2) |
|
|
25
24
|
| **TL / Reviewer** (human) | Co-approves spec for technical decisions (Gate 2), reviews and approves the PR (Gate 3) |
|
|
26
|
-
| **Claude** |
|
|
25
|
+
| **Claude** | Brainstorming (context reading + approaches), spec writing — acts on PM instruction via chat or via upstream label |
|
|
27
26
|
| **Implementation Agent** | Implementation, running tests, opening the PR |
|
|
28
27
|
| **Workflow** | All label swaps and card movements — the source of truth for board state |
|
|
29
28
|
|
|
@@ -38,33 +37,22 @@ Issue exists in the backlog with no `stage:` label.
|
|
|
38
37
|
|
|
39
38
|
---
|
|
40
39
|
|
|
41
|
-
### 🔍 Exploration
|
|
42
|
-
|
|
43
|
-
**Trigger (two equivalent paths):**
|
|
44
|
-
- PM tells Claude directly in chat → Claude adds `stage:exploration` to the issue, OR
|
|
45
|
-
- PM adds `stage:exploration` directly to the issue
|
|
46
|
-
|
|
47
|
-
**Workflow:** `project-automation.yml` detects `stage:exploration` → moves card to Exploration.
|
|
48
|
-
|
|
49
|
-
**Who works:** Claude reads relevant code and context.
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
40
|
### 🧠 Brainstorming
|
|
54
41
|
|
|
55
|
-
**Trigger:** Claude
|
|
42
|
+
**Trigger:** PM tells Claude to work on the issue (in chat) or applies `stage:brainstorming` directly.
|
|
56
43
|
|
|
57
44
|
**Actions:**
|
|
58
|
-
- Claude
|
|
59
|
-
- Claude
|
|
45
|
+
- Claude applies `stage:brainstorming` immediately
|
|
46
|
+
- Claude reads relevant code and context
|
|
47
|
+
- Claude posts a single comment with: (1) brief problem summary, (2) 2–3 proposed approaches with trade-offs
|
|
60
48
|
|
|
61
|
-
**Workflow:** `project-automation.yml` moves card to Brainstorming.
|
|
49
|
+
**Workflow:** `project-automation.yml` detects `stage:brainstorming` → moves card to Brainstorming.
|
|
62
50
|
|
|
63
51
|
**⏸ Human gate (Gate 1 — PM):** PM reads the brainstorming comment and selects an approach. This can be done:
|
|
64
52
|
- By commenting on the issue (e.g., "Option A", "Go with B", "approved", "lgtm")
|
|
65
53
|
- By telling Claude in chat
|
|
66
54
|
|
|
67
|
-
**Note on implicit approval:**
|
|
55
|
+
**Note on implicit approval:** Selecting one option (e.g., "Option A") counts as implicit approval. The `upstream-gate.yml` detects option-selection patterns in addition to explicit approval words.
|
|
68
56
|
|
|
69
57
|
---
|
|
70
58
|
|
|
@@ -141,7 +129,6 @@ Issue exists in the backlog with no `stage:` label.
|
|
|
141
129
|
|
|
142
130
|
| Label | Added by | Removed by |
|
|
143
131
|
|-------|----------|------------|
|
|
144
|
-
| `stage:exploration` | PM (human) or Claude | Claude |
|
|
145
132
|
| `stage:brainstorming` | Claude | `upstream-gate.yml` |
|
|
146
133
|
| `stage:detailing` | `upstream-gate.yml` | Claude |
|
|
147
134
|
| `stage:approval` | Claude | `agent-trigger.yml` |
|
package/docs/pdlc.md
CHANGED
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
| Column | Meaning | Who moves the card |
|
|
6
6
|
|---|---|---|
|
|
7
|
-
| 💡 Idea
|
|
8
|
-
|
|
|
9
|
-
| 🧠 Brainstorming | AI proposed approaches and trade-offs | Label `stage:brainstorming` |
|
|
7
|
+
| 💡 Idea | Backlog — tell agent: "work on issue #XX" | Don't move manually |
|
|
8
|
+
| 🧠 Brainstorming | AI reading context, proposing approaches and trade-offs | Label `stage:brainstorming` |
|
|
10
9
|
| 📐 Detail Solution | AI is writing the technical spec | Label `stage:detailing` |
|
|
11
10
|
| ✅ Approval | Your turn, awaiting `spec:approved` label | Label `spec:approved` |
|
|
12
11
|
| ⚙️ Development | AI implementing the spec | Label `stage:development` |
|
|
@@ -32,7 +31,6 @@ REPO = {{REPO_OWNER}}/{{REPO_NAME}}
|
|
|
32
31
|
| Column | Option ID |
|
|
33
32
|
|---|---|
|
|
34
33
|
| 💡 Idea | `{{ID_IDEA}}` |
|
|
35
|
-
| 🔍 Exploration | `{{ID_EXPLORATION}}` |
|
|
36
34
|
| 🧠 Brainstorming | `{{ID_BRAINSTORMING}}` |
|
|
37
35
|
| 📐 Detail Solution | `{{ID_DETAIL}}` |
|
|
38
36
|
| ✅ Approval | `{{ID_APPROVAL}}` |
|
|
@@ -65,7 +63,6 @@ REPO = {{REPO_OWNER}}/{{REPO_NAME}}
|
|
|
65
63
|
|
|
66
64
|
| Label | Entity | Color | Meaning |
|
|
67
65
|
|---|---|---|---|
|
|
68
|
-
| `stage:exploration` | Issue | Purple | Issue is being evaluated |
|
|
69
66
|
| `stage:brainstorming` | Issue | Pink | Proposed approaches awaiting PM gate |
|
|
70
67
|
| `stage:detailing` | Issue | Blue | Technical spec is being written |
|
|
71
68
|
| `stage:development` | Issue | Orange | Agent is implementing the spec |
|
|
@@ -73,15 +70,15 @@ REPO = {{REPO_OWNER}}/{{REPO_NAME}}
|
|
|
73
70
|
| `pr:in-review` | PR | Yellow | Awaiting code review |
|
|
74
71
|
| `pr:approved` | PR | Green | Code review approved |
|
|
75
72
|
| `type:us` | Issue | Blue | New feature or behavioral change — full flow |
|
|
76
|
-
| `type:task` | Issue | Yellow | Operational/non-functional change —
|
|
77
|
-
| `type:bug` | Issue | Red | Something broken —
|
|
73
|
+
| `type:task` | Issue | Yellow | Operational/non-functional change — full flow |
|
|
74
|
+
| `type:bug` | Issue | Red | Something broken — full flow |
|
|
78
75
|
| `type:spike` | Issue | Gray | Research/evaluation — never reaches Development |
|
|
79
76
|
|
|
80
77
|
## Approval Gates
|
|
81
78
|
|
|
82
79
|
**Gate 1 — PM/Ideation (Brainstorming):**
|
|
83
|
-
|
|
84
|
-
Format: *"Approved — proceed with option X."*
|
|
80
|
+
Agent presents problem summary + 2–3 solution options in a single message. You select an approach.
|
|
81
|
+
Format: *"Option X"* or *"Go with B"* or *"Approved — proceed with option X."*
|
|
85
82
|
|
|
86
83
|
**Gate 2 — Tech Lead (Spec):**
|
|
87
84
|
You add the `spec:approved` label to the issue after reviewing the technical spec in the body.
|
|
@@ -93,13 +90,24 @@ The `type:*` label is the authoritative signal — set automatically by the agen
|
|
|
93
90
|
|
|
94
91
|
| Label | Flow |
|
|
95
92
|
|---|---|
|
|
96
|
-
| `type:us` |
|
|
97
|
-
| `type:task` |
|
|
98
|
-
| `type:bug` |
|
|
99
|
-
| `type:spike` |
|
|
93
|
+
| `type:us` | brainstorming → Gate 1 → detailing → approval |
|
|
94
|
+
| `type:task` | brainstorming → Gate 1 → detailing → approval |
|
|
95
|
+
| `type:bug` | brainstorming → Gate 1 → detailing → approval |
|
|
96
|
+
| `type:spike` | brainstorming → Gate 1 → detailing → conclusion comment (never reaches Development) |
|
|
100
97
|
|
|
101
98
|
If no `type:*` label present and agent confidence < 85%, defaults to `type:us` (safe fallback — never skips gates by omission).
|
|
102
99
|
|
|
100
|
+
## Bypass Mechanism
|
|
101
|
+
|
|
102
|
+
Agents MUST NOT skip any stage. The ONLY authorized bypasses are:
|
|
103
|
+
|
|
104
|
+
| Mechanism | Who authorizes | What it bypasses |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `human-approved` label on issue | PM (human) only | All stage gates |
|
|
107
|
+
| Branch prefix `hotfix/` | PM (human) only | PR gate only |
|
|
108
|
+
|
|
109
|
+
Agents MUST NOT self-authorize a bypass. Stop and ask the PM explicitly.
|
|
110
|
+
|
|
103
111
|
## Definition of Done
|
|
104
112
|
|
|
105
113
|
An issue is truly done when:
|
package/package.json
CHANGED
|
@@ -75,7 +75,7 @@ jobs:
|
|
|
75
75
|
console.log(`Issue #${number} → Development`);
|
|
76
76
|
|
|
77
77
|
- name: Comment on issue to trigger agent and prevent race conditions
|
|
78
|
-
if: ${{ !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') }}
|
|
78
|
+
if: ${{ !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') && vars.JULES_ENABLED == 'true' }}
|
|
79
79
|
uses: actions/github-script@v7
|
|
80
80
|
with:
|
|
81
81
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -118,7 +118,7 @@ jobs:
|
|
|
118
118
|
contents: read
|
|
119
119
|
steps:
|
|
120
120
|
- name: Comment on issue to trigger agent
|
|
121
|
-
if: ${{ !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') }}
|
|
121
|
+
if: ${{ !contains('{{IMPLEMENTATION_AGENT_LABEL}}', '{{') && vars.JULES_ENABLED == 'true' }}
|
|
122
122
|
uses: actions/github-script@v7
|
|
123
123
|
with:
|
|
124
124
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -38,3 +38,17 @@ jobs:
|
|
|
38
38
|
if: ${{ !contains('{{TEST_COMMAND}}', '{{') }}
|
|
39
39
|
run: |
|
|
40
40
|
{{TEST_COMMAND}}
|
|
41
|
+
|
|
42
|
+
ci-status:
|
|
43
|
+
name: Sentinel / CI
|
|
44
|
+
needs: [validate]
|
|
45
|
+
if: always()
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
steps:
|
|
48
|
+
- name: Check validate result
|
|
49
|
+
run: |
|
|
50
|
+
result="${{ needs.validate.result }}"
|
|
51
|
+
if [[ "$result" != "success" && "$result" != "skipped" ]]; then
|
|
52
|
+
echo "CI failed: validate=$result"
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
@@ -8,7 +8,6 @@ on:
|
|
|
8
8
|
env:
|
|
9
9
|
PROJECT_ID: "{{PROJECT_ID}}"
|
|
10
10
|
STATUS_FIELD_ID: "{{STATUS_FIELD_ID}}"
|
|
11
|
-
STATUS_EXPLORATION: "{{ID_EXPLORATION}}"
|
|
12
11
|
STATUS_BRAINSTORMING: "{{ID_BRAINSTORMING}}"
|
|
13
12
|
STATUS_DETAILING: "{{ID_DETAILING}}"
|
|
14
13
|
STATUS_APPROVAL: "{{ID_APPROVAL}}"
|
|
@@ -35,7 +34,6 @@ jobs:
|
|
|
35
34
|
const projectId = process.env.PROJECT_ID;
|
|
36
35
|
const statusFieldId = process.env.STATUS_FIELD_ID;
|
|
37
36
|
const envVars = {
|
|
38
|
-
'STATUS_EXPLORATION': process.env.STATUS_EXPLORATION,
|
|
39
37
|
'STATUS_BRAINSTORMING': process.env.STATUS_BRAINSTORMING,
|
|
40
38
|
'STATUS_DETAILING': process.env.STATUS_DETAILING,
|
|
41
39
|
'STATUS_APPROVAL': process.env.STATUS_APPROVAL,
|