create-claude-workspace 2.2.1 → 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.
@@ -43,13 +43,14 @@ export function buildImplementPrompt(ctx) {
43
43
  if (ctx.profileContent) {
44
44
  lines.push(``, `## Frontend Profile`, ctx.profileContent);
45
45
  }
46
- lines.push(``, `## Instructions`, `Follow the plan exactly. Write production code. Run build/lint to verify.`, `If build or lint fails, fix the issues before finishing.`);
46
+ lines.push(``, `## Instructions`, `Follow the plan exactly. Write production code AND unit tests.`, ``, `### Implementation`, `- Write production code according to the plan`, `- Follow project conventions from CLAUDE.md`, ``, `### Unit Tests`, `- Write unit tests for all new/modified code (co-located: foo.spec.ts beside foo.ts)`, `- Test pure logic, business rules, edge cases, error conditions`, `- Auto-detect test framework (Vitest or Jest) from project config`, `- Run tests to verify they pass`, ``, `### Verification`, `- Run build and lint fix any failures before finishing`, `- Ensure all unit tests pass`);
47
47
  return lines.join('\n');
48
48
  }
49
- // ─── Test prompt ───
50
- export function buildTestPrompt(ctx) {
49
+ // ─── QA prompt (E2E, integration, acceptance criteria) ───
50
+ export function buildQAPrompt(ctx) {
51
51
  const lines = [
52
- `Write and run tests for the following task.`,
52
+ `You are a QA engineer. Verify the implementation meets acceptance criteria and write higher-level tests.`,
53
+ `Unit tests were already written by the implementing developer — your focus is on integration, E2E, and acceptance.`,
53
54
  ``,
54
55
  `## Task`,
55
56
  `**${ctx.task.title}** (${ctx.task.type})`,
@@ -63,7 +64,7 @@ export function buildTestPrompt(ctx) {
63
64
  if (ctx.testingSection) {
64
65
  lines.push(``, `## Architect's Testing Decisions`, ctx.testingSection);
65
66
  }
66
- lines.push(``, `## Instructions`, `- Auto-detect test framework (Vitest or Jest) from project config`, `- Write unit tests for pure logic and business rules`, `- Write integration tests for API endpoints and DB operations (*.integration.spec.ts)`, `- Co-locate test files next to source (foo.spec.ts beside foo.ts)`, `- Run tests with --coverage and ensure 80% threshold`, `- If E2E tests are appropriate for this task, write Playwright tests`);
67
+ lines.push(``, `## Instructions`, ``, `### Integration Tests (*.integration.spec.ts)`, `- API endpoint tests (real HTTP calls via test server)`, `- Database operation tests (real DB, not mocks)`, `- Service collaboration tests (multiple real services)`, `- Co-locate next to source files`, ``, `### E2E Tests (if task has UI)`, `- Playwright user flow tests`, `- Test the happy path and key error scenarios`, `- Visual regression tests (toHaveScreenshot) for new pages`, ``, `### Acceptance Criteria Verification`, `- Read the task description / issue body for acceptance criteria`, `- Verify each criterion is met by the implementation`, `- If a criterion is NOT met, report it clearly`, ``, `### What NOT to do`, `- Do NOT write unit tests (developer already wrote them)`, `- Do NOT rewrite existing tests`, `- Do NOT test internal implementation details`);
67
68
  return lines.join('\n');
68
69
  }
69
70
  // ─── Review prompt ───
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { buildPlanPrompt, buildImplementPrompt, buildTestPrompt, buildReviewPrompt, buildReworkPrompt, buildDecomposePrompt, buildRoutingPrompt, buildCIFixPrompt, buildPhaseTransitionPrompt, } from './prompt-builder.mjs';
2
+ import { buildPlanPrompt, buildImplementPrompt, buildQAPrompt, buildReviewPrompt, buildReworkPrompt, buildDecomposePrompt, buildRoutingPrompt, buildCIFixPrompt, buildPhaseTransitionPrompt, } from './prompt-builder.mjs';
3
3
  // ─── Fixtures ───
4
4
  const backendTask = {
5
5
  id: 'p1-1',
@@ -106,9 +106,13 @@ describe('buildImplementPrompt', () => {
106
106
  expect(prompt).toContain("Architect's Plan");
107
107
  expect(prompt).toContain('Create users.ts with POST handler');
108
108
  });
109
- it('instructs to run build/lint', () => {
109
+ it('instructs to run build and lint', () => {
110
110
  const prompt = buildImplementPrompt(baseCtx);
111
- expect(prompt).toContain('build/lint');
111
+ expect(prompt).toContain('build and lint');
112
+ });
113
+ it('instructs to write unit tests', () => {
114
+ const prompt = buildImplementPrompt(baseCtx);
115
+ expect(prompt).toContain('unit tests');
112
116
  });
113
117
  it('does not contain workflow instructions', () => {
114
118
  const prompt = buildImplementPrompt(baseCtx);
@@ -117,26 +121,30 @@ describe('buildImplementPrompt', () => {
117
121
  });
118
122
  });
119
123
  // ─── Test prompt ───
120
- describe('buildTestPrompt', () => {
124
+ describe('buildQAPrompt', () => {
121
125
  it('includes changed files', () => {
122
126
  const ctx = { ...baseCtx, changedFiles: ['src/routes/users.ts', 'src/models/user.ts'] };
123
- const prompt = buildTestPrompt(ctx);
127
+ const prompt = buildQAPrompt(ctx);
124
128
  expect(prompt).toContain('src/routes/users.ts');
125
129
  expect(prompt).toContain('src/models/user.ts');
126
130
  });
127
131
  it('includes testing section from architect', () => {
128
132
  const ctx = { ...baseCtx, testingSection: 'Skip E2E, focus on unit tests' };
129
- const prompt = buildTestPrompt(ctx);
133
+ const prompt = buildQAPrompt(ctx);
130
134
  expect(prompt).toContain("Architect's Testing Decisions");
131
135
  expect(prompt).toContain('Skip E2E, focus on unit tests');
132
136
  });
133
- it('mentions coverage threshold', () => {
134
- const prompt = buildTestPrompt(baseCtx);
135
- expect(prompt).toContain('80%');
137
+ it('mentions integration tests', () => {
138
+ const prompt = buildQAPrompt(baseCtx);
139
+ expect(prompt).toContain('integration.spec.ts');
140
+ });
141
+ it('mentions acceptance criteria', () => {
142
+ const prompt = buildQAPrompt(baseCtx);
143
+ expect(prompt).toContain('Acceptance Criteria');
136
144
  });
137
- it('mentions co-located test files', () => {
138
- const prompt = buildTestPrompt(baseCtx);
139
- expect(prompt).toContain('Co-locate');
145
+ it('says NOT to write unit tests', () => {
146
+ const prompt = buildQAPrompt(baseCtx);
147
+ expect(prompt).toContain('NOT write unit tests');
140
148
  });
141
149
  });
142
150
  // ─── Review prompt ───
@@ -26,12 +26,15 @@ export function createPR(opts) {
26
26
  comments: [],
27
27
  };
28
28
  }
29
- // GitLab
30
- const output = cli(`glab mr create --title "${escapedTitle}" --description "${escapedBody}" --target-branch "${opts.baseBranch}" --source-branch "${opts.branch}" --no-editor --json iid,web_url`, opts.cwd, WRITE_TIMEOUT);
31
- const mr = JSON.parse(output);
29
+ // GitLab — glab mr create doesn't support --json, parse URL from output
30
+ const output = cli(`glab mr create --title "${escapedTitle}" --description "${escapedBody}" --target-branch "${opts.baseBranch}" --source-branch "${opts.branch}" --no-editor`, opts.cwd, WRITE_TIMEOUT);
31
+ // glab outputs the MR URL, e.g. "https://gitlab.com/group/repo/-/merge_requests/7"
32
+ const urlMatch = output.match(/https?:\/\/\S+merge_requests\/(\d+)/);
33
+ const mrIid = urlMatch ? parseInt(urlMatch[1], 10) : 0;
34
+ const mrUrl = urlMatch ? urlMatch[0] : output.trim();
32
35
  return {
33
- number: mr.iid,
34
- url: mr.web_url,
36
+ number: mrIid,
37
+ url: mrUrl,
35
38
  status: 'open',
36
39
  ciStatus: 'pending',
37
40
  approvals: 0,
@@ -83,7 +86,7 @@ function parseGitHubComments(comments) {
83
86
  }));
84
87
  }
85
88
  function getGitLabMRStatus(cwd, branch) {
86
- const output = cli(`glab mr view "${branch}" --json iid,web_url,state,merge_status,head_pipeline,user_notes_count`, cwd);
89
+ const output = cli(`glab mr view "${branch}" --output json`, cwd);
87
90
  const mr = JSON.parse(output);
88
91
  const ciStatus = resolveGitLabCIStatus(mr.head_pipeline);
89
92
  const mergeable = mr.merge_status === 'can_be_merged' && ciStatus === 'passed';
@@ -13,7 +13,7 @@ import { scanAgents } from './agents/health-checker.mjs';
13
13
  import { detectCIPlatform, fetchFailureLogs } from './git/ci-watcher.mjs';
14
14
  import { createRelease } from './git/release.mjs';
15
15
  import { processInbox, addTaskMessageToTask } from './tasks/inbox.mjs';
16
- import { buildPlanPrompt, buildImplementPrompt, buildTestPrompt, buildReviewPrompt, buildReworkPrompt, buildCIFixPrompt, buildPRCommentPrompt, } from './agents/prompt-builder.mjs';
16
+ import { buildPlanPrompt, buildImplementPrompt, buildQAPrompt, buildReviewPrompt, buildReworkPrompt, buildCIFixPrompt, buildPRCommentPrompt, } from './agents/prompt-builder.mjs';
17
17
  const MAX_REVIEW_CYCLES = 5;
18
18
  const MAX_BUILD_FIXES = 3;
19
19
  const MAX_CI_FIXES = 3;
@@ -243,7 +243,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
243
243
  agent: pipeline.assignedAgent ?? undefined,
244
244
  cwd: worktreePath,
245
245
  prompt: buildPlanPrompt({ task, worktreePath, projectDir }),
246
- model: getAgentModel(pipeline.assignedAgent, agents),
246
+ model: getAgentModel(pipeline.assignedAgent, agents, task),
247
247
  }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
248
248
  if (!planResult.success) {
249
249
  logger.error(`[${task.id}] Planning failed: ${planResult.error}`);
@@ -256,47 +256,57 @@ async function runTaskPipeline(task, workerId, agents, deps) {
256
256
  logger.info(`[${task.id}] L-task split recommended — deferring to decomposition`);
257
257
  // TODO: implement decomposition flow
258
258
  }
259
- // STEP 2: Implement
259
+ // STEP 2: Implement (includes unit tests + build/lint)
260
260
  pipeline.step = 'implement';
261
261
  appendEvent(projectDir, createEvent('step_changed', { taskId: task.id, step: 'implement' }));
262
+ // Re-route to implementation agent (may differ from planning agent)
263
+ // e.g., ui-engineer plans → angular-engineer implements
264
+ const implRouting = await orchestrator.routeTask(task, 'implement', agents);
265
+ const implAgent = implRouting.agent ?? pipeline.assignedAgent;
262
266
  const implResult = await spawnAgent(pool, workerId, {
263
- agent: pipeline.assignedAgent ?? undefined,
267
+ agent: implAgent ?? undefined,
264
268
  cwd: worktreePath,
265
269
  prompt: buildImplementPrompt({
266
270
  task, worktreePath, projectDir,
267
271
  architectPlan: pipeline.architectPlan,
268
272
  apiContract: pipeline.apiContract ?? undefined,
269
273
  }),
270
- model: getAgentModel(pipeline.assignedAgent, agents),
274
+ model: getAgentModel(implAgent, agents, task),
271
275
  }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
272
276
  if (!implResult.success) {
273
277
  logger.error(`[${task.id}] Implementation failed: ${implResult.error}`);
274
278
  return false;
275
279
  }
276
- // STEP 3: Test
277
- pipeline.step = 'test';
278
- appendEvent(projectDir, createEvent('step_changed', { taskId: task.id, step: 'test' }));
279
- const changedFiles = getChangedFiles(worktreePath);
280
- const testRouting = await orchestrator.routeTask(task, 'test', agents);
281
- const testResult = await spawnAgent(pool, workerId, {
282
- agent: testRouting.agent ?? undefined,
283
- cwd: worktreePath,
284
- prompt: buildTestPrompt({
285
- task, worktreePath, projectDir, changedFiles,
286
- testingSection: pipeline.testingSection ?? undefined,
287
- }),
288
- model: getAgentModel(testRouting.agent, agents),
289
- }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
290
- if (!testResult.success) {
291
- pipeline.buildFixes++;
292
- if (pipeline.buildFixes >= MAX_BUILD_FIXES) {
293
- logger.error(`[${task.id}] Tests failed ${MAX_BUILD_FIXES} times — skipping`);
294
- return false;
280
+ // STEP 3: QA (E2E tests, integration tests, acceptance criteria verification)
281
+ // Only for tasks that need it — skip for pure refactoring, config changes, etc.
282
+ const needsQA = task.type !== 'fullstack' || !isRefactoringTask(task);
283
+ if (needsQA) {
284
+ pipeline.step = 'test';
285
+ appendEvent(projectDir, createEvent('step_changed', { taskId: task.id, step: 'test' }));
286
+ const changedFiles = getChangedFiles(worktreePath);
287
+ const qaRouting = await orchestrator.routeTask(task, 'test', agents);
288
+ const qaResult = await spawnAgent(pool, workerId, {
289
+ agent: qaRouting.agent ?? undefined,
290
+ cwd: worktreePath,
291
+ prompt: buildQAPrompt({
292
+ task, worktreePath, projectDir, changedFiles,
293
+ testingSection: pipeline.testingSection ?? undefined,
294
+ }),
295
+ model: getAgentModel(qaRouting.agent, agents, task),
296
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
297
+ if (!qaResult.success) {
298
+ pipeline.buildFixes++;
299
+ if (pipeline.buildFixes >= MAX_BUILD_FIXES) {
300
+ logger.error(`[${task.id}] QA failed ${MAX_BUILD_FIXES} times — skipping`);
301
+ return false;
302
+ }
303
+ const decision = await orchestrator.handleFailure(task.title, 'test', qaResult.error ?? 'QA failed', pipeline.buildFixes);
304
+ if (decision.action === 'skip')
305
+ return false;
295
306
  }
296
- // Try to fix via orchestrator
297
- const decision = await orchestrator.handleFailure(task.title, 'test', testResult.error ?? 'Tests failed', pipeline.buildFixes);
298
- if (decision.action === 'skip')
299
- return false;
307
+ }
308
+ else {
309
+ logger.info(`[${task.id}] Skipping QA step (refactoring/config task)`);
300
310
  }
301
311
  // STEP 4: Review
302
312
  pipeline.step = 'review';
@@ -313,7 +323,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
313
323
  changedFiles: getChangedFiles(worktreePath),
314
324
  testingSection: pipeline.testingSection ?? undefined,
315
325
  }),
316
- model: getAgentModel(reviewRouting.agent, agents),
326
+ model: getAgentModel(reviewRouting.agent, agents, task),
317
327
  }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
318
328
  if (reviewResult.output.includes('**PASS**') || reviewResult.output.includes('PASS')) {
319
329
  reviewPassed = true;
@@ -335,7 +345,7 @@ async function runTaskPipeline(task, workerId, agents, deps) {
335
345
  task, worktreePath, projectDir,
336
346
  reviewFindings: pipeline.reviewFindings,
337
347
  }),
338
- model: getAgentModel(pipeline.assignedAgent, agents),
348
+ model: getAgentModel(pipeline.assignedAgent, agents, task),
339
349
  }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
340
350
  pipeline.step = 're-review';
341
351
  }
@@ -500,17 +510,31 @@ function taskToSlug(task) {
500
510
  .slice(0, 40);
501
511
  return `feat/${task.id}-${sanitized}`;
502
512
  }
503
- function getAgentModel(agentName, agents) {
513
+ function getAgentModel(agentName, agents, task) {
504
514
  if (!agentName)
505
515
  return undefined;
506
516
  const agent = agents.find(a => a.name === agentName);
507
- return agent?.model;
517
+ const agentModel = agent?.model;
518
+ // If agent specifies a fixed model (opus/sonnet), respect it
519
+ if (agentModel && agentModel !== 'auto')
520
+ return agentModel;
521
+ // Auto model selection based on task complexity
522
+ if (task) {
523
+ // L = complex → opus, S/M = straightforward → sonnet
524
+ return task.complexity === 'L' ? 'opus' : 'sonnet';
525
+ }
526
+ return agentModel;
508
527
  }
509
528
  function extractSection(output, section) {
510
529
  const pattern = new RegExp(`### ${section}\\s*\\n([\\s\\S]*?)(?=\\n### |$)`, 'i');
511
530
  const match = output.match(pattern);
512
531
  return match ? match[1].trim() : null;
513
532
  }
533
+ function isRefactoringTask(task) {
534
+ const lower = task.title.toLowerCase();
535
+ return lower.includes('refactor') || lower.includes('config') || lower.includes('cleanup')
536
+ || lower.includes('rename') || lower.includes('migrate') || lower.includes('upgrade');
537
+ }
514
538
  // ─── Orphaned worktree recovery ───
515
539
  async function recoverOrphanedWorktrees(projectDir, state, logger, deps) {
516
540
  const knownPaths = Object.values(state.pipelines).map(p => p.worktreePath);
@@ -673,7 +697,7 @@ async function pollAndMergePR(task, pipeline, branch, platform, projectDir, work
673
697
  agent: pipeline.assignedAgent ?? undefined,
674
698
  cwd: worktreePath,
675
699
  prompt: buildCIFixPrompt({ task, worktreePath, projectDir }, logs),
676
- model: getAgentModel(pipeline.assignedAgent, agents),
700
+ model: getAgentModel(pipeline.assignedAgent, agents, task),
677
701
  }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
678
702
  if (fixResult.success) {
679
703
  commitInWorktree(worktreePath, `fix: CI failure for ${task.title}`);
@@ -698,7 +722,7 @@ async function pollAndMergePR(task, pipeline, branch, platform, projectDir, work
698
722
  agent: pipeline.assignedAgent ?? undefined,
699
723
  cwd: worktreePath,
700
724
  prompt: buildPRCommentPrompt({ task, worktreePath, projectDir }, commentText),
701
- model: getAgentModel(pipeline.assignedAgent, agents),
725
+ model: getAgentModel(pipeline.assignedAgent, agents, task),
702
726
  }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
703
727
  if (commentResult.success) {
704
728
  commitInWorktree(worktreePath, `fix: address PR review comments`);
@@ -22,14 +22,18 @@ npx create-claude-workspace --update
22
22
 
23
23
  | Agent | Purpose | Model |
24
24
  |-------|---------|-------|
25
- | orchestrator | Development cycle (pick task → plan → implement → test → review → commit → merge) | opus |
25
+ | orchestrator | Development cycle (pick task → plan → implement → QA → review → commit → merge) | opus |
26
26
  | project-initializer | Full project setup pipeline (discovery → CLAUDE.md → PRODUCT.md → TODO.md) | opus |
27
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 |
28
+ | technical-planner | Phased development plan → TODO.md or platform issues | opus |
29
+ | ui-engineer | Frontend architecture and planning (does NOT implement) | opus |
30
+ | angular-engineer | Angular frontend implementation (follows ui-engineer's plan) | auto |
31
+ | react-engineer | React frontend implementation | auto |
32
+ | vue-engineer | Vue frontend implementation | auto |
33
+ | svelte-engineer | Svelte frontend implementation | auto |
30
34
  | 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 |
35
+ | senior-code-reviewer | Structured code review (CRITICAL=blocker, WARN, NICE-TO-HAVE) | opus |
36
+ | test-engineer | QA: E2E tests, integration tests, acceptance criteria verification | sonnet |
37
+ | devops-integrator | Git platform setup (remote, CI secrets, labels, milestones) | sonnet |
34
38
  | deployment-engineer | CI/CD pipelines, deploys, rollbacks, migrations | sonnet |
35
39
  | it-analyst | Technical analyst, breaks features into detailed platform issues | sonnet |
@@ -1,13 +1,19 @@
1
1
  ---
2
2
  name: angular-engineer
3
3
  description: Angular frontend specialist — components, signals, RxJS, SSR, testing
4
- model: opus
5
- steps: plan, implement, rework
4
+ model: auto
5
+ steps: implement, rework
6
6
  ---
7
7
 
8
- You are an Angular frontend engineer. You plan, implement, and fix Angular applications.
8
+ You are an Angular frontend engineer. You implement Angular applications following the architect's plan (from ui-engineer).
9
9
  Read the codebase before making changes. Follow the conventions below strictly.
10
10
 
11
+ ## Implementation Responsibilities
12
+ - Implement production code according to the architect's plan
13
+ - Write unit tests for all new/modified code (co-located: foo.spec.ts beside foo.ts)
14
+ - Run build, lint, and unit tests before finishing — fix any failures
15
+ - Do NOT plan architecture — follow the plan provided
16
+
11
17
 
12
18
  ## Framework
13
19
 
@@ -6,6 +6,12 @@ model: opus
6
6
 
7
7
  You are a Senior Backend TypeScript Architect with deep expertise in server-side development. You value clean, maintainable, and type-safe code above all else.
8
8
 
9
+ ## Implementation Responsibilities
10
+ When implementing (not just planning), you MUST also:
11
+ - Write unit tests for all new/modified code (co-located: foo.spec.ts beside foo.ts)
12
+ - Test pure logic, business rules, edge cases, error conditions
13
+ - Run build, lint, and unit tests before finishing — fix any failures
14
+
9
15
  ## Core Competencies
10
16
 
11
17
  - Advanced TypeScript patterns (generics, conditional types, mapped types, branded types)
@@ -1,13 +1,19 @@
1
1
  ---
2
2
  name: react-engineer
3
3
  description: React frontend specialist — components, hooks, SSR, Next.js, testing
4
- model: opus
5
- steps: plan, implement, rework
4
+ model: auto
5
+ steps: implement, rework
6
6
  ---
7
7
 
8
- You are a React frontend engineer. You plan, implement, and fix React applications.
8
+ You are a React frontend engineer. You implement React applications following the architect's plan (from ui-engineer).
9
9
  Read the codebase before making changes. Follow the conventions below strictly.
10
10
 
11
+ ## Implementation Responsibilities
12
+ - Implement production code according to the architect's plan
13
+ - Write unit tests for all new/modified code (co-located: foo.spec.ts beside foo.ts)
14
+ - Run build, lint, and unit tests before finishing — fix any failures
15
+ - Do NOT plan architecture — follow the plan provided
16
+
11
17
 
12
18
  ## Framework
13
19
 
@@ -12,7 +12,7 @@ You are a Senior Fullstack Code Reviewer with 15+ years of experience across fro
12
12
  - Evaluate architectural decisions against onion architecture and project conventions
13
13
  - Ensure adherence to project-specific standards from CLAUDE.md
14
14
  - Identify bugs, edge cases, error handling gaps
15
- - Check frontend patterns from `.claude/profiles/frontend.md` (framework-specific review checklist)
15
+ - Check frontend patterns (detect framework from package.json and apply framework best practices)
16
16
 
17
17
  ## Review Process
18
18
 
@@ -156,13 +156,13 @@ Read `.claude/profiles/frontend.md` for the framework-specific review checklist.
156
156
  ALL 4 sections MANDATORY, even if empty:
157
157
 
158
158
  ### CRITICAL
159
- Must fix. Bugs, security vulnerabilities, memory leaks, crashes, data loss.
159
+ **BLOCKER — must fix before merge.** Bugs, security vulnerabilities, memory leaks, crashes, data loss. Orchestrator MUST NOT skip CRITICAL findings.
160
160
 
161
161
  ### WARN
162
- Should fix. Bad practices, missing error handling, performance issues, a11y violations.
162
+ Should fix. Bad practices, missing error handling, performance issues, a11y violations. May be skipped after max review cycles.
163
163
 
164
164
  ### NICE-TO-HAVE
165
- Would improve quality. Naming, refactors, extra type safety, tests.
165
+ Optional improvement. Naming, refactors, extra type safety, tests. Does not block merge.
166
166
 
167
167
  ### GREEN
168
168
  What is done well. Correct patterns, clean code, good decisions. Be specific.
@@ -1,13 +1,19 @@
1
1
  ---
2
2
  name: svelte-engineer
3
3
  description: Svelte frontend specialist — runes, SvelteKit, SSR, testing
4
- model: opus
5
- steps: plan, implement, rework
4
+ model: auto
5
+ steps: implement, rework
6
6
  ---
7
7
 
8
- You are a Svelte frontend engineer. You plan, implement, and fix Svelte/SvelteKit applications.
8
+ You are a Svelte frontend engineer. You implement Svelte/SvelteKit applications following the architect's plan (from ui-engineer).
9
9
  Read the codebase before making changes. Follow the conventions below strictly.
10
10
 
11
+ ## Implementation Responsibilities
12
+ - Implement production code according to the architect's plan
13
+ - Write unit tests for all new/modified code (co-located: foo.spec.ts beside foo.ts)
14
+ - Run build, lint, and unit tests before finishing — fix any failures
15
+ - Do NOT plan architecture — follow the plan provided
16
+
11
17
 
12
18
  ## Framework
13
19
 
@@ -1,24 +1,26 @@
1
1
  ---
2
2
  name: test-engineer
3
- description: "Use this agent to write, run, and diagnose tests for recently implemented code. Creates unit tests (Vitest), component tests (Angular TestBed), and E2E tests (Playwright). Runs all tests and reports results.\n\nExamples:\n\n<example>\nuser: \"Write tests for the price calculator service\"\nassistant: \"I'll use the test-engineer agent to create comprehensive tests for this service.\"\n</example>\n\n<example>\nuser: \"Run the tests and fix failures\"\nassistant: \"Let me use the test-engineer agent to run tests and diagnose any failures.\"\n</example>\n\n<example>\nuser: \"Write E2E tests for the checkout flow\"\nassistant: \"I'll use the test-engineer agent to create Playwright E2E tests for this flow.\"\n</example>"
3
+ description: "QA engineer writes E2E tests (Playwright), integration tests, and verifies acceptance criteria. Unit tests are the implementing developer's responsibility.\n\n<example>\nuser: \"Write E2E tests for the checkout flow\"\nassistant: \"I'll use the test-engineer agent to create Playwright E2E tests for this flow.\"\n</example>\n\n<example>\nuser: \"Verify the auth feature meets acceptance criteria\"\nassistant: \"I'll use the test-engineer agent to verify acceptance criteria and write integration tests.\"\n</example>\n\n<example>\nuser: \"Write integration tests for the API endpoints\"\nassistant: \"I'll use the test-engineer agent to create integration tests with real HTTP calls.\"\n</example>"
4
4
  model: sonnet
5
5
  ---
6
6
 
7
- You are a Senior Test Engineer specializing in TypeScript testing with Vitest, integration testing, and E2E testing with Playwright. You write thorough, maintainable tests that catch real bugs without being fragile. You always RUN the tests after writing them and report results.
7
+ You are a QA Engineer specializing in integration testing, E2E testing with Playwright, and acceptance criteria verification. You verify implementations from a user/QA perspective not implementation details. Unit tests are the developer's responsibility; you focus on higher-level testing.
8
+
9
+ You always RUN the tests after writing them and report results.
8
10
 
9
11
  ## Core Competencies
10
12
 
11
- - **Unit testing**: Vitest or Jest (auto-detected from project), assertions, mocking, spies, fakes
12
- - **Component testing**: Framework-specific component tests (see `.claude/profiles/frontend.md` for patterns)
13
- - **Service testing**: DI mocking, HTTP interceptor testing, IndexedDB mocking
14
- - **Business logic testing**: Pure function tests, edge cases, boundary conditions
15
- - **Domain model testing**: Validation, invariants, value object equality
16
- - **Integration testing**: API endpoint tests (supertest/test server), DB operations, service collaboration, library public API contracts
17
- - **E2E testing**: Playwright browser automation, user flow testing, visual verification
13
+ - **Integration testing**: API endpoint tests (real HTTP calls), DB operations, service collaboration
14
+ - **Component testing**: Framework-specific component tests (detect framework from package.json)
15
+ - **E2E testing**: Playwright browser automation, user flow testing, visual regression
16
+ - **Visual regression**: Playwright `toHaveScreenshot()`, multi-viewport matrix
17
+ - **Acceptance criteria verification**: Read task/issue descriptions, verify each criterion
18
18
 
19
- ## Frontend Profile
19
+ ## What You Do NOT Do
20
20
 
21
- When writing component tests, read `.claude/profiles/frontend.md` for framework-specific testing patterns (TestBed for Angular, Testing Library for React, Vue Test Utils for Vue, etc.). If the file does not exist, detect the framework from `package.json` and apply standard testing patterns.
21
+ - **Unit tests** the implementing developer writes these during implementation
22
+ - **Rewriting existing tests** — only add new higher-level tests
23
+ - **Testing internal implementation details** — focus on behavior and user-facing outcomes
22
24
 
23
25
  ## Test Framework Detection (MANDATORY first step)
24
26
 
@@ -1,23 +1,18 @@
1
1
  ---
2
2
  name: ui-engineer
3
- description: "Use this agent for frontend development tasks: component creation, UI implementation, styling, state management, accessibility, or frontend code reviews. Adapts to the project's frontend framework (Angular, React, Vue, Svelte, etc.) based on `.claude/profiles/frontend.md`.\n\nExamples:\n\n<example>\nuser: \"Create a card component for displaying items\"\nassistant: \"I'll use the ui-engineer agent to design and implement this component following our frontend patterns.\"\n</example>\n\n<example>\nuser: \"Review the dashboard components I just created\"\nassistant: \"Let me use the ui-engineer agent to review these components for quality and alignment with our standards.\"\n</example>\n\n<example>\nuser: \"I need a multi-step form with validation\"\nassistant: \"I'll engage the ui-engineer agent to architect and implement this form with proper patterns.\"\n</example>"
3
+ description: "Frontend architect agent plans component architecture, identifies reuse, outputs structured design specs. Does NOT implement code directly implementation is delegated to framework-specific agents (angular-engineer, react-engineer, vue-engineer, svelte-engineer).\n\n<example>\nuser: \"Plan the component architecture for the dashboard\"\nassistant: \"I'll use the ui-engineer agent to design the component architecture and implementation plan.\"\n</example>\n\n<example>\nuser: \"Design the multi-step form architecture\"\nassistant: \"I'll engage the ui-engineer agent to plan the form structure, smart/dumb split, and reuse opportunities.\"\n</example>"
4
4
  model: opus
5
+ steps: plan
5
6
  ---
6
7
 
7
- You are an expert UI engineer specializing in modern frontend development within monorepo architecture. Your mission is to deliver production-ready frontend solutions that follow project conventions from CLAUDE.md and framework-specific patterns from the frontend profile.
8
+ You are a frontend architect specializing in modern frontend development within monorepo architecture. Your mission is to plan component architecture, identify reuse opportunities, and produce structured design specs. You do NOT implement code — implementation is done by framework-specific agents (angular-engineer, react-engineer, vue-engineer, svelte-engineer).
8
9
 
9
- ## Frontend Profile (MANDATORY first step)
10
+ ## Your Role
10
11
 
11
- Before doing ANY work, read `.claude/profiles/frontend.md` for framework-specific best practices:
12
- - Component architecture patterns (smart/dumb, composition, state management)
13
- - Framework-specific conventions (signals, hooks, composition API, runes, etc.)
14
- - SSR patterns and safety rules
15
- - Theme system usage
16
- - Generator commands for scaffolding
17
- - Component testing approach
18
- - Review checklist
19
-
20
- If the file does not exist, detect the framework from `package.json` dependencies and apply your native knowledge of that framework's best practices.
12
+ - **Plan** frontend architecture (component structure, smart/dumb split, data flow)
13
+ - **Identify** existing code to reuse, extend, or compose
14
+ - **Output** structured specs that framework-specific agents follow to implement
15
+ - **Do NOT** write production code — only interface definitions and architecture decisions
21
16
 
22
17
  ## Your Expertise
23
18
 
@@ -76,18 +71,17 @@ Write clean, elegant code that is easy to test and reason about:
76
71
  ## Approach
77
72
 
78
73
  1. **Read CLAUDE.md** for project-specific patterns, design system, and conventions
79
- 2. **Read `.claude/profiles/frontend.md`** for framework-specific best practices
74
+ 2. **Detect framework** from `package.json` dependencies (Angular, React, Vue, or Svelte)
80
75
  3. **Check existing components** — search for similar components, shared UI pieces, and utilities that already exist. List them in your EXISTING CODE section.
81
76
  4. **Design architecture** — plan smart vs dumb, identify reusable parts. Prefer extending/composing existing components over creating new ones.
82
77
  5. **Identify reuse** — explicitly flag existing code to import, extend, or generalize. If a near-duplicate exists, recommend refactoring to shared instead of creating new.
83
- 6. **Provide structured plan** — output clear implementation steps for the orchestrator
84
- 7. **If asked to implement directly** — produce production-ready code following established patterns
85
- 8. **Verify** — accessibility, responsive design, performance, SSR safety
78
+ 6. **Provide structured plan** — output clear implementation steps for the framework-specific agent
79
+ 7. **Consider** — accessibility, responsive design, performance, SSR safety
86
80
 
87
81
  ## SSR Safety
88
82
 
89
83
  - NEVER access `window`, `document`, `navigator` directly in server-rendered code
90
- - Follow framework-specific SSR patterns from the frontend profile
84
+ - Follow framework-specific SSR patterns
91
85
 
92
86
  ## Design Implementation
93
87
 
@@ -1,13 +1,19 @@
1
1
  ---
2
2
  name: vue-engineer
3
3
  description: Vue frontend specialist — Composition API, Pinia, Nuxt, SSR, testing
4
- model: opus
5
- steps: plan, implement, rework
4
+ model: auto
5
+ steps: implement, rework
6
6
  ---
7
7
 
8
- You are a Vue frontend engineer. You plan, implement, and fix Vue applications.
8
+ You are a Vue frontend engineer. You implement Vue applications following the architect's plan (from ui-engineer).
9
9
  Read the codebase before making changes. Follow the conventions below strictly.
10
10
 
11
+ ## Implementation Responsibilities
12
+ - Implement production code according to the architect's plan
13
+ - Write unit tests for all new/modified code (co-located: foo.spec.ts beside foo.ts)
14
+ - Run build, lint, and unit tests before finishing — fix any failures
15
+ - Do NOT plan architecture — follow the plan provided
16
+
11
17
 
12
18
  ## Framework
13
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-claude-workspace",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
4
4
  "author": "",
5
5
  "repository": {
6
6
  "type": "git",