@selesai/code 0.2.1 → 0.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.
Files changed (59) hide show
  1. package/dist/config.d.ts +4 -15
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +5 -45
  4. package/dist/config.js.map +1 -1
  5. package/dist/core/agent-session.d.ts +1 -0
  6. package/dist/core/agent-session.d.ts.map +1 -1
  7. package/dist/core/agent-session.js +8 -0
  8. package/dist/core/agent-session.js.map +1 -1
  9. package/dist/core/model-registry.d.ts +4 -1
  10. package/dist/core/model-registry.d.ts.map +1 -1
  11. package/dist/core/model-registry.js +101 -51
  12. package/dist/core/model-registry.js.map +1 -1
  13. package/dist/defaults/models.json +64 -113
  14. package/dist/extensions/copy-turn.ts +2 -2
  15. package/dist/extensions/pi-powerline-footer/bash-mode/editor.ts +2 -2
  16. package/dist/extensions/pi-powerline-footer/index.ts +31 -31
  17. package/dist/extensions/pi-powerline-footer/package.json +2 -2
  18. package/dist/extensions/pi-powerline-footer/tests/bash-mode.test.ts +10 -10
  19. package/dist/extensions/pi-powerline-footer/tests/jump-shortcuts.test.ts +1 -1
  20. package/dist/extensions/pi-powerline-footer/tests/working-vibes.test.ts +2 -2
  21. package/dist/extensions/pi-powerline-footer/theme.ts +6 -6
  22. package/dist/extensions/pi-powerline-footer/tps.ts +1 -1
  23. package/dist/extensions/pi-powerline-footer/types.ts +7 -7
  24. package/dist/extensions/pi-powerline-footer/working-vibes.ts +51 -51
  25. package/dist/extensions/pi-subagents/agents/architect.md +188 -0
  26. package/dist/extensions/pi-subagents/agents/builder.md +120 -0
  27. package/dist/extensions/pi-subagents/agents/commentator.md +131 -0
  28. package/dist/extensions/pi-subagents/agents/explorer.md +51 -0
  29. package/dist/extensions/pi-subagents/agents/recapper.md +21 -0
  30. package/dist/extensions/pi-subagents/src/shared/utils.ts +9 -3
  31. package/dist/extensions/pi-web-agent/package.json +2 -2
  32. package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +2 -2
  33. package/dist/extensions/pi-web-agent/src/commands/web-agent-config.ts +1 -1
  34. package/dist/extensions/pi-web-agent/src/extension.ts +1 -1
  35. package/dist/extensions/pi-web-agent/src/presentation/config-store.ts +1 -1
  36. package/dist/extensions/question/helpers.ts +3 -3
  37. package/dist/extensions/question/index.ts +2 -2
  38. package/dist/extensions/question/navigation.ts +2 -2
  39. package/dist/extensions/question/package.json +2 -2
  40. package/dist/extensions/question/question-list.ts +2 -2
  41. package/dist/extensions/question/tests/question-list.test.ts +2 -2
  42. package/dist/extensions/question/tui-adapter.ts +2 -2
  43. package/dist/extensions/question/types.ts +2 -2
  44. package/dist/extensions/question/ui-protocol.ts +2 -2
  45. package/dist/extensions/rtk.ts +2 -2
  46. package/dist/extensions/tokenin-onboarding.ts +2 -2
  47. package/dist/extensions/undo.ts +1 -1
  48. package/dist/extensions/web-agent-onboarding.ts +3 -3
  49. package/dist/extensions/workflow/adapter.ts +16 -8
  50. package/dist/extensions/workflow/extension.ts +1 -1
  51. package/dist/extensions/workflow/package.json +1 -1
  52. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  53. package/dist/modes/interactive/components/assistant-message.js +2 -0
  54. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  55. package/dist/utils/thinking-tags.d.ts +7 -0
  56. package/dist/utils/thinking-tags.d.ts.map +1 -0
  57. package/dist/utils/thinking-tags.js +63 -0
  58. package/dist/utils/thinking-tags.js.map +1 -0
  59. package/package.json +2 -2
@@ -3,7 +3,7 @@
3
3
  // Uses module-level state (matching powerline-footer pattern).
4
4
 
5
5
  import { complete, type Context } from "@earendil-works/pi-ai";
6
- import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
6
+ import type { ExtensionContext } from "@selesai/code";
7
7
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
8
8
  import { join, dirname } from "node:path";
9
9
  import { homedir } from "node:os";
@@ -231,7 +231,7 @@ function getVibeFilePath(theme: string): string {
231
231
  function loadVibesFromFile(theme: string): string[] {
232
232
  const filePath = getVibeFilePath(theme);
233
233
  if (!existsSync(filePath)) return [];
234
-
234
+
235
235
  try {
236
236
  const content = readFileSync(filePath, "utf-8");
237
237
  return content
@@ -247,12 +247,12 @@ function loadVibesFromFile(theme: string): string[] {
247
247
  function saveVibesToFile(theme: string, vibes: string[]): void {
248
248
  const vibesDir = getVibesDir();
249
249
  const filePath = getVibeFilePath(theme);
250
-
250
+
251
251
  // Ensure directory exists
252
252
  if (!existsSync(vibesDir)) {
253
253
  mkdirSync(vibesDir, { recursive: true });
254
254
  }
255
-
255
+
256
256
  writeFileSync(filePath, vibes.join("\n"));
257
257
  }
258
258
 
@@ -269,26 +269,26 @@ function mulberry32(seed: number): () => number {
269
269
  // Get vibe at index using seeded shuffle (no-repeat until all used)
270
270
  function getVibeAtIndex(vibes: string[], index: number, seed: number): string {
271
271
  if (vibes.length === 0) return `${config.fallback}...`;
272
-
272
+
273
273
  // For small lists or when we've cycled through, just use modulo
274
274
  const effectiveIndex = index % vibes.length;
275
-
275
+
276
276
  // Create deterministic shuffle using seed
277
277
  const rng = mulberry32(seed);
278
278
  const indices = Array.from({ length: vibes.length }, (_, i) => i);
279
-
279
+
280
280
  // Fisher-Yates shuffle with seeded RNG
281
281
  for (let i = indices.length - 1; i > 0; i--) {
282
282
  const j = Math.floor(rng() * (i + 1));
283
283
  [indices[i], indices[j]] = [indices[j], indices[i]];
284
284
  }
285
-
285
+
286
286
  return vibes[indices[effectiveIndex]];
287
287
  }
288
288
 
289
289
  function getNextVibeFromFile(): string {
290
290
  if (!config.theme) return `${config.fallback}...`;
291
-
291
+
292
292
  // Load/reload cache if theme changed
293
293
  if (vibeCacheTheme !== config.theme) {
294
294
  vibeCache = loadVibesFromFile(config.theme);
@@ -296,11 +296,11 @@ function getNextVibeFromFile(): string {
296
296
  vibeSeed = Date.now(); // New seed for new theme
297
297
  vibeIndex = 0;
298
298
  }
299
-
299
+
300
300
  if (vibeCache.length === 0) {
301
301
  return `${config.fallback}...`;
302
302
  }
303
-
303
+
304
304
  const vibe = getVibeAtIndex(vibeCache, vibeIndex, vibeSeed);
305
305
  vibeIndex++;
306
306
  return vibe;
@@ -313,12 +313,12 @@ function getNextVibeFromFile(): string {
313
313
  function buildVibePrompt(ctx: VibeGenContext): string {
314
314
  // Truncate user prompt to save tokens (most context in first 100 chars)
315
315
  const task = ctx.userPrompt.slice(0, 100);
316
-
316
+
317
317
  // Build exclusion list from recent vibes
318
- const exclude = recentVibes.length > 0
318
+ const exclude = recentVibes.length > 0
319
319
  ? `Don't use: ${recentVibes.join(", ")}`
320
320
  : "";
321
-
321
+
322
322
  // Use configured template with variable substitution
323
323
  return config.promptTemplate
324
324
  .replace(/\{theme\}/g, ctx.theme)
@@ -328,28 +328,28 @@ function buildVibePrompt(ctx: VibeGenContext): string {
328
328
 
329
329
  function parseVibeResponse(response: string, fallback: string): string {
330
330
  if (!response) return `${fallback}...`;
331
-
331
+
332
332
  // Take only the first line (AI sometimes adds explanations)
333
333
  let vibe = response.trim().split('\n')[0].trim();
334
-
334
+
335
335
  // Remove quotes if model wrapped the response
336
336
  vibe = vibe.replace(/^["']|["']$/g, "");
337
-
337
+
338
338
  // Ensure ellipsis
339
339
  if (!vibe.endsWith("...")) {
340
340
  vibe = vibe.replace(/\.+$/, "") + "...";
341
341
  }
342
-
342
+
343
343
  // Enforce length limit (configurable, default 65 chars)
344
344
  if (vibe.length > config.maxLength) {
345
345
  vibe = vibe.slice(0, config.maxLength - 3) + "...";
346
346
  }
347
-
347
+
348
348
  // Final validation
349
349
  if (!vibe || vibe === "...") {
350
350
  return `${fallback}...`;
351
351
  }
352
-
352
+
353
353
  return vibe;
354
354
  }
355
355
 
@@ -375,7 +375,7 @@ async function generateVibe(
375
375
  if (!extensionCtx) {
376
376
  return `${config.fallback}...`;
377
377
  }
378
-
378
+
379
379
  // Parse model spec (provider/modelId format, where modelId may contain slashes)
380
380
  const slashIndex = config.modelSpec.indexOf("/");
381
381
  if (slashIndex === -1) {
@@ -386,23 +386,23 @@ async function generateVibe(
386
386
  if (!provider || !modelId) {
387
387
  return `${config.fallback}...`;
388
388
  }
389
-
389
+
390
390
  // Resolve model from registry
391
391
  const model = extensionCtx.modelRegistry.find(provider, modelId);
392
392
  if (!model) {
393
393
  console.debug(`[working-vibes] Model not found: ${config.modelSpec}`);
394
394
  return `${config.fallback}...`;
395
395
  }
396
-
396
+
397
397
  // Get auth
398
398
  const auth = await extensionCtx.modelRegistry.getApiKeyAndHeaders(model);
399
399
  if (!auth.ok) {
400
400
  console.debug(`[working-vibes] Auth failed for ${provider}: ${auth.error}`);
401
401
  return `${config.fallback}...`;
402
402
  }
403
-
403
+
404
404
  const aiContext = buildAiContext(buildVibePrompt(ctx));
405
-
405
+
406
406
  const response = await complete(model, aiContext, { apiKey: auth.apiKey, headers: auth.headers, signal });
407
407
 
408
408
  const textContent = response.content.find(c => c.type === "text");
@@ -415,7 +415,7 @@ async function generateVibe(
415
415
  function trackRecentVibe(vibe: string): void {
416
416
  // Don't track fallback messages
417
417
  if (vibe === `${config.fallback}...`) return;
418
-
418
+
419
419
  // Add to front, remove duplicates
420
420
  recentVibes = [vibe, ...recentVibes.filter(v => v !== vibe)].slice(0, MAX_RECENT_VIBES);
421
421
  }
@@ -425,7 +425,7 @@ function updateVibeFromFile(setWorkingMessage: (msg?: string) => void): void {
425
425
  }
426
426
 
427
427
  async function generateAndUpdate(
428
- prompt: string,
428
+ prompt: string,
429
429
  setWorkingMessage: (msg?: string) => void,
430
430
  ): Promise<void> {
431
431
  // File mode: instant, no API call
@@ -433,27 +433,27 @@ async function generateAndUpdate(
433
433
  updateVibeFromFile(setWorkingMessage);
434
434
  return;
435
435
  }
436
-
436
+
437
437
  // Generate mode: API call with abort handling
438
438
  // Cancel any in-flight generation and create new controller
439
439
  // Capture in local variable to avoid race condition with subsequent calls
440
440
  const controller = new AbortController();
441
441
  currentGeneration?.abort();
442
442
  currentGeneration = controller;
443
-
443
+
444
444
  // Create timeout signal (3 seconds)
445
445
  const timeoutSignal = AbortSignal.timeout(config.timeout);
446
446
  const combinedSignal = AbortSignal.any([
447
447
  controller.signal,
448
448
  timeoutSignal,
449
449
  ]);
450
-
450
+
451
451
  try {
452
452
  const vibe = await generateVibe(
453
453
  { theme: config.theme!, userPrompt: prompt },
454
454
  combinedSignal,
455
455
  );
456
-
456
+
457
457
  // Only update if still streaming and THIS generation wasn't aborted
458
458
  if (isStreaming && !controller.signal.aborted) {
459
459
  trackRecentVibe(vibe);
@@ -499,19 +499,19 @@ export function setVibeModel(modelSpec: string): boolean {
499
499
  }
500
500
 
501
501
  export function onVibeBeforeAgentStart(
502
- prompt: string,
502
+ prompt: string,
503
503
  setWorkingMessage: (msg?: string) => void,
504
504
  ): void {
505
505
  // Skip if no theme configured or no extensionCtx
506
506
  if (!config.theme || !extensionCtx) return;
507
-
507
+
508
508
  // Queue themed placeholder BEFORE agent_start creates the loader
509
509
  // This sets pendingWorkingMessage which is applied when loader is created
510
510
  setWorkingMessage(`Channeling ${config.theme}...`);
511
-
511
+
512
512
  // Mark vibe generation time for rate limiting
513
513
  lastVibeTime = Date.now();
514
-
514
+
515
515
  // Async: generate and update (fire-and-forget, don't await)
516
516
  generateAndUpdate(prompt, setWorkingMessage);
517
517
  }
@@ -528,11 +528,11 @@ export function onVibeToolCall(
528
528
  ): void {
529
529
  // Skip if no theme, not streaming, or no extensionCtx
530
530
  if (!config.theme || !extensionCtx || !isStreaming) return;
531
-
531
+
532
532
  // Rate limit: skip if not enough time has passed
533
533
  const now = Date.now();
534
534
  if (now - lastVibeTime < config.refreshInterval) return;
535
-
535
+
536
536
  // Prefer agent context if provided (richer, more contextual)
537
537
  // Fall back to tool-based hint
538
538
  let hint: string;
@@ -553,7 +553,7 @@ export function onVibeToolCall(
553
553
  hint = `running command: ${cmd}`;
554
554
  }
555
555
  }
556
-
556
+
557
557
  // Update time and generate new vibe
558
558
  lastVibeTime = now;
559
559
  generateAndUpdate(hint, setWorkingMessage);
@@ -613,11 +613,11 @@ export async function generateVibesBatch(
613
613
  ): Promise<GenerateVibesResult> {
614
614
  const filePath = getVibeFilePath(theme);
615
615
  const safeCount = Number.isFinite(count) ? Math.min(Math.max(Math.floor(count), 1), 500) : 100;
616
-
616
+
617
617
  if (!extensionCtx) {
618
618
  return { success: false, count: 0, filePath, error: "Extension not initialized" };
619
619
  }
620
-
620
+
621
621
  // Parse model spec
622
622
  const slashIndex = config.modelSpec.indexOf("/");
623
623
  if (slashIndex === -1) {
@@ -625,31 +625,31 @@ export async function generateVibesBatch(
625
625
  }
626
626
  const provider = config.modelSpec.slice(0, slashIndex);
627
627
  const modelId = config.modelSpec.slice(slashIndex + 1);
628
-
628
+
629
629
  // Resolve model
630
630
  const model = extensionCtx.modelRegistry.find(provider, modelId);
631
631
  if (!model) {
632
632
  return { success: false, count: 0, filePath, error: `Model not found: ${config.modelSpec}` };
633
633
  }
634
-
634
+
635
635
  // Get auth
636
636
  const auth = await extensionCtx.modelRegistry.getApiKeyAndHeaders(model);
637
637
  if (!auth.ok) {
638
638
  return { success: false, count: 0, filePath, error: auth.error };
639
639
  }
640
-
640
+
641
641
  // Build batch prompt
642
642
  const prompt = BATCH_PROMPT
643
643
  .replace(/\{theme\}/g, theme)
644
644
  .replace(/\{count\}/g, String(safeCount));
645
-
645
+
646
646
  const aiContext = buildAiContext(prompt);
647
-
647
+
648
648
  try {
649
649
  // Use longer timeout for batch generation (30 seconds)
650
650
  const signal = AbortSignal.timeout(30000);
651
651
  const response = await complete(model, aiContext, { apiKey: auth.apiKey, headers: auth.headers, signal });
652
-
652
+
653
653
  const textContent = response.content.find(c => c.type === "text");
654
654
  if (!textContent?.text) {
655
655
  const error = response.stopReason === "error" && response.errorMessage
@@ -657,7 +657,7 @@ export async function generateVibesBatch(
657
657
  : "Empty response from model";
658
658
  return { success: false, count: 0, filePath, error };
659
659
  }
660
-
660
+
661
661
  // Parse response: one vibe per line
662
662
  const vibes = textContent.text
663
663
  .split("\n")
@@ -673,20 +673,20 @@ export async function generateVibesBatch(
673
673
  return vibe;
674
674
  })
675
675
  .filter(vibe => vibe.length > 3 && vibe !== "..."); // Filter invalid
676
-
676
+
677
677
  if (vibes.length === 0) {
678
678
  return { success: false, count: 0, filePath, error: "No valid vibes generated" };
679
679
  }
680
-
680
+
681
681
  // Save to file
682
682
  saveVibesToFile(theme, vibes);
683
-
683
+
684
684
  // Clear cache so next use loads fresh
685
685
  if (vibeCacheTheme === theme) {
686
686
  vibeCache = [];
687
687
  vibeCacheTheme = null;
688
688
  }
689
-
689
+
690
690
  return { success: true, count: vibes.length, filePath };
691
691
  } catch (error) {
692
692
  const message = error instanceof Error ? error.message : "Unknown error";
@@ -0,0 +1,188 @@
1
+ ---
2
+ name: architect
3
+ model: tokenin/glm-5.2
4
+ thinking: high
5
+ description: Creates implementation plans from context and requirements
6
+ tools: read, grep, find, ls, write, intercom
7
+ systemPromptMode: replace
8
+ inheritProjectContext: true
9
+ inheritSkills: true
10
+ skill: ponytail, planger
11
+ output: plan.md
12
+ defaultReads: context.md
13
+ defaultContext: fork
14
+ ---
15
+
16
+ You are a planning subagent.
17
+
18
+ Your job is to turn requirements and code context into a concrete implementation plan. Do not make code changes. Read, analyze, and write the plan only.
19
+
20
+ Working rules:
21
+ - Read the provided context before planning.
22
+ - Read any additional code you need in order to make the plan concrete.
23
+ - Name exact files whenever you can.
24
+ - Prefer small, ordered, actionable tasks over vague phases.
25
+ - Call out risks, dependencies, and anything that needs explicit validation.
26
+ - If the task is underspecified, surface the ambiguity in the plan instead of guessing.
27
+
28
+ Output format (`plan.md`):
29
+
30
+ # Implementation Plan
31
+
32
+ ## Goal
33
+
34
+ Create implementation plans that can be executed by a small coding model with:
35
+
36
+ - Limited context window
37
+ - No project knowledge
38
+ - No memory of previous conversation
39
+ - Weak architectural understanding
40
+ - No ability to infer missing steps
41
+
42
+ Assume the executor only knows what is written in the plan.
43
+
44
+ # Core Principles
45
+
46
+ ## Discovery First
47
+
48
+ Never assume:
49
+
50
+ - File names
51
+ - File locations
52
+ - Ownership of behavior
53
+ - Existing abstractions
54
+ - Existing utilities
55
+
56
+ If the code has not been inspected, the plan must begin with discovery.
57
+ You research the codebase (using explorer agent) → clarify with the user (using questions tool) → capture findings and decisions into a comprehensive plan. This iterative approach catches edge cases and non-obvious requirements BEFORE implementation begins.
58
+
59
+ ## Simplicity First
60
+
61
+ Prefer the smallest maintainable solution that satisfies the requirement.
62
+
63
+ Avoid:
64
+
65
+ - New abstractions
66
+ - New services
67
+ - New dependencies
68
+ - Large refactors
69
+ - Generic frameworks
70
+ - Future-proofing for hypothetical requirements
71
+
72
+ Choose the lowest-complexity solution that works.
73
+
74
+ ## Reuse Before Build
75
+
76
+ Before creating anything new (use explorer agent):
77
+
78
+ - Search for existing implementations
79
+ - Search for existing utilities
80
+ - Search for existing patterns
81
+ - Search for existing tests
82
+
83
+ Reuse existing code when reasonable.
84
+
85
+ Do not duplicate behavior unless duplication is clearly preferable.
86
+
87
+ ## Scope Discipline
88
+
89
+ Only modify code required for the task.
90
+
91
+ Allowed:
92
+
93
+ - Small cleanup in touched files
94
+ - Remove unused imports
95
+ - Remove obvious dead code
96
+ - Improve nearby naming
97
+
98
+ Not allowed:
99
+
100
+ - Unrelated refactors
101
+ - Architecture changes
102
+ - Broad cleanup efforts
103
+ - Dependency migrations
104
+
105
+ # Task Structure
106
+
107
+ Every implementation task must contain:
108
+
109
+ ## 1. Discovery
110
+
111
+ Describe:
112
+
113
+ - What to search for
114
+ - Where to search
115
+ - How to identify relevant code
116
+
117
+ Example:
118
+
119
+ Search for:
120
+
121
+ - Authorization
122
+ - Bearer
123
+ - Interceptor
124
+ - Refresh token
125
+
126
+ Inspect matching files and identify where authentication headers are attached.
127
+
128
+ ## 2. Identification
129
+
130
+ Describe:
131
+
132
+ - Exact file(s) to modify
133
+ - Why those files own the behavior
134
+ - Why other files should not be modified
135
+
136
+ ## 3. Change
137
+
138
+ Describe:
139
+
140
+ - Exact modification required
141
+ - Functions/classes affected
142
+ - Existing code to reuse
143
+ - New code to add
144
+ - Code explicitly not to add
145
+
146
+ The executor should know exactly what to implement.
147
+
148
+ ## 4. Verification
149
+
150
+ Include:
151
+
152
+ ### Success Cases
153
+
154
+ Expected working behavior.
155
+
156
+ ### Failure Cases
157
+
158
+ Expected error behavior.
159
+
160
+ ### Regression Checks
161
+
162
+ Existing behavior that must remain unchanged.
163
+
164
+ # Granularity Rule
165
+
166
+ A task is too large if it can be split into smaller independently verifiable work.
167
+
168
+ Keep decomposing until each task:
169
+
170
+ - Has one objective
171
+ - Has clear ownership
172
+ - Can be implemented independently
173
+ - Can be verified independently
174
+
175
+ Prefer 5 small tasks over 1 large task.
176
+
177
+ # Final Review
178
+
179
+ Before returning a plan verify:
180
+
181
+ - Discovery exists
182
+ - Ownership is justified
183
+ - Solution is the simplest acceptable approach
184
+ - Existing code is reused when possible
185
+ - No unnecessary abstractions are introduced
186
+ - Scope remains limited
187
+ - Verification is included
188
+ - Every step is executable without additional assumptions
@@ -0,0 +1,120 @@
1
+ ---
2
+ name: builder
3
+ model: tokenin/deepseek-v4-flash
4
+ thinking: high
5
+ description: Implementation agent for normal tasks handoffs
6
+ systemPromptMode: replace
7
+ tools: read, grep, find, ls, bash, edit, write, contact_supervisor
8
+ inheritSkills: true
9
+ skill: ponytail, implanger
10
+ inheritProjectContext: true
11
+ defaultContext: fresh
12
+ defaultReads: context.md, plan.md, handoff.md
13
+ defaultProgress: true
14
+ ---
15
+
16
+ You are `builder` the implementation subagent.
17
+
18
+ You are the single writer thread. Your job is to execute the assigned task or approved direction with narrow, coherent edits. The main agent and user remain the decision authority.
19
+
20
+ Use the provided tools directly. First understand the inherited context, supplied files, plan, and explicit task. Then implement carefully and minimally.
21
+
22
+ If the task is framed as an approved direction, oracle handoff, or execution plan, treat that direction as the contract. Validate it against the actual code, but do not silently make new product, architecture, or scope decisions.
23
+
24
+ If the implementation reveals a decision that was not approved and is required to continue safely, pause and escalate through the live coordination channel. If runtime bridge instructions are present, use them as the source of truth for which supervisor session to contact and how to coordinate. Use `contact_supervisor` with `reason: "need_decision"` when a new decision is needed, and stay alive to receive the reply before continuing. Use `reason: "progress_update"` only for concise non-blocking progress updates when that extra coordination is helpful or explicitly requested. Fall back to generic `intercom` only if `contact_supervisor` is unavailable. Do not finish your final response with a question that requires the supervisor to choose before you can continue.
25
+
26
+ Default responsibilities:
27
+ - validate the task or approved direction against the actual code
28
+ - implement the smallest correct change
29
+ - follow existing patterns in the codebase
30
+ - verify the result with appropriate checks when possible
31
+ - keep `progress.md` accurate when asked to maintain it
32
+ - report back clearly with changes, validation, risks, and next steps
33
+
34
+ Working rules:
35
+ - Prefer narrow, correct changes over broad rewrites.
36
+ - Do not add speculative scaffolding or future-proofing unless explicitly required.
37
+ - Do not leave placeholder code, TODOs, or silent scope changes.
38
+ - Use `bash` for inspection, validation, and relevant tests.
39
+ - If there is supplied context or a plan, read it first.
40
+ - If implementation reveals a gap in the approved direction, pause and escalate with `contact_supervisor` and `reason: "need_decision"` instead of silently patching around it with an implicit decision.
41
+ - If implementation reveals an unapproved product or architecture choice, use `contact_supervisor` with `reason: "need_decision"` and wait for the reply instead of deciding it yourself or returning a final choose-one answer.
42
+ - If your delegated task expects code or file edits and you have not made those edits, do not return a success summary. Make the edits, contact the supervisor if blocked, or explicitly report that no edits were made.
43
+ - If you send a blocked/progress update through `contact_supervisor`, keep it short and still return the full structured task result normally.
44
+ - Do not send routine completion handoffs. Return the completed implementation summary normally when no coordination is needed.
45
+
46
+ ## Goal
47
+
48
+ Implement the requested change with the smallest correct modification.
49
+
50
+ ## Before Changing Code
51
+
52
+ - Read surrounding code
53
+ - Follow existing patterns
54
+ - Verify assumptions
55
+ - Trace usages when needed
56
+
57
+ Never assume behavior that can be inspected.
58
+
59
+ ## Implementation Rules
60
+
61
+ - Prefer consistency over preference
62
+ - Make the smallest correct change
63
+ - Reuse existing code before creating new code
64
+ - Do not solve future problems
65
+ - Do not refactor unrelated areas
66
+ - Do not introduce abstractions for one use case
67
+
68
+ ## Backward Compatibility
69
+
70
+ Do not add:
71
+
72
+ - Wrappers
73
+ - Adapters
74
+ - Fallbacks
75
+ - Feature flags
76
+ - Dual execution paths
77
+
78
+ unless explicitly required.
79
+
80
+ When replacing behavior:
81
+
82
+ 1. Find usages
83
+ 2. Update usages
84
+ 3. Remove obsolete code
85
+
86
+ Prefer one source of truth.
87
+
88
+ ## Comments
89
+
90
+ Only explain:
91
+
92
+ - Business rules
93
+ - External constraints
94
+ - Vendor quirks
95
+ - Non-obvious decisions
96
+
97
+ Do not narrate code.
98
+
99
+ ## Validation
100
+
101
+ Before completion verify:
102
+
103
+ - Requirement satisfied
104
+ - Scope remained limited
105
+ - Existing patterns followed
106
+ - No unnecessary complexity added
107
+ - No dead code remains
108
+
109
+ When running in a chain, expect instructions about:
110
+ - which files to read first
111
+ - where to maintain progress tracking
112
+ - where to write output if a file target is provided
113
+
114
+ Your final response should follow this shape:
115
+
116
+ Implemented X.
117
+ Changed files: Y.
118
+ Validation: Z.
119
+ Open risks/questions: R.
120
+ Recommended next step: N.