@yemi33/minions 0.1.1678 → 0.1.1680

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1680 (2026-05-02)
4
+
5
+ ### Other
6
+ - Improve agent playbook accuracy
7
+
8
+ ## 0.1.1679 (2026-05-02)
9
+
10
+ ### Fixes
11
+ - preserve PR context for linked fix work items
12
+
3
13
  ## 0.1.1678 (2026-05-02)
4
14
 
5
15
  ### Fixes
package/dashboard.js CHANGED
@@ -110,6 +110,22 @@ function normalizePrMetadata(metadata) {
110
110
  };
111
111
  }
112
112
 
113
+ function getWorkItemPrRef(input) {
114
+ if (!input || typeof input !== 'object') return null;
115
+ return input.targetPr || input.pr || input.prId || input.prNumber || input.pullRequest || input.sourcePr || input.prUrl || null;
116
+ }
117
+
118
+ function copyWorkItemPrFields(item, input, pr = null) {
119
+ const prRef = getWorkItemPrRef(input);
120
+ if (!prRef && !pr) return;
121
+ const prNumber = pr ? shared.getPrNumber(pr) : shared.getPrNumber(prRef);
122
+ item.targetPr = pr?.id || prRef;
123
+ item.pr_id = pr?.id || (typeof prRef === 'string' ? prRef : '');
124
+ if (prNumber != null) item.prNumber = prNumber;
125
+ if (pr?.branch || input.prBranch) item.prBranch = pr?.branch || input.prBranch;
126
+ if (pr?.title || input.prTitle) item.prTitle = pr?.title || input.prTitle;
127
+ if (pr?.url || input.prUrl) item.prUrl = pr?.url || input.prUrl;
128
+ }
113
129
  function linkPullRequestForTracking({ url, title, project: projectName, autoObserve, context, workItemId }, config = CONFIG, options = {}) {
114
130
  if (!url) {
115
131
  const err = new Error('url required');
@@ -1395,6 +1411,8 @@ async function executeCCActions(actions) {
1395
1411
  const workType = routing.normalizeWorkType(action.workType || (action.type !== 'dispatch' ? action.type : WORK_TYPE.IMPLEMENT), WORK_TYPE.IMPLEMENT);
1396
1412
  const id = 'W-' + shared.uid();
1397
1413
  const project = action.project || '';
1414
+ const prRef = getWorkItemPrRef(action);
1415
+ let linkedPr = null;
1398
1416
 
1399
1417
  // Strict project resolution. Silent fallback to PROJECTS[0] when the model named an unknown
1400
1418
  // project caused work items to land in the wrong repo. Now: unknown name → error; ambiguous
@@ -1408,6 +1426,18 @@ async function executeCCActions(actions) {
1408
1426
  results.push({ type: action.type, error: `Project "${project}" not found. Known projects: ${known}` });
1409
1427
  break;
1410
1428
  }
1429
+ } else if (prRef) {
1430
+ const allPrs = getPullRequests().filter(p => !p._ghost);
1431
+ linkedPr = shared.findPrRecord(allPrs, prRef) || null;
1432
+ if (linkedPr?._project && linkedPr._project !== 'central') {
1433
+ targetProject = PROJECTS.find(p => p.name?.toLowerCase() === String(linkedPr._project).toLowerCase()) || null;
1434
+ }
1435
+ if (!targetProject && PROJECTS.length > 1) {
1436
+ results.push({ type: action.type, error: `project field is required when ${PROJECTS.length} projects are configured: ${PROJECTS.map(p => p.name).join(', ')}` });
1437
+ break;
1438
+ } else if (!targetProject && PROJECTS.length === 1) {
1439
+ targetProject = PROJECTS[0];
1440
+ }
1411
1441
  } else if (PROJECTS.length > 1) {
1412
1442
  results.push({ type: action.type, error: `project field is required when ${PROJECTS.length} projects are configured: ${PROJECTS.map(p => p.name).join(', ')}` });
1413
1443
  break;
@@ -1416,6 +1446,16 @@ async function executeCCActions(actions) {
1416
1446
  }
1417
1447
  // PROJECTS.length === 0 → targetProject stays null, falls back to root work-items.json (existing behavior).
1418
1448
 
1449
+ if (prRef && !linkedPr && targetProject) {
1450
+ const projectPrs = shared.safeJson(shared.projectPrPath(targetProject)) || [];
1451
+ shared.normalizePrRecords(projectPrs, targetProject);
1452
+ linkedPr = shared.findPrRecord(projectPrs, prRef, targetProject) || null;
1453
+ }
1454
+ if (prRef && (workType === WORK_TYPE.FIX || workType === WORK_TYPE.REVIEW || workType === WORK_TYPE.TEST) && !linkedPr) {
1455
+ results.push({ type: action.type, error: `PR not found: ${prRef}` });
1456
+ break;
1457
+ }
1458
+
1419
1459
  const wiPath = targetProject ? shared.projectWorkItemsPath(targetProject) : path.join(MINIONS_DIR, 'work-items.json');
1420
1460
 
1421
1461
  // Promote `agent` (singular) → `agents` (array). Models emit either shape and the prior code
@@ -1438,14 +1478,16 @@ async function executeCCActions(actions) {
1438
1478
  const isOneShot = action.oneShot === true || (action.oneShot !== false && ccOneShotTypes.has(workType));
1439
1479
  shared.mutateJsonFileLocked(wiPath, items => {
1440
1480
  if (!Array.isArray(items)) items = [];
1441
- items.push({
1481
+ const item = {
1442
1482
  id, title: action.title, type: workType,
1443
1483
  priority: action.priority || 'medium', description: action.description || '',
1444
1484
  status: WI_STATUS.PENDING, created: new Date().toISOString(),
1445
- createdBy: 'command-center', project,
1485
+ createdBy: 'command-center', project: targetProject?.name || project,
1446
1486
  ...(agentHints.length ? { preferred_agent: agentHints[0], agents: agentHints } : {}),
1447
1487
  ...(isOneShot ? { oneShot: true } : {}),
1448
- });
1488
+ };
1489
+ copyWorkItemPrFields(item, action, linkedPr);
1490
+ items.push(item);
1449
1491
  return items;
1450
1492
  }, { defaultValue: [] });
1451
1493
  results.push({ type: action.type, id, ok: true });
@@ -2740,6 +2782,7 @@ const server = http.createServer(async (req, res) => {
2740
2782
  if (body.acceptanceCriteria) item.acceptanceCriteria = body.acceptanceCriteria;
2741
2783
  if (body.skipPr) item.skipPr = true;
2742
2784
  if (body.oneShot) item.oneShot = true;
2785
+ copyWorkItemPrFields(item, body);
2743
2786
  let dupId = null;
2744
2787
  mutateJsonFileLocked(wiPath, (items) => {
2745
2788
  if (!Array.isArray(items)) items = [];
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "runtime": "copilot",
3
3
  "models": null,
4
- "cachedAt": "2026-05-02T05:22:33.108Z"
4
+ "cachedAt": "2026-05-02T13:32:18.770Z"
5
5
  }
@@ -628,9 +628,13 @@ function selectPlaybook(workType, item) {
628
628
  if (workType === WORK_TYPE.IMPLEMENT || workType === WORK_TYPE.IMPLEMENT_LARGE) {
629
629
  return 'implement';
630
630
  }
631
- if (workType === WORK_TYPE.REVIEW && !item?._pr && !item?.pr_id) {
631
+ const hasPrContext = !!(item?._pr || item?.pr_id || item?.targetPr || item?.sourcePr || item?.pr);
632
+ if (workType === WORK_TYPE.REVIEW && !hasPrContext) {
632
633
  return 'work-item';
633
634
  }
635
+ if (workType === WORK_TYPE.FIX && hasPrContext) {
636
+ return 'fix';
637
+ }
634
638
  const typeSpecificPlaybooks = ['explore', 'review', 'test', 'plan-to-prd', 'plan', 'ask', 'verify', 'decompose', 'docs', 'meeting-investigate', 'meeting-debate', 'meeting-conclude'];
635
639
  return typeSpecificPlaybooks.includes(workType) ? workType : 'work-item';
636
640
  }
package/engine.js CHANGED
@@ -2592,6 +2592,14 @@ function renderProjectWorkItemPromptForAgent(item, workType, agentId, config, pr
2592
2592
  worktree_path: path.resolve(root, config.engine?.worktreeRoot || '../worktrees', `${branchName}`),
2593
2593
  commit_message: item.commitMessage || `feat: ${item.title || item.id}`,
2594
2594
  notes_content: '',
2595
+ pr_id: item.pr_id || item._pr || item.targetPr || item.sourcePr || item.pr || '',
2596
+ pr_number: item.prNumber || item.pr_number || '',
2597
+ pr_title: item.pr_title || item.prTitle || '',
2598
+ pr_branch: item.pr_branch || item.prBranch || '',
2599
+ pr_author: item.pr_author || item.prAuthor || '',
2600
+ pr_url: item.pr_url || item.prUrl || '',
2601
+ reviewer: item.reviewer || 'Reviewer',
2602
+ review_note: item.review_note || item.reviewNote || item.description || item.title || 'See PR thread comments',
2595
2603
  };
2596
2604
  const cpResult = buildWorkItemDispatchVars(item, vars, config, {
2597
2605
  worktreePath: vars.worktree_path || root,
@@ -2612,6 +2620,38 @@ function renderProjectWorkItemPromptForAgent(item, workType, agentId, config, pr
2612
2620
  };
2613
2621
  }
2614
2622
 
2623
+ function getWorkItemPrRef(item) {
2624
+ if (!item || typeof item !== 'object') return null;
2625
+ return item.targetPr || item.pr || item.pr_id || item.sourcePr || item.pullRequest || item.prUrl || item.prNumber || null;
2626
+ }
2627
+
2628
+ function resolveWorkItemPrRecord(item, project) {
2629
+ if (!project) return null;
2630
+ const prRef = getWorkItemPrRef(item);
2631
+ if (!prRef) return null;
2632
+ const prs = safeJson(projectPrPath(project)) || [];
2633
+ shared.normalizePrRecords(prs, project);
2634
+ return shared.findPrRecord(prs, prRef, project);
2635
+ }
2636
+
2637
+ function withWorkItemPrContext(item, pr) {
2638
+ if (!pr) return item;
2639
+ const prNumber = shared.getPrNumber(pr);
2640
+ return {
2641
+ ...item,
2642
+ _pr: pr.id,
2643
+ pr_id: pr.id,
2644
+ targetPr: item.targetPr || pr.id,
2645
+ prNumber: prNumber ?? item.prNumber,
2646
+ pr_number: prNumber ?? item.pr_number,
2647
+ pr_title: pr.title || item.pr_title || item.prTitle || '',
2648
+ pr_branch: pr.branch || item.pr_branch || item.prBranch || '',
2649
+ pr_author: pr.agent || item.pr_author || item.prAuthor || '',
2650
+ pr_url: pr.url || item.pr_url || item.prUrl || '',
2651
+ reviewer: item.reviewer || 'Reviewer',
2652
+ review_note: item.review_note || item.reviewNote || item.description || item.title || 'See PR thread comments',
2653
+ };
2654
+ }
2615
2655
  function projectFromDispatchMeta(metaProject, config) {
2616
2656
  if (!metaProject) return null;
2617
2657
  const projects = getProjects(config);
@@ -2775,8 +2815,17 @@ function discoverFromWorkItems(config, project) {
2775
2815
  skipped.noAgent++; continue;
2776
2816
  }
2777
2817
 
2818
+ const linkedPr = resolveWorkItemPrRecord(item, project);
2819
+ const promptItem = linkedPr ? withWorkItemPrContext(item, linkedPr) : item;
2820
+ const prBranch = linkedPr?.branch || '';
2821
+ const isPrTargeted = !!(linkedPr && (workType === WORK_TYPE.FIX || workType === WORK_TYPE.REVIEW || workType === WORK_TYPE.TEST));
2822
+ if (!linkedPr && getWorkItemPrRef(item) && (workType === WORK_TYPE.FIX || workType === WORK_TYPE.REVIEW || workType === WORK_TYPE.TEST)) {
2823
+ if (item._pendingReason !== 'pr_not_found') { item._pendingReason = 'pr_not_found'; needsWrite = true; }
2824
+ log('warn', `Work item ${item.id} references PR ${getWorkItemPrRef(item)} but no tracked PR record was found`);
2825
+ continue;
2826
+ }
2778
2827
  const isShared = item.branchStrategy === 'shared-branch' && item.featureBranch;
2779
- const branchName = isShared ? item.featureBranch : (item.branch || `work/${item.id}`);
2828
+ const branchName = isPrTargeted && prBranch ? prBranch : (isShared ? item.featureBranch : (item.branch || `work/${item.id}`));
2780
2829
  const deferredAgentResolution = agentId === routing.ANY_AGENT;
2781
2830
 
2782
2831
  // Branch mutex: skip if target branch is locked by an active dispatch
@@ -2789,7 +2838,7 @@ function discoverFromWorkItems(config, project) {
2789
2838
  }
2790
2839
 
2791
2840
  const promptAgentId = deferredAgentResolution ? reservedAgentId : agentId;
2792
- const promptResult = renderProjectWorkItemPromptForAgent(item, workType, promptAgentId, config, project, root, branchName);
2841
+ const promptResult = renderProjectWorkItemPromptForAgent(promptItem, workType, promptAgentId, config, project, root, branchName);
2793
2842
  if (promptResult.needsReview) {
2794
2843
  log('warn', `Work item ${item.id} exceeded 3 checkpoint-resumes — marking as failed for manual intervention`);
2795
2844
  item.status = WI_STATUS.FAILED;
@@ -2827,7 +2876,7 @@ function discoverFromWorkItems(config, project) {
2827
2876
  agentRole: config.agents[agentId]?.role || tempAgents.get(agentId)?.role || 'Agent',
2828
2877
  task: `[${project?.name || 'project'}] ${item.title || item.description?.slice(0, 80) || item.id}`,
2829
2878
  prompt,
2830
- meta: { dispatchKey: key, source: 'work-item', branch: branchName, branchStrategy: item.branchStrategy || 'parallel', useExistingBranch: !!(item.branchStrategy === 'shared-branch' && item.featureBranch), item, project: { name: project?.name, localPath: project?.localPath }, deferAgentResolution: deferredAgentResolution }
2879
+ meta: { dispatchKey: key, source: 'work-item', branch: branchName, branchStrategy: item.branchStrategy || 'parallel', useExistingBranch: !!(isPrTargeted || (item.branchStrategy === 'shared-branch' && item.featureBranch)), item: promptItem, project: { name: project?.name, localPath: project?.localPath }, deferAgentResolution: deferredAgentResolution, ...(linkedPr ? { pr: linkedPr } : {}) }
2831
2880
  });
2832
2881
 
2833
2882
  setCooldown(key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1678",
3
+ "version": "0.1.1680",
4
4
  "description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
5
5
  "bin": {
6
6
  "minions": "bin/minions.js"
package/playbooks/fix.md CHANGED
@@ -17,6 +17,14 @@ Branch: `{{pr_branch}}`
17
17
 
18
18
  {{review_note}}
19
19
 
20
+ ## Finding Triage
21
+
22
+ Before editing, split the feedback into:
23
+
24
+ - **Blocking findings to fix:** correctness, safety, build/test failure, missing requested behavior, broken compatibility, or review comments explicitly required for approval.
25
+ - **Findings to answer with rationale:** comments where the current approach is intentionally correct, the reviewer misunderstood the code, or the requested change would broaden the PR beyond its purpose.
26
+ - **Non-blocking suggestions:** style, optional refactors, extra docs, or enhancements that are not required for approval. Do not implement these unless they are necessary to resolve a blocking issue.
27
+
20
28
  ## Health Check
21
29
 
22
30
  Before starting work, run `git status` and verify the worktree is clean and on the expected branch (`{{pr_branch}}`). If the worktree is dirty or on the wrong branch, report the issue and stop.
@@ -42,6 +50,7 @@ Before pushing, prove the review fix did not break the branch:
42
50
 
43
51
  - Use the project's source of truth for commands: `CLAUDE.md`, README, package scripts, Makefile, or equivalent build config.
44
52
  - Run checks that are relevant to the addressed findings. Prefer the full suite when practical.
53
+ - Capture the exact commands run and meaningful results in the PR comment and completion report.
45
54
  - Fix regressions you introduced. If failures are pre-existing or unrelated, capture the evidence and include it in the PR comment.
46
55
  - Do not push code that breaks existing tests or the build because of your changes.
47
56
 
@@ -34,11 +34,21 @@ Before starting work, run `git status` and verify the worktree is clean and on t
34
34
 
35
35
  Use subagents only for genuinely parallel, independent tasks (e.g., editing files in unrelated modules simultaneously). For sequential work, single-file edits, searches, and file reads, work directly — do not spawn subagents.
36
36
 
37
+ ## Context Discovery
38
+
39
+ Before editing, assemble a small, dependency-aware context pack:
40
+
41
+ - Read project instructions first (`CLAUDE.md`, README, package scripts, Makefile, or equivalent).
42
+ - Identify candidate files from the task text, existing symbols, comparable implementations, direct imports/callers, and corresponding tests.
43
+ - Read the smallest useful set of files first (usually 5-8). Expand only when a concrete question, failing validation, or missing pattern requires it.
44
+ - For large files, read imports, exported/public entry points, and task-relevant sections before reading the whole file.
45
+
37
46
  ## Delivery Contract
38
47
 
39
48
  Deliver this as if the user asked you directly in a CLI:
40
49
 
41
50
  - Understand the requested behavior and relevant acceptance criteria before editing.
51
+ - State the likely files to touch, patterns to follow, and main risks to yourself before making the first code change.
42
52
  - Read the smallest useful set of source, tests, docs, and comparable implementations needed to make the change correctly.
43
53
  - Follow existing project conventions, including logging, typing, error handling, and test structure.
44
54
  - Make the complete change required by the task; do not add unrelated cleanups or speculative improvements.
@@ -55,6 +65,7 @@ Before publishing, prove the change with the repo's own documented checks:
55
65
 
56
66
  - Use the project's source of truth for commands: `CLAUDE.md`, README, package scripts, Makefile, or equivalent build config.
57
67
  - Run the checks that are relevant to this task, including tests that cover the changed behavior. Prefer the full suite when practical.
68
+ - Capture the exact commands run and the meaningful result in the PR description or completion report. Do not summarize validation as "tests passed" without naming what ran.
58
69
  - Fix regressions you introduced. If failures are pre-existing or outside the task, capture the evidence and make that explicit in the PR.
59
70
  - Do not publish changes with a broken build or failing tests that you introduced.
60
71
 
package/playbooks/plan.md CHANGED
@@ -28,12 +28,14 @@ A user has described a feature they want built. Your job is to create a detailed
28
28
  - Map the areas of code that this feature will touch
29
29
  - Identify existing patterns, conventions, and extension points
30
30
  - Note dependencies and potential conflicts with in-progress work
31
+ - Build a concise context pack before planning: start with 5-15 candidate files from paths, symbols, comparable implementations, imports/callers, and tests; read the smallest useful set (usually 5-8 files) and expand only for specific unknowns
31
32
 
32
33
  ### 3. Design the Approach
33
34
  - Outline the high-level architecture for the feature
34
35
  - Identify what needs to be created vs modified
35
36
  - Consider edge cases, error handling, and backwards compatibility
36
37
  - Note any prerequisites or migrations needed
38
+ - Record non-obvious design decisions with the alternatives considered and why the chosen option best fits existing architecture
37
39
 
38
40
  ### 4. Break Down into Work Items
39
41
  - Decompose into discrete, PR-sized chunks of work
@@ -23,7 +23,14 @@ Use subagents only for genuinely parallel, independent tasks (e.g., reviewing un
23
23
  git diff {{main_branch}}...origin/{{pr_branch}}
24
24
  ```
25
25
 
26
- 2. For each changed file, verify:
26
+ 2. Think about deploy risk before commenting:
27
+ - What user-visible behavior changed?
28
+ - What dependencies, callers, or tests could be affected?
29
+ - What security, data-loss, concurrency, or compatibility risks are plausible for this diff?
30
+
31
+ 3. Run or inspect the repo's documented checks when practical. Use `CLAUDE.md`, README, package scripts, Makefile, or equivalent as the command source of truth, and record the exact commands/results in the review body.
32
+
33
+ 4. For each changed file, verify:
27
34
  - Does it follow existing patterns?
28
35
  - Are file paths and imports correct?
29
36
  - Follows the project's logging conventions (check CLAUDE.md)?
@@ -31,14 +38,19 @@ Use subagents only for genuinely parallel, independent tasks (e.g., reviewing un
31
38
  - Tests cover the important logic?
32
39
  - No security issues (injection, unsanitized input)?
33
40
 
34
- 3. Do NOT blindly approve. If you find real issues:
41
+ 5. Classify findings by ship risk:
42
+ - **Blocking:** failing checks, security/data-loss risk, broken existing behavior, missing requested behavior, invalid API/schema/data migration, or tests that do not cover changed critical logic.
43
+ - **Non-blocking:** style preferences, minor refactors, optional documentation, low-risk performance ideas, or additional tests that are useful but not required for safety.
44
+
45
+ 6. Do NOT blindly approve. If you find real blocking issues:
35
46
  - Verdict: **REQUEST_CHANGES**
36
47
  - List specific issues with file paths and line numbers
37
48
  - Describe what needs to change
38
49
 
39
- 4. If the code is genuinely ready:
50
+ 7. If the code is genuinely ready:
40
51
  - Verdict: **APPROVE**
41
52
  - Note any minor non-blocking suggestions
53
+ - Do not request changes for nits, speculative edge cases, or unrelated improvements
42
54
 
43
55
  ## Post Review — Submit your verdict
44
56
 
@@ -55,6 +67,19 @@ Your review body **MUST** start with one of these verdict lines (exactly as show
55
67
  Follow the verdict line with your detailed review findings, then sign off:
56
68
  - Sign: `Review by Minions ({{agent_name}} — {{agent_role}})`
57
69
 
70
+ Use this structure after the verdict:
71
+
72
+ ```markdown
73
+ Automated checks:
74
+ - `<command>`: pass/fail/skipped — short result or reason
75
+
76
+ Blocking issues:
77
+ - None, or `path:line` — issue and required fix
78
+
79
+ Non-blocking suggestions:
80
+ - None, or `path:line` — suggestion
81
+ ```
82
+
58
83
  After running the command, confirm it succeeded (check the command output for errors). If it fails, retry once.
59
84
 
60
85
  ## Handling Merge Conflicts
@@ -13,6 +13,8 @@ Treat a Minions assignment like the user typed the same task directly into a cap
13
13
  - Optimize for the requested outcome, not for mechanically completing checklist steps.
14
14
  - Use judgment to choose the smallest reliable workflow that fully satisfies the task.
15
15
  - Read only the context needed to make correct decisions; do not perform broad archaeology unless the task requires it.
16
+ - Build an initial context pack before editing: start from repo docs and team memory, identify 5-15 candidate files by path names, symbols, imports, tests, and comparable implementations, then read the smallest useful pack (usually 5-8 files). Expand beyond that only when a specific gap or failure proves more context is needed.
17
+ - Prefer dependency-aware context over keyword-only searching: when touching a file, also check its direct imports, direct callers when easy to find, and corresponding tests. For small repos, a simple repo map plus targeted search is enough.
16
18
  - Validate with the repo's own documented commands and acceptance criteria. If full validation is impossible or pre-existing failures block it, explain that precisely instead of inventing a green result.
17
19
  - Prefer direct work over ceremony. Branches, PRs, inbox notes, completion reports/blocks, and status comments exist for traceability; they should not change what "done" means for the user.
18
20
  - Safety and observability rules still win: stay in the engine-created worktree, do not self-merge, do not edit engine-managed status files, do not hide failures, and leave enough evidence for the human and engine to track the result.
@@ -80,8 +80,8 @@ I'll dispatch dallas to fix that bug.
80
80
  - `knowledge`: `title`, `content`, and `category` REQUIRED. Valid categories: architecture, conventions, project-notes, build-reports, reviews.
81
81
 
82
82
  Core action types:
83
- - **dispatch**: title (REQUIRED), workType, priority (low/medium/high), agents[] or agent (optional — both shapes accepted), project (REQUIRED when multi-project), description
84
- workTypes: `explore` (research/report only, NO PR), `ask` (answer/report, NO PR), `implement` (new code, PR REQUIRED), `fix` (bug fix, PR REQUIRED), `review` (code review, NO PR), `test` (tests, PR if new), `verify` (merge/build/maintenance, NO PR)
83
+ - **dispatch**: title (REQUIRED), workType, priority (low/medium/high), agents[] or agent (optional — both shapes accepted), project (REQUIRED when multi-project unless `pr` resolves to a tracked PR), description, pr (optional PR number/id/url for work that targets an existing PR)
84
+ workTypes: `explore` (research/report only, NO PR), `ask` (answer/report, NO PR), `implement` (new code, PR REQUIRED), `fix` (standalone bug fix creates a PR; include `pr` when fixing review comments/build failures on an existing PR), `review` (code review, NO PR), `test` (tests, PR if new), `verify` (merge/build/maintenance, NO PR)
85
85
  If the user wants a design/architecture artifact committed through a PR, dispatch `implement` or `docs` rather than `explore`.
86
86
  When the user names a specific agent ("assign this to lambert"), put exactly that one name in `agents` (e.g. `"agents": ["lambert"]`). A single-agent assignment is hard-pinned by the server — it will queue for that agent only and skip the routing table. Use multi-agent arrays only when the user names multiple agents or asks for fan-out.
87
87
  - **build-and-test**: pr, project (optional), agent (optional) — Run the build-and-test playbook against a PR. The agent will checkout the PR branch, run the project's build/test commands, and report results. Use when the user asks to "run tests on PR X" or "build PR X" or after a fix to verify nothing regressed.