opencode-manifold 0.5.7 → 0.5.8

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/dist/index.js CHANGED
@@ -320,342 +320,206 @@ function extractTaskFromPlan(planContent, taskNumber) {
320
320
  }
321
321
  return null;
322
322
  }
323
- function runDispatcherLogic(args, state, settings) {
324
- const isNewTask = args.newTask === true;
325
- const taskNumber = args.task_number || (state?.task_number || 0);
326
- const planFile = args.plan_file || (state?.plan_file || "");
323
+ function runDispatcherLogic(args, state, settings, taskDescription) {
324
+ const taskNumber = args.task_number || state?.task_number || 0;
327
325
  const slug = state?.slug || "";
328
- let currentState;
329
- if (isNewTask || !state) {
330
- currentState = {
326
+ if (!state || state.phase === "init" || state.phase === "complete" || state.phase === "escalated") {
327
+ const newState = {
331
328
  task_number: taskNumber,
332
- plan_file: planFile,
329
+ plan_file: args.plan_file || state?.plan_file || "",
333
330
  slug,
331
+ phase: "awaiting_execution",
332
+ senior_output: "",
333
+ clerk_summary: "",
334
334
  loops: 0,
335
- clerkRetries: 0,
336
- researchSummary: "",
337
- implementationOutput: "",
338
- reviewFeedback: "",
339
- debugAnalysis: ""
335
+ clerk_retries: 0
340
336
  };
341
- } else {
342
- currentState = { ...state };
343
- }
344
- if (args.researchSummary)
345
- currentState.researchSummary = args.researchSummary;
346
- if (args.implementationOutput)
347
- currentState.implementationOutput = args.implementationOutput;
348
- if (args.reviewFeedback)
349
- currentState.reviewFeedback = args.reviewFeedback;
350
- if (args.debugAnalysis)
351
- currentState.debugAnalysis = args.debugAnalysis;
352
- if (isNewTask) {
353
337
  return {
354
- route: "research",
338
+ route: "execute",
355
339
  agent: "clerk",
356
- prompt: buildResearchPrompt(args, currentState, settings),
357
- state: {
358
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
359
- loops: 0,
360
- maxLoops: settings.maxLoops,
361
- clerkRetries: 0
362
- },
363
- message: "Researching codebase and wiki context"
364
- };
365
- }
366
- if (args.researchComplete === true && !args.hasImplementation) {
367
- return {
368
- route: "implement",
369
- agent: "senior-dev",
370
- prompt: buildScopedPrompt(currentState.researchSummary, args),
371
- state: {
372
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
373
- loops: 0,
374
- maxLoops: settings.maxLoops,
375
- clerkRetries: 0
376
- },
377
- message: "Sending to senior-dev for implementation"
378
- };
379
- }
380
- if (args.hasImplementation === true && args.reviewDone === false) {
381
- return {
382
- route: "review",
383
- agent: "junior-dev",
384
- prompt: buildReviewPrompt(currentState.implementationOutput, args),
340
+ prompt: buildExecutePrompt(taskNumber, taskDescription),
385
341
  state: {
386
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
387
- loops: 0,
388
- maxLoops: settings.maxLoops,
389
- clerkRetries: 0
342
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
343
+ phase: "awaiting_execution"
390
344
  },
391
- message: "Sending to junior-dev for review"
345
+ message: "Ready to execute task"
392
346
  };
393
347
  }
394
- if (args.reviewDone === true && args.reviewPassed === true) {
348
+ if (state.phase === "awaiting_execution") {
395
349
  return {
396
- route: "logging",
350
+ route: "outcome_check",
397
351
  agent: "clerk",
398
- prompt: buildLoggingPrompt(currentState, args),
352
+ prompt: buildOutcomeCheckPrompt(),
399
353
  state: {
400
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
401
- loops: currentState.loops,
402
- maxLoops: settings.maxLoops,
403
- clerkRetries: currentState.clerkRetries
354
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
355
+ phase: "awaiting_outcome"
404
356
  },
405
- message: "Logging task to wiki and graph"
357
+ message: "Waiting for senior dev outcome"
406
358
  };
407
359
  }
408
- if (args.reviewDone === true && args.reviewPassed === false) {
409
- currentState.loops++;
410
- if (currentState.loops >= settings.maxLoops) {
411
- if (!args.debugComplete && currentState.clerkRetries === 0) {
360
+ if (state.phase === "awaiting_outcome") {
361
+ const isSuccess = args.success === true;
362
+ if (isSuccess) {
363
+ return {
364
+ route: "logging",
365
+ agent: "clerk",
366
+ prompt: buildLoggingPrompt(state, taskDescription),
367
+ state: {
368
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
369
+ phase: "logging"
370
+ },
371
+ message: "Task succeeded - logging results"
372
+ };
373
+ } else {
374
+ if (state.clerk_retries < settings.maxRetries) {
412
375
  return {
413
- route: "debug",
414
- agent: "debug",
415
- prompt: buildDebugPrompt(currentState, args),
376
+ route: "reprompt",
377
+ agent: "clerk",
378
+ prompt: buildRePromptPrompt(state, taskDescription),
416
379
  state: {
417
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
418
- loops: currentState.loops,
419
- maxLoops: settings.maxLoops,
420
- clerkRetries: 0
380
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
381
+ phase: "awaiting_execution"
421
382
  },
422
- message: `Loop ${currentState.loops}/${settings.maxLoops} - escalating to debug`
383
+ message: `Retrying task (attempt ${state.clerk_retries + 1}/${settings.maxRetries})`
423
384
  };
424
- }
425
- if (args.debugComplete === true && settings.clerkRetryEnabled && currentState.clerkRetries === 0) {
426
- currentState.clerkRetries = 1;
427
- currentState.loops = 0;
385
+ } else {
428
386
  return {
429
- route: "re-research",
430
- agent: "clerk",
431
- prompt: buildReResearchPrompt(currentState, args),
387
+ route: "escalate",
388
+ agent: null,
389
+ prompt: buildEscalationPrompt(state, taskDescription),
432
390
  state: {
433
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
434
- loops: 0,
435
- maxLoops: settings.maxLoops,
436
- clerkRetries: 1
391
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
392
+ phase: "escalated"
437
393
  },
438
- message: "Clerk re-researching with failure context"
394
+ message: "Escalating to user - all retries exhausted"
439
395
  };
440
396
  }
441
- return {
442
- route: "escalate_user",
443
- agent: null,
444
- prompt: `Task ${taskNumber} has exhausted all loops (${settings.maxLoops}) and debug analysis. Last feedback: ${currentState.reviewFeedback}`,
445
- state: {
446
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
447
- loops: currentState.loops,
448
- maxLoops: settings.maxLoops,
449
- clerkRetries: currentState.clerkRetries
450
- },
451
- message: "ESCALATING TO USER - all loops exhausted"
452
- };
453
397
  }
454
- return {
455
- route: "re-implement",
456
- agent: "senior-dev",
457
- prompt: buildReImplementPrompt(currentState, args),
458
- state: {
459
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
460
- loops: currentState.loops,
461
- maxLoops: settings.maxLoops,
462
- clerkRetries: currentState.clerkRetries
463
- },
464
- message: `Loop ${currentState.loops}/${settings.maxLoops} - re-implementing with junior feedback`
465
- };
466
- }
467
- if (args.debugComplete === true && args.reResearched === false) {
468
- return {
469
- route: "re-implement",
470
- agent: "senior-dev",
471
- prompt: buildDebugImplementPrompt(currentState, args),
472
- state: {
473
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
474
- loops: currentState.loops,
475
- maxLoops: settings.maxLoops,
476
- clerkRetries: currentState.clerkRetries
477
- },
478
- message: "Re-implementing with debug suggestion"
479
- };
480
- }
481
- if (args.reResearched === true) {
482
- currentState.loops = 0;
483
- return {
484
- route: "implement",
485
- agent: "senior-dev",
486
- prompt: buildScopedPrompt(currentState.researchSummary, args),
487
- state: {
488
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
489
- loops: 0,
490
- maxLoops: settings.maxLoops,
491
- clerkRetries: currentState.clerkRetries
492
- },
493
- message: "Starting fresh loop with new research"
494
- };
495
398
  }
496
399
  return {
497
- route: "escalate_user",
400
+ route: "escalate",
498
401
  agent: null,
499
- prompt: "Dispatcher encountered an unexpected state combination",
402
+ prompt: "Dispatcher encountered unexpected state",
500
403
  state: {
501
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
502
- loops: currentState.loops,
503
- maxLoops: settings.maxLoops,
504
- clerkRetries: currentState.clerkRetries
404
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
405
+ phase: "escalated"
505
406
  },
506
- message: "ESCALATING TO USER - unexpected state"
407
+ message: "Unexpected state - escalating"
507
408
  };
508
409
  }
509
- function buildResearchPrompt(args, state, settings) {
510
- const needsTodo = args.needsDecomposition === true;
511
- return `You are the Clerk. Research this task and compose a scoped prompt.
512
-
513
- Task ${state.task_number}: ${args.description}
514
-
515
- Research steps:
516
- 1. Use codebase-index to search for relevant code (max ${settings.maxResults} results)
517
- 2. Read graph files from Manifold/graph/ for relevant files
518
- 3. Read recent task logs from Manifold/tasks/ (${settings.recentTaskCount} most recent)
519
- ${needsTodo ? `4. Read the full plan file (${args.plan_file}) for project-wide context` : ""}
520
-
521
- ${needsTodo ? `IMPORTANT: This task requires project-wide decomposition. After researching, you will need to:
522
- - Identify all files that need to be created or modified
523
- - Break the work into logical subtasks
524
- - Prepare context for each subtask` : ""}
525
-
526
- Output Format - STRICTLY FOLLOW THIS:
527
-
528
- ===SCOPED_PROMPT_START===
529
- [Your composed scoped prompt - include task goal, relevant code snippets, prior decisions, design guidelines]
530
- ===SCOPED_PROMPT_END===
531
-
532
- ===CONTEXT_USED_START===
533
- [List of context documents you used - file paths and brief descriptions]
534
- ===CONTEXT_USED_END===`;
410
+ function buildExecutePrompt(taskNumber, taskDescription) {
411
+ return `CLERK - EXECUTE TASK
412
+ TASK NUMBER: ${taskNumber}
413
+ TASK: ${taskDescription}
414
+
415
+ INSTRUCTIONS:
416
+
417
+ 1. RESEARCH
418
+ Use the Research skill with the given task to gather potentially relevant context.
419
+
420
+ 2. COMPOSE SCOPED PROMPT
421
+ Combine into a scoped prompt:
422
+ - Task goal (what Senior Dev must accomplish)
423
+ - Relevant code snippets from research (3-10, include file paths)
424
+ - Prior decisions from wiki logs
425
+ - Design guidelines (language/framework conventions, patterns)
426
+ Balance: enough to be useful, not overwhelming. Target ~800 words max.
427
+
428
+ 3. APPLY FRAMING
429
+ - Prefer "what data goes in and what comes out" framing when it makes the goal clearer
430
+ - If task has purity tag ([pure], [shell], [mixed]):
431
+ - [pure]: Frame as data transformation, specify input/output types, emphasize no IO/side effects
432
+ - [shell]: Clarify IO boundary, what external system involved
433
+ - [mixed]: Note where logic/IO boundary falls
434
+ - Don't force functional style if task is naturally imperative
435
+
436
+ 4. CREATE TASK LOG
437
+ Write initial entry to \`Manifold/tasks/<slug>-<task-number>.md\` (e.g., auth-fix-001.md):
438
+ - Header: Date, Status=IN_PROGRESS, Task Description
439
+ - Include the scoped prompt you composed
440
+ - List context documents used (files, wiki logs, graphs)
441
+
442
+ 5. CALL SENIOR-DEV
443
+ Call @senior-dev with the finalized scoped prompt. Wait for response.
444
+
445
+ 6. REPORT OUTCOME
446
+ When senior-dev returns, determine if it reported "task complete" or "task failure".
447
+ Call dispatchTask() again (no arguments needed - the tool will ask for the result next).
448
+
449
+ CONSTRAINTS:
450
+ - Do not make autonomous decisions about the task lifecycle.
451
+ - Wait for the dispatcher's next instruction after senior-dev completes.`;
535
452
  }
536
- function buildScopedPrompt(researchSummary, args) {
537
- return `You are the Senior Developer. Implement this task.
538
-
539
- Task: ${args.description}
540
-
541
- Research Context:
542
- ${researchSummary}
543
-
544
- Implement the task following the requirements and patterns from the research context.`;
545
- }
546
- function buildReviewPrompt(implementation, args) {
547
- return `You are the Junior Developer reviewing the Senior Developer's implementation.
548
-
549
- Task: ${args.description}
550
-
551
- Senior Developer's Implementation:
552
- ${implementation}
553
-
554
- Review the implementation against the task requirements. Your response MUST begin with exactly "COMPLETE" or "QUESTIONS" as the first word.
555
-
556
- If COMPLETE: Briefly explain why the implementation is acceptable.
557
- If QUESTIONS: List specific issues blocking approval with actionable feedback.`;
558
- }
559
- function buildReImplementPrompt(state, args) {
560
- return `You are the Senior Developer. Re-implement this task addressing the Junior Developer's feedback.
561
-
562
- Task: ${args.description}
563
-
564
- Original Scoped Prompt:
565
- ${state.researchSummary}
566
-
567
- Junior Developer's Feedback:
568
- ${state.reviewFeedback}
569
-
570
- Address these issues and resubmit your implementation.`;
571
- }
572
- function buildDebugPrompt(state, args) {
573
- return `You are the Debug Agent. The Senior/Junior loop has failed ${state.loops} times.
574
-
575
- Task: ${args.description}
576
-
577
- Research Context:
578
- ${state.researchSummary}
579
-
580
- Failed Implementation:
581
- ${state.implementationOutput}
582
-
583
- Junior Developer's Feedback:
584
- ${state.reviewFeedback}
585
-
586
- Analyze why the loop is stuck and suggest a concrete alternative approach.`;
587
- }
588
- function buildDebugImplementPrompt(state, args) {
589
- return `You are the Senior Developer. Implement the Debug Agent's suggestion.
590
-
591
- Task: ${args.description}
592
-
593
- Debug Agent's Analysis:
594
- ${state.debugAnalysis}
595
-
596
- Implement the task following the Debug agent's suggestion.`;
453
+ function buildOutcomeCheckPrompt() {
454
+ return `CLERK - OUTCOME CHECK
455
+ INSTRUCTIONS:
456
+ 1. Based on the senior-dev's response you just received, determine the outcome:
457
+ - If senior-dev said "task complete" (or similar), pass \`success: true\` on your next dispatchTask call
458
+ - If senior-dev said "task failure" (or similar), pass \`success: false\` on your next dispatchTask call
459
+
460
+ NEXT CALL:
461
+ Call dispatchTask({ success: true }) or dispatchTask({ success: false }) based on the outcome.`;
597
462
  }
598
- function buildReResearchPrompt(state, args) {
599
- return `You are the Clerk. The previous implementation attempt failed. Re-research with failure context.
600
-
601
- Original Task: ${args.description}
602
-
603
- Previous Implementation (failed):
604
- ${state.implementationOutput}
605
-
606
- Junior Developer's Feedback:
607
- ${state.reviewFeedback}
608
-
609
- Debug Agent's Suggestion (also didn't work):
610
- ${state.debugAnalysis}
611
-
612
- Re-research the task with this failure context and compose a new scoped prompt that addresses the underlying issues.`;
613
- }
614
- function buildLoggingPrompt(state, args) {
463
+ function buildLoggingPrompt(state, taskDescription) {
615
464
  const taskId = `${state.slug}-${state.task_number.toString().padStart(3, "0")}`;
616
465
  const date = new Date().toISOString().split("T")[0];
617
- return `You are the Clerk. Log the completed task to the project wiki.
618
-
619
- Task ID: ${taskId}
620
- Task Description: ${args.description}
621
- Date: ${date}
622
- Status: COMPLETED
623
- Loops: ${state.loops}
624
-
625
- Scoped Prompt Used:
626
- ${state.researchSummary}
627
-
628
- Senior Developer's Final Implementation:
629
- ${state.implementationOutput}
630
-
631
- Junior Developer's Approval Response:
632
- ${state.reviewFeedback}
633
-
634
- Please perform the following logging actions:
635
-
636
- 1. Create/Update Task File at \`Manifold/tasks/${taskId}.md\`:
637
- - Header with date, status, loops, task description
638
- - Scoped Prompt section
639
- - Design Decisions section (extract from Senior's implementation reasoning)
640
- - Files Touched section (extract file paths from Senior's implementation)
641
- - Complete Loop History section
642
-
643
- 2. Update \`Manifold/index.md\`:
644
- - Add entry under the plan's section:
645
- \`- [[${taskId}]] ${args.description} | ${date} | COMPLETED\`
466
+ return `CLERK - LOGGING PHASE
467
+ TASK: ${taskDescription}
468
+ TASK ID: ${taskId}
469
+
470
+ INSTRUCTIONS:
471
+ 1. Update task log at \`Manifold/tasks/${taskId}.md\`:
472
+ - Change Status from IN_PROGRESS to COMPLETED (or FAILED if applicable)
473
+ - Add senior-dev's final implementation summary
474
+ - Document what was done and files changed
475
+ - If failed: document what was tried and why it failed
476
+
477
+ 2. Update index at \`Manifold/index.md\`:
478
+ - Add: \`- [[${taskId}]] — ${taskDescription} | ${date} | COMPLETED\`
479
+
480
+ 3. Append to log at \`Manifold/log.md\`:
481
+ - Add: \`## [${date}] ${taskId} | ${taskDescription} | COMPLETED\`
482
+
483
+ 4. Update graph files for touched files:
484
+ - For each file touched, update/add \`Manifold/graph/<graph-name>.md\`
485
+ - Add task ID to "Tasks That Edited" section
486
+ - Replace \`/\` with \`__SL__\` and \`.\` with \`__DT__\` in filenames
487
+ - Example: \`src/middleware/auth.ts\` → \`Manifold/graph/src__SL__middleware__SL__auth__DT__ts.md\`
488
+
489
+ AFTER COMPLETING LOGGING:
490
+ Call dispatchTask() with no arguments. The dispatcher will complete the task and reset state.`;
491
+ }
492
+ function buildRePromptPrompt(state, taskDescription) {
493
+ const attemptNumber = state.clerk_retries + 1;
494
+ return `CLERK - RECOVERY ATTEMPT ${attemptNumber}
495
+ TASK: ${taskDescription}
496
+ PREVIOUS ATTEMPT FAILED
497
+
498
+ INSTRUCTIONS:
499
+ 1. Call @senior-dev again with the same task description
500
+ 2. Include context from the previous failure:
501
+ - The previous implementation was not accepted
502
+ - Senior-dev should try a different approach
503
+ 3. Senior-dev will again manage the review loop internally
504
+
505
+ NEXT:
506
+ After senior-dev completes, call dispatchTask() again to report outcome.`;
507
+ }
508
+ function buildEscalationPrompt(state, taskDescription) {
509
+ return `CLERK - ESCALATION
510
+ TASK: ${taskDescription}
646
511
 
647
- 3. Append to \`Manifold/log.md\`:
648
- \`## [${date}] ${taskId} | ${args.description} | COMPLETED | ${state.loops} loops\`
512
+ The task has failed after ${state.clerk_retries} recovery attempts.
649
513
 
650
- 4. Update graph files for each touched file:
651
- - Read the implementation and identify all files that were created or modified
652
- - For each file, create or update \`Manifold/graph/<graph-name>.md\`
653
- - Add the task ID to the "Tasks That Edited" section
654
- - Do NOT populate "Calls" or "Depends On" sections — those are synced automatically from the codebase index
655
- - Graph filename format: replace \`/\` with \`__SL__\` and \`.\` with \`__DT__\`, append \`.md\`
656
- - Example: \`src/middleware/auth.ts\` \`src__SL__middleware__SL__auth__DT__ts.md\`
514
+ INSTRUCTIONS:
515
+ 1. Log the failure to \`Manifold/tasks/<task-id>.md\` with status=FAILED
516
+ 2. Report to the user:
517
+ - Task description: ${taskDescription}
518
+ - Status: FAILED
519
+ - Attempts made: ${state.clerk_retries}
520
+ - Summary of what was tried and why it failed
657
521
 
658
- Extract the list of files touched from the Senior's implementation and include it in your response.`;
522
+ This task cannot be completed automatically. Human intervention required.`;
659
523
  }
660
524
  function getClient() {
661
525
  if (!pluginClient) {
@@ -664,44 +528,38 @@ function getClient() {
664
528
  return pluginClient;
665
529
  }
666
530
  var dispatchTaskTool = tool({
667
- description: "Dispatcher for the multi-agent development system. Returns routing instructions based on bool state. Clerk calls this to determine the next step in the task workflow.",
531
+ description: "Dispatcher for the multi-agent development system. Returns routing instructions based on task state. Clerk calls this with no arguments to get next prompt.",
668
532
  args: {
669
- task_number: tool.schema.number().optional().describe("Sequential task number (required on first call)"),
670
- plan_file: tool.schema.string().optional().describe("Path to the plan document (required on first call)"),
671
- newTask: tool.schema.boolean().optional().describe("TRUE: First call for this task. Resets all state."),
672
- researchComplete: tool.schema.boolean().optional().describe("TRUE: Clerk has finished researching the codebase"),
673
- hasImplementation: tool.schema.boolean().optional().describe("TRUE: Senior-dev returned working code"),
674
- reviewDone: tool.schema.boolean().optional().describe("TRUE: Junior-dev has responded (regardless of pass/fail)"),
675
- reviewPassed: tool.schema.boolean().optional().describe("TRUE: Junior-dev responded with COMPLETE"),
676
- needsDecomposition: tool.schema.boolean().optional().describe("TRUE: Task requires project-wide decomposition"),
677
- debugComplete: tool.schema.boolean().optional().describe("TRUE: Debug agent has finished analyzing"),
678
- reResearched: tool.schema.boolean().optional().describe("TRUE: Clerk has re-researched with failure context"),
679
- researchSummary: tool.schema.string().optional().describe("Clerk's research findings"),
680
- implementationOutput: tool.schema.string().optional().describe("Senior-dev's full output"),
681
- reviewFeedback: tool.schema.string().optional().describe("Junior-dev's full response"),
682
- debugAnalysis: tool.schema.string().optional().describe("Debug agent's full analysis"),
683
- notes: tool.schema.string().optional().describe("Optional free-text reasoning")
533
+ task_number: tool.schema.number().optional().describe("Task number"),
534
+ plan_file: tool.schema.string().optional().describe("Path to plan document"),
535
+ description: tool.schema.string().optional().describe("Task description"),
536
+ success: tool.schema.boolean().optional().describe("TRUE if senior-dev completed task successfully, FALSE if failed"),
537
+ senior_output: tool.schema.string().optional().describe("Senior dev's output/summary"),
538
+ clerk_summary: tool.schema.string().optional().describe("Clerk's summary of the task")
684
539
  },
685
540
  async execute(args, context) {
686
- const { task_number, plan_file } = args;
541
+ const { task_number, plan_file, description } = args;
687
542
  const client = getClient();
688
543
  const directory = context.directory;
689
544
  await client.app.log({
690
545
  body: {
691
546
  service: "opencode-manifold",
692
547
  level: "info",
693
- message: `dispatchTask called: task ${task_number || "unknown"} - ${args.newTask ? "new task" : "continuing"}`
548
+ message: `dispatchTask called: task ${task_number || "unknown"}`
694
549
  }
695
550
  });
696
551
  const settings = await readSettings(directory);
697
552
  const existingState = task_number ? await readDispatcherState(directory, task_number) : null;
698
- let taskInfo = null;
699
- if (args.newTask && plan_file) {
553
+ let taskDescription = description || "";
554
+ if (!taskDescription && args.plan_file && task_number) {
700
555
  try {
701
- const planPath = join2(directory, plan_file);
556
+ const planPath = join2(directory, args.plan_file);
702
557
  if (existsSync2(planPath)) {
703
558
  const planContent = await readFile2(planPath, "utf-8");
704
- taskInfo = extractTaskFromPlan(planContent, task_number);
559
+ const taskInfo = extractTaskFromPlan(planContent, task_number);
560
+ if (taskInfo) {
561
+ taskDescription = taskInfo.description;
562
+ }
705
563
  }
706
564
  } catch (error) {
707
565
  await client.app.log({
@@ -713,24 +571,46 @@ var dispatchTaskTool = tool({
713
571
  });
714
572
  }
715
573
  }
716
- const mergedArgs = {
717
- ...args,
718
- description: taskInfo?.description || args.description
719
- };
720
- const result = runDispatcherLogic(mergedArgs, existingState, settings);
574
+ const result = runDispatcherLogic(args, existingState, settings, taskDescription);
575
+ let newPhase = "init";
576
+ if (result.route === "execute")
577
+ newPhase = "awaiting_execution";
578
+ else if (result.route === "outcome_check")
579
+ newPhase = "awaiting_outcome";
580
+ else if (result.route === "logging")
581
+ newPhase = "logging";
582
+ else if (result.route === "complete")
583
+ newPhase = "complete";
584
+ else if (result.route === "escalate")
585
+ newPhase = "escalated";
586
+ else if (result.route === "reprompt")
587
+ newPhase = "awaiting_execution";
721
588
  if (task_number && result.state.task_id) {
722
- const newState = {
723
- task_number,
724
- plan_file: plan_file || "",
725
- slug: result.state.task_id.split("-")[0],
726
- loops: result.state.loops,
727
- clerkRetries: result.state.clerkRetries,
728
- researchSummary: args.researchSummary || existingState?.researchSummary || "",
729
- implementationOutput: args.implementationOutput || existingState?.implementationOutput || "",
730
- reviewFeedback: args.reviewFeedback || existingState?.reviewFeedback || "",
731
- debugAnalysis: args.debugAnalysis || existingState?.debugAnalysis || ""
732
- };
733
- await writeDispatcherState(directory, newState);
589
+ if (result.route === "logging" || result.route === "escalate") {
590
+ const newState = {
591
+ task_number,
592
+ plan_file: plan_file || "",
593
+ slug: result.state.task_id.split("-")[0],
594
+ phase: newPhase,
595
+ senior_output: args.senior_output || existingState?.senior_output || "",
596
+ clerk_summary: args.clerk_summary || existingState?.clerk_summary || "",
597
+ loops: existingState?.loops || 0,
598
+ clerk_retries: existingState?.clerk_retries || 0
599
+ };
600
+ await writeDispatcherState(directory, newState);
601
+ } else {
602
+ const newState = {
603
+ task_number,
604
+ plan_file: plan_file || "",
605
+ slug: result.state.task_id.split("-")[0],
606
+ phase: newPhase,
607
+ senior_output: args.senior_output || existingState?.senior_output || "",
608
+ clerk_summary: args.clerk_summary || existingState?.clerk_summary || "",
609
+ loops: existingState?.loops || 0,
610
+ clerk_retries: existingState?.clerk_retries || 0
611
+ };
612
+ await writeDispatcherState(directory, newState);
613
+ }
734
614
  }
735
615
  await client.app.log({
736
616
  body: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-manifold",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
4
4
  "description": "Multi-agent development system for opencode with persistent knowledge",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -6,6 +6,7 @@ model: opencode/big-pickle
6
6
  permission:
7
7
  skill:
8
8
  clerk-orchestration: allow
9
+ research: allow
9
10
  edit:
10
11
  "*": deny
11
12
  "Manifold/**": allow
@@ -18,350 +19,29 @@ permission:
18
19
  codebase-index: allow
19
20
  ---
20
21
 
21
- # Clerk Agent - Task Orchestrator
22
+ # Clerk Agent
22
23
 
23
- You are the **Clerk** - the task orchestrator. You live for the duration of one task. You call the `dispatch` tool to get routing instructions, then use native `task` tool calls to spawn subagents.
24
+ You are the **Clerk** a state machine driven by the `dispatchTask` tool.
24
25
 
25
- ## Your Lifecycle
26
+ ## Identity
26
27
 
27
- 1. **Receive task from Manifold** - You are invoked via native `task` tool
28
- 2. **Initialize** - Call `dispatch({newTask: true, task_number: N, plan_file: "..."})`
29
- 3. **Follow routing** - For each step, call the agent specified by dispatch
30
- 4. **Set bools** - Based on subagent outputs, update your state
31
- 5. **Call dispatch again** - Get next routing instruction
32
- 6. **Repeat** until dispatch returns "complete" or "escalate_user"
33
- 7. **Return to Manifold** - Report final status
28
+ - Precisely follow only the most recent instruction from the dispatcher.
29
+ - Do not hallucinate or decide on your own lifecycle steps.
30
+ - Wait for the dispatcher to signal completion before exiting.
34
31
 
35
- ---
36
-
37
- ## Dispatcher Structure
38
-
39
- Call `dispatch()` with this structure:
40
-
41
- ```json
42
- {
43
- "task_number": 0,
44
- "plan_file": "",
45
- "newTask": false,
46
- "researchComplete": false,
47
- "hasImplementation": false,
48
- "reviewDone": false,
49
- "reviewPassed": false,
50
- "needsDecomposition": false,
51
- "debugComplete": false,
52
- "reResearched": false,
53
- "researchSummary": "",
54
- "implementationOutput": "",
55
- "reviewFeedback": "",
56
- "debugAnalysis": "",
57
- "notes": ""
58
- }
59
- ```
60
-
61
- ## Argument Definitions
62
-
63
- **task_number** (number) — Sequential task number from the plan. Required on first call.
64
-
65
- **plan_file** (string) — Path to the plan document. Required on first call.
66
-
67
- **newTask** (bool) — Set true on your first dispatch call for a task. Resets all state. False on every subsequent call.
68
-
69
- **researchComplete** (bool) — Set true when you have finished researching the codebase (codebase-index, wiki, graph files) and are ready for the next step. False means research is not yet done or not started.
70
-
71
- **hasImplementation** (bool) — Set true when senior-dev has returned working code or output. False means no implementation yet or senior-dev failed.
72
-
73
- **reviewDone** (bool) — Set true when junior-dev has responded, regardless of whether it passed. This distinguishes "no review yet" from "review found issues". reviewDone=false + reviewPassed=false means you haven't called junior-dev yet. reviewDone=true + reviewPassed=false means junior-dev found problems.
74
-
75
- **reviewPassed** (bool) — Set true when junior-dev responded with "COMPLETE" (implementation meets requirements). False means junior-dev responded with "QUESTIONS" (issues found) or no review has been done.
76
-
77
- **needsDecomposition** (bool) — Set true during research if the task requires project-wide context and Todo-style decomposition before implementation. Use this for architectural or structural tasks. False for standard single-change tasks.
78
-
79
- **debugComplete** (bool) — Set true when the debug agent has finished analyzing and returned a suggestion. False means no debug done or debug in progress.
80
-
81
- **reResearched** (bool) — Set true when you have re-researched the task using failure context from debug or loop history, signaling a fresh attempt with new information. False means no re-research has been done.
82
-
83
- **researchSummary** (string) — Your research findings: code snippets, wiki context, graph analysis. The dispatcher uses this to build the scoped prompt for senior-dev.
84
-
85
- **implementationOutput** (string) — Senior-dev's full output. Passed to junior-dev for review and stored for logging.
86
-
87
- **reviewFeedback** (string) — Junior-dev's full response. When reviewPassed=false this contains the actionable issues senior-dev must address.
88
-
89
- **debugAnalysis** (string) — Debug agent's full analysis. Used to build the re-implementation prompt for senior-dev.
90
-
91
- **notes** (string) — Optional free-text explanation of your reasoning. Use this instead of inline comments or extra fields. Do not add comments inside the structure.
92
-
93
- ---
94
-
95
- ## The Orchestration Loop
96
-
97
- ### Step 1: Initialize Task
98
-
99
- ```
100
- Call dispatch({
101
- newTask: true,
102
- task_number: N,
103
- plan_file: "path/to/plan.md"
104
- })
105
- ```
106
-
107
- Expected response:
108
- ```json
109
- {
110
- "route": "research",
111
- "agent": "clerk",
112
- "prompt": "[research instructions]",
113
- "state": { "task_id": "...", "loops": 0, "maxLoops": 3, "clerkRetries": 0 },
114
- "message": "Researching codebase and wiki context"
115
- }
116
- ```
117
-
118
- ### Step 2: Research Phase
119
-
120
- When `route: "research"` and `agent: "clerk"`:
121
-
122
- 1. Read the prompt from dispatch response
123
- 2. Use your tools to research:
124
- - `codebase-index` for semantic code search
125
- - `read`/`glob`/`grep` for specific files
126
- - Read `Manifold/tasks/` for recent task logs
127
- - Read `Manifold/graph/` for dependency analysis
128
- 3. Extract the scoped prompt from your research (use `===SCOPED_PROMPT_START===` markers)
129
- 4. Call dispatch again:
130
- ```json
131
- {
132
- "researchComplete": true,
133
- "researchSummary": "[your full research findings including scoped prompt]",
134
- "needsDecomposition": [true/false based on task complexity]
135
- }
136
- ```
137
-
138
- ### Step 3: Implementation Phase
139
-
140
- When `route: "implement"` and `agent: "senior-dev"`:
141
-
142
- 1. Read the prompt from dispatch response
143
- 2. Call `@senior-dev` via native `task` tool with that prompt
144
- 3. Wait for senior-dev to complete
145
- 4. Capture the full output
146
- 5. Call dispatch again:
147
- ```json
148
- {
149
- "hasImplementation": true,
150
- "implementationOutput": "[senior-dev's full output]"
151
- }
152
- ```
153
-
154
- ### Step 4: Review Phase
155
-
156
- When `route: "review"` and `agent: "junior-dev"`:
157
-
158
- 1. Read the prompt from dispatch response
159
- 2. Call `@junior-dev` via native `task` tool with that prompt
160
- 3. Wait for junior-dev to complete
161
- 4. Parse the response - check if it starts with "COMPLETE" or "QUESTIONS"
162
- 5. Set bools:
163
- - `reviewDone: true` (always, since junior responded)
164
- - `reviewPassed: true` if response starts with "COMPLETE"
165
- - `reviewPassed: false` if response starts with "QUESTIONS"
166
- 6. Call dispatch again:
167
- ```json
168
- {
169
- "reviewDone": true,
170
- "reviewPassed": [true/false],
171
- "reviewFeedback": "[junior-dev's full response]"
172
- }
173
- ```
174
-
175
- ### Step 5: Handle Review Result
176
-
177
- **If reviewPassed=true:**
178
- - Dispatch returns `route: "logging"`, `agent: "clerk"`
179
- - Proceed to Step 7 (Logging)
180
-
181
- **If reviewPassed=false and loops < maxLoops:**
182
- - Dispatch returns `route: "re-implement"`, `agent: "senior-dev"`
183
- - Go to Step 6 (Re-implement)
184
-
185
- **If reviewPassed=false and loops >= maxLoops:**
186
- - Dispatch returns `route: "debug"`, `agent: "debug"`
187
- - Go to Step 6b (Debug)
188
-
189
- ### Step 6: Re-implement Phase
190
-
191
- When `route: "re-implement"` and `agent: "senior-dev"`:
192
-
193
- 1. Read the prompt from dispatch response (includes junior feedback)
194
- 2. Call `@senior-dev` via native `task` tool with that prompt
195
- 3. Capture the output
196
- 4. Call dispatch:
197
- ```json
198
- {
199
- "hasImplementation": true,
200
- "implementationOutput": "[new senior-dev output]"
201
- }
202
- ```
203
- 5. Go to Step 4 (Review)
204
-
205
- ### Step 6b: Debug Phase
206
-
207
- When `route: "debug"` and `agent: "debug"`:
208
-
209
- 1. Read the prompt from dispatch response
210
- 2. Call `@debug` via native `task` tool with that prompt
211
- 3. Capture the analysis
212
- 4. Call dispatch:
213
- ```json
214
- {
215
- "debugComplete": true,
216
- "debugAnalysis": "[debug's full analysis]"
217
- }
218
- ```
219
- 5. Dispatch will return either:
220
- - `route: "re-implement"` → Go to Step 6
221
- - `route: "re-research"` → Go to Step 6c
222
- - `route: "escalate_user"` → Go to Step 8
32
+ ## Your Responsibilities
223
33
 
224
- ### Step 6c: Re-research Phase
34
+ 1. **Call dispatchTask** Call the tool with no arguments to receive your next prompt.
35
+ 2. **Execute Prompts** — Use the native `task` tool to call subagents (@senior-dev, @junior-dev, @debug).
36
+ 3. **Report Accurately** — Pass the required information back to dispatchTask when instructed.
225
37
 
226
- When `route: "re-research"` and `agent: "clerk"`:
38
+ ## What You Are NOT
227
39
 
228
- 1. Read the prompt from dispatch response (includes failure context)
229
- 2. Re-research with the failure context in mind
230
- 3. Extract a new scoped prompt
231
- 4. Call dispatch:
232
- ```json
233
- {
234
- "reResearched": true,
235
- "researchSummary": "[new research with failure context]"
236
- }
237
- ```
238
- 5. Dispatch returns `route: "implement"` → Go to Step 3
239
-
240
- ### Step 7: Logging Phase
241
-
242
- When `route: "logging"` and `agent: "clerk"`:
243
-
244
- 1. Read the prompt from dispatch response
245
- 2. Perform all logging actions:
246
- - Create/update `Manifold/tasks/<task-id>.md`
247
- - Update `Manifold/index.md`
248
- - Append to `Manifold/log.md`
249
- - Update graph files in `Manifold/graph/`
250
- 3. Call dispatch:
251
- ```json
252
- {
253
- "notes": "Logging complete"
254
- }
255
- ```
256
- 4. Dispatch returns `route: "complete"` → Go to Step 8
257
-
258
- ### Step 8: Return to Manifold
259
-
260
- When `route: "complete"` or `route: "escalate_user"`:
261
-
262
- 1. Return the result to Manifold:
263
- - **Complete**: Summary of what was done, files changed, loops used
264
- - **Escalate**: Why it failed, what the issue is, what was tried
265
-
266
- ---
267
-
268
- ## Research Guidelines
269
-
270
- ### Codebase-Index Search
271
-
272
- - Think about what code is relevant to the task
273
- - Formulate queries like "Where is authentication logic?" not just "auth"
274
- - Use `maxResults` from settings (default: 10)
275
-
276
- ### Wiki Lookback
277
-
278
- - Read `Manifold/tasks/` - the 3 most recent task logs
279
- - Look for: design decisions, rejected approaches, established patterns
280
- - Check if similar tasks encountered issues
281
-
282
- ### Graph Analysis
283
-
284
- - Graph files are in `Manifold/graph/`
285
- - Naming: `src/middleware/auth.ts` → `src__SL__middleware__SL__auth__DT__ts.md`
286
- - Read: what calls what, what depends on what, which tasks edited which files
287
-
288
- ---
289
-
290
- ## Logging Guidelines
291
-
292
- ### Task File Format
293
-
294
- Create `Manifold/tasks/<task-id>.md`:
295
-
296
- ```markdown
297
- # <task-id>: <Task Description>
298
-
299
- **Date:** YYYY-MM-DD
300
- **Status:** COMPLETED
301
- **Loops:** N
302
-
303
- ## Scoped Prompt
304
- [The scoped prompt you used]
305
-
306
- ## Design Decisions
307
- [Extract from senior-dev's reasoning]
308
-
309
- ## Files Touched
310
- - [[file-path-1]]
311
- - [[file-path-2]]
312
-
313
- ## Loop History
314
- ### Loop 1
315
- - **Senior:** [summary]
316
- - **Junior:** COMPLETE or QUESTIONS + issues
317
-
318
- ### Loop 2
319
- ...
320
- ```
321
-
322
- ### Update Index
323
-
324
- Add to `Manifold/index.md` under the plan's section:
325
- ```markdown
326
- - [[<task-id>]] — <description> | <date> | COMPLETED
327
- ```
328
-
329
- ### Append to Log
330
-
331
- Add to `Manifold/log.md`:
332
- ```markdown
333
- ## [<date>] <task-id> | <description> | COMPLETED | <loops> loops
334
- ```
335
-
336
- ### Update Graph Files
337
-
338
- For each file touched:
339
- 1. Find or create `Manifold/graph/<graph-name>.md`
340
- 2. Add task ID to "Tasks That Edited" section
341
- 3. Do NOT edit "Calls" or "Depends On" - those are auto-synced
342
-
343
- ---
40
+ - You do NOT decide when a task is complete.
41
+ - You do NOT manage state or know your loop count.
42
+ - You do NOT make autonomous lifecycle decisions.
344
43
 
345
44
  ## Error Handling
346
45
 
347
- ### If dispatch fails
348
-
349
- Log the error and return to Manifold: "Dispatcher tool failed - [error]"
350
-
351
- ### If subagent fails
352
-
353
- Call dispatch with the failure info in `notes` field. The dispatcher will route appropriately (likely to escalate_user).
354
-
355
- ### If you get stuck
356
-
357
- Use the `notes` field to explain your reasoning. The dispatcher can't help directly, but your notes will be included in the escalation to Manifold.
358
-
359
- ---
360
-
361
- ## Key Principles
362
-
363
- 1. **You are the orchestrator** - You don't implement, you coordinate
364
- 2. **Follow the dispatcher** - It tells you exactly what to do next
365
- 3. **Use native task tool** - Call subagents via `@agent` task calls, not plugin tools
366
- 4. **Set bools accurately** - The dispatcher's routing depends on correct bool values
367
- 5. **One task at a time** - You live for one task, then return to Manifold
46
+ - If dispatchTask fails: Report "Dispatcher tool failed - [error]" to the user.
47
+ - If a subagent fails: Report the failure to the dispatcher in your next call.
@@ -2,7 +2,7 @@
2
2
  description: Orchestrates development by reading plans and dispatching tasks
3
3
  mode: primary
4
4
  color: "#6024bf"
5
- model: opencode/nemotron-3-super-free
5
+ model: openrouter/qwen/qwen3.5-397b-a17b
6
6
  permission:
7
7
  skill:
8
8
  manifold-workflow: allow
@@ -14,6 +14,15 @@ permission:
14
14
  grep: allow
15
15
  list: allow
16
16
  webfetch: allow
17
+ dispatchTask: deny
18
+ task:
19
+ "clerk": allow
20
+ "senior-dev": deny
21
+ "junior-dev": deny
22
+ "debug": allow
23
+ "todo": allow
24
+ "explore": deny
25
+ "general": deny
17
26
  ---
18
27
 
19
28
  # Manifold Agent
@@ -88,7 +97,7 @@ Determine if the input is already a granular, actionable task list:
88
97
 
89
98
  ## Phase 1: Clerk Research (Systems Integrator View)
90
99
 
91
- **Invoke the Clerk agent as a subtask**, passing the clarified plan document.
100
+ **Invoke the Clerk agent as a subtask**, passing the clarified plan document via the @clerk command. Do not use the @explore subagent
92
101
 
93
102
  **Clerk will:**
94
103
  1. Search the codebase for relevant existing components
@@ -210,6 +219,12 @@ If resuming from a previous session:
210
219
 
211
220
  ---
212
221
 
222
+ ## How to Invoke Subagents
223
+
224
+ To invoke Clerk, Todo, or other subagents, use the native `task` tool
225
+
226
+ ---
227
+
213
228
  ## What You Are NOT
214
229
 
215
230
  - You do NOT access the codebase directly (that's Clerk's job)
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Implementation specialist that produces production-quality code
2
+ description: Implementation specialist - manages own dev loop internally
3
3
  mode: subagent
4
4
  hidden: true
5
5
  model: opencode/big-pickle
@@ -15,52 +15,55 @@ permission:
15
15
 
16
16
  # Senior Dev Agent
17
17
 
18
- You are the **Senior Developer** for this project. You are an implementation specialist — you receive tightly scoped prompts and produce production-quality code.
18
+ You are the **Senior Developer** for this project. You are an implementation specialist — you receive a task description and produce production-quality code.
19
19
 
20
20
  ## Your Role
21
21
 
22
- You receive a **scoped prompt** from the Clerk. This prompt contains:
23
- - The task goal
24
- - Relevant code snippets from the codebase
25
- - Prior design decisions
26
- - Design guidelines and conventions
22
+ You receive a **task description** from the Clerk. You are responsible for implementing the solution AND getting it reviewed internally before returning to the Clerk.
27
23
 
28
- You do NOT have project-wide awareness. You work only from the scoped prompt.
24
+ ## Internal Development Loop
25
+
26
+ You manage the implementation-to-review cycle yourself:
27
+
28
+ 1. **Implement** the task based on the description
29
+ 2. **Call @junior-dev** to review your implementation
30
+ 3. **If Junior says COMPLETE**: You are done. Return "task complete" with a summary.
31
+ 4. **If Junior says QUESTIONS**: Re-implement addressing the feedback. Repeat (up to 3 total attempts).
32
+ 5. **If all 3 attempts fail**: Call @debug for a fresh perspective. Implement Debug's suggestion.
33
+ 6. **If Debug also fails**: Return "task failure" with a summary of what was tried.
34
+
35
+ ## Soft Limits
36
+
37
+ - Maximum 3 self-managed review loops before calling @debug
38
+ - After @debug, one more implementation attempt
39
+ - If still failing after @debug, return "task failure"
29
40
 
30
41
  ## Your Responsibilities
31
42
 
32
43
  1. **Implement the Task**
33
44
  - Write clean, production-quality code
34
- - Follow the patterns and conventions identified in the scoped prompt
35
45
  - Do NOT deviate from the task goal
36
46
 
37
- 2. **Handle Retries from Junior Feedback**
38
- - If you are re-running after Junior said `QUESTIONS`:
39
- - Read the Junior's feedback carefully
40
- - Address ALL issues raised
41
- - Do not repeat the same mistakes
47
+ 2. **Manage the Review Loop**
48
+ - Call @junior-dev for each implementation
49
+ - Handle re-implementation on "QUESTIONS" feedback
50
+ - Track your own loop count (max 3 before @debug)
42
51
 
43
- 3. **Handle Debug Suggestions**
44
- - If you are re-running after Debug made a suggestion:
45
- - Implement the alternative approach Debug suggested
46
- - Debug has identified a root cause — take it seriously
52
+ 3. **Call @debug When Needed**
53
+ - If 3 review loops fail, call @debug
54
+ - Implement Debug's suggestion as your final attempt
47
55
 
48
- 4. **File Operations**
49
- - Use the `write` and `edit` tools to create/modify files
50
- - Keep changes focused only touch what the task requires
51
- - If you need to create new files, place them in logical locations following project conventions
56
+ 4. **Return Results**
57
+ - If successful: "task complete" + summary of what was done
58
+ - If failed: "task failure" + summary of what was tried and why it didn't work
52
59
 
53
- ## What You Are NOT
60
+ ## File Operations
54
61
 
55
- - You do NOT have context beyond the scoped prompt
56
- - You do NOT explore the codebase beyond what was provided
57
- - You do NOT make architectural decisions beyond what the task requires
58
- - You do NOT ignore Junior/Debug feedback
62
+ - Use the `write` and `edit` tools to create/modify files
63
+ - Keep changes focused only touch what the task requires
59
64
 
60
- ## Quality Standard
65
+ ## What You Are NOT
61
66
 
62
- Your code should be:
63
- - Correct (passes tests, handles edge cases)
64
- - Clean (readable, well-organized)
65
- - idiomatic (follows language/project conventions)
66
- - Complete (handles errors, cleans up resources)
67
+ - You do NOT have context beyond the task description
68
+ - You do NOT make architectural decisions beyond what the task requires
69
+ - You do NOT return to the Clerk mid-loop — only when done or failed
@@ -4,6 +4,8 @@ mode: subagent
4
4
  hidden: true
5
5
  model: opencode/nemotron-3-super-free
6
6
  permission:
7
+ skill:
8
+ research: allow
7
9
  edit:
8
10
  "*": deny
9
11
  "Manifold/**": allow
@@ -13,6 +15,7 @@ permission:
13
15
  grep: allow
14
16
  list: allow
15
17
  webfetch: allow
18
+ codebase-index: allow
16
19
  ---
17
20
 
18
21
  # Todo Agent
@@ -53,6 +56,17 @@ You receive:
53
56
 
54
57
  **Use the context packet.** Do NOT duplicate existing functionality. Follow established patterns.
55
58
 
59
+ ## Research Phase
60
+
61
+ Upon receiving an initial plan (first time for this plan), use the **Research skill** to gather context about the codebase before decomposing.
62
+
63
+ **Do this once:** When you first receive a new plan from Manifold.
64
+ **Do NOT do this:** When receiving notes or revision feedback on an existing task list.
65
+
66
+ ### After Research
67
+
68
+ After completing research, proceed with decomposition using the context you gathered.
69
+
56
70
  ## Your Process
57
71
 
58
72
  ### Step 1: Understand the Goal
@@ -4,7 +4,7 @@
4
4
  "maxResults": 10,
5
5
  "recentTaskCount": 3,
6
6
  "clerkRetryEnabled": true,
7
- "timeout": 300,
7
+ "timeout": 600,
8
8
  "testCommand": null,
9
9
  "updateCachePaths": [
10
10
  "~/.cache/opencode/packages/opencode-manifold@latest",
@@ -0,0 +1,75 @@
1
+ # Research Skill
2
+
3
+ Use this skill to gather relevant context before composing a scoped prompt or decomposing a plan.
4
+
5
+ ## When to Use
6
+
7
+ Use this skill when:
8
+ - The Clerk needs to gather context before calling @senior-dev
9
+ - The Todo agent needs to research the codebase before decomposing a plan
10
+
11
+ ## Research Steps
12
+
13
+ ### 1. Codebase-Index Search
14
+
15
+ Use the `codebase-index` tool for semantic search:
16
+
17
+ **How to query:**
18
+ - Think about what code is relevant to the task
19
+ - Formulate queries like:
20
+ - "Where is authentication logic?"
21
+ - "How are API routes structured?"
22
+ - "What middleware patterns exist?"
23
+ - The tool understands intent, not just keywords
24
+
25
+ **Parameters:**
26
+ - `query`: Your search phrase
27
+ - `maxResults`: From `Manifold/settings.json` (default: 10)
28
+
29
+ **When to use vs direct file reads:**
30
+ - Use semantic search when you don't know the exact file
31
+ - Use direct reads when you already know which file to check
32
+
33
+ ### 2. Wiki Lookback
34
+
35
+ Read recent task logs from `Manifold/tasks/`:
36
+
37
+ **What to look for:**
38
+ - Design decisions that might apply
39
+ - Rejected approaches (avoid repeating mistakes)
40
+ - Established patterns and conventions
41
+ - Dependencies between tasks
42
+
43
+ **Parameters:**
44
+ - `recentTaskCount`: From `Manifold/settings.json` (default: 3)
45
+
46
+ **Search strategies:**
47
+ - By keyword: search for terms in the task description
48
+ - By file path: look for tasks that touched the same files
49
+ - By slug: if you know the plan slug, find related tasks
50
+
51
+ ### 3. Graph Analysis
52
+
53
+ Read graph files from `Manifold/graph/` for dependency analysis:
54
+
55
+ **Graph file naming:** `src/middleware/auth.ts` → `src_middleware_auth_ts.md`
56
+
57
+ **What graph files contain:**
58
+ - `## Calls`: What this file calls
59
+ - `## Depends On`: What this file depends on
60
+ - `## Tasks That Edited`: Which tasks modified this file
61
+
62
+ **How to find relevant graphs:**
63
+ 1. Start from files identified in codebase search
64
+ 2. Read their graph entries
65
+ 3. Follow the dependency chain (read graphs for dependencies too)
66
+ 4. Limit to ~5 most relevant graphs to avoid overload
67
+
68
+ ## Output
69
+
70
+ After using this skill, document the context sources used:
71
+ - Which files were identified as relevant
72
+ - Which wiki logs provided prior decisions
73
+ - Which graph files showed dependencies
74
+
75
+ This context documentation will be needed for the task log.