tmux-ide 2.1.2 → 2.1.4

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 (41) hide show
  1. package/dashboard/out/404/index.html +1 -1
  2. package/dashboard/out/404.html +1 -1
  3. package/dashboard/out/__next.__PAGE__.txt +1 -1
  4. package/dashboard/out/__next._full.txt +1 -1
  5. package/dashboard/out/__next._head.txt +1 -1
  6. package/dashboard/out/__next._index.txt +1 -1
  7. package/dashboard/out/__next._tree.txt +1 -1
  8. package/dashboard/out/_next/static/chunks/{422e1bb4d41ce5ba.js → aae0253c73fba984.js} +1 -1
  9. package/dashboard/out/_not-found/__next._full.txt +1 -1
  10. package/dashboard/out/_not-found/__next._head.txt +1 -1
  11. package/dashboard/out/_not-found/__next._index.txt +1 -1
  12. package/dashboard/out/_not-found/__next._not-found.__PAGE__.txt +1 -1
  13. package/dashboard/out/_not-found/__next._not-found.txt +1 -1
  14. package/dashboard/out/_not-found/__next._tree.txt +1 -1
  15. package/dashboard/out/_not-found/index.html +1 -1
  16. package/dashboard/out/_not-found/index.txt +1 -1
  17. package/dashboard/out/index.html +1 -1
  18. package/dashboard/out/index.txt +1 -1
  19. package/dashboard/out/project/__fallback/__next._full.txt +2 -2
  20. package/dashboard/out/project/__fallback/__next._head.txt +1 -1
  21. package/dashboard/out/project/__fallback/__next._index.txt +1 -1
  22. package/dashboard/out/project/__fallback/__next._tree.txt +1 -1
  23. package/dashboard/out/project/__fallback/__next.project.$d$name.__PAGE__.txt +2 -2
  24. package/dashboard/out/project/__fallback/__next.project.$d$name.txt +1 -1
  25. package/dashboard/out/project/__fallback/__next.project.txt +1 -1
  26. package/dashboard/out/project/__fallback/index.html +1 -1
  27. package/dashboard/out/project/__fallback/index.txt +2 -2
  28. package/package.json +1 -1
  29. package/src/init.ts +78 -11
  30. package/src/launch.ts +121 -13
  31. package/src/lib/daemon.ts +7 -1
  32. package/src/lib/orchestrator.ts +3 -2
  33. package/src/stop.ts +9 -0
  34. package/templates/skills/backend.md +13 -0
  35. package/templates/skills/frontend.md +13 -0
  36. package/templates/skills/general-worker.md +13 -0
  37. package/templates/skills/researcher.md +9 -0
  38. package/templates/skills/reviewer.md +12 -0
  39. /package/dashboard/out/_next/static/{hKfaRIxA4e3yTmkv1VUnK → Tl1KoIH7mHCyjo5KtXqQ0}/_buildManifest.js +0 -0
  40. /package/dashboard/out/_next/static/{hKfaRIxA4e3yTmkv1VUnK → Tl1KoIH7mHCyjo5KtXqQ0}/_clientMiddlewareManifest.json +0 -0
  41. /package/dashboard/out/_next/static/{hKfaRIxA4e3yTmkv1VUnK → Tl1KoIH7mHCyjo5KtXqQ0}/_ssgManifest.js +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmux-ide",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "description": "Turn any project into a tmux-powered terminal IDE with a simple ide.yml",
5
5
  "type": "module",
6
6
  "bin": {
package/src/init.ts CHANGED
@@ -30,25 +30,85 @@ function copyTemplateSkills(targetDir: string): string[] {
30
30
  return created;
31
31
  }
32
32
 
33
- function scaffoldMissionsWorkspace(dir: string, name: string): string[] {
33
+ function scaffoldLibraryStubs(dir: string): string[] {
34
34
  const created: string[] = [];
35
- const skillsDir = join(dir, ".tmux-ide", "skills");
36
- created.push(...copyTemplateSkills(skillsDir));
37
-
38
35
  const libraryDir = join(dir, ".tmux-ide", "library");
39
36
  if (!existsSync(libraryDir)) {
40
37
  mkdirSync(libraryDir, { recursive: true });
41
38
  created.push(libraryDir);
42
39
  }
43
40
 
41
+ const archPath = join(libraryDir, "architecture.md");
42
+ if (!existsSync(archPath)) {
43
+ writeFileSync(
44
+ archPath,
45
+ "# Architecture\n\n<!-- Describe your project's architecture here. This context is injected into agent dispatch prompts. -->\n",
46
+ );
47
+ created.push(archPath);
48
+ }
49
+
50
+ const learningsPath = join(libraryDir, "learnings.md");
51
+ if (!existsSync(learningsPath)) {
52
+ writeFileSync(
53
+ learningsPath,
54
+ "# Learnings\n\n<!-- Task summaries are automatically appended here by the orchestrator. -->\n",
55
+ );
56
+ created.push(learningsPath);
57
+ }
58
+
59
+ return created;
60
+ }
61
+
62
+ function scaffoldValidationContract(dir: string): string[] {
63
+ const created: string[] = [];
64
+ const tasksDir = join(dir, ".tasks");
65
+ if (!existsSync(tasksDir)) {
66
+ mkdirSync(tasksDir, { recursive: true });
67
+ }
68
+
69
+ const contractPath = join(tasksDir, "validation-contract.md");
70
+ if (!existsSync(contractPath)) {
71
+ writeFileSync(
72
+ contractPath,
73
+ "# Validation Contract\n\n<!-- Define assertions that the validator agent will verify. Example: -->\n<!-- - VAL-001: All tests pass -->\n<!-- - VAL-002: No TypeScript errors -->\n<!-- - VAL-003: Lint passes with zero warnings -->\n",
74
+ );
75
+ created.push(contractPath);
76
+ }
77
+
78
+ return created;
79
+ }
80
+
81
+ function scaffoldAgentsMd(dir: string, name: string): string[] {
82
+ const created: string[] = [];
44
83
  const agentsTemplatePath = resolve(__dirname, "..", "templates", "AGENTS.md");
45
84
  if (existsSync(agentsTemplatePath)) {
46
85
  const agentsPath = join(dir, "AGENTS.md");
47
- const content = readFileSync(agentsTemplatePath, "utf-8").replace(/{{name}}/g, name);
48
- writeFileSync(agentsPath, content);
49
- created.push(agentsPath);
86
+ if (!existsSync(agentsPath)) {
87
+ const content = readFileSync(agentsTemplatePath, "utf-8").replace(/{{name}}/g, name);
88
+ writeFileSync(agentsPath, content);
89
+ created.push(agentsPath);
90
+ }
50
91
  }
92
+ return created;
93
+ }
51
94
 
95
+ function isTeamTemplate(templateName: string): boolean {
96
+ return templateName === "missions" || templateName.startsWith("agent-team");
97
+ }
98
+
99
+ function scaffoldTeamWorkspace(dir: string, name: string): string[] {
100
+ const created: string[] = [];
101
+ created.push(...scaffoldLibraryStubs(dir));
102
+ created.push(...scaffoldValidationContract(dir));
103
+ created.push(...scaffoldAgentsMd(dir, name));
104
+ return created;
105
+ }
106
+
107
+ function scaffoldMissionsWorkspace(dir: string, name: string): string[] {
108
+ const created: string[] = [];
109
+ const skillsDir = join(dir, ".tmux-ide", "skills");
110
+ created.push(...copyTemplateSkills(skillsDir));
111
+ created.push(...scaffoldTeamWorkspace(dir, name));
52
112
  return created;
53
113
  }
54
114
 
@@ -76,10 +136,17 @@ export async function init({
76
136
  const tmpPath = configPath + ".tmp";
77
137
  writeFileSync(tmpPath, content);
78
138
  renameSync(tmpPath, configPath);
79
- const created =
80
- template === "missions"
81
- ? scaffoldMissionsWorkspace(dir, name)
82
- : copyTemplateSkills(join(dir, ".tmux-ide", "skills"));
139
+ let created: string[];
140
+ if (template === "missions") {
141
+ created = scaffoldMissionsWorkspace(dir, name);
142
+ } else if (isTeamTemplate(template)) {
143
+ created = [
144
+ ...copyTemplateSkills(join(dir, ".tmux-ide", "skills")),
145
+ ...scaffoldTeamWorkspace(dir, name),
146
+ ];
147
+ } else {
148
+ created = copyTemplateSkills(join(dir, ".tmux-ide", "skills"));
149
+ }
83
150
 
84
151
  if (json) {
85
152
  console.log(JSON.stringify({ created: true, template, name, paths: created }));
package/src/launch.ts CHANGED
@@ -2,7 +2,7 @@ import { resolve, dirname, join } from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { execSync } from "node:child_process";
4
4
  import { createHash } from "node:crypto";
5
- import { readFileSync, writeFileSync, existsSync } from "node:fs";
5
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
6
6
  import { readConfig, getSessionName } from "./lib/yaml-io.ts";
7
7
  import { computeSizes, toSplitPercents } from "./lib/sizes.ts";
8
8
  import { outputError } from "./lib/output.ts";
@@ -183,7 +183,9 @@ function runBeforeHook(command: string | undefined, dir: string): void {
183
183
  async function waitForDaemon(port: number, maxAttempts = 30, delayMs = 100): Promise<boolean> {
184
184
  for (let i = 0; i < maxAttempts; i++) {
185
185
  try {
186
- const res = await fetch(`http://localhost:${port}/health`);
186
+ const res = await fetch(`http://localhost:${port}/health`, {
187
+ signal: AbortSignal.timeout(1000),
188
+ });
187
189
  if (res.ok) return true;
188
190
  } catch {
189
191
  // Not ready yet
@@ -233,6 +235,21 @@ export async function launch(
233
235
  const daemonAlive = await isDaemonAlive(commandCenterPort);
234
236
  if (!daemonAlive) {
235
237
  console.log("Daemon not responding — restarting...");
238
+
239
+ // Clean up any orphaned daemon processes from previous runs
240
+ try {
241
+ execSync(`pkill -f "daemon-watchdog.ts ${session}" 2>/dev/null || true`, {
242
+ stdio: "ignore",
243
+ });
244
+ execSync(`pkill -f "daemon.ts ${session}" 2>/dev/null || true`, { stdio: "ignore" });
245
+ } catch {
246
+ // Best-effort cleanup
247
+ }
248
+
249
+ // Brief wait for orphaned processes to release the port
250
+ const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
251
+ await sleep(500);
252
+
236
253
  const monitorScript = resolve(
237
254
  dirname(fileURLToPath(import.meta.url)),
238
255
  "lib",
@@ -322,6 +339,18 @@ export async function launch(
322
339
  // Store config hash for drift detection on re-launch
323
340
  setSessionVariable(session, "@config_hash", configHash(config));
324
341
 
342
+ // Clean up any orphaned daemon processes from previous runs
343
+ try {
344
+ execSync(`pkill -f "daemon-watchdog.ts ${session}" 2>/dev/null || true`, { stdio: "ignore" });
345
+ execSync(`pkill -f "daemon.ts ${session}" 2>/dev/null || true`, { stdio: "ignore" });
346
+ } catch {
347
+ // Best-effort cleanup
348
+ }
349
+
350
+ // Brief wait for orphaned processes to release the port
351
+ const sleepAsync = (ms: number) => new Promise((r) => setTimeout(r, ms));
352
+ await sleepAsync(500);
353
+
325
354
  // Start background daemon watchdog (command center + session monitor)
326
355
  const monitorScript = resolve(
327
356
  dirname(fileURLToPath(import.meta.url)),
@@ -376,10 +405,22 @@ export function buildMasterAgentPrompt(config: IdeConfig): string {
376
405
  .map((p: Pane) => p.title)
377
406
  .filter(Boolean);
378
407
 
379
- return `You are the Master Agent for this tmux-ide session.
408
+ const isMissionsMode = config.orchestrator?.dispatch_mode === "missions";
409
+
410
+ const milestonesSection = isMissionsMode
411
+ ? `
412
+ ## Milestones
413
+ Milestones gate execution — tasks in M2 won't dispatch until M1 is validated.
414
+ - tmux-ide milestone create "title" --sequence N
415
+ - tmux-ide milestone list --json
416
+ - tmux-ide mission plan-complete (activates milestones, starts dispatch)
417
+ `
418
+ : "";
419
+
420
+ return `You are the Lead Agent for this tmux-ide session.
380
421
 
381
422
  ## Your role
382
- You coordinate a team of coding agents. The human gives you high-level goals, and you break them into structured tasks that your teammates execute.
423
+ You coordinate a team of coding agents. The human gives you high-level goals, and you break them into structured tasks that your teammates execute. You plan, delegate, and review — you do not implement.
383
424
 
384
425
  ## Your teammates
385
426
  ${teammatePanes.map((t) => `- ${t}`).join("\n")}
@@ -388,21 +429,38 @@ ${teammatePanes.map((t) => `- ${t}`).join("\n")}
388
429
  - tmux-ide mission set "title" --description "..."
389
430
  - tmux-ide goal create "title" --priority N --acceptance "criteria"
390
431
  - tmux-ide goal list --json
391
- - tmux-ide task create "title" --goal NN --priority N
432
+ - tmux-ide task create "title" --goal NN --priority N --specialty "type" --fulfills "VAL-001,VAL-002"
392
433
  - tmux-ide task list --json
393
434
  - tmux-ide task show NNN --json (shows full mission→goal→task context)
394
435
  - tmux-ide task done NNN --proof "what was accomplished"
395
436
  - tmux-ide goal done NN
396
437
 
397
438
  ## How it works
398
- 1. You create tasks with tmux-ide task create
399
- 2. The orchestrator automatically assigns unassigned tasks to idle teammates
400
- 3. Teammates work in the project directory
401
- 4. When teammates finish, they run tmux-ide task done
402
- 5. You get notified and review their work
403
- 6. You report progress to the human
439
+ 1. Set the mission: tmux-ide mission set "title" --description "..."
440
+ 2. Create goals with acceptance criteria
441
+ 3. Create tasks under goals — use --specialty to hint agent type, --fulfills to link validation assertions
442
+ 4. The orchestrator automatically dispatches unassigned tasks to idle teammates
443
+ 5. Teammates work in the project directory
444
+ 6. When teammates finish, they run tmux-ide task done
445
+ 7. You get notified and review their work
446
+ 8. You report progress to the human
447
+ ${milestonesSection}
448
+ ## Validation contracts
449
+ Define acceptance criteria in .tasks/validation-contract.md using assertion IDs:
450
+ **VAL-001**: All tests pass
451
+ **VAL-002**: No TypeScript errors
452
+ Link tasks to assertions: tmux-ide task create "title" --fulfills "VAL-001,VAL-002"
453
+ After a milestone's tasks complete, the Validator agent automatically verifies assertions.
454
+
455
+ ## Knowledge library
456
+ - .tmux-ide/library/architecture.md — project context injected into agent prompts
457
+ - .tmux-ide/library/learnings.md — auto-appended by orchestrator after task completion
458
+ - AGENTS.md — project boundaries injected into all agent prompts
459
+ Update architecture.md when the project structure changes significantly.
404
460
 
405
461
  ## Important
462
+ - Do NOT use --assign when creating tasks — the orchestrator handles dispatch automatically
463
+ - Use --specialty to hint which agent type should pick it up
406
464
  - Focus on PLANNING and REVIEWING, not implementing
407
465
  - Break work into small, clear tasks (one per teammate)
408
466
  - Each task should be completable independently
@@ -460,6 +518,22 @@ The \`--proof\` flag accepts either a plain string (stored as \`notes\`) or a JS
460
518
  ### Task Dependencies
461
519
 
462
520
  Use \`--depends "001,002"\` to declare that a task depends on other tasks. The orchestrator will not dispatch a task until all its dependencies are complete.
521
+
522
+ ### Milestones
523
+
524
+ \`\`\`bash
525
+ tmux-ide milestone create "title" --sequence N
526
+ tmux-ide milestone list [--json]
527
+ tmux-ide mission plan-complete # activate milestones and start dispatch
528
+ \`\`\`
529
+
530
+ ### Validation
531
+
532
+ \`\`\`bash
533
+ tmux-ide validate show [--json]
534
+ tmux-ide validate assert VAL-001 --status passing --evidence "what you verified"
535
+ tmux-ide validate coverage [--json]
536
+ \`\`\`
463
537
  `;
464
538
 
465
539
  export function ensureTaskDocs(dir: string): void {
@@ -467,9 +541,43 @@ export function ensureTaskDocs(dir: string): void {
467
541
 
468
542
  if (existsSync(claudeMdPath)) {
469
543
  const content = readFileSync(claudeMdPath, "utf-8");
470
- if (content.includes(TASK_DOCS_MARKER)) return;
471
- writeFileSync(claudeMdPath, content + TASK_DOCS_SECTION);
544
+ if (!content.includes(TASK_DOCS_MARKER)) {
545
+ writeFileSync(claudeMdPath, content + TASK_DOCS_SECTION);
546
+ }
472
547
  } else {
473
548
  writeFileSync(claudeMdPath, `# Project\n${TASK_DOCS_SECTION}`);
474
549
  }
550
+
551
+ // Ensure library directory and stubs exist
552
+ const libraryDir = join(dir, ".tmux-ide", "library");
553
+ if (!existsSync(libraryDir)) {
554
+ mkdirSync(libraryDir, { recursive: true });
555
+ }
556
+ const archPath = join(libraryDir, "architecture.md");
557
+ if (!existsSync(archPath)) {
558
+ writeFileSync(
559
+ archPath,
560
+ "# Architecture\n\n<!-- Describe your project architecture here. This is injected into agent dispatch prompts. -->\n",
561
+ );
562
+ }
563
+ const learningsPath = join(libraryDir, "learnings.md");
564
+ if (!existsSync(learningsPath)) {
565
+ writeFileSync(
566
+ learningsPath,
567
+ "# Learnings\n\n<!-- Task summaries are automatically appended here by the orchestrator. -->\n",
568
+ );
569
+ }
570
+
571
+ // Ensure .tasks/ directory and validation contract stub
572
+ const tasksDir = join(dir, ".tasks");
573
+ if (!existsSync(tasksDir)) {
574
+ mkdirSync(tasksDir, { recursive: true });
575
+ }
576
+ const contractPath = join(tasksDir, "validation-contract.md");
577
+ if (!existsSync(contractPath)) {
578
+ writeFileSync(
579
+ contractPath,
580
+ "# Validation Contract\n\n<!-- Define assertions for the validator agent. Example: -->\n<!-- - VAL-001: All tests pass -->\n<!-- - VAL-002: No TypeScript errors -->\n",
581
+ );
582
+ }
475
583
  }
package/src/lib/daemon.ts CHANGED
@@ -12,8 +12,14 @@ import { execFileSync } from "node:child_process";
12
12
  import { existsSync, readdirSync, statSync, unlinkSync } from "node:fs";
13
13
  import { join } from "node:path";
14
14
  import { createServer, type Server } from "node:http";
15
+ import { createRequire } from "node:module";
15
16
  import { computePortPanes, computeAgentStates } from "./session-monitor.ts";
16
17
 
18
+ // Anchor bare-specifier resolution to this file so dependencies like
19
+ // @hono/node-server resolve from tmux-ide's own node_modules regardless
20
+ // of the process's working directory.
21
+ const _require = createRequire(import.meta.url);
22
+
17
23
  /** Remove dispatch files older than 24 hours */
18
24
  function cleanupDispatchFiles(dir: string): void {
19
25
  const dispatchDir = join(dir, ".tasks", "dispatch");
@@ -246,7 +252,7 @@ let httpServer: Server | null = null;
246
252
  async function startCommandCenter(): Promise<void> {
247
253
  try {
248
254
  const { createApp } = await import("../command-center/server.ts");
249
- const { getRequestListener } = await import("@hono/node-server");
255
+ const { getRequestListener } = await import(_require.resolve("@hono/node-server"));
250
256
  const { AuthService } = await import("./auth/auth-service.ts");
251
257
  const { AuthConfigSchema } = await import("./auth/types.ts");
252
258
  const { TunnelManager } = await import("./tunnels/manager.ts");
@@ -236,8 +236,9 @@ export function buildTaskPrompt(dir: string, task: Task, config?: OrchestratorCo
236
236
  }
237
237
 
238
238
  // 4. Skill context
239
- if (task.specialty) {
240
- const skill = loadSkill(dir, task.specialty);
239
+ {
240
+ const skillName = task.specialty ?? "general-worker";
241
+ const skill = loadSkill(dir, skillName);
241
242
  if (skill?.body) {
242
243
  prompt += `## Your Role: ${skill.name}\n`;
243
244
  prompt += `${skill.body}\n\n`;
package/src/stop.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { resolve } from "node:path";
2
+ import { execSync } from "node:child_process";
2
3
  import { getSessionName } from "./lib/yaml-io.ts";
3
4
  import { outputError } from "./lib/output.ts";
4
5
  import { killSession, stopSessionMonitor } from "./lib/tmux.ts";
@@ -13,6 +14,14 @@ export async function stop(
13
14
  // Stop the session monitor before killing the session
14
15
  stopSessionMonitor(session);
15
16
 
17
+ // Kill any orphaned daemon processes for this session
18
+ try {
19
+ execSync(`pkill -f "daemon-watchdog.ts ${session}" 2>/dev/null || true`, { stdio: "ignore" });
20
+ execSync(`pkill -f "daemon.ts ${session}" 2>/dev/null || true`, { stdio: "ignore" });
21
+ } catch {
22
+ // Best-effort cleanup
23
+ }
24
+
16
25
  const result = killSession(session);
17
26
 
18
27
  if (result.stopped) {
@@ -21,6 +21,19 @@ You are a backend development specialist.
21
21
  4. Verify behavior against acceptance criteria
22
22
  5. Report the result, evidence, and any operational concerns
23
23
 
24
+ ## Context
25
+
26
+ Your dispatch prompt includes relevant excerpts from the knowledge library (.tmux-ide/library/) and AGENTS.md. Use these for architectural decisions.
27
+
28
+ ## After Completion
29
+
30
+ When you finish, the orchestrator will:
31
+
32
+ - Notify the lead with your proof and summary
33
+ - Run any configured after-run hooks (e.g., linting)
34
+ - Auto-dispatch the next available task
35
+ - Append your summary to the learnings library
36
+
24
37
  ## Completion Protocol
25
38
 
26
39
  When done, run:
@@ -21,6 +21,19 @@ You are a frontend development specialist.
21
21
  4. Run relevant tests or validation checks
22
22
  5. Report what changed, what you verified, and any follow-up risks
23
23
 
24
+ ## Context
25
+
26
+ Your dispatch prompt includes relevant excerpts from the knowledge library (.tmux-ide/library/) and AGENTS.md. Use these for architectural decisions.
27
+
28
+ ## After Completion
29
+
30
+ When you finish, the orchestrator will:
31
+
32
+ - Notify the lead with your proof and summary
33
+ - Run any configured after-run hooks (e.g., linting)
34
+ - Auto-dispatch the next available task
35
+ - Append your summary to the learnings library
36
+
24
37
  ## Completion Protocol
25
38
 
26
39
  When done, run:
@@ -21,6 +21,19 @@ You are a general-purpose development agent.
21
21
  4. Verify all tests pass
22
22
  5. Report completion with proof and a summary of key learnings
23
23
 
24
+ ## Context
25
+
26
+ You are a general-purpose agent. Your dispatch prompt includes mission, goal, and task context along with relevant library excerpts. Follow the task description closely.
27
+
28
+ ## After Completion
29
+
30
+ When you finish, the orchestrator will:
31
+
32
+ - Notify the lead with your proof and summary
33
+ - Run any configured after-run hooks (e.g., linting)
34
+ - Auto-dispatch the next available task
35
+ - Append your summary to the learnings library
36
+
24
37
  ## Completion Protocol
25
38
 
26
39
  When done, run:
@@ -67,3 +67,12 @@ Your proof should include:
67
67
  - The most important findings
68
68
  - Why they matter
69
69
  - The exact next action you recommend
70
+
71
+ ## After Completion
72
+
73
+ When you finish, the orchestrator will:
74
+
75
+ - Notify the lead with your proof and summary
76
+ - Run any configured after-run hooks
77
+ - Auto-dispatch the next available task
78
+ - Append your summary to the learnings library
@@ -28,3 +28,15 @@ tmux-ide validate assert <ASSERT_ID> --status failing --evidence "what's wrong"
28
28
  tmux-ide validate assert <ASSERT_ID> --status blocked --evidence "why it's blocked"
29
29
 
30
30
  The orchestrator will detect your results and advance the milestone automatically.
31
+
32
+ If you find issues beyond the validation contract:
33
+ tmux-ide task update <TASK_ID> --discovered-issues "description of issue"
34
+
35
+ ## After Completion
36
+
37
+ When you finish, the orchestrator will:
38
+
39
+ - Notify the lead with your proof and summary
40
+ - Run any configured after-run hooks (e.g., linting)
41
+ - Auto-dispatch the next available task
42
+ - Append your summary to the learnings library