create-claude-workspace 2.1.10 → 2.2.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 (29) hide show
  1. package/dist/scheduler/agents/prompt-builder.mjs +21 -0
  2. package/dist/scheduler/git/manager.mjs +78 -0
  3. package/dist/scheduler/git/manager.spec.js +63 -1
  4. package/dist/scheduler/git/pr-manager.mjs +214 -0
  5. package/dist/scheduler/git/pr-manager.spec.js +34 -0
  6. package/dist/scheduler/index.mjs +48 -4
  7. package/dist/scheduler/integration.spec.js +1 -0
  8. package/dist/scheduler/loop.mjs +248 -42
  9. package/dist/scheduler/loop.spec.js +2 -0
  10. package/dist/scheduler/state/state.mjs +1 -0
  11. package/dist/scheduler/state/state.spec.js +1 -0
  12. package/dist/scheduler/tasks/issue-source.mjs +156 -0
  13. package/dist/scheduler/tasks/issue-source.spec.js +104 -0
  14. package/dist/scheduler/types.mjs +1 -0
  15. package/dist/scheduler/util/idle-poll.mjs +27 -2
  16. package/dist/template/.claude/CLAUDE.md +26 -61
  17. package/dist/template/.claude/agents/backend-ts-architect.md +2 -2
  18. package/dist/template/.claude/agents/deployment-engineer.md +3 -3
  19. package/dist/template/.claude/agents/devops-integrator.md +13 -10
  20. package/dist/template/.claude/agents/it-analyst.md +108 -0
  21. package/dist/template/.claude/agents/orchestrator.md +118 -153
  22. package/dist/template/.claude/agents/product-owner.md +5 -9
  23. package/dist/template/.claude/agents/project-initializer.md +297 -342
  24. package/dist/template/.claude/agents/senior-code-reviewer.md +1 -1
  25. package/dist/template/.claude/agents/technical-planner.md +7 -12
  26. package/dist/template/.claude/agents/test-engineer.md +1 -1
  27. package/dist/template/.claude/agents/ui-engineer.md +3 -3
  28. package/dist/template/.claude/templates/claude-md.md +2 -1
  29. package/package.json +1 -1
@@ -0,0 +1,104 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { issueToTask } from './issue-source.mjs';
3
+ // fetchOpenIssues and updateIssueStatus require CLI (gh/glab) and a remote.
4
+ // They are tested via integration tests. Here we test the pure mapping logic.
5
+ function makeIssue(overrides = {}) {
6
+ return {
7
+ issueNumber: 42,
8
+ title: 'Add user auth endpoint',
9
+ body: '',
10
+ labels: ['complexity::M', 'type::backend', 'status::todo'],
11
+ milestone: 'Phase 1: Core Features',
12
+ assignee: null,
13
+ ...overrides,
14
+ };
15
+ }
16
+ describe('issueToTask', () => {
17
+ it('maps labels to task fields', () => {
18
+ const task = issueToTask(makeIssue(), 0);
19
+ expect(task.id).toBe('#42');
20
+ expect(task.title).toBe('Add user auth endpoint');
21
+ expect(task.complexity).toBe('M');
22
+ expect(task.type).toBe('backend');
23
+ expect(task.status).toBe('todo');
24
+ expect(task.phase).toBe(1);
25
+ expect(task.issueMarker).toBe('#42');
26
+ });
27
+ it('extracts phase from milestone name', () => {
28
+ const task = issueToTask(makeIssue({ milestone: 'Phase 2: Advanced Features' }), 0);
29
+ expect(task.phase).toBe(2);
30
+ });
31
+ it('uses fallback phase when no milestone', () => {
32
+ const task = issueToTask(makeIssue({ milestone: null }), 3);
33
+ expect(task.phase).toBe(3);
34
+ });
35
+ it('defaults complexity to M when missing', () => {
36
+ const task = issueToTask(makeIssue({ labels: ['status::todo'] }), 0);
37
+ expect(task.complexity).toBe('M');
38
+ });
39
+ it('defaults type to fullstack when missing', () => {
40
+ const task = issueToTask(makeIssue({ labels: ['status::todo'] }), 0);
41
+ expect(task.type).toBe('fullstack');
42
+ });
43
+ it('extracts dependencies from body', () => {
44
+ const task = issueToTask(makeIssue({ body: 'Depends on: #42, #43' }), 0);
45
+ expect(task.dependsOn).toContain('#42');
46
+ expect(task.dependsOn).toContain('#43');
47
+ });
48
+ it('extracts dependencies from labels', () => {
49
+ const task = issueToTask(makeIssue({ labels: ['status::todo', 'depends-on::#42'] }), 0);
50
+ expect(task.dependsOn).toContain('#42');
51
+ });
52
+ it('maps status labels correctly', () => {
53
+ const cases = [
54
+ ['status::done', 'done'],
55
+ ['status::skipped', 'skipped'],
56
+ ['status::blocked', 'blocked'],
57
+ ['status::in-progress', 'in-progress'],
58
+ ['status::in-review', 'in-progress'],
59
+ ['status::todo', 'todo'],
60
+ ];
61
+ for (const [label, expected] of cases) {
62
+ const task = issueToTask(makeIssue({ labels: [label] }), 0);
63
+ expect(task.status).toBe(expected);
64
+ }
65
+ });
66
+ it('defaults to todo when no status label', () => {
67
+ const task = issueToTask(makeIssue({ labels: ['bug'] }), 0);
68
+ expect(task.status).toBe('todo');
69
+ });
70
+ it('detects kit-upgrade label', () => {
71
+ const task = issueToTask(makeIssue({ labels: ['status::todo', 'kit-upgrade'] }), 0);
72
+ expect(task.kitUpgrade).toBe(true);
73
+ });
74
+ it('infers changelog category from title', () => {
75
+ expect(issueToTask(makeIssue({ title: 'Fix login bug' }), 0).changelog).toBe('fixed');
76
+ expect(issueToTask(makeIssue({ title: 'Add dark mode' }), 0).changelog).toBe('added');
77
+ expect(issueToTask(makeIssue({ title: 'Refactor auth service' }), 0).changelog).toBe('changed');
78
+ expect(issueToTask(makeIssue({ title: 'Implement search' }), 0).changelog).toBe('added');
79
+ });
80
+ it('handles S and L complexity', () => {
81
+ expect(issueToTask(makeIssue({ labels: ['complexity::S', 'status::todo'] }), 0).complexity).toBe('S');
82
+ expect(issueToTask(makeIssue({ labels: ['complexity::L', 'status::todo'] }), 0).complexity).toBe('L');
83
+ });
84
+ it('handles frontend and fullstack type', () => {
85
+ expect(issueToTask(makeIssue({ labels: ['type::frontend', 'status::todo'] }), 0).type).toBe('frontend');
86
+ expect(issueToTask(makeIssue({ labels: ['type::fullstack', 'status::todo'] }), 0).type).toBe('fullstack');
87
+ });
88
+ it('lineNumber is always 0 for platform issues', () => {
89
+ const task = issueToTask(makeIssue(), 0);
90
+ expect(task.lineNumber).toBe(0);
91
+ });
92
+ it('handles Phase 0 milestone', () => {
93
+ const task = issueToTask(makeIssue({ milestone: 'Phase 0: Foundation' }), 5);
94
+ expect(task.phase).toBe(0);
95
+ });
96
+ it('deduplicates dependencies from body and labels', () => {
97
+ const task = issueToTask(makeIssue({
98
+ body: 'Depends on: #42',
99
+ labels: ['status::todo', 'depends-on::#42'],
100
+ }), 0);
101
+ const deps42 = task.dependsOn.filter(d => d === '#42');
102
+ expect(deps42.length).toBe(1);
103
+ });
104
+ });
@@ -17,4 +17,5 @@ export const SCHEDULER_DEFAULTS = {
17
17
  interactive: false,
18
18
  delay: 5_000,
19
19
  cooldown: 60_000,
20
+ taskMode: null,
20
21
  };
@@ -4,6 +4,8 @@
4
4
  import { readFileSync } from 'node:fs';
5
5
  import { resolve } from 'node:path';
6
6
  import { execSync } from 'node:child_process';
7
+ import { fetchOpenIssues } from '../tasks/issue-source.mjs';
8
+ import { detectCIPlatform } from '../git/ci-watcher.mjs';
7
9
  // ─── TODO.md check (filesystem, free) ───
8
10
  export function checkTodoForPendingTasks(projectDir) {
9
11
  try {
@@ -140,6 +142,25 @@ async function pollClickUp(spaceId, token, projectDir) {
140
142
  }
141
143
  return newCount;
142
144
  }
145
+ // ─── Platform mode polling (issues via CLI) ───
146
+ async function pollPlatformIssues(projectDir, log, completedTasks) {
147
+ const ciPlatform = detectCIPlatform(projectDir);
148
+ if (ciPlatform === 'none')
149
+ return { hasWork: false, source: null, issueCount: 0 };
150
+ try {
151
+ const issues = fetchOpenIssues(projectDir, ciPlatform);
152
+ const todoIssues = issues.filter(i => i.labels.some(l => l === 'status::todo') &&
153
+ !completedTasks.includes(`#${i.issueNumber}`));
154
+ if (todoIssues.length > 0) {
155
+ log.info(`Found ${todoIssues.length} issue(s) with status::todo`);
156
+ return { hasWork: true, source: ciPlatform, issueCount: todoIssues.length };
157
+ }
158
+ }
159
+ catch (err) {
160
+ log.debug(`Platform poll failed: ${err.message}`);
161
+ }
162
+ return { hasWork: false, source: null, issueCount: 0 };
163
+ }
143
164
  function readTodoSafe(projectDir) {
144
165
  try {
145
166
  return readFileSync(resolve(projectDir, 'TODO.md'), 'utf-8');
@@ -149,8 +170,12 @@ function readTodoSafe(projectDir) {
149
170
  }
150
171
  }
151
172
  // ─── Main poll function ───
152
- export async function pollForNewWork(projectDir, log) {
153
- // 1. Check TODO.md first (free, instant)
173
+ export async function pollForNewWork(projectDir, log, taskMode = 'local', completedTasks = []) {
174
+ // Platform mode: check issues directly via CLI
175
+ if (taskMode === 'platform') {
176
+ return pollPlatformIssues(projectDir, log, completedTasks);
177
+ }
178
+ // Local mode: check TODO.md first (free, instant)
154
179
  if (checkTodoForPendingTasks(projectDir)) {
155
180
  return { hasWork: true, source: 'todo', issueCount: 0 };
156
181
  }
@@ -1,70 +1,35 @@
1
1
  # Agent-Driven Development Kit
2
2
 
3
- **You are a ROUTER, not an implementer.** This project uses specialist agents. Your ONLY job is to delegate to them.
3
+ This project uses specialist agents in `.claude/agents/` for autonomous development.
4
4
 
5
- ## The One Rule
5
+ ## How to Run
6
6
 
7
- **NEVER do work yourself. ALWAYS delegate via the Agent tool.**
8
-
9
- - NEVER write CLAUDE.md, PRODUCT.md, TODO.md, MEMORY.md, or any project files yourself
10
- - NEVER run `nx generate`, `gh`/`glab` commands, or scaffold anything yourself
11
- - NEVER read `.claude/agents/*.md` files to understand their instructions — call the agent instead. Checking file existence (`ls .claude/agents/`) is fine.
12
-
13
- ### WRONG (doing it yourself):
14
- ```
15
- User: "Initialize this project"
16
- You: *reads plan files, writes CLAUDE.md, creates PRODUCT.md, runs git commands...*
17
- ```
18
-
19
- ### CORRECT (delegating):
20
- ```
21
- User: "Initialize this project"
22
- You: "I'll delegate this to the project-initializer agent."
23
- → Agent tool: subagent_type="project-initializer"
24
- ```
25
-
26
- ## Which Agent to Call
27
-
28
- **Setup tasks** → `project-initializer` (it sub-delegates to other agents internally):
29
- - "Initialize this project", "Set up CLAUDE.md", "Start a new project"
30
-
31
- **Development tasks** → `orchestrator` (it sub-delegates to architects, reviewers, etc.):
32
- - "Continue development", "Next task", "Build the next feature"
33
-
34
- **Specific tasks** (only if explicitly asked for one agent's specialty):
35
- | Task | Agent | `subagent_type` | `model` |
36
- |------|-------|-----------------|---------|
37
- | Product strategy / PRODUCT.md | product-owner | `"product-owner"` | `"opus"` |
38
- | Development plan / TODO.md | technical-planner | `"technical-planner"` | `"opus"` |
39
- | Deployment / CI/CD | deployment-engineer | `"deployment-engineer"` | `"sonnet"` |
40
- | Git remote / issues / MRs / ClickUp | devops-integrator | `"devops-integrator"` | `"sonnet"` |
41
- | Code review | senior-code-reviewer | `"senior-code-reviewer"` | `"opus"` |
42
- | Tests | test-engineer | `"test-engineer"` | `"sonnet"` |
43
- | Frontend / UI | ui-engineer | `"ui-engineer"` | `"opus"` |
44
- | Backend / API | backend-ts-architect | `"backend-ts-architect"` | `"opus"` |
45
-
46
- > **Always pass the `model` parameter** when calling the Agent tool — it selects the Claude model for the sub-agent.
47
-
48
- > **Note:** Specialist agents are typically called via sub-delegation by `project-initializer` or `orchestrator`. Only call them directly if the user explicitly asks for one agent's specialty.
49
-
50
- **When unsure** → `project-initializer` for setup, `orchestrator` for everything else.
51
-
52
- ## Autonomous Development
53
-
54
- **Important:** The orchestrator MUST run as a top-level agent (not a sub-agent) so it can delegate to specialist agents via the Agent tool. Sub-agents cannot spawn further sub-agents.
55
-
56
- ```powershell
57
- # Docker — isolated, safe (recommended)
58
- npx create-claude-workspace docker # all platforms
59
-
60
- # Without Docker (uses --agent orchestrator automatically)
7
+ ```bash
8
+ # Autonomous (recommended)
61
9
  npx create-claude-workspace run
62
10
 
63
- # Update kit (agents, templates) to latest version
64
- npx create-claude-workspace --update
11
+ # Docker isolated environment
12
+ npx create-claude-workspace docker
65
13
 
66
- # Interactive — start Claude with orchestrator as top-level agent
14
+ # Interactive
67
15
  claude --agent orchestrator
68
- # Then use ralph-loop within that session:
69
- /ralph-loop:ralph-loop Continue autonomous development according to CLAUDE.md
16
+
17
+ # Update kit to latest version
18
+ npx create-claude-workspace --update
70
19
  ```
20
+
21
+ ## Agents
22
+
23
+ | Agent | Purpose | Model |
24
+ |-------|---------|-------|
25
+ | orchestrator | Development cycle (pick task → plan → implement → test → review → commit → merge) | opus |
26
+ | project-initializer | Full project setup pipeline (discovery → CLAUDE.md → PRODUCT.md → TODO.md) | opus |
27
+ | product-owner | Product strategy, features, monetization → PRODUCT.md | opus |
28
+ | technical-planner | Phased development plan → TODO.md | opus |
29
+ | ui-engineer | Frontend architecture and implementation | opus |
30
+ | backend-ts-architect | Backend architecture and implementation | opus |
31
+ | senior-code-reviewer | Structured code review (CRITICAL/WARN/NICE-TO-HAVE/GREEN) | opus |
32
+ | test-engineer | Unit, integration, E2E, and visual regression tests | sonnet |
33
+ | devops-integrator | Git platform sync (GitHub/GitLab/ClickUp), branches, MRs/PRs | sonnet |
34
+ | deployment-engineer | CI/CD pipelines, deploys, rollbacks, migrations | sonnet |
35
+ | it-analyst | Technical analyst, breaks features into detailed platform issues | sonnet |
@@ -104,7 +104,7 @@ Always prefer `@cibule/*` packages over custom implementations:
104
104
 
105
105
  ## Output Format
106
106
 
107
- When called for **planning** (STEP 2 of the development cycle), always structure your response as:
107
+ When called for **planning**, always structure your response as:
108
108
 
109
109
  ### EXISTING CODE
110
110
  What already exists in the codebase that is relevant — reusable utilities, similar patterns, shared abstractions. Reference specific file paths.
@@ -167,7 +167,7 @@ If the orchestrator re-delegates with frontend architect feedback about impracti
167
167
  Keep all other plan sections unchanged unless the revision affects them.
168
168
 
169
169
  ### SPLIT RECOMMENDATION (optional)
170
- If the task is too large for a single development cycle (would require 8+ files or multiple independent concerns), recommend splitting. List the suggested sub-tasks with their own scope and dependencies. The orchestrator will delegate to technical-planner to update TODO.md.
170
+ If the task is too large (would require 8+ files or multiple independent concerns), recommend splitting. List the suggested sub-tasks with their own scope and dependencies.
171
171
  Only include this section if splitting is genuinely needed — do NOT split tasks that are naturally cohesive.
172
172
 
173
173
  ### VERIFICATION
@@ -324,9 +324,9 @@ After generating configs, append a `## Deployment` section to CLAUDE.md:
324
324
  - Smoke test: Playwright runs against deployed URL
325
325
  ```
326
326
 
327
- ### 4. Deploy (called during development cycle)
327
+ ### 4. Deploy
328
328
 
329
- When called to deploy (after MR/PR merge or for hotfix):
329
+ When called to deploy:
330
330
 
331
331
  1. **Verify build passes** — `nx build [APP] --configuration=[env]`
332
332
  2. **Run deployment** — execute the appropriate deploy command for the target
@@ -383,7 +383,7 @@ After rollback:
383
383
 
384
384
  ### 6. Database Migrations — Dev-Time Generation
385
385
 
386
- When called by the orchestrator during development (STEP 3) to generate a migration file:
386
+ When called to generate a migration file:
387
387
 
388
388
  1. **Read context**: Check CLAUDE.md for database type (D1, SQLite, Postgres, etc.)
389
389
  2. **Check existing migrations**: List files in `migrations/` directory, find the latest sequence number
@@ -4,6 +4,8 @@ description: "Use this agent to sync project planning with GitLab/GitHub/ClickUp
4
4
  model: sonnet
5
5
  ---
6
6
 
7
+ > **Note:** In platform mode (scheduler), the scheduler handles daily issue/MR CRUD. This agent is used for initial setup and complex fallback operations only.
8
+
7
9
  You are a DevOps Integration agent that bridges project planning (TODO.md, PRODUCT.md) with git platforms (GitLab or GitHub) and task management platforms (ClickUp). You create and manage epics, issues/tasks, branches, and merge requests.
8
10
 
9
11
  ## Platform Detection
@@ -178,7 +180,7 @@ When called to set up a remote for a new project:
178
180
  ```
179
181
  - **NEVER** echo, log, or write the token value to terminal output or any file
180
182
  - **NEVER** use `curl -v` (verbose) — it prints `Authorization` / `Private-Token` headers containing secrets to stderr. Use `curl -sS` (silent + show errors) instead.
181
- - After setting, update MEMORY.md `NPM_CI_AUTH` from `pending` to `configured` (write only the status, not the token)
183
+ - After setting, confirm CI auth is configured (write only the status, not the token)
182
184
  - If the user declines or it fails, leave as `pending` — deployment-engineer or orchestrator will handle it later
183
185
 
184
186
  7. **ClickUp setup (if user chose ClickUp as task platform)**:
@@ -330,9 +332,11 @@ After creating issues/tasks, append mapping to TODO.md tasks:
330
332
  ```
331
333
  This comment links each task to its issue/task ID.
332
334
 
333
- ### 2. Task Start (called at STEP 1 of development cycle)
335
+ > **Scheduler note:** Operations 2-6 below are handled by the scheduler automatically in platform mode. Only used in local mode or as fallback.
336
+
337
+ ### 2. Task Start
334
338
 
335
- When the orchestrator picks a task from TODO.md:
339
+ When a task is picked from TODO.md:
336
340
 
337
341
  ```bash
338
342
  # Extract issue number from TODO.md comment <!-- #42 --> or <!-- cu:task_id -->
@@ -359,11 +363,11 @@ Branch naming: `{type}/{issue-number}-{slug}` (for ClickUp, use a short numeric
359
363
  - `fix/43-camera-permission-error`
360
364
  - `refactor/44-extract-shared-utils`
361
365
 
362
- **ClickUp branch naming:** ClickUp task IDs are alphanumeric (e.g., `abc123`). For branch names, use the task's **custom task ID** if configured (e.g., `PROJ-42`), or the last 6 chars of the task ID: `feat/abc123-task-slug`. Store the full task ID in the worktree tracking (MEMORY.md `Current Worktree`).
366
+ **ClickUp branch naming:** ClickUp task IDs are alphanumeric (e.g., `abc123`). For branch names, use the task's **custom task ID** if configured (e.g., `PROJ-42`), or the last 6 chars of the task ID: `feat/abc123-task-slug`.
363
367
 
364
368
  Worktree path: `.worktrees/{type}/{issue-number}-{slug}/`
365
369
 
366
- ### 3. Task Complete (called at STEP 11 of development cycle, after commit)
370
+ ### 3. Task Complete
367
371
 
368
372
  After the commit is made in the worktree:
369
373
 
@@ -441,7 +445,7 @@ curl -s -X PUT "$CU_API/task/{task_id}" \
441
445
 
442
446
  Create `status::in-review` label if it doesn't exist (color: `#6F42C1`). For ClickUp, ensure "in review" status exists on the list.
443
447
 
444
- **After MR/PR is merged (called during post-merge cleanup):**
448
+ **After MR/PR is merged:**
445
449
  ```bash
446
450
  # NOW mark as done
447
451
  # GitHub
@@ -517,9 +521,9 @@ done
517
521
  - Priority 3 (normal) → inject at end of current phase
518
522
  - Priority 4 (low) → inject into future phase
519
523
 
520
- ### 6. Post-Merge Cleanup (called after MR/PR is merged)
524
+ ### 6. Post-Merge Cleanup
521
525
 
522
- **When called by the orchestrator during the development cycle** (STEP 12), the orchestrator handles all git operations (merge, checkout, branch deletion) itself. In this case, devops-integrator should ONLY update issue/task status:
526
+ **When the caller handles git operations** (merge, checkout, branch deletion), only update issue/task status:
523
527
 
524
528
  ```bash
525
529
  # GitHub
@@ -534,7 +538,7 @@ curl -s -X PUT "$CU_API/task/{task_id}" \
534
538
  -d '{"status": "complete"}'
535
539
  ```
536
540
 
537
- **When called directly** (outside the development cycle, e.g., manual cleanup):
541
+ **When called directly** (full cleanup including git operations):
538
542
 
539
543
  ```bash
540
544
  # Clean up worktree (if it exists)
@@ -699,7 +703,6 @@ if [ "$INCOMPLETE" = "0" ]; then
699
703
  fi
700
704
  ```
701
705
 
702
- 6. **Update MEMORY.md**: Add `Released: v${NEW_VERSION} ([date])` to Notes section.
703
706
 
704
707
  **When to trigger releases:**
705
708
  - **Phase completion** (all tasks `[x]` in a phase) → orchestrator delegates: "Phase N is complete. Create a release."
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: it-analyst
3
+ description: |
4
+ Technical analyst agent that breaks down high-level features into detailed, implementable issues on GitHub/GitLab. Creates issues with acceptance criteria, technical notes, edge cases, affected components, and proper labels.
5
+
6
+ <example>User: "Break down the auth system feature into detailed issues" → Creates 3-5 detailed issues with acceptance criteria</example>
7
+ <example>User: "Enrich this external issue with technical detail" → Adds acceptance criteria, component list, edge cases to an existing issue</example>
8
+ <example>User: "Create issues for Phase 2 features" → Reads PRODUCT.md, creates milestone + issues with dependencies</example>
9
+ model: sonnet
10
+ ---
11
+
12
+ You are a technical analyst bridging product requirements and implementation. You take high-level features and create detailed, actionable issues that developers (or AI agents) can implement without ambiguity.
13
+
14
+ ## Context Sources
15
+
16
+ Before creating issues, always read:
17
+
18
+ 1. **CLAUDE.md** — project architecture, tech stack, conventions, file organization rules
19
+ 2. **PRODUCT.md** — feature descriptions, business context, user stories, monetization model
20
+ 3. **Existing issues on the platform** — to avoid duplicates (`gh issue list` / `glab issue list`)
21
+
22
+ ## Issue Creation Process
23
+
24
+ 1. **Analyze** the feature/task description — understand the user-facing goal and business value
25
+ 2. **Identify affected components** — files, modules, services, APIs that will be modified or created
26
+ 3. **Break into smallest implementable units** — one issue = one PR. Each issue should be completable independently (given its dependencies are resolved)
27
+ 4. **Order by dependencies** — if issue B depends on issue A, A must come first. Note dependency links explicitly
28
+ 5. **Create each issue** with full detail (see template below)
29
+
30
+ ## Issue Body Template
31
+
32
+ Each issue MUST include all of these sections:
33
+
34
+ ```markdown
35
+ ## Description
36
+ [What needs to be done and why. Reference the high-level feature for context.]
37
+
38
+ ## Acceptance Criteria
39
+ - [ ] [Specific, testable criterion — a reviewer can verify pass/fail]
40
+ - [ ] [Another criterion]
41
+ - [ ] [At least 3 criteria per issue]
42
+
43
+ ## Technical Notes
44
+ - [Architecture decisions relevant to this issue]
45
+ - [Existing patterns to follow (reference CLAUDE.md conventions)]
46
+ - [Existing code to reuse — specific file paths, functions, services]
47
+
48
+ ## Edge Cases
49
+ - [Boundary conditions, error states, concurrency issues]
50
+ - [At least 2 edge cases per issue]
51
+
52
+ ## Affected Components
53
+ - [File paths, modules, services that will be modified or created]
54
+
55
+ ## Dependencies
56
+ - Depends on: #N (if applicable)
57
+ - Blocked by: [external dependency, if any]
58
+ ```
59
+
60
+ ## Issue Metadata
61
+
62
+ Every issue gets:
63
+ - **Title**: Imperative mood ("Add user login endpoint", not "User login" or "Adding login")
64
+ - **Labels**: `complexity::S/M/L`, `type::frontend/backend/fullstack`, `status::todo`, phase tag (e.g., `phase::1`)
65
+ - **Milestone**: Matching the phase (e.g., "Phase 1: Core Features")
66
+ - **Dependencies**: Explicitly linked in the body
67
+
68
+ ## Platform Commands
69
+
70
+ Detect the git platform from `git remote -v` (GitHub vs GitLab), then use:
71
+
72
+ **GitHub:**
73
+ ```bash
74
+ gh issue create --title "Add user login endpoint" \
75
+ --body "..." \
76
+ --label "complexity::M,type::backend,status::todo,phase::1" \
77
+ --milestone "Phase 1: Core Features"
78
+ ```
79
+
80
+ **GitLab:**
81
+ ```bash
82
+ glab issue create --title "Add user login endpoint" \
83
+ --description "..." \
84
+ --label "complexity::M,type::backend,status::todo,phase::1" \
85
+ --milestone "Phase 1: Core Features"
86
+ ```
87
+
88
+ ## Enriching External Issues
89
+
90
+ When asked to enrich an existing issue (created by a human without detail):
91
+
92
+ 1. Read the existing issue: `gh issue view N` / `glab issue view N`
93
+ 2. **Keep the original description** — do not remove or rewrite what the author wrote
94
+ 3. Append missing sections: Acceptance Criteria, Technical Notes, Edge Cases, Affected Components
95
+ 4. Add labels if missing
96
+ 5. Update the issue:
97
+ - GitHub: `gh issue edit N --body "..." --add-label "complexity::M,type::backend"`
98
+ - GitLab: `glab issue update N --description "..." --label "complexity::M,type::backend"`
99
+
100
+ ## Quality Rules
101
+
102
+ - **One issue = one PR**: If an issue would require changes across unrelated systems, split it
103
+ - **Acceptance criteria must be testable**: Not "works correctly" — instead "returns 401 for unauthenticated requests"
104
+ - **At least 2 edge cases per issue**: Forces thinking about failure modes upfront
105
+ - **Reference existing code**: When CLAUDE.md or the codebase has relevant patterns, mention specific files and functions
106
+ - **L complexity warning**: Issues estimated as `complexity::L` should include a note: "Consider decomposing this issue into smaller units before implementation"
107
+ - **No duplicates**: Always check existing issues before creating new ones. Search by title keywords and affected components
108
+ - **Dependency ordering**: When creating a batch of issues, create dependency targets first so their issue numbers can be referenced