create-claude-workspace 2.3.19 → 2.3.20

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/README.md CHANGED
@@ -65,6 +65,15 @@ Write to `.claude/scheduler/inbox.json` while the scheduler is running:
65
65
 
66
66
  The scheduler reads the inbox every iteration and processes messages immediately.
67
67
 
68
+ #### Proactive problem resolution
69
+
70
+ Agents never dismiss problems as "pre-existing." The scheduler injects a `report_issue` MCP tool into every agent. When an agent discovers an out-of-scope problem:
71
+
72
+ - **Non-blocker**: calls `report_issue(severity: 'non-blocker')` and continues working
73
+ - **Blocker**: calls `report_issue(severity: 'blocker')`, wraps up, and returns
74
+
75
+ The scheduler records the issue locally (`discovered.ndjson`) and creates a platform issue (GitHub/GitLab) if available. Discovered issues enter the task queue on the next iteration.
76
+
68
77
  ### npx Options
69
78
 
70
79
  ```bash
@@ -42,6 +42,8 @@ export class WorkerPool {
42
42
  queryOptions.agent = opts.agent;
43
43
  if (opts.model)
44
44
  queryOptions.model = opts.model;
45
+ if (opts.mcpServers)
46
+ queryOptions.mcpServers = opts.mcpServers;
45
47
  if (opts.resume) {
46
48
  queryOptions.resume = opts.resume;
47
49
  }
@@ -0,0 +1,54 @@
1
+ // ─── Platform issue creation (GitHub/GitLab) ───
2
+ // Creates issues on the remote platform for discovered problems.
3
+ // Non-fatal — returns null on failure (local record always exists).
4
+ import { execFileSync } from 'node:child_process';
5
+ const CLI_TIMEOUT = 30_000;
6
+ function run(cmd, args, cwd) {
7
+ return execFileSync(cmd, args, { cwd, timeout: CLI_TIMEOUT, stdio: 'pipe', encoding: 'utf-8' }).trim();
8
+ }
9
+ /**
10
+ * Create an issue on the remote platform.
11
+ * Returns the created issue info, or null if creation failed (non-fatal).
12
+ */
13
+ export function createPlatformIssue(cwd, platform, opts) {
14
+ try {
15
+ if (platform === 'github')
16
+ return createGitHubIssue(cwd, opts);
17
+ return createGitLabIssue(cwd, opts);
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ function createGitHubIssue(cwd, opts) {
24
+ const args = ['issue', 'create', '--title', opts.title, '--body', opts.body];
25
+ for (const label of opts.labels) {
26
+ args.push('--label', label);
27
+ }
28
+ if (opts.milestone)
29
+ args.push('--milestone', opts.milestone);
30
+ const output = run('gh', args, cwd);
31
+ // gh issue create prints the URL: https://github.com/owner/repo/issues/42
32
+ const urlMatch = output.match(/https:\/\/github\.com\/[^/]+\/[^/]+\/issues\/(\d+)/);
33
+ if (!urlMatch)
34
+ return null;
35
+ return { number: parseInt(urlMatch[1], 10), url: urlMatch[0] };
36
+ }
37
+ function createGitLabIssue(cwd, opts) {
38
+ const args = ['issue', 'create', '--title', opts.title, '--description', opts.body];
39
+ if (opts.labels.length > 0) {
40
+ args.push('--label', opts.labels.join(','));
41
+ }
42
+ if (opts.milestone)
43
+ args.push('--milestone', opts.milestone);
44
+ const output = run('glab', args, cwd);
45
+ // glab outputs: Creating issue... or the URL
46
+ const urlMatch = output.match(/https:\/\/gitlab\.[^/]+\/[^/]+\/[^/]+\/-\/issues\/(\d+)/);
47
+ if (urlMatch)
48
+ return { number: parseInt(urlMatch[1], 10), url: urlMatch[0] };
49
+ // Fallback: look for issue number in output like "#42" or "issue #42"
50
+ const numMatch = output.match(/#(\d+)/);
51
+ if (numMatch)
52
+ return { number: parseInt(numMatch[1], 10), url: output };
53
+ return null;
54
+ }
@@ -14,6 +14,7 @@ import { runIteration } from './loop.mjs';
14
14
  import { checkAuth } from './agents/health-checker.mjs';
15
15
  import { pollForNewWork } from './util/idle-poll.mjs';
16
16
  import { TUI } from './ui/tui.mjs';
17
+ import { DiscoveredIssueStore } from './tools/report-issue.mjs';
17
18
  // ─── Args ───
18
19
  export function parseSchedulerArgs(argv) {
19
20
  const opts = { ...SCHEDULER_DEFAULTS };
@@ -281,6 +282,8 @@ export async function runScheduler(opts) {
281
282
  const onMessage = (msg) => tui.handleMessage(msg);
282
283
  const onSpawnStart = (name) => tui.pushAgent(name);
283
284
  const onSpawnEnd = () => tui.popAgent();
285
+ // Discovered issue store (shared across all agent spawns)
286
+ const discoveredIssueStore = new DiscoveredIssueStore();
284
287
  // Orchestrator client
285
288
  const orchestrator = new OrchestratorClient({
286
289
  pool,
@@ -317,6 +320,7 @@ export async function runScheduler(opts) {
317
320
  state,
318
321
  opts,
319
322
  logger,
323
+ discoveredIssueStore,
320
324
  onMessage,
321
325
  onSpawnStart,
322
326
  onSpawnEnd,
@@ -15,6 +15,8 @@ import { detectCIPlatform, fetchFailureLogs } from './git/ci-watcher.mjs';
15
15
  import { createRelease } from './git/release.mjs';
16
16
  import { processInbox, addTaskMessageToTask } from './tasks/inbox.mjs';
17
17
  import { buildPlanPrompt, buildImplementPrompt, buildQAPrompt, buildReviewPrompt, buildReworkPrompt, buildCIFixPrompt, buildPRCommentPrompt, } from './agents/prompt-builder.mjs';
18
+ import { discoveredIssueToTask } from './tools/report-issue.mjs';
19
+ import { createSchedulerToolServer } from './tools/scheduler-tools.mjs';
18
20
  const MAX_REVIEW_CYCLES = 5;
19
21
  const MAX_BUILD_FIXES = 3;
20
22
  const MAX_CI_FIXES = 3;
@@ -28,15 +30,16 @@ export async function runIteration(deps) {
28
30
  // Rotate log if needed
29
31
  rotateLog(projectDir);
30
32
  // Process inbox — immediate, non-blocking
33
+ const inboxTasks = [];
31
34
  const inboxMessages = processInbox(projectDir);
32
35
  for (const msg of inboxMessages) {
33
36
  if (msg.type === 'add-task') {
34
37
  const addMsg = msg;
35
38
  const nextId = `inbox-${Date.now()}`;
36
39
  const newTask = addTaskMessageToTask(addMsg, state.currentPhase, nextId);
40
+ inboxTasks.push(newTask);
37
41
  logger.info(`[inbox] New task: ${newTask.title}`);
38
42
  appendEvent(projectDir, createEvent('task_started', { taskId: nextId, detail: `inbox: ${newTask.title}` }));
39
- // Task will be picked up when we load tasks below
40
43
  }
41
44
  else if (msg.type === 'message') {
42
45
  const freeMsg = msg;
@@ -129,6 +132,18 @@ export async function runIteration(deps) {
129
132
  }
130
133
  }
131
134
  }
135
+ // Merge inbox tasks into loaded tasks
136
+ if (inboxTasks.length > 0) {
137
+ tasks.push(...inboxTasks);
138
+ }
139
+ // Drain discovered issues from agent report_issue tool calls (previous iteration)
140
+ const discovered = deps.discoveredIssueStore.drain();
141
+ for (const issue of discovered) {
142
+ const task = discoveredIssueToTask(issue, state.currentPhase);
143
+ tasks.push(task);
144
+ logger.info(`[discovered] ${issue.severity}: ${issue.title} (reported by ${issue.reportedBy})`);
145
+ appendEvent(projectDir, createEvent('issue_discovered', { taskId: task.id, detail: `${issue.severity}: ${issue.title}` }));
146
+ }
132
147
  // Reconcile task status with scheduler state (handles restart without --resume)
133
148
  for (const task of tasks) {
134
149
  if (state.completedTasks.includes(task.id) && task.status !== 'done') {
@@ -261,6 +276,7 @@ export async function runIteration(deps) {
261
276
  issueMarker: taskId,
262
277
  kitUpgrade: false,
263
278
  lineNumber: 0,
279
+ source: 'todo',
264
280
  status: 'in-progress',
265
281
  changelog: 'changed',
266
282
  };
@@ -359,6 +375,10 @@ export async function runIteration(deps) {
359
375
  async function runTaskPipeline(task, workerId, agents, deps) {
360
376
  const { pool, orchestrator, state, opts, logger, onMessage, onSpawnStart, onSpawnEnd } = deps;
361
377
  const projectDir = opts.projectDir;
378
+ // Create per-pipeline MCP server with scheduler tools (report_issue, etc.)
379
+ const ciPlatform = detectCIPlatform(projectDir);
380
+ const mcpServer = createSchedulerToolServer(deps.discoveredIssueStore, task.id, projectDir, ciPlatform === 'none' ? 'none' : ciPlatform);
381
+ const mcpServers = { 'scheduler-tools': mcpServer };
362
382
  // Check for existing pipeline (recovered from previous run)
363
383
  const existing = state.pipelines[task.id];
364
384
  const resumeStep = existing?.step;
@@ -414,7 +434,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
414
434
  cwd: worktreePath,
415
435
  prompt: buildPlanPrompt({ task, worktreePath, projectDir }),
416
436
  model: getAgentModel(pipeline.assignedAgent, agents, task),
417
- }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
437
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd, mcpServers);
418
438
  if (!planResult.success) {
419
439
  logger.error(`[${task.id}] Planning failed: ${planResult.error}`);
420
440
  return false;
@@ -442,7 +462,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
442
462
  apiContract: pipeline.apiContract ?? undefined,
443
463
  }),
444
464
  model: getAgentModel(implAgent, agents, task),
445
- }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
465
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd, mcpServers);
446
466
  if (!implResult.success) {
447
467
  logger.error(`[${task.id}] Implementation failed: ${implResult.error}`);
448
468
  return false;
@@ -461,7 +481,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
461
481
  reviewFindings: 'This task was interrupted. The branch has existing work but may have build/lint failures, merge conflicts, or failing CI. Please:\n1. Run git fetch origin main && git rebase origin/main (resolve any conflicts)\n2. Run the build and lint scripts from package.json\n3. Fix any errors found\n4. Ensure all tests pass',
462
482
  }),
463
483
  model: getAgentModel(pipeline.assignedAgent, agents, task),
464
- }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
484
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd, mcpServers);
465
485
  }
466
486
  // STEP 3: QA (E2E tests, integration tests, acceptance criteria verification)
467
487
  // Only for tasks that need it — skip for pure refactoring, config changes, etc.
@@ -480,7 +500,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
480
500
  testingSection: pipeline.testingSection ?? undefined,
481
501
  }),
482
502
  model: getAgentModel(qaRouting.agent, agents, task),
483
- }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
503
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd, mcpServers);
484
504
  if (!qaResult.success) {
485
505
  pipeline.buildFixes++;
486
506
  if (pipeline.buildFixes >= MAX_BUILD_FIXES) {
@@ -513,7 +533,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
513
533
  testingSection: pipeline.testingSection ?? undefined,
514
534
  }),
515
535
  model: getAgentModel(reviewRouting.agent, agents, task),
516
- }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
536
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd, mcpServers);
517
537
  if (reviewResult.output.includes('**PASS**') || reviewResult.output.includes('PASS')) {
518
538
  reviewPassed = true;
519
539
  }
@@ -535,7 +555,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
535
555
  reviewFindings: pipeline.reviewFindings,
536
556
  }),
537
557
  model: getAgentModel(pipeline.assignedAgent, agents, task),
538
- }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
558
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd, mcpServers);
539
559
  pipeline.step = 're-review';
540
560
  }
541
561
  }
@@ -676,7 +696,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
676
696
  }
677
697
  }
678
698
  // ─── Helpers ───
679
- async function spawnAgent(pool, slotId, opts, state, taskId, logger, onMessage, onSpawnStart, onSpawnEnd) {
699
+ async function spawnAgent(pool, slotId, opts, state, taskId, logger, onMessage, onSpawnStart, onSpawnEnd, mcpServers) {
680
700
  const agentName = opts.agent ?? 'claude';
681
701
  onSpawnStart?.(agentName);
682
702
  // Check for existing session (resume on crash)
@@ -685,6 +705,7 @@ async function spawnAgent(pool, slotId, opts, state, taskId, logger, onMessage,
685
705
  ...opts,
686
706
  resume: existingSession ?? undefined,
687
707
  onMessage,
708
+ mcpServers,
688
709
  });
689
710
  onSpawnEnd?.();
690
711
  // Record session for crash recovery
@@ -1052,6 +1073,7 @@ function loadTasksJson(path) {
1052
1073
  issueMarker: t.issueMarker ?? null,
1053
1074
  kitUpgrade: t.kitUpgrade ?? false,
1054
1075
  lineNumber: t.lineNumber ?? 0,
1076
+ source: t.source ?? 'todo',
1055
1077
  changelog: t.changelog ?? 'added',
1056
1078
  })));
1057
1079
  }
@@ -1113,7 +1135,7 @@ async function checkPRWatch(taskId, pipeline, projectDir, agents, deps) {
1113
1135
  const task = {
1114
1136
  id: taskId, title: `Resolve merge conflict for ${taskId}`, phase: state.currentPhase,
1115
1137
  type: 'fullstack', complexity: 'S', dependsOn: [], issueMarker: taskId,
1116
- kitUpgrade: false, lineNumber: 0, status: 'in-progress', changelog: 'fixed',
1138
+ kitUpgrade: false, lineNumber: 0, source: 'todo', status: 'in-progress', changelog: 'fixed',
1117
1139
  };
1118
1140
  // Fetch the main branch into the worktree so agent can see what changed
1119
1141
  try {
@@ -1240,7 +1262,7 @@ async function checkPRWatch(taskId, pipeline, projectDir, agents, deps) {
1240
1262
  const task = {
1241
1263
  id: taskId, title: `Fix CI for ${taskId}`, phase: state.currentPhase,
1242
1264
  type: 'fullstack', complexity: 'S', dependsOn: [], issueMarker: taskId,
1243
- kitUpgrade: false, lineNumber: 0, status: 'in-progress', changelog: 'fixed',
1265
+ kitUpgrade: false, lineNumber: 0, source: 'todo', status: 'in-progress', changelog: 'fixed',
1244
1266
  };
1245
1267
  const fixResult = await spawnAgent(pool, slot.id, {
1246
1268
  agent: pipeline.assignedAgent ?? undefined,
@@ -1272,7 +1294,7 @@ async function checkPRWatch(taskId, pipeline, projectDir, agents, deps) {
1272
1294
  const task = {
1273
1295
  id: taskId, title: `Address PR comments for ${taskId}`, phase: state.currentPhase,
1274
1296
  type: 'fullstack', complexity: 'S', dependsOn: [], issueMarker: taskId,
1275
- kitUpgrade: false, lineNumber: 0, status: 'in-progress', changelog: 'fixed',
1297
+ kitUpgrade: false, lineNumber: 0, source: 'todo', status: 'in-progress', changelog: 'fixed',
1276
1298
  };
1277
1299
  const result = await spawnAgent(pool, slot.id, {
1278
1300
  agent: pipeline.assignedAgent ?? undefined,
@@ -66,6 +66,7 @@ export function addTaskMessageToTask(msg, phase, nextId) {
66
66
  issueMarker: null,
67
67
  kitUpgrade: false,
68
68
  lineNumber: 0,
69
+ source: 'inbox',
69
70
  changelog: 'added',
70
71
  };
71
72
  }
@@ -56,6 +56,7 @@ export function issueToTask(issue, fallbackPhase) {
56
56
  issueMarker: `#${issue.issueNumber}`,
57
57
  kitUpgrade: issue.labels.some(l => l.toLowerCase().includes('kit-upgrade')),
58
58
  lineNumber: 0, // not applicable for platform issues
59
+ source: 'platform',
59
60
  status,
60
61
  changelog: inferChangelog(issue.title, issue.labels),
61
62
  };
@@ -111,6 +111,7 @@ export function parseTodoMd(content) {
111
111
  issueMarker: pendingTask.issueMarker,
112
112
  kitUpgrade: meta.kitUpgrade,
113
113
  lineNumber: pendingTask.lineNumber,
114
+ source: 'todo',
114
115
  changelog: inferChangelogCategory(title, pendingTask.status),
115
116
  });
116
117
  pendingTask = null;
@@ -0,0 +1,94 @@
1
+ // ─── report_issue MCP tool for agents ───
2
+ // Allows agents to report discovered issues outside their current task scope.
3
+ // Handler runs in-process in the scheduler — records locally + creates platform issues.
4
+ import { appendFileSync } from 'node:fs';
5
+ import { resolve } from 'node:path';
6
+ import { tool } from '@anthropic-ai/claude-agent-sdk';
7
+ import { z } from 'zod/v4';
8
+ import { createPlatformIssue } from '../git/issue-creator.mjs';
9
+ // ─── In-memory store ───
10
+ export class DiscoveredIssueStore {
11
+ issues = [];
12
+ add(issue) {
13
+ this.issues.push(issue);
14
+ }
15
+ /** Returns all issues and clears the store. */
16
+ drain() {
17
+ return this.issues.splice(0);
18
+ }
19
+ /** Read without clearing. */
20
+ peek() {
21
+ return this.issues;
22
+ }
23
+ }
24
+ // ─── Tool definition factory ───
25
+ const DISCOVERED_NDJSON = '.claude/scheduler/discovered.ndjson';
26
+ export function buildReportIssueTool(store, currentTaskId, projectDir, platform) {
27
+ return tool('report_issue', 'Report a discovered issue outside your current task scope. Use severity "non-blocker" for issues that don\'t prevent your work (then continue normally), or "blocker" for issues that prevent you from completing your task (then wrap up what you can and return).', {
28
+ title: z.string().describe('Concise issue title'),
29
+ type: z.enum(['frontend', 'backend', 'fullstack']).describe('Affected layer'),
30
+ complexity: z.enum(['S', 'M', 'L']).default('M').describe('Estimated complexity'),
31
+ severity: z.enum(['blocker', 'non-blocker']).describe('Whether this blocks your current task'),
32
+ description: z.string().describe('What is broken, where, and what the fix should look like'),
33
+ evidence: z.string().default('').describe('Error messages, file paths, stack traces'),
34
+ }, async (args) => {
35
+ const id = `discovered-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
36
+ const issue = {
37
+ id,
38
+ title: args.title,
39
+ type: args.type,
40
+ complexity: args.complexity,
41
+ severity: args.severity,
42
+ description: args.description,
43
+ evidence: args.evidence,
44
+ reportedBy: currentTaskId,
45
+ timestamp: Date.now(),
46
+ };
47
+ // Record in memory (scheduler drains on next iteration)
48
+ store.add(issue);
49
+ // Persist for crash recovery
50
+ try {
51
+ const ndjsonPath = resolve(projectDir, DISCOVERED_NDJSON);
52
+ appendFileSync(ndjsonPath, JSON.stringify(issue) + '\n', 'utf-8');
53
+ }
54
+ catch { /* best-effort — in-memory store is primary */ }
55
+ // Create platform issue if available
56
+ if (platform !== 'none') {
57
+ try {
58
+ const labels = [`discovered`, `type::${args.type}`, `complexity::${args.complexity}`, 'status::todo'];
59
+ const created = createPlatformIssue(projectDir, platform, {
60
+ title: args.title,
61
+ body: `**Discovered during:** ${currentTaskId}\n**Severity:** ${args.severity}\n\n${args.description}\n\n**Evidence:**\n\`\`\`\n${args.evidence}\n\`\`\``,
62
+ labels,
63
+ });
64
+ if (created) {
65
+ issue.platformIssue = created;
66
+ }
67
+ }
68
+ catch { /* non-fatal */ }
69
+ }
70
+ const platformNote = issue.platformIssue
71
+ ? ` Platform issue: ${issue.platformIssue.url}`
72
+ : '';
73
+ return {
74
+ content: [{ type: 'text', text: `Issue recorded: ${args.title} (${id}).${platformNote}` }],
75
+ };
76
+ });
77
+ }
78
+ // ─── Convert discovered issue to Task ───
79
+ export function discoveredIssueToTask(issue, currentPhase) {
80
+ return {
81
+ id: issue.id,
82
+ title: issue.title,
83
+ phase: currentPhase,
84
+ type: issue.type,
85
+ complexity: issue.complexity,
86
+ dependsOn: [],
87
+ issueMarker: issue.platformIssue ? `#${issue.platformIssue.number}` : null,
88
+ kitUpgrade: false,
89
+ lineNumber: 0,
90
+ source: 'discovered',
91
+ status: 'todo',
92
+ changelog: 'added',
93
+ };
94
+ }
@@ -0,0 +1,17 @@
1
+ // ─── In-process MCP server with scheduler-provided tools ───
2
+ // Creates a per-agent MCP server instance injected into query() options.
3
+ // Each agent gets its own server (currentTaskId differs per spawn).
4
+ import { createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk';
5
+ import { buildReportIssueTool } from './report-issue.mjs';
6
+ /**
7
+ * Create an in-process MCP server with scheduler tools for a specific agent.
8
+ * Returns a config that can be passed to query() via options.mcpServers.
9
+ */
10
+ export function createSchedulerToolServer(store, currentTaskId, projectDir, platform) {
11
+ const reportIssueTool = buildReportIssueTool(store, currentTaskId, projectDir, platform);
12
+ return createSdkMcpServer({
13
+ name: 'scheduler-tools',
14
+ version: '1.0.0',
15
+ tools: [reportIssueTool],
16
+ });
17
+ }
@@ -561,4 +561,8 @@ When reviewing Angular code, check:
561
561
  - @defer for heavy below-fold components
562
562
  - Naming: PascalCase components, lib- selectors, kebab-case files
563
563
  - i18n: ALL user-facing text has `i18n` attribute (templates) or `$localize` (TS) — no bare text
564
- - VRT: new pages/routes have corresponding `*.vrt.spec.ts` with 3-viewport coverage (375px, 768px, 1280px), baseline snapshots committed
564
+ - VRT: new pages/routes have corresponding `*.vrt.spec.ts` with 3-viewport coverage (375px, 768px, 1280px), baseline snapshots committed
565
+
566
+ ## Out-of-Scope Issues
567
+
568
+ If you discover problems outside your current task (broken infrastructure, misconfigurations, deprecated APIs in other code), use the `report_issue` tool to create a tracked issue. Set `severity: 'non-blocker'` and continue your work, or `severity: 'blocker'` if the problem prevents you from completing your task — in that case, finish what you can and return. Never dismiss problems as "pre-existing."
@@ -136,3 +136,7 @@ When called for **direct implementation**, provide complete production-ready cod
136
136
  - Explain architectural decisions and trade-offs
137
137
  - Proactively identify potential issues
138
138
  - No fluff — every word serves a purpose
139
+
140
+ ## Out-of-Scope Issues
141
+
142
+ If you discover problems outside your current task (broken infrastructure, misconfigurations, deprecated APIs in other code), use the `report_issue` tool to create a tracked issue. Set `severity: 'non-blocker'` and continue your work, or `severity: 'blocker'` if the problem prevents you from completing your task — in that case, finish what you can and return. Never dismiss problems as "pre-existing."
@@ -870,70 +870,18 @@ If a merge conflict occurs:
870
870
  4. Push: `git push origin HEAD`
871
871
  5. Then clean up: `git worktree remove .worktrees/feat/{slug} && git branch -d feat/{slug}`
872
872
 
873
- ## DISCOVERED ISSUES Protocol
873
+ ## Proactive Problem Resolution
874
874
 
875
- Agents encounter problems outside their current scope during work. This protocol gives them a structured way to report issues without breaking their flow, and ensures the orchestrator processes every report.
875
+ All agents have access to a `report_issue` tool provided by the scheduler. When an agent encounters a problem outside its current task scope, it calls this tool to create a tracked issue. The scheduler picks it up on the next iteration and routes it through the normal pipeline.
876
876
 
877
- ### Agent-side: How agents report issues
877
+ **Agent behavior:**
878
+ - **In-scope problem** → fix it directly (it's the agent's job)
879
+ - **Out-of-scope, non-blocking** → call `report_issue` with `severity: 'non-blocker'`, then continue working
880
+ - **Out-of-scope, blocking** → call `report_issue` with `severity: 'blocker'`, finish what's possible, then return
881
+ - **Warnings are actionable** — unless they originate from inside a third-party package's own source code
882
+ - **Never dismiss** — "pre-existing" and "not in scope" are not valid reasons to ignore a problem
878
883
 
879
- Every agent (architect, implementer, reviewer, test-engineer) MAY include a `## DISCOVERED ISSUES` section at the END of their response. Format:
880
-
881
- ```
882
- ## DISCOVERED ISSUES
883
-
884
- ### [NON-BLOCKER] Title describing the problem
885
- - **Scope**: which agent should handle this (e.g., `deployment-engineer`, `backend-ts-architect`)
886
- - **Type**: frontend | backend | fullstack | devops
887
- - **Complexity**: S | M
888
- - **Description**: What is broken, where, and what the fix should look like
889
- - **Evidence**: error message, file:line, warning output
890
-
891
- ### [BLOCKER] Title describing the blocking problem
892
- - **Scope**: which agent should handle this
893
- - **Type**: frontend | backend | fullstack | devops
894
- - **Complexity**: S | M
895
- - **Description**: What is broken and why it blocks the current task
896
- - **Evidence**: error message, file:line, warning output
897
- - **Impact**: What cannot proceed until this is resolved
898
- ```
899
-
900
- **Agent rules:**
901
- - **In-scope problem** → fix it directly, do NOT add to DISCOVERED ISSUES (it's your job)
902
- - **Out-of-scope, non-blocking** → add as `[NON-BLOCKER]`, then **continue and deliver your task**
903
- - **Out-of-scope, blocking** → add as `[BLOCKER]`, finish what you can, then return. The orchestrator will handle delegation
904
- - **Warnings count** — treat project warnings as issues unless they originate from inside a third-party package's own source code. Misconfiguration or misuse of a third-party tool is a project problem.
905
- - **"Third-party issue" is narrow** — only valid when the bug is in the third-party package's source code itself
906
- - **Never dismiss** — if you see a problem, either fix it or report it. "Pre-existing" and "not in scope" are not valid reasons to ignore a problem.
907
-
908
- ### Orchestrator-side: Processing DISCOVERED ISSUES
909
-
910
- **After EVERY agent delegation** (STEP 2, 3, 4, 5, 6, 7, 8), scan the agent's response for a `## DISCOVERED ISSUES` section. If present:
911
-
912
- #### NON-BLOCKER items → create tasks, continue current workflow
913
- 1. **Local mode**: Add each item to TODO.md in the CURRENT phase (after the current task). Format:
914
- ```
915
- - [ ] **[Title from DISCOVERED ISSUES]** — [Description]. Discovered during #[current-task-id] (Complexity: [S|M], Type: [type])
916
- ```
917
- 2. **Platform mode**: Delegate to `devops-integrator`: "Create issues for these discovered problems: [list items]. Label: `status::todo`, `discovered`. Milestone: current phase. Do NOT perform git operations."
918
- 3. **Continue with the current task** — non-blockers do NOT interrupt the workflow.
919
-
920
- #### BLOCKER items → resolve before continuing
921
- 1. **Assess if truly blocking**: Can the current task still be completed without resolving this? If the agent completed their deliverable despite reporting `[BLOCKER]`, reclassify as `[NON-BLOCKER]` and process accordingly.
922
- 2. **If blocking and in another agent's scope**: Delegate to the appropriate agent IMMEDIATELY (before continuing the current step). Include the evidence and description from the DISCOVERED ISSUES entry. This is an interruption to the current workflow — resume the current step after the blocker is resolved.
923
- 3. **If blocking and unfixable now** (requires human action, external dependency, missing credentials): Mark the current task as `[~]` SKIPPED with reason referencing the blocker. Create the task for the blocker issue. Move to next task.
924
- 4. **Max 1 blocker delegation per step** — if resolving a blocker reveals another blocker, skip the current task and create tasks for both blockers.
925
-
926
- #### Deduplication
927
- Before creating a task from a discovered issue:
928
- - Check TODO.md / platform issues for existing tasks with similar title or description
929
- - Check if the issue was already reported in a previous iteration (grep TODO.md for keywords)
930
- - Skip duplicates — do NOT create redundant tasks
931
-
932
- ### Including the protocol in delegation prompts
933
-
934
- **Add this paragraph to ALL agent delegation prompts** (STEP 2, 3, 4, 6 — all Agent tool calls to specialist agents):
935
-
936
- > "If you encounter any problems, warnings, or broken infrastructure outside the scope of this task, include a `## DISCOVERED ISSUES` section at the end of your response. Use `[NON-BLOCKER]` for issues that don't prevent you from completing this task, `[BLOCKER]` for issues that do. Format: title, scope (which agent), type (frontend/backend/fullstack/devops), complexity (S/M), description, evidence. Do not dismiss issues as pre-existing — report everything you find."
884
+ **Orchestrator does NOT process discovered issues.** The scheduler handles everything creating tasks from `report_issue` calls, creating platform issues, and routing them to the right agent via the normal task queue. The orchestrator just picks tasks and delegates as usual.
937
885
 
938
886
  ## When Stuck
939
887
 
@@ -393,3 +393,7 @@ When reviewing React code, check:
393
393
  - No unstable nested component definitions (components defined inside render)
394
394
  - `React.memo` only on components with measured re-render cost — not as a default
395
395
  - VRT: new pages/routes have corresponding `*.vrt.spec.ts` with 3-viewport coverage (375px, 768px, 1280px), baseline snapshots committed
396
+
397
+ ## Out-of-Scope Issues
398
+
399
+ If you discover problems outside your current task (broken infrastructure, misconfigurations, deprecated APIs in other code), use the `report_issue` tool to create a tracked issue. Set `severity: 'non-blocker'` and continue your work, or `severity: 'blocker'` if the problem prevents you from completing your task — in that case, finish what you can and return. Never dismiss problems as "pre-existing."
@@ -195,3 +195,7 @@ What is done well. Correct patterns, clean code, good decisions. Be specific.
195
195
  4. **Prioritize impact** — security > correctness > performance > style
196
196
  5. **Respect project standards** — align with CLAUDE.md conventions
197
197
  6. **Don't offer to fix** — this is not interactive, the user cannot respond
198
+
199
+ ## Out-of-Scope Issues
200
+
201
+ If you discover problems outside your current task (broken infrastructure, misconfigurations, deprecated APIs in other code), use the `report_issue` tool to create a tracked issue. Set `severity: 'non-blocker'` and continue your work, or `severity: 'blocker'` if the problem prevents you from completing your task — in that case, finish what you can and return. Never dismiss problems as "pre-existing."
@@ -394,3 +394,7 @@ When reviewing Svelte code, check:
394
394
  - Callback props for outputs (not `createEventDispatcher` — that's Svelte 4)
395
395
  - Resource cleanup in `onDestroy` or `$effect` return for manual subscriptions
396
396
  - VRT: new pages/routes have corresponding `*.vrt.spec.ts` with 3-viewport coverage (375px, 768px, 1280px), baseline snapshots committed
397
+
398
+ ## Out-of-Scope Issues
399
+
400
+ If you discover problems outside your current task (broken infrastructure, misconfigurations, deprecated APIs in other code), use the `report_issue` tool to create a tracked issue. Set `severity: 'non-blocker'` and continue your work, or `severity: 'blocker'` if the problem prevents you from completing your task — in that case, finish what you can and return. Never dismiss problems as "pre-existing."
@@ -538,3 +538,7 @@ Tests should be easy to write. If they are not, the production code needs refact
538
538
  - **No flaky tests** — if a test fails intermittently, fix it or delete it
539
539
  - **Test public API** — don't test private methods directly
540
540
  - **Pure functions are easy to test** — prefer pure transformations over stateful operations. If a function is hard to test, it likely has too many responsibilities or side effects.
541
+
542
+ ## Out-of-Scope Issues
543
+
544
+ If you discover problems outside your current task (broken infrastructure, misconfigurations, deprecated APIs in other code), use the `report_issue` tool to create a tracked issue. Set `severity: 'non-blocker'` and continue your work, or `severity: 'blocker'` if the problem prevents you from completing your task — in that case, finish what you can and return. Never dismiss problems as "pre-existing."
@@ -144,4 +144,8 @@ When called for **direct implementation**, provide:
144
144
  - TypeScript interfaces and types
145
145
  - Follow project conventions from CLAUDE.md (App Separation Principle, Onion Architecture layers)
146
146
  - Monorepo-compatible solutions for shared functionality
147
- - When uncertain about approach, ask for clarification before proceeding
147
+ - When uncertain about approach, ask for clarification before proceeding
148
+
149
+ ## Out-of-Scope Issues
150
+
151
+ If you discover problems outside your current task (broken infrastructure, misconfigurations, deprecated APIs in other code), use the `report_issue` tool to create a tracked issue. Set `severity: 'non-blocker'` and continue your work, or `severity: 'blocker'` if the problem prevents you from completing your task — in that case, finish what you can and return. Never dismiss problems as "pre-existing."
@@ -423,3 +423,7 @@ When reviewing Vue code, check:
423
423
  - Naming: PascalCase components, `Base` prefix for atoms, `use` prefix for composables
424
424
  - i18n: ALL user-facing text goes through `$t()` / `t()` — no bare strings in templates or script
425
425
  - VRT: new pages/routes have corresponding `*.vrt.spec.ts` with 3-viewport coverage (375px, 768px, 1280px), baseline snapshots committed
426
+
427
+ ## Out-of-Scope Issues
428
+
429
+ If you discover problems outside your current task (broken infrastructure, misconfigurations, deprecated APIs in other code), use the `report_issue` tool to create a tracked issue. Set `severity: 'non-blocker'` and continue your work, or `severity: 'blocker'` if the problem prevents you from completing your task — in that case, finish what you can and return. Never dismiss problems as "pre-existing."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-claude-workspace",
3
- "version": "2.3.19",
3
+ "version": "2.3.20",
4
4
  "author": "",
5
5
  "repository": {
6
6
  "type": "git",