Skip to content

Commit e6ba17e

Browse files
committed
feat(ci-squad): GitHub Issues → auto-branch, squad pipeline, draft PR (0.13.3)
Label any issue to trigger a full squad pipeline in GitHub Actions — no local setup needed. Draft PR opened on completion. - New opt-in prompt in ______ __ __ __ __ _ __ / ____/ ____ ____ / /_ ___ _ __ / /_ / //_/ (_) / /_ / / / __ \ / __ \ / __/ / _ \ | |/_/ / __/ / ,< / / / __/ / /___ / /_/ / / / / / / /_ / __/ _> < / /_ / /| | / / / /_ \____/ \____/ /_/ /_/ \__/ \___/ /_/|_| \__/ /_/ |_| /_/ \__/ 🎵 Installing ContextKit... 🧩 Detected project: node 📦 Package manager: pnpm ? ContextKit is already installed. Do you want to reinstall? (y/N) �[67D�[67C�[2K�[G? ContextKit is already installed. Do you want to reinstall? No�[63D�[63C ⏭️ Installation cancelled 💡 To get the latest command and squad files, run: ck update / ______ __ __ __ __ _ __ / ____/ ____ ____ / /_ ___ _ __ / /_ / //_/ (_) / /_ / / / __ \ / __ \ / __/ / _ \ | |/_/ / __/ / ,< / / / __/ / /___ / /_/ / / / / / / /_ / __/ _> < / /_ / /| | / / / /_ \____/ \____/ /_/ /_/ \__/ \___/ /_/|_| \__/ /_/ |_| /_/ \__/ 🔄 Updating ContextKit... 📦 Updating from latest to latest 🪝 Setting up Git hooks... ✅ Git hooks path set to .contextkit/hooks ✅ Git hooks setup complete ✅ Refreshed 1 platform integration(s) ✅ ContextKit updated successfully! for squad-issue.yml - New squad-ci.md command for non-interactive CI pipeline mode - squad_ci_workflow flag persisted in config.yml - Docs: new CI Squad page, sidebar entry, squad page callout - Fix: commit-msg hook types (style → improve)
1 parent 8d6f0f8 commit e6ba17e

File tree

15 files changed

+1115
-20
lines changed

15 files changed

+1115
-20
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Changelog
22

3+
## [0.13.3] - 2026-03-16
4+
5+
### Added
6+
- **CI Squad** — label any GitHub issue `squad-ready` to trigger a full squad pipeline in GitHub Actions (PO → Architect → Dev → Test → Review → Doc) and open a draft PR automatically. No local setup required.
7+
- **`ck install` CI Squad prompt** — opt-in prompt during install downloads `squad-issue.yml` to `.github/workflows/` and records `squad_ci_workflow: true` in config
8+
- **`ck update` CI Squad sync** — re-downloads `squad-issue.yml` on `ck update` when `squad_ci_workflow` flag is set
9+
- **`squad-ci.md` command** — new command distributed via install/update; instructs Claude Code CLI to run the full pipeline non-interactively in CI mode. On clarify: posts a GitHub comment and exits 0. On completion: writes `ci-result.md` for the PR body.
10+
- **`templates/github-actions/squad-issue.yml`** — new GitHub Actions workflow template with branch creation, clarify comment flow, concurrency guard, and draft PR creation
11+
- **Docs: CI Squad page** — new website page covering setup, how it works, writing good issues, clarify flow, and behaviour table
12+
13+
### Fixed
14+
- **Website: commit types** — quality-gates page was showing stale `style` type; updated to `improve` (matches CLI and standards)
15+
16+
---
17+
318
## [0.13.2] - 2026-03-13
419

520
### Fixed

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
This project uses [ContextKit](https://github.com/nolrm/contextkit) for AI development standards.
55

66
## ContextKit
7-
Version: 0.13.1
7+
Version: 0.13.2
88

99
## Project Standards
1010

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,36 @@ Hooks are optional and can be skipped with `ck install --no-hooks`.
284284

285285
---
286286

287+
## CI Squad — GitHub Issues → PR
288+
289+
ContextKit can automatically turn GitHub issues into pull requests — no local development required.
290+
291+
**How it works:**
292+
293+
1. Label any issue `squad-ready`
294+
2. GitHub Actions runs the full squad pipeline (architect → dev → test → review) using Claude
295+
3. A draft PR is opened, linked to the issue
296+
297+
**Setup:**
298+
299+
```bash
300+
ck install # answer "yes" to the CI squad prompt
301+
```
302+
303+
Then add your Anthropic API key as a repository secret:
304+
305+
> **Settings → Secrets and variables → Actions → New repository secret**
306+
> Name: `ANTHROPIC_API_KEY`
307+
308+
**Tips:**
309+
310+
- Write issues with clear acceptance criteria for the best results
311+
- If the issue is too vague, the workflow posts a comment asking for clarification instead of generating a bad PR
312+
- PRs always open as **draft** — you review and merge manually
313+
- Re-apply the `squad-ready` label after answering a clarification comment to re-trigger the pipeline
314+
315+
---
316+
287317
## Key Features
288318

289319
- 🧠 **Context Engineering** - Structured MD files your AI reads automatically

__tests__/commands/install.test.js

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -273,14 +273,19 @@ describe('InstallCommand', () => {
273273
};
274274
getIntegration.mockReturnValue(mockIntegration);
275275

276-
// First prompt: platform choice, second: git hooks (prePush), third: git hooks (commitMsg)
277-
inquirer.prompt
278-
.mockResolvedValueOnce({ platform: 'cursor' })
279-
.mockResolvedValueOnce({ prePush: false })
280-
.mockResolvedValueOnce({ commitMsg: false });
276+
// Force CI=true so promptGitHubActionsWorkflow() returns early (no prompt consumed)
277+
const savedCI = process.env.CI;
278+
process.env.CI = 'true';
279+
inquirer.prompt.mockReset();
280+
inquirer.prompt.mockResolvedValueOnce({ platform: 'cursor' });
281281

282282
const install = getInstallModule();
283-
await install({ fullInstall: true });
283+
try {
284+
await install({ fullInstall: true, noHooks: true });
285+
} finally {
286+
if (savedCI === undefined) delete process.env.CI;
287+
else process.env.CI = savedCI;
288+
}
284289

285290
// Should have prompted for platform
286291
expect(inquirer.prompt).toHaveBeenCalledWith(
@@ -342,6 +347,58 @@ describe('InstallCommand', () => {
342347
expect(config).toContain('npm: "https://www.npmjs.com/package/@nolrm/contextkit"');
343348
});
344349

350+
it('23. CI squad workflow is installed when prompt returns yes', async () => {
351+
// Temporarily unset CI env so promptGitHubActionsWorkflow runs interactively
352+
const savedCI = process.env.CI;
353+
delete process.env.CI;
354+
355+
try {
356+
inquirer.prompt.mockReset();
357+
// noHooks=true skips hook prompts; mock squad CI (yes) then platform (none)
358+
inquirer.prompt
359+
.mockResolvedValueOnce({ squadCi: true })
360+
.mockResolvedValueOnce({ platform: null });
361+
362+
const install = getInstallModule();
363+
await install({ noHooks: true });
364+
365+
expect(await fs.pathExists('.github/workflows/squad-issue.yml')).toBe(true);
366+
const config = await fs.readFile('.contextkit/config.yml', 'utf8');
367+
expect(config).toContain('squad_ci_workflow: true');
368+
} finally {
369+
process.env.CI = savedCI;
370+
}
371+
});
372+
373+
it('24. config.yml sets squad_ci_workflow: false when prompt declined', async () => {
374+
const savedCI = process.env.CI;
375+
delete process.env.CI;
376+
377+
try {
378+
inquirer.prompt.mockReset();
379+
inquirer.prompt
380+
.mockResolvedValueOnce({ squadCi: false })
381+
.mockResolvedValueOnce({ platform: null });
382+
383+
const install = getInstallModule();
384+
await install({ noHooks: true });
385+
386+
expect(await fs.pathExists('.github/workflows/squad-issue.yml')).toBe(false);
387+
const config = await fs.readFile('.contextkit/config.yml', 'utf8');
388+
expect(config).toContain('squad_ci_workflow: false');
389+
} finally {
390+
process.env.CI = savedCI;
391+
}
392+
});
393+
394+
it('25. config.yml sets squad_ci_workflow: false by default', async () => {
395+
const install = getInstallModule();
396+
await install({ nonInteractive: true, noHooks: true });
397+
398+
const config = await fs.readFile('.contextkit/config.yml', 'utf8');
399+
expect(config).toContain('squad_ci_workflow: false');
400+
});
401+
345402
it('22. ck install <platform> when already installed adds platform without reinstall prompt', async () => {
346403
const { getIntegration } = require('../../lib/integrations');
347404
const mockIntegration = {

__tests__/commands/update.test.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,46 @@ describe('UpdateCommand', () => {
223223
expect(await fs.pathExists('.contextkit/commands/my-custom-command.md')).toBe(true);
224224
});
225225

226+
it('12. always downloads squad-ci.md command on update', async () => {
227+
const DownloadManager = require('../../lib/utils/download');
228+
await fs.ensureDir('.contextkit');
229+
await fs.writeFile('.contextkit/config.yml', baseConfig);
230+
231+
const update = getUpdateModule();
232+
await update({ force: true });
233+
234+
const downloadMock = DownloadManager.mock.results.at(-1).value;
235+
const downloadedUrls = downloadMock.downloadFile.mock.calls.map(c => c[0]);
236+
expect(downloadedUrls.some(u => u.includes('squad-ci.md'))).toBe(true);
237+
});
238+
239+
it('13. updates squad-issue.yml when squad_ci_workflow feature is enabled', async () => {
240+
const DownloadManager = require('../../lib/utils/download');
241+
const configWithSquadCi = baseConfig + ' squad_ci_workflow: true\n';
242+
await fs.ensureDir('.contextkit');
243+
await fs.writeFile('.contextkit/config.yml', configWithSquadCi);
244+
245+
const update = getUpdateModule();
246+
await update({ force: true });
247+
248+
const downloadMock = DownloadManager.mock.results.at(-1).value;
249+
const downloadedDests = downloadMock.downloadFile.mock.calls.map(c => c[1]);
250+
expect(downloadedDests.some(d => d.includes('squad-issue.yml'))).toBe(true);
251+
});
252+
253+
it('14. does not update squad-issue.yml when squad_ci_workflow is false', async () => {
254+
const DownloadManager = require('../../lib/utils/download');
255+
await fs.ensureDir('.contextkit');
256+
await fs.writeFile('.contextkit/config.yml', baseConfig);
257+
258+
const update = getUpdateModule();
259+
await update({ force: true });
260+
261+
const downloadMock = DownloadManager.mock.results.at(-1).value;
262+
const downloadedDests = downloadMock.downloadFile.mock.calls.map(c => c[1]);
263+
expect(downloadedDests.some(d => d.includes('squad-issue.yml'))).toBe(false);
264+
});
265+
226266
it('11. version comparison works correctly', async () => {
227267
// Access the class to test isNewerVersion
228268
delete require.cache[require.resolve('../../lib/commands/update')];

commands/squad-ci.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Squad CI — Automated Pipeline
2+
3+
You are the **Squad CI Runner** — an automated agent executing the full squad pipeline inside a GitHub Actions workflow. There is no human present. Do not pause for input, ask questions interactively, or wait for confirmation.
4+
5+
## Key Differences from Interactive Squad
6+
7+
| Interactive (`/squad-auto`) | CI mode (this command) |
8+
|-----------------------------|------------------------|
9+
| Can pause for clarification | Posts a comment instead and exits |
10+
| Can use sub-agents | Runs all phases inline |
11+
| Checkpoints configurable | Always runs full pipeline |
12+
| Human reviews handoff | Writes `ci-result.md` for the workflow |
13+
14+
---
15+
16+
## Step 1 — Read context
17+
18+
Read `.contextkit/squad/handoff.md`. Note the `task:` field and the issue context in the PO Spec `### Answers` section.
19+
20+
Check `ISSUE_NUMBER` from the environment (`$ISSUE_NUMBER`).
21+
22+
---
23+
24+
## Step 2 — PO Phase
25+
26+
The handoff arrives with `status: po` and raw issue content in the spec. Your job:
27+
28+
1. Read the issue title (task field) and issue body (in `### Answers`)
29+
2. **Assess clarity**: Is the issue specific enough to write testable acceptance criteria?
30+
31+
**If too vague** (missing: what to build, success criteria, or key constraints):
32+
- Write `### Questions` listing up to 5 specific questions that would unblock the spec
33+
- Write `.contextkit/squad/ci-result.md`:
34+
```
35+
status: clarify
36+
37+
### Questions
38+
39+
1. [question]
40+
2. [question]
41+
```
42+
- Set handoff `status: po-clarify`
43+
- **Stop here.** The workflow will post a GitHub comment with the questions.
44+
45+
**If clear enough**: Write the full PO Spec:
46+
- **User Story** — As a [role], I want [feature], so that [benefit]
47+
- **Acceptance Criteria** — specific, testable, numbered
48+
- **Edge Cases** — what dev and tester should handle
49+
- **Out of Scope** — scope guard
50+
51+
Set `## 1. PO Spec``status: done`. Set top-level `status:``architect`.
52+
53+
---
54+
55+
## Step 3 — Architect Phase
56+
57+
Read the PO Spec. Explore the codebase. Fill in `## 2. Architect Plan`:
58+
- **Approach**: High-level technical approach
59+
- **Files to Change**: Every file to create/modify with a summary
60+
- **Trade-offs**: Alternatives considered
61+
- **Implementation Steps**: Numbered, ordered steps for dev
62+
63+
Set `## 2. Architect Plan``status: done`. Set top-level `status:``dev`.
64+
65+
---
66+
67+
## Step 4 — Dev Phase
68+
69+
Read PO Spec and Architect Plan. Implement the code following the architect's steps exactly.
70+
71+
Fill in `## 3. Dev Implementation`:
72+
- **Changes Made**: Files changed and what was done
73+
- **Decisions & Deviations**: Any deviations from the plan and why
74+
75+
Set `## 3. Dev Implementation``status: done`. Set top-level `status:``test`.
76+
77+
---
78+
79+
## Step 5 — Test Phase
80+
81+
Write tests against the acceptance criteria. Run the tests.
82+
83+
Fill in `## 4. Test Report`:
84+
- **Tests Written**: Numbered test cases (follow project testing standards)
85+
- **Results**: Pass/fail counts and exit code
86+
- **Coverage Notes**: Which acceptance criteria are covered
87+
88+
Set `## 4. Test Report``status: done`. Set top-level `status:``review`.
89+
90+
---
91+
92+
## Step 6 — Review Phase
93+
94+
Read the full handoff. Fill in `## 6. Review`:
95+
- **Checklist**: Verify each acceptance criterion is met
96+
- **Issues Found**: List any issues (or "None")
97+
- **Verdict**: `pass` or `needs-work`
98+
99+
Set `## 6. Review``status: done`.
100+
101+
**If verdict is `needs-work`**: Set top-level `status:``review`. Write `ci-result.md`:
102+
```
103+
status: needs-work
104+
105+
## Review Issues
106+
107+
[list of issues found]
108+
```
109+
Then continue to write the PR body anyway (draft PR will be opened with the issues noted).
110+
111+
**If verdict is `pass`**: Set top-level `status:``doc`. Continue to Doc phase.
112+
113+
---
114+
115+
## Step 7 — Doc Phase
116+
117+
For each new file: create a companion `<filename>.md` with Purpose, Public API, Usage Example, Edge Cases.
118+
For modified files: update companion `.md` if the change was significant.
119+
Check if README or `.contextkit/` docs reference changed files — update if stale.
120+
121+
Fill in `## 7. Doc``status: done`. Set top-level `status:``done`.
122+
123+
---
124+
125+
## Step 8 — Write ci-result.md
126+
127+
Write `.contextkit/squad/ci-result.md` so the workflow can build the PR:
128+
129+
```markdown
130+
status: done
131+
132+
## Summary
133+
134+
[1-3 sentences: what was built and why]
135+
136+
## Changes
137+
138+
- [file]: [what changed]
139+
- [file]: [what changed]
140+
141+
## Test Results
142+
143+
[pass count] tests passing. [any notes]
144+
145+
## Review Verdict
146+
147+
pass
148+
```
149+
150+
If review was `needs-work`, write:
151+
```markdown
152+
status: needs-work
153+
154+
## Summary
155+
156+
[what was built]
157+
158+
## Review Issues
159+
160+
[list of issues — the PR will be opened as draft for human review]
161+
162+
## Test Results
163+
164+
[results]
165+
```
166+
167+
---
168+
169+
## Important Rules
170+
171+
- Never pause for user input
172+
- Never use interactive prompts or spinner tools
173+
- Run all phases inline — no sub-agents
174+
- If any phase produces an error you cannot recover from, write `ci-result.md` with `status: error\n\n[description]` and stop
175+
- Follow all project standards from `.contextkit/standards/`
176+
- Numbered test cases are required: `it('1. description')`

0 commit comments

Comments
 (0)