ai-whisper 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -100,7 +100,7 @@ whisper collab mount claude
100
100
  whisper collab mount codex
101
101
  ```
102
102
 
103
- The first `mount` creates the collab and starts the broker daemon for the workspace; the second binds the other agent. From either session, start a workflow against a spec or goal file — `spec-driven-development` for a spec, `ralph-loop` for an open-ended goal, plus `complex-bug-fixing` and `deliberation` (see [Workflows](docs/workflows.md)). Watch it run with:
103
+ The first `mount` creates the collab and starts the broker daemon for the workspace; the second binds the other agent. From either session, start a workflow against a spec or goal file — `spec-driven-development` for a spec, `ralph-loop` for an open-ended goal, plus `quick-task`, `complex-bug-fixing`, and `deliberation` (see [Workflows](docs/workflows.md)). Watch it run with:
104
104
 
105
105
  ```bash
106
106
  whisper collab dashboard
@@ -136,7 +136,7 @@ It's cosmetic and entirely optional. Turn it off per mount with `--no-duo`, or p
136
136
 
137
137
  ## Learn more
138
138
 
139
- - [Workflows](docs/workflows.md) — how to use the four workflows well: choosing between `spec-driven-development`, `ralph-loop`, `complex-bug-fixing`, and `deliberation`, and authoring the spec, goal, bug report, or seed that drives the run.
139
+ - [Workflows](docs/workflows.md) — how to use the five workflows well: choosing between `spec-driven-development`, `quick-task`, `ralph-loop`, `complex-bug-fixing`, and `deliberation`, and authoring the spec, task brief, goal, bug report, or seed that drives the run.
140
140
  - [Concepts](docs/concepts.md) — the mental model: baton handoff, real mounted sessions, supervised autonomy, workflow-first execution.
141
141
  - [Relay & handoff flows](docs/relay-handoff-flows.md) — the complete handoff state machine, capture-status table, hotkey reference, per-step verdicts, and troubleshooting.
142
142
  - [Evaluator configuration](docs/evaluator-configuration.md) — required credentials and options for the LLM evaluator that gates workflows.
@@ -2808,6 +2808,47 @@ var DELIBERATION = {
2808
2808
  }
2809
2809
  ]
2810
2810
  };
2811
+ var QUICK_TASK_KICKOFF = `You are the implementer in an autonomous quick-task workflow. No human is in the loop \u2014 never ask for confirmation, permission, or clarification; do the work yourself.
2812
+
2813
+ Read the task brief at {specPath}. It was written after a human approved the approach \u2014 treat it as the ratified contract: implement the "Approved approach" section as written; do NOT redesign it.
2814
+
2815
+ 1. The files under "Scope" are the declared blast radius. Implement the task, add or adjust the tests the brief's "Acceptance checks" imply, run the project's verification command and ensure it passes.
2816
+ 2. Commit your changes (do NOT commit the task brief; .ai-whisper/ is gitignored).
2817
+
2818
+ Scope guard: if the work is materially bigger than the brief \u2014 you need to touch non-test files beyond the "Scope" list, the approved approach does not survive contact with the code, or a hidden dependency/migration appears \u2014 do NOT push through. Hand back that you CANNOT PROCEED, naming what exploded; the run halts to the human, who re-scopes or escalates to spec-driven-development.
2819
+
2820
+ Hand back the commit SHAs and the verification output, plus a 1-2 sentence summary; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.`;
2821
+ var QUICK_TASK_REVIEW = `The implementer claims the task in the brief at {specPath} is complete \u2014 the changes are commits {commitRange}. The upper bound is a LIVE \`HEAD\`: resolve it against the current repository at review time and INCLUDE any commits added during this review round (e.g. fixes for your prior findings); do not pin the review to an earlier tip. Verify against the brief's "Acceptance checks" and confirm the change stays inside the brief's "Scope": touching non-test files beyond the declared Scope list is a blocking finding \u2014 the implementer should have halted instead. Run the project's verification/tests yourself. This is an autonomous workflow with no human in the loop.
2822
+
2823
+ ` + CODE_REVIEW_SKILL_GUIDANCE + WORKFLOW_REVIEW_PROTOCOL;
2824
+ var QUICK_TASK_FIX = "Apply the reviewer's findings to commits {commitRange} now (amend or add commits as needed). This is an autonomous workflow \u2014 no human will respond. Do the work yourself and hand back the updated commit SHAs and verification output; never ask for confirmation, permission, or clarification. End your handback with a 1-2 sentence summary of what you changed; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.";
2825
+ var QUICK_TASK = {
2826
+ type: "quick-task",
2827
+ displayName: "Quick Task",
2828
+ description: "Human-approved task brief \u2192 implement \u2192 acceptance review, hard-gated to small pre-scoped tasks",
2829
+ defaultImplementer: "claude",
2830
+ defaultReviewer: "codex",
2831
+ phases: [
2832
+ {
2833
+ name: "implement-and-review",
2834
+ implementerRole: "implementer",
2835
+ reviewerRole: "reviewer",
2836
+ maxRounds: 5,
2837
+ initialHandoffStep: "implement",
2838
+ kickoffTemplate: QUICK_TASK_KICKOFF,
2839
+ stepTemplates: {
2840
+ implement: QUICK_TASK_KICKOFF,
2841
+ review: QUICK_TASK_REVIEW,
2842
+ fix: QUICK_TASK_FIX
2843
+ },
2844
+ reviewMode: "acceptance-review",
2845
+ evaluatorPromptKey: "review-loop",
2846
+ artifactOut: { kind: "commit-range" },
2847
+ anchorCommitBaseOnEntry: true,
2848
+ renderFixTemplateOnFindings: true
2849
+ }
2850
+ ]
2851
+ };
2811
2852
  function withOperatorControl(def) {
2812
2853
  return {
2813
2854
  ...def,
@@ -2823,7 +2864,8 @@ var REGISTRY = {
2823
2864
  [SPEC_DRIVEN_DEVELOPMENT.type]: withOperatorControl(SPEC_DRIVEN_DEVELOPMENT),
2824
2865
  [RALPH_LOOP.type]: withOperatorControl(RALPH_LOOP),
2825
2866
  [COMPLEX_BUG_FIXING.type]: withOperatorControl(COMPLEX_BUG_FIXING),
2826
- [DELIBERATION.type]: withOperatorControl(DELIBERATION)
2867
+ [DELIBERATION.type]: withOperatorControl(DELIBERATION),
2868
+ [QUICK_TASK.type]: withOperatorControl(QUICK_TASK)
2827
2869
  };
2828
2870
  function ralphRunDir(workspaceRoot, workflowId) {
2829
2871
  return join(workspaceRoot, ".ai-whisper", "ralph", workflowId);
@@ -2831,6 +2831,47 @@ var DELIBERATION = {
2831
2831
  }
2832
2832
  ]
2833
2833
  };
2834
+ var QUICK_TASK_KICKOFF = `You are the implementer in an autonomous quick-task workflow. No human is in the loop \u2014 never ask for confirmation, permission, or clarification; do the work yourself.
2835
+
2836
+ Read the task brief at {specPath}. It was written after a human approved the approach \u2014 treat it as the ratified contract: implement the "Approved approach" section as written; do NOT redesign it.
2837
+
2838
+ 1. The files under "Scope" are the declared blast radius. Implement the task, add or adjust the tests the brief's "Acceptance checks" imply, run the project's verification command and ensure it passes.
2839
+ 2. Commit your changes (do NOT commit the task brief; .ai-whisper/ is gitignored).
2840
+
2841
+ Scope guard: if the work is materially bigger than the brief \u2014 you need to touch non-test files beyond the "Scope" list, the approved approach does not survive contact with the code, or a hidden dependency/migration appears \u2014 do NOT push through. Hand back that you CANNOT PROCEED, naming what exploded; the run halts to the human, who re-scopes or escalates to spec-driven-development.
2842
+
2843
+ Hand back the commit SHAs and the verification output, plus a 1-2 sentence summary; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.`;
2844
+ var QUICK_TASK_REVIEW = `The implementer claims the task in the brief at {specPath} is complete \u2014 the changes are commits {commitRange}. The upper bound is a LIVE \`HEAD\`: resolve it against the current repository at review time and INCLUDE any commits added during this review round (e.g. fixes for your prior findings); do not pin the review to an earlier tip. Verify against the brief's "Acceptance checks" and confirm the change stays inside the brief's "Scope": touching non-test files beyond the declared Scope list is a blocking finding \u2014 the implementer should have halted instead. Run the project's verification/tests yourself. This is an autonomous workflow with no human in the loop.
2845
+
2846
+ ` + CODE_REVIEW_SKILL_GUIDANCE + WORKFLOW_REVIEW_PROTOCOL;
2847
+ var QUICK_TASK_FIX = "Apply the reviewer's findings to commits {commitRange} now (amend or add commits as needed). This is an autonomous workflow \u2014 no human will respond. Do the work yourself and hand back the updated commit SHAs and verification output; never ask for confirmation, permission, or clarification. End your handback with a 1-2 sentence summary of what you changed; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.";
2848
+ var QUICK_TASK = {
2849
+ type: "quick-task",
2850
+ displayName: "Quick Task",
2851
+ description: "Human-approved task brief \u2192 implement \u2192 acceptance review, hard-gated to small pre-scoped tasks",
2852
+ defaultImplementer: "claude",
2853
+ defaultReviewer: "codex",
2854
+ phases: [
2855
+ {
2856
+ name: "implement-and-review",
2857
+ implementerRole: "implementer",
2858
+ reviewerRole: "reviewer",
2859
+ maxRounds: 5,
2860
+ initialHandoffStep: "implement",
2861
+ kickoffTemplate: QUICK_TASK_KICKOFF,
2862
+ stepTemplates: {
2863
+ implement: QUICK_TASK_KICKOFF,
2864
+ review: QUICK_TASK_REVIEW,
2865
+ fix: QUICK_TASK_FIX
2866
+ },
2867
+ reviewMode: "acceptance-review",
2868
+ evaluatorPromptKey: "review-loop",
2869
+ artifactOut: { kind: "commit-range" },
2870
+ anchorCommitBaseOnEntry: true,
2871
+ renderFixTemplateOnFindings: true
2872
+ }
2873
+ ]
2874
+ };
2834
2875
  function withOperatorControl(def) {
2835
2876
  return {
2836
2877
  ...def,
@@ -2846,7 +2887,8 @@ var REGISTRY = {
2846
2887
  [SPEC_DRIVEN_DEVELOPMENT.type]: withOperatorControl(SPEC_DRIVEN_DEVELOPMENT),
2847
2888
  [RALPH_LOOP.type]: withOperatorControl(RALPH_LOOP),
2848
2889
  [COMPLEX_BUG_FIXING.type]: withOperatorControl(COMPLEX_BUG_FIXING),
2849
- [DELIBERATION.type]: withOperatorControl(DELIBERATION)
2890
+ [DELIBERATION.type]: withOperatorControl(DELIBERATION),
2891
+ [QUICK_TASK.type]: withOperatorControl(QUICK_TASK)
2850
2892
  };
2851
2893
  function ralphRunDir(workspaceRoot, workflowId) {
2852
2894
  return join(workspaceRoot, ".ai-whisper", "ralph", workflowId);
@@ -2805,6 +2805,47 @@ var DELIBERATION = {
2805
2805
  }
2806
2806
  ]
2807
2807
  };
2808
+ var QUICK_TASK_KICKOFF = `You are the implementer in an autonomous quick-task workflow. No human is in the loop \u2014 never ask for confirmation, permission, or clarification; do the work yourself.
2809
+
2810
+ Read the task brief at {specPath}. It was written after a human approved the approach \u2014 treat it as the ratified contract: implement the "Approved approach" section as written; do NOT redesign it.
2811
+
2812
+ 1. The files under "Scope" are the declared blast radius. Implement the task, add or adjust the tests the brief's "Acceptance checks" imply, run the project's verification command and ensure it passes.
2813
+ 2. Commit your changes (do NOT commit the task brief; .ai-whisper/ is gitignored).
2814
+
2815
+ Scope guard: if the work is materially bigger than the brief \u2014 you need to touch non-test files beyond the "Scope" list, the approved approach does not survive contact with the code, or a hidden dependency/migration appears \u2014 do NOT push through. Hand back that you CANNOT PROCEED, naming what exploded; the run halts to the human, who re-scopes or escalates to spec-driven-development.
2816
+
2817
+ Hand back the commit SHAs and the verification output, plus a 1-2 sentence summary; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.`;
2818
+ var QUICK_TASK_REVIEW = `The implementer claims the task in the brief at {specPath} is complete \u2014 the changes are commits {commitRange}. The upper bound is a LIVE \`HEAD\`: resolve it against the current repository at review time and INCLUDE any commits added during this review round (e.g. fixes for your prior findings); do not pin the review to an earlier tip. Verify against the brief's "Acceptance checks" and confirm the change stays inside the brief's "Scope": touching non-test files beyond the declared Scope list is a blocking finding \u2014 the implementer should have halted instead. Run the project's verification/tests yourself. This is an autonomous workflow with no human in the loop.
2819
+
2820
+ ` + CODE_REVIEW_SKILL_GUIDANCE + WORKFLOW_REVIEW_PROTOCOL;
2821
+ var QUICK_TASK_FIX = "Apply the reviewer's findings to commits {commitRange} now (amend or add commits as needed). This is an autonomous workflow \u2014 no human will respond. Do the work yourself and hand back the updated commit SHAs and verification output; never ask for confirmation, permission, or clarification. End your handback with a 1-2 sentence summary of what you changed; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.";
2822
+ var QUICK_TASK = {
2823
+ type: "quick-task",
2824
+ displayName: "Quick Task",
2825
+ description: "Human-approved task brief \u2192 implement \u2192 acceptance review, hard-gated to small pre-scoped tasks",
2826
+ defaultImplementer: "claude",
2827
+ defaultReviewer: "codex",
2828
+ phases: [
2829
+ {
2830
+ name: "implement-and-review",
2831
+ implementerRole: "implementer",
2832
+ reviewerRole: "reviewer",
2833
+ maxRounds: 5,
2834
+ initialHandoffStep: "implement",
2835
+ kickoffTemplate: QUICK_TASK_KICKOFF,
2836
+ stepTemplates: {
2837
+ implement: QUICK_TASK_KICKOFF,
2838
+ review: QUICK_TASK_REVIEW,
2839
+ fix: QUICK_TASK_FIX
2840
+ },
2841
+ reviewMode: "acceptance-review",
2842
+ evaluatorPromptKey: "review-loop",
2843
+ artifactOut: { kind: "commit-range" },
2844
+ anchorCommitBaseOnEntry: true,
2845
+ renderFixTemplateOnFindings: true
2846
+ }
2847
+ ]
2848
+ };
2808
2849
  function withOperatorControl(def) {
2809
2850
  return {
2810
2851
  ...def,
@@ -2820,7 +2861,8 @@ var REGISTRY = {
2820
2861
  [SPEC_DRIVEN_DEVELOPMENT.type]: withOperatorControl(SPEC_DRIVEN_DEVELOPMENT),
2821
2862
  [RALPH_LOOP.type]: withOperatorControl(RALPH_LOOP),
2822
2863
  [COMPLEX_BUG_FIXING.type]: withOperatorControl(COMPLEX_BUG_FIXING),
2823
- [DELIBERATION.type]: withOperatorControl(DELIBERATION)
2864
+ [DELIBERATION.type]: withOperatorControl(DELIBERATION),
2865
+ [QUICK_TASK.type]: withOperatorControl(QUICK_TASK)
2824
2866
  };
2825
2867
  function ralphRunDir(workspaceRoot, workflowId) {
2826
2868
  return join(workspaceRoot, ".ai-whisper", "ralph", workflowId);
@@ -2890,7 +2890,7 @@ function derivePlanPath(specPath, dateIso) {
2890
2890
  const date = dateIso.slice(0, 10);
2891
2891
  return `docs/superpowers/plans/${date}-${slug}.md`;
2892
2892
  }
2893
- var RALPH_ITEM_DELIVERED_MARKER, RALPH_GOAL_COMPLETE_MARKER, WORKFLOW_REVIEW_PROTOCOL, WORKFLOW_OPERATOR_CONTROL, WORKFLOW_DIAGNOSIS_PROTOCOL, WORKFLOW_DELIBERATION_PROTOCOL, CODE_REVIEW_SKILL_GUIDANCE, PLAN_EXECUTION_SKILL_GUIDANCE, DELIBERATION_CRAFT_SKILL_GUIDANCE, SDD_SPEC_REVIEW, SDD_CODE_REVIEW, SDD_PLAN_EXECUTION, SPEC_DRIVEN_DEVELOPMENT, RALPH_KICKOFF, RALPH_FIX, RALPH_ITEM_REVIEW, RALPH_ACCEPTANCE_REVIEW, RALPH_LOOP, BUGFIX_DIAGNOSIS_KICKOFF, BUGFIX_DIAGNOSIS_REVIEW, BUGFIX_DIAGNOSIS_FIX, BUGFIX_FIX_KICKOFF, BUGFIX_FIX_REVIEW, BUGFIX_FIX_FIX, BUGFIX_POSTMORTEM_KICKOFF, BUGFIX_POSTMORTEM_REVIEW, BUGFIX_POSTMORTEM_FIX, COMPLEX_BUG_FIXING, DELIB_REVIEW, DELIB_SYNTHESIS_REVIEW, DELIB_FIX, DELIB_OBJECTIVES, DELIB_APPROACHES, DELIB_TRADEOFFS, DELIB_SYNTHESIS_FIX, DELIB_SYNTHESIS, DELIBERATION, REGISTRY;
2893
+ var RALPH_ITEM_DELIVERED_MARKER, RALPH_GOAL_COMPLETE_MARKER, WORKFLOW_REVIEW_PROTOCOL, WORKFLOW_OPERATOR_CONTROL, WORKFLOW_DIAGNOSIS_PROTOCOL, WORKFLOW_DELIBERATION_PROTOCOL, CODE_REVIEW_SKILL_GUIDANCE, PLAN_EXECUTION_SKILL_GUIDANCE, DELIBERATION_CRAFT_SKILL_GUIDANCE, SDD_SPEC_REVIEW, SDD_CODE_REVIEW, SDD_PLAN_EXECUTION, SPEC_DRIVEN_DEVELOPMENT, RALPH_KICKOFF, RALPH_FIX, RALPH_ITEM_REVIEW, RALPH_ACCEPTANCE_REVIEW, RALPH_LOOP, BUGFIX_DIAGNOSIS_KICKOFF, BUGFIX_DIAGNOSIS_REVIEW, BUGFIX_DIAGNOSIS_FIX, BUGFIX_FIX_KICKOFF, BUGFIX_FIX_REVIEW, BUGFIX_FIX_FIX, BUGFIX_POSTMORTEM_KICKOFF, BUGFIX_POSTMORTEM_REVIEW, BUGFIX_POSTMORTEM_FIX, COMPLEX_BUG_FIXING, DELIB_REVIEW, DELIB_SYNTHESIS_REVIEW, DELIB_FIX, DELIB_OBJECTIVES, DELIB_APPROACHES, DELIB_TRADEOFFS, DELIB_SYNTHESIS_FIX, DELIB_SYNTHESIS, DELIBERATION, QUICK_TASK_KICKOFF, QUICK_TASK_REVIEW, QUICK_TASK_FIX, QUICK_TASK, REGISTRY;
2894
2894
  var init_workflow_registry = __esm({
2895
2895
  "../broker/dist/runtime/workflow-registry.js"() {
2896
2896
  "use strict";
@@ -3344,11 +3344,53 @@ ${DELIBERATION_CRAFT_SKILL_GUIDANCE}End your handback with a 1-2 sentence summar
3344
3344
  }
3345
3345
  ]
3346
3346
  };
3347
+ QUICK_TASK_KICKOFF = `You are the implementer in an autonomous quick-task workflow. No human is in the loop \u2014 never ask for confirmation, permission, or clarification; do the work yourself.
3348
+
3349
+ Read the task brief at {specPath}. It was written after a human approved the approach \u2014 treat it as the ratified contract: implement the "Approved approach" section as written; do NOT redesign it.
3350
+
3351
+ 1. The files under "Scope" are the declared blast radius. Implement the task, add or adjust the tests the brief's "Acceptance checks" imply, run the project's verification command and ensure it passes.
3352
+ 2. Commit your changes (do NOT commit the task brief; .ai-whisper/ is gitignored).
3353
+
3354
+ Scope guard: if the work is materially bigger than the brief \u2014 you need to touch non-test files beyond the "Scope" list, the approved approach does not survive contact with the code, or a hidden dependency/migration appears \u2014 do NOT push through. Hand back that you CANNOT PROCEED, naming what exploded; the run halts to the human, who re-scopes or escalates to spec-driven-development.
3355
+
3356
+ Hand back the commit SHAs and the verification output, plus a 1-2 sentence summary; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.`;
3357
+ QUICK_TASK_REVIEW = `The implementer claims the task in the brief at {specPath} is complete \u2014 the changes are commits {commitRange}. The upper bound is a LIVE \`HEAD\`: resolve it against the current repository at review time and INCLUDE any commits added during this review round (e.g. fixes for your prior findings); do not pin the review to an earlier tip. Verify against the brief's "Acceptance checks" and confirm the change stays inside the brief's "Scope": touching non-test files beyond the declared Scope list is a blocking finding \u2014 the implementer should have halted instead. Run the project's verification/tests yourself. This is an autonomous workflow with no human in the loop.
3358
+
3359
+ ` + CODE_REVIEW_SKILL_GUIDANCE + WORKFLOW_REVIEW_PROTOCOL;
3360
+ QUICK_TASK_FIX = "Apply the reviewer's findings to commits {commitRange} now (amend or add commits as needed). This is an autonomous workflow \u2014 no human will respond. Do the work yourself and hand back the updated commit SHAs and verification output; never ask for confirmation, permission, or clarification. End your handback with a 1-2 sentence summary of what you changed; your reply must be at least two sentences, well over 100 characters \u2014 never hand back only a single word.";
3361
+ QUICK_TASK = {
3362
+ type: "quick-task",
3363
+ displayName: "Quick Task",
3364
+ description: "Human-approved task brief \u2192 implement \u2192 acceptance review, hard-gated to small pre-scoped tasks",
3365
+ defaultImplementer: "claude",
3366
+ defaultReviewer: "codex",
3367
+ phases: [
3368
+ {
3369
+ name: "implement-and-review",
3370
+ implementerRole: "implementer",
3371
+ reviewerRole: "reviewer",
3372
+ maxRounds: 5,
3373
+ initialHandoffStep: "implement",
3374
+ kickoffTemplate: QUICK_TASK_KICKOFF,
3375
+ stepTemplates: {
3376
+ implement: QUICK_TASK_KICKOFF,
3377
+ review: QUICK_TASK_REVIEW,
3378
+ fix: QUICK_TASK_FIX
3379
+ },
3380
+ reviewMode: "acceptance-review",
3381
+ evaluatorPromptKey: "review-loop",
3382
+ artifactOut: { kind: "commit-range" },
3383
+ anchorCommitBaseOnEntry: true,
3384
+ renderFixTemplateOnFindings: true
3385
+ }
3386
+ ]
3387
+ };
3347
3388
  REGISTRY = {
3348
3389
  [SPEC_DRIVEN_DEVELOPMENT.type]: withOperatorControl(SPEC_DRIVEN_DEVELOPMENT),
3349
3390
  [RALPH_LOOP.type]: withOperatorControl(RALPH_LOOP),
3350
3391
  [COMPLEX_BUG_FIXING.type]: withOperatorControl(COMPLEX_BUG_FIXING),
3351
- [DELIBERATION.type]: withOperatorControl(DELIBERATION)
3392
+ [DELIBERATION.type]: withOperatorControl(DELIBERATION),
3393
+ [QUICK_TASK.type]: withOperatorControl(QUICK_TASK)
3352
3394
  };
3353
3395
  }
3354
3396
  });
@@ -6755,6 +6797,97 @@ var init_workflow_event_bridge = __esm({
6755
6797
  }
6756
6798
  });
6757
6799
 
6800
+ // ../broker/dist/runtime/task-brief.js
6801
+ function isTestFilePath(path4) {
6802
+ if (/(^|\/)(test|tests|__tests__)\//.test(path4))
6803
+ return true;
6804
+ const basename4 = path4.slice(path4.lastIndexOf("/") + 1);
6805
+ if (basename4.includes(".test.") || basename4.includes(".spec."))
6806
+ return true;
6807
+ if (/_test\.[^.]+$/.test(basename4))
6808
+ return true;
6809
+ return false;
6810
+ }
6811
+ function findHeadings(lines) {
6812
+ const headings = [];
6813
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
6814
+ const match = /^(#{1,6})\s(.*)$/.exec(lines[lineIndex]);
6815
+ if (match) {
6816
+ headings.push({ lineIndex, level: match[1].length, text: match[2].trim() });
6817
+ }
6818
+ }
6819
+ return headings;
6820
+ }
6821
+ function sectionBody(lines, heading, allHeadings) {
6822
+ const next = allHeadings.find((h) => h.lineIndex > heading.lineIndex);
6823
+ const end = next ? next.lineIndex : lines.length;
6824
+ return lines.slice(heading.lineIndex + 1, end);
6825
+ }
6826
+ function isNonEmptyBody(body) {
6827
+ return body.some((line) => line.trim().length > 0);
6828
+ }
6829
+ function stripEnclosingBackticks(token) {
6830
+ if (token.length >= 2 && token.startsWith("`") && token.endsWith("`")) {
6831
+ return token.slice(1, -1);
6832
+ }
6833
+ return token;
6834
+ }
6835
+ function parseScopeBullets(body) {
6836
+ const paths = [];
6837
+ for (const line of body) {
6838
+ const match = /^[-*]\s+(.+)$/.exec(line);
6839
+ if (!match)
6840
+ continue;
6841
+ const firstToken = match[1].trim().split(/\s+/)[0];
6842
+ paths.push(stripEnclosingBackticks(firstToken));
6843
+ }
6844
+ return paths;
6845
+ }
6846
+ function validateTaskBrief(content) {
6847
+ const lines = content.split(/\r?\n/);
6848
+ const headings = findHeadings(lines);
6849
+ const violations = [];
6850
+ let scopeBody = null;
6851
+ for (const { key, canonical } of REQUIRED_SECTIONS) {
6852
+ const heading = headings.find((h) => (h.level === 2 || h.level === 3) && h.text.toLowerCase() === key);
6853
+ const body = heading ? sectionBody(lines, heading, headings) : null;
6854
+ if (!heading || !isNonEmptyBody(body)) {
6855
+ violations.push(`missing or empty required section "${canonical}"`);
6856
+ continue;
6857
+ }
6858
+ if (key === "scope") {
6859
+ scopeBody = body;
6860
+ }
6861
+ }
6862
+ const scopeFiles = scopeBody ? parseScopeBullets(scopeBody) : [];
6863
+ if (scopeBody && scopeFiles.length === 0) {
6864
+ violations.push('"## Scope" must declare the files the task touches as a bullet list (one file per bullet)');
6865
+ }
6866
+ const nonTestScopeCount = scopeFiles.filter((path4) => !isTestFilePath(path4)).length;
6867
+ if (nonTestScopeCount > QUICK_TASK_SCOPE_CAP) {
6868
+ violations.push(`scope declares ${nonTestScopeCount} non-test files; the cap is ${QUICK_TASK_SCOPE_CAP}`);
6869
+ }
6870
+ return {
6871
+ ok: violations.length === 0,
6872
+ violations,
6873
+ scopeFiles,
6874
+ nonTestScopeCount
6875
+ };
6876
+ }
6877
+ var QUICK_TASK_SCOPE_CAP, REQUIRED_SECTIONS;
6878
+ var init_task_brief = __esm({
6879
+ "../broker/dist/runtime/task-brief.js"() {
6880
+ "use strict";
6881
+ QUICK_TASK_SCOPE_CAP = 5;
6882
+ REQUIRED_SECTIONS = [
6883
+ { key: "task", canonical: "## Task" },
6884
+ { key: "approved approach", canonical: "## Approved approach" },
6885
+ { key: "scope", canonical: "## Scope" },
6886
+ { key: "acceptance checks", canonical: "## Acceptance checks" }
6887
+ ];
6888
+ }
6889
+ });
6890
+
6758
6891
  // ../broker/dist/storage/repositories/workspace-repository.js
6759
6892
  function upsertWorkspace(db, input) {
6760
6893
  db.prepare(`
@@ -6824,6 +6957,7 @@ var init_dist2 = __esm({
6824
6957
  init_relay_evaluator_diagnostics_repository();
6825
6958
  init_relay_turn_event_diagnostics_repository();
6826
6959
  init_workflow_registry();
6960
+ init_task_brief();
6827
6961
  init_workspace_repository();
6828
6962
  init_session_attachment_repository();
6829
6963
  init_broker_daemon_repository();
@@ -14494,8 +14628,8 @@ function compareSemver(a, b) {
14494
14628
  var EZIO_PROVENANCE = {
14495
14629
  ezioCliVersion: "0.4.0",
14496
14630
  ezioGitSha: "77a3b48",
14497
- builtAt: "2026-07-03T06:53:50.854Z",
14498
- whisperVersion: "0.12.1"
14631
+ builtAt: "2026-07-04T05:15:42.289Z",
14632
+ whisperVersion: "0.13.0"
14499
14633
  };
14500
14634
 
14501
14635
  // src/ezio-provenance-types.ts
@@ -19220,6 +19354,7 @@ function launchSessions(input) {
19220
19354
  // src/commands/workflow/start.ts
19221
19355
  init_dist();
19222
19356
  init_dist2();
19357
+ import { readFileSync as readFileSync12 } from "node:fs";
19223
19358
  var EVALUATOR_README_HINT = 'See the README "Evaluator configuration" section for details.';
19224
19359
  async function runWorkflowStart(deps) {
19225
19360
  const daemon = getBrokerDaemonByCollab(deps.broker.db, deps.collabId);
@@ -19243,6 +19378,23 @@ async function runWorkflowStart(deps) {
19243
19378
  );
19244
19379
  }
19245
19380
  }
19381
+ if (deps.workflowType === "quick-task") {
19382
+ const read = deps.readTaskBrief ?? ((p) => readFileSync12(p, "utf8"));
19383
+ let briefContent;
19384
+ try {
19385
+ briefContent = read(deps.specPath);
19386
+ } catch {
19387
+ throw new Error(
19388
+ `Task brief not readable at ${deps.specPath}. Check the path and try again.`
19389
+ );
19390
+ }
19391
+ const brief = validateTaskBrief(briefContent);
19392
+ if (!brief.ok) {
19393
+ throw new Error(
19394
+ "Task brief failed the quick-task scope gate:\n" + brief.violations.map((v) => ` - ${v}`).join("\n") + "\nSplit the task or use spec-driven-development."
19395
+ );
19396
+ }
19397
+ }
19246
19398
  const def = getWorkflowDefinition(deps.workflowType);
19247
19399
  const boundAgents = deps.broker.control.listSessionBindings(deps.collabId).filter((b) => b.bindingState === "bound").map((b) => b.agentType).filter((t) => agentTypes.includes(t));
19248
19400
  let resolved;
@@ -19481,7 +19633,7 @@ async function runSkillInstall(input) {
19481
19633
  init_dist2();
19482
19634
 
19483
19635
  // src/runtime/cli-package-info.ts
19484
- import { readFileSync as readFileSync12 } from "node:fs";
19636
+ import { readFileSync as readFileSync13 } from "node:fs";
19485
19637
  import { dirname as dirname9 } from "node:path";
19486
19638
  import { fileURLToPath as fileURLToPath7 } from "node:url";
19487
19639
  var PKG_CANDIDATES = ["../../package.json", "../package.json"];
@@ -19489,7 +19641,7 @@ function readWhisperPackage() {
19489
19641
  for (const rel of PKG_CANDIDATES) {
19490
19642
  try {
19491
19643
  const url = new URL(rel, import.meta.url);
19492
- const pkg = JSON.parse(readFileSync12(url, "utf8"));
19644
+ const pkg = JSON.parse(readFileSync13(url, "utf8"));
19493
19645
  if (pkg.name === "ai-whisper" && typeof pkg.version === "string") {
19494
19646
  return { url, version: pkg.version };
19495
19647
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-whisper",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "description": "Terminal-first relay for paired AI coding agents (Claude + Codex), driven by structured workflows.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -53,12 +53,12 @@
53
53
  "@types/react": "^19.2.14",
54
54
  "ink-testing-library": "^4.0.0",
55
55
  "@ai-whisper/adapter-ai-ezio": "0.0.0",
56
- "@ai-whisper/adapter-antigravity": "0.0.0",
56
+ "@ai-whisper/adapter-claude": "0.0.0",
57
57
  "@ai-whisper/adapter-codex": "0.0.0",
58
- "@ai-whisper/companion-core": "0.0.0",
58
+ "@ai-whisper/adapter-antigravity": "0.0.0",
59
59
  "@ai-whisper/broker": "0.0.0",
60
- "@ai-whisper/adapter-claude": "0.0.0",
61
- "@ai-whisper/shared": "0.0.0"
60
+ "@ai-whisper/shared": "0.0.0",
61
+ "@ai-whisper/companion-core": "0.0.0"
62
62
  },
63
63
  "files": [
64
64
  "dist",
@@ -46,7 +46,8 @@ Parse the JSON. The expected shape is:
46
46
  "agents": [
47
47
  { "agentType": "codex", "bindingState": "bound" | "pending_attach" | "unbound" | null },
48
48
  { "agentType": "claude", "bindingState": "bound" | "pending_attach" | "unbound" | null },
49
- { "agentType": "ezio", "bindingState": "bound" | "pending_attach" | "unbound" | null }
49
+ { "agentType": "ezio", "bindingState": "bound" | "pending_attach" | "unbound" | null },
50
+ { "agentType": "agy", "bindingState": "bound" | "pending_attach" | "unbound" | null }
50
51
  ],
51
52
  "recovery": { "state": "normal" | "recovery_required" | "recovered" },
52
53
  "evaluator": { "ready": true | false, "status": "ready" | "missing_anthropic_key" | "invalid_config" | "disabled" | "unknown" }
@@ -57,17 +58,17 @@ Required for readiness:
57
58
  - `daemon !== null`
58
59
  - `status === "active"`
59
60
  - `recovery.state === "normal"`
60
- - **EXACTLY TWO agents bound** — among `codex`, `claude`, and `ezio`, exactly two
61
- must have `bindingState === "bound"` (the implementer + reviewer pair). **`ezio`
62
- is a replacement role**: it stands in for `codex` or `claude`, so do NOT require
63
- `codex` and `claude` specifically. A pair of `ezio` + `claude`, `ezio` + `codex`,
64
- or `codex` + `claude` all pass. (The displaced slot reads `null`/`unbound` and
65
- that is expected when `ezio` replaces it.)
61
+ - **EXACTLY TWO agents bound** — among the supported agent types (`codex`, `claude`,
62
+ `ezio`, `agy`), exactly two must have `bindingState === "bound"` (the implementer +
63
+ reviewer pair). **`ezio` and `agy` are replacement roles**: either stands in for
64
+ `codex` or `claude`, so do NOT require `codex` and `claude` specifically — any
65
+ pair of two distinct supported agents passes. (The displaced slots read `null`/`unbound`
66
+ and that is expected when a replacement agent takes a seat.)
66
67
  - `evaluator.status` is NOT `"missing_anthropic_key"` or `"invalid_config"` (i.e., `ready`, `disabled`, and `unknown` all pass this gate; only the two true-misconfiguration statuses block)
67
68
 
68
69
  If the JSON has `{ "error": "no_collab_for_cwd", ... }`:
69
70
 
70
- > No collab found in this workspace. Mount any **two** agents (e.g. `whisper collab mount ezio` in one terminal and `whisper collab mount codex` — or `claude` — in another), then re-run this skill.
71
+ > No collab found in this workspace. Mount any **two** agents (e.g. `whisper collab mount ezio` in one terminal and `whisper collab mount codex` — or `claude` / `agy` — in another), then re-run this skill.
71
72
 
72
73
  If `recovery.state === "recovery_required"`:
73
74
 
@@ -75,14 +76,14 @@ If `recovery.state === "recovery_required"`:
75
76
 
76
77
  If `recovery.state === "recovered"`:
77
78
 
78
- > The collab has been recovered and still needs reconnect. Run `whisper collab reconnect codex` and `whisper collab reconnect claude`, then re-run this skill.
79
+ > The collab has been recovered and still needs reconnect. Run `whisper collab reconnect <agent>` for each bound agent, then re-run this skill.
79
80
 
80
81
  If FEWER than two agents are bound (count `bindingState === "bound"` across
81
- `codex`/`claude`/`ezio`):
82
+ the supported agent types):
82
83
 
83
84
  > Only <N> agent(s) bound (<list bound agentTypes>). A workflow needs two — an
84
- > implementer and a reviewer. Mount another agent (`whisper collab mount <codex|claude|ezio>`)
85
- > in a separate terminal, then re-run this skill. `ezio` may replace `codex` or `claude`.
85
+ > implementer and a reviewer. Mount another agent (`whisper collab mount <codex|claude|ezio|agy>`)
86
+ > in a separate terminal, then re-run this skill. `ezio` or `agy` may replace `codex` or `claude`.
86
87
 
87
88
  (Do NOT append permission flags — mount already spawns the agent in full-permission mode; passing `--dangerously-skip-permissions` / `--dangerously-bypass-approvals-and-sandbox` again can crash the agent on a duplicate-argument error.)
88
89
 
@@ -50,7 +50,8 @@ Parse the JSON. The expected shape is:
50
50
  "agents": [
51
51
  { "agentType": "codex", "bindingState": "bound" | "pending_attach" | "unbound" | null },
52
52
  { "agentType": "claude", "bindingState": "bound" | "pending_attach" | "unbound" | null },
53
- { "agentType": "ezio", "bindingState": "bound" | "pending_attach" | "unbound" | null }
53
+ { "agentType": "ezio", "bindingState": "bound" | "pending_attach" | "unbound" | null },
54
+ { "agentType": "agy", "bindingState": "bound" | "pending_attach" | "unbound" | null }
54
55
  ],
55
56
  "recovery": { "state": "normal" | "recovery_required" | "recovered" },
56
57
  "evaluator": { "ready": true | false, "status": "ready" | "missing_anthropic_key" | "invalid_config" | "disabled" | "unknown" }
@@ -61,17 +62,17 @@ Required for readiness:
61
62
  - `daemon !== null`
62
63
  - `status === "active"`
63
64
  - `recovery.state === "normal"`
64
- - **EXACTLY TWO agents bound** — among `codex`, `claude`, and `ezio`, exactly two
65
- must have `bindingState === "bound"` (the implementer + reviewer pair). **`ezio`
66
- is a replacement role**: it stands in for `codex` or `claude`, so do NOT require
67
- `codex` and `claude` specifically. A pair of `ezio` + `claude`, `ezio` + `codex`,
68
- or `codex` + `claude` all pass. (The displaced slot reads `null`/`unbound` and
69
- that is expected when `ezio` replaces it.)
65
+ - **EXACTLY TWO agents bound** — among the supported agent types (`codex`, `claude`,
66
+ `ezio`, `agy`), exactly two must have `bindingState === "bound"` (the implementer +
67
+ reviewer pair). **`ezio` and `agy` are replacement roles**: either stands in for
68
+ `codex` or `claude`, so do NOT require `codex` and `claude` specifically — any
69
+ pair of two distinct supported agents passes. (The displaced slots read `null`/`unbound`
70
+ and that is expected when a replacement agent takes a seat.)
70
71
  - `evaluator.status` is NOT `"missing_anthropic_key"` or `"invalid_config"` (i.e., `ready`, `disabled`, and `unknown` all pass this gate; only the two true-misconfiguration statuses block)
71
72
 
72
73
  If the JSON has `{ "error": "no_collab_for_cwd", ... }`:
73
74
 
74
- > No collab found in this workspace. Mount any **two** agents (e.g. `whisper collab mount ezio` in one terminal and `whisper collab mount codex` — or `claude` — in another), then re-run this skill.
75
+ > No collab found in this workspace. Mount any **two** agents (e.g. `whisper collab mount ezio` in one terminal and `whisper collab mount codex` — or `claude` / `agy` — in another), then re-run this skill.
75
76
 
76
77
  If `recovery.state === "recovery_required"`:
77
78
 
@@ -79,14 +80,14 @@ If `recovery.state === "recovery_required"`:
79
80
 
80
81
  If `recovery.state === "recovered"`:
81
82
 
82
- > The collab has been recovered and still needs reconnect. Run `whisper collab reconnect codex` and `whisper collab reconnect claude`, then re-run this skill.
83
+ > The collab has been recovered and still needs reconnect. Run `whisper collab reconnect <agent>` for each bound agent, then re-run this skill.
83
84
 
84
85
  If FEWER than two agents are bound (count `bindingState === "bound"` across
85
- `codex`/`claude`/`ezio`):
86
+ the supported agent types):
86
87
 
87
88
  > Only <N> agent(s) bound (<list bound agentTypes>). A workflow needs two — an
88
- > implementer and a reviewer. Mount another agent (`whisper collab mount <codex|claude|ezio>`)
89
- > in a separate terminal, then re-run this skill. `ezio` may replace `codex` or `claude`.
89
+ > implementer and a reviewer. Mount another agent (`whisper collab mount <codex|claude|ezio|agy>`)
90
+ > in a separate terminal, then re-run this skill. `ezio` or `agy` may replace `codex` or `claude`.
90
91
 
91
92
  (Do NOT append permission flags — mount already spawns the agent in full-permission mode; passing `--dangerously-skip-permissions` / `--dangerously-bypass-approvals-and-sandbox` again can crash the agent on a duplicate-argument error.)
92
93
 
@@ -45,7 +45,7 @@ Read the plan once; extract every task with its full text. Then:
45
45
 
46
46
  Invariants: **reviewer tier ≥ implementer tier, always.** On the **2nd failed review of the same task**, bump the task implementer one tier and pass the failure history into the new dispatch.
47
47
 
48
- ## Path B — no subagent dispatch (e.g. Codex, ezio)
48
+ ## Path B — no subagent dispatch (e.g. Codex, ezio, agy)
49
49
 
50
50
  Execute the plan inline: task-by-task in plan order, run per-task verification, commit as the plan specifies, and hand back per the workflow prompt with the mode line `Execution mode: inline (no subagent dispatch)`. Path A does not apply to you — nothing in this skill blocks or changes your handback.
51
51
 
@@ -0,0 +1,215 @@
1
+ ---
2
+ name: ai-whisper-quick-task
3
+ description: Kick off the quick-task workflow on a small, already-approved unit of work. Use when the user says things like "run quick task on <path or task>", "kick off quick-task with <path or task>", "/aiw-quick-task <path or task>", "$aiw-quick-task <path or task>", or otherwise asks to start the quick-task workflow on a small, ready-to-execute task.
4
+ ---
5
+
6
+ # ai-whisper-quick-task
7
+
8
+ Kick off the ai-whisper quick-task workflow on a small, already-approved unit of work. This skill is fire-and-forget: it verifies the collab is ready, runs `whisper workflow start`, and exits. **Do NOT continue polling or narrating after kickoff** — continuous activity from the calling agent keeps it busy, which blocks the broker's idle detection and stalls the workflow. The dashboard (`whisper collab dashboard`) is the inspection surface during the run.
9
+
10
+ Unlike `ai-whisper-sdd`, which kicks off against a spec someone already wrote, this skill also **writes the task brief itself** (Steps 1–2) from an approach approved earlier in the conversation.
11
+
12
+ ## When to invoke
13
+
14
+ Match phrases like:
15
+ - *"run quick task on docs/notes.md"* / *"kick off quick-task with @docs/notes.md"*
16
+ - *"run quick task: fix the off-by-one in the pagination helper"* (task described inline, no file yet)
17
+ - *"/aiw-quick-task docs/notes.md"* (Claude picker form)
18
+ - *"$aiw-quick-task docs/notes.md"* (Codex picker form)
19
+
20
+ If the user references the task ambiguously and no approach has been discussed yet, that's fine — proceed to Step 1 and work it out there. Do not guess at scope or approach.
21
+
22
+ ## Steps
23
+
24
+ ### 1. Executability pre-check
25
+
26
+ Quick-task is for work that is executable right away — a small, scoped change to a codebase you already understand, with an approach already agreed. Before doing anything else, check whether the task actually needs:
27
+ - **research** — unknowns that require investigation before a design is even possible,
28
+ - **unsettled design decisions** — multiple viable approaches not yet chosen between, or
29
+ - **schema/contract migrations** — breaking changes to a shared data shape, API, or wire format.
30
+
31
+ If any of these apply, REFUSE this workflow and recommend spec-driven-development (or deliberation first, if the idea itself still needs sharpening):
32
+
33
+ > This needs more upfront design than quick-task is for. I'd recommend spec-driven-development instead — write a spec and kick off SDD (or run deliberation first if the idea needs sharpening).
34
+
35
+ If the approach was never explicitly approved by the user in this conversation, ask ONCE for approval before proceeding:
36
+
37
+ > Before I kick off quick-task: here's the approach I'd take — <approach>. Approve it and I'll write the brief and start the workflow.
38
+
39
+ Never invent an approach and kick off in the same breath. The human approves the approach in chat; the workflow's implementer must not redesign it.
40
+
41
+ ### 2. Write or resolve the brief
42
+
43
+ If the user gave a path to an existing brief, resolve it to an absolute path and verify it's a readable file via the Read tool. If not readable:
44
+
45
+ > Task brief `<path>` is not readable. Check the path and try again.
46
+
47
+ Otherwise, write the brief yourself from the approach approved in Step 1. Create the `.ai-whisper/tasks/` directory first if it doesn't already exist, and make sure `.ai-whisper/` is gitignored — this workflow has no broker setup step to do it for you, so do it here (create only if absent; never clobber an existing file):
48
+
49
+ ```bash
50
+ mkdir -p .ai-whisper/tasks
51
+ [ -f .ai-whisper/.gitignore ] || printf '*\n' > .ai-whisper/.gitignore
52
+ ```
53
+
54
+ Then write the brief to `.ai-whisper/tasks/<YYYY-MM-DD>-<slug>.md` (slug derived from the task title, kebab-case).
55
+
56
+ Embed this template VERBATIM:
57
+
58
+ ```markdown
59
+ # Task: <short title>
60
+
61
+ ## Task
62
+ <what + why, 2–5 lines>
63
+
64
+ ## Approved approach
65
+ <the approach the human approved in chat — the implementer must not redesign it>
66
+
67
+ ## Scope
68
+ - `path/to/file-a.ts`
69
+ - `path/to/file-b.ts`
70
+ - `test/file-a.test.ts`
71
+
72
+ ## Acceptance checks
73
+ - <how the reviewer verifies: commands to run, expected behavior>
74
+ ```
75
+
76
+ `whisper workflow start` enforces a hard gate on this brief: all four sections above (`## Task`, `## Approved approach`, `## Scope`, `## Acceptance checks`) are required and must be non-empty; `## Scope` must list every file the task touches, one bullet per file; and at most 5 non-test files (test files are uncounted).
77
+
78
+ ### 3. Verify collab readiness
79
+
80
+ Run:
81
+
82
+ ```bash
83
+ whisper collab status --json
84
+ ```
85
+
86
+ Parse the JSON. The expected shape is:
87
+
88
+ ```json
89
+ {
90
+ "collabId": "collab_xyz",
91
+ "workspaceRoot": "/path",
92
+ "status": "active",
93
+ "daemon": { "host": "127.0.0.1", "port": 4311, "pid": 12345 },
94
+ "agents": [
95
+ { "agentType": "codex", "bindingState": "bound" | "pending_attach" | "unbound" | null },
96
+ { "agentType": "claude", "bindingState": "bound" | "pending_attach" | "unbound" | null },
97
+ { "agentType": "ezio", "bindingState": "bound" | "pending_attach" | "unbound" | null },
98
+ { "agentType": "agy", "bindingState": "bound" | "pending_attach" | "unbound" | null }
99
+ ],
100
+ "recovery": { "state": "normal" | "recovery_required" | "recovered" },
101
+ "evaluator": { "ready": true | false, "status": "ready" | "missing_anthropic_key" | "invalid_config" | "disabled" | "unknown" }
102
+ }
103
+ ```
104
+
105
+ Required for readiness:
106
+ - `daemon !== null`
107
+ - `status === "active"`
108
+ - `recovery.state === "normal"`
109
+ - **EXACTLY TWO agents bound** — among the supported agent types (`codex`, `claude`,
110
+ `ezio`, `agy`), exactly two must have `bindingState === "bound"` (the implementer +
111
+ reviewer pair). **`ezio` and `agy` are replacement roles**: either stands in for
112
+ `codex` or `claude`, so do NOT require `codex` and `claude` specifically — any
113
+ pair of two distinct supported agents passes. (The `agents` array may list all
114
+ supported types; the displaced slots read `null`/`unbound` and that is expected
115
+ when a replacement agent takes a seat.)
116
+ - `evaluator.status` is NOT `"missing_anthropic_key"` or `"invalid_config"` (i.e., `ready`, `disabled`, and `unknown` all pass this gate; only the two true-misconfiguration statuses block)
117
+
118
+ If the JSON has `{ "error": "no_collab_for_cwd", ... }`:
119
+
120
+ > No collab found in this workspace. Mount any **two** agents (e.g. `whisper collab mount ezio` in one terminal and `whisper collab mount codex` — or `claude` / `agy` — in another), then re-run this skill.
121
+
122
+ If `recovery.state === "recovery_required"`:
123
+
124
+ > The collab is in recovery_required state. Run `whisper collab recover`, then re-run this skill.
125
+
126
+ If `recovery.state === "recovered"`:
127
+
128
+ > The collab has been recovered and still needs reconnect. Run `whisper collab reconnect <agent>` for each bound agent, then re-run this skill.
129
+
130
+ If FEWER than two agents are bound (count `bindingState === "bound"` across
131
+ the supported agent types):
132
+
133
+ > Only <N> agent(s) bound (<list bound agentTypes>). A workflow needs two — an
134
+ > implementer and a reviewer. Mount another agent (`whisper collab mount <codex|claude|ezio|agy>`)
135
+ > in a separate terminal, then re-run this skill. `ezio` or `agy` may replace `codex` or `claude`.
136
+
137
+ (Do NOT append permission flags — mount already spawns the agent in full-permission mode; passing `--dangerously-skip-permissions` / `--dangerously-bypass-approvals-and-sandbox` again can crash the agent on a duplicate-argument error.)
138
+
139
+ If `evaluator.status === "missing_anthropic_key"` (i.e., `evaluator.ready === false` AND status is `missing_anthropic_key`):
140
+
141
+ > The evaluator has no Anthropic API key. Create `~/.ai-whisper/auth.json` with `{ "ANTHROPIC_API_KEY": "sk-ant-..." }` (chmod 600), then restart the daemon (`whisper collab stop` and re-mount, or restart the broker), and re-run this skill. See the README "Evaluator configuration" section.
142
+
143
+ If `evaluator.status === "invalid_config"` (i.e., `evaluator.ready === false` AND status is `invalid_config`):
144
+
145
+ > The evaluator config is malformed. Fix the JSON in `~/.ai-whisper/auth.json` or `~/.ai-whisper/config.json`, then restart the daemon and re-run this skill. See the README "Evaluator configuration" section.
146
+
147
+ If `evaluator.status === "disabled"`: this means the orchestrator is intentionally off — it is NOT a misconfiguration and does NOT block this skill gate. Proceed to step 4; `workflow start` will surface the orchestrator-disabled error itself.
148
+
149
+ (Note: `evaluator.ready` is `false` for `missing_anthropic_key`, `invalid_config`, AND `disabled`; it is `true` only for `ready` and `unknown`. That's why this gate keys off `status` rather than `ready` — so `disabled` does not block the skill while the two true-misconfiguration statuses do.)
150
+
151
+ ### 4. Kick off the workflow
152
+
153
+ Run:
154
+
155
+ ```bash
156
+ whisper workflow start --type=quick-task --spec=<resolved-absolute-path>
157
+ ```
158
+
159
+ (No `--implementer` / `--reviewer` needed — the agent triggering this skill becomes the implementer and the other agent the reviewer. Pass `--implementer <agent> --reviewer <agent>` only to override.)
160
+
161
+ If the scope gate rejects the brief, `whisper workflow start` exits non-zero and prints every violation together. Relay these violations to the user VERBATIM and STOP — do NOT silently rewrite or shrink the `## Scope` list to squeeze under the cap. The user decides whether to split the task into smaller pieces or escalate to spec-driven-development.
162
+
163
+ Otherwise, parse the workflowId from stdout (format: `Workflow started: <workflowId>`).
164
+
165
+ ### 5. Report and exit
166
+
167
+ Print exactly:
168
+
169
+ > Workflow `<workflowId>` started. Track progress with `whisper collab dashboard`.
170
+
171
+ Then stop. Do NOT poll `whisper workflow inspect`. Do NOT continue narrating. The workflow runs in the broker driver; your job is done.
172
+
173
+ ## Why fire-and-forget
174
+
175
+ The broker's relay handoff system uses **idle detection** to know when an agent is ready to receive the next handoff. If this skill polled the workflow's status every few seconds, the calling agent (you) would emit output continuously, the broker would never see you as idle, and the workflow's first handoff couldn't be delivered to you — the workflow stalls. Kick off and exit; observation belongs to the dashboard.
176
+
177
+ ## Duo roleplay
178
+
179
+ The mount may have assigned you a movie-duo character for this collab session — check the `AI_WHISPER_CHARACTER` / `AI_WHISPER_CHARACTER_ROLE` env vars, or the `[ai-whisper duo]` brief injected at session start, to find out. If so, staying in character is welcome — but **conversational prose only**: chat, status updates, banter with the operator or your teammate.
180
+
181
+ Never let character flavor into code, commit messages, PR descriptions, or file contents. The reviewer/evaluator protocol output (verdict labels, approve/findings/escalate) stays protocol-exact regardless of who you're playing.
182
+
183
+ ## Resume / cancel
184
+
185
+ If the user asks to resume a halted workflow, run:
186
+
187
+ ```bash
188
+ whisper workflow resume <workflowId>
189
+ ```
190
+
191
+ If they ask to cancel:
192
+
193
+ ```bash
194
+ whisper workflow cancel <workflowId>
195
+ ```
196
+
197
+ Same fire-and-forget shape: invoke, report one line, exit.
198
+
199
+ ## Pausing the workflow (operator control)
200
+
201
+ If the user interrupts you mid-workflow and asks to pause it (e.g. "pause the workflow, I need to fix X"):
202
+
203
+ 1. Find the active workflow id: `whisper workflow list`.
204
+ 2. Run `whisper workflow pause <workflowId>`.
205
+ 3. Acknowledge and **stop working** — do not start the next change.
206
+
207
+ The operator edits artifacts while paused, then resumes:
208
+
209
+ ```bash
210
+ whisper workflow resume <workflowId> --message "what I changed and why"
211
+ ```
212
+
213
+ On resume the agents receive a notice listing the changed files plus the operator note, and must re-read those files before continuing.
214
+
215
+ Provider gotcha: the Codex CLI **exits its session** on Ctrl+C at an idle prompt (a mid-task Ctrl+C only interrupts the running task). The user typically interrupts a *busy* agent before issuing the pause instruction — do not assume Ctrl+C is a safe no-op.
@@ -46,7 +46,8 @@ Parse the JSON. The expected shape is:
46
46
  "agents": [
47
47
  { "agentType": "codex", "bindingState": "bound" | "pending_attach" | "unbound" | null },
48
48
  { "agentType": "claude", "bindingState": "bound" | "pending_attach" | "unbound" | null },
49
- { "agentType": "ezio", "bindingState": "bound" | "pending_attach" | "unbound" | null }
49
+ { "agentType": "ezio", "bindingState": "bound" | "pending_attach" | "unbound" | null },
50
+ { "agentType": "agy", "bindingState": "bound" | "pending_attach" | "unbound" | null }
50
51
  ],
51
52
  "recovery": { "state": "normal" | "recovery_required" | "recovered" },
52
53
  "evaluator": { "ready": true | false, "status": "ready" | "missing_anthropic_key" | "invalid_config" | "disabled" | "unknown" }
@@ -57,17 +58,17 @@ Required for readiness:
57
58
  - `daemon !== null`
58
59
  - `status === "active"`
59
60
  - `recovery.state === "normal"`
60
- - **EXACTLY TWO agents bound** — among `codex`, `claude`, and `ezio`, exactly two
61
- must have `bindingState === "bound"` (the implementer + reviewer pair). **`ezio`
62
- is a replacement role**: it stands in for `codex` or `claude`, so do NOT require
63
- `codex` and `claude` specifically. A pair of `ezio` + `claude`, `ezio` + `codex`,
64
- or `codex` + `claude` all pass. (The displaced slot reads `null`/`unbound` and
65
- that is expected when `ezio` replaces it.)
61
+ - **EXACTLY TWO agents bound** — among the supported agent types (`codex`, `claude`,
62
+ `ezio`, `agy`), exactly two must have `bindingState === "bound"` (the implementer +
63
+ reviewer pair). **`ezio` and `agy` are replacement roles**: either stands in for
64
+ `codex` or `claude`, so do NOT require `codex` and `claude` specifically — any
65
+ pair of two distinct supported agents passes. (The displaced slots read `null`/`unbound`
66
+ and that is expected when a replacement agent takes a seat.)
66
67
  - `evaluator.status` is NOT `"missing_anthropic_key"` or `"invalid_config"` (i.e., `ready`, `disabled`, and `unknown` all pass this gate; only the two true-misconfiguration statuses block)
67
68
 
68
69
  If the JSON has `{ "error": "no_collab_for_cwd", ... }`:
69
70
 
70
- > No collab found in this workspace. Mount any **two** agents (e.g. `whisper collab mount ezio` in one terminal and `whisper collab mount codex` — or `claude` — in another), then re-run this skill.
71
+ > No collab found in this workspace. Mount any **two** agents (e.g. `whisper collab mount ezio` in one terminal and `whisper collab mount codex` — or `claude` / `agy` — in another), then re-run this skill.
71
72
 
72
73
  If `recovery.state === "recovery_required"`:
73
74
 
@@ -75,14 +76,14 @@ If `recovery.state === "recovery_required"`:
75
76
 
76
77
  If `recovery.state === "recovered"`:
77
78
 
78
- > The collab has been recovered and still needs reconnect. Run `whisper collab reconnect codex` and `whisper collab reconnect claude`, then re-run this skill.
79
+ > The collab has been recovered and still needs reconnect. Run `whisper collab reconnect <agent>` for each bound agent, then re-run this skill.
79
80
 
80
81
  If FEWER than two agents are bound (count `bindingState === "bound"` across
81
- `codex`/`claude`/`ezio`):
82
+ the supported agent types):
82
83
 
83
84
  > Only <N> agent(s) bound (<list bound agentTypes>). A workflow needs two — an
84
- > implementer and a reviewer. Mount another agent (`whisper collab mount <codex|claude|ezio>`)
85
- > in a separate terminal, then re-run this skill. `ezio` may replace `codex` or `claude`.
85
+ > implementer and a reviewer. Mount another agent (`whisper collab mount <codex|claude|ezio|agy>`)
86
+ > in a separate terminal, then re-run this skill. `ezio` or `agy` may replace `codex` or `claude`.
86
87
 
87
88
  (Do NOT append permission flags — mount already spawns the agent in full-permission mode; passing `--dangerously-skip-permissions` / `--dangerously-bypass-approvals-and-sandbox` again can crash the agent on a duplicate-argument error.)
88
89
 
@@ -43,7 +43,8 @@ Parse the JSON. The expected shape is:
43
43
  "agents": [
44
44
  { "agentType": "codex", "bindingState": "bound" | "pending_attach" | "unbound" | null },
45
45
  { "agentType": "claude", "bindingState": "bound" | "pending_attach" | "unbound" | null },
46
- { "agentType": "ezio", "bindingState": "bound" | "pending_attach" | "unbound" | null }
46
+ { "agentType": "ezio", "bindingState": "bound" | "pending_attach" | "unbound" | null },
47
+ { "agentType": "agy", "bindingState": "bound" | "pending_attach" | "unbound" | null }
47
48
  ],
48
49
  "recovery": { "state": "normal" | "recovery_required" | "recovered" },
49
50
  "evaluator": { "ready": true | false, "status": "ready" | "missing_anthropic_key" | "invalid_config" | "disabled" | "unknown" }
@@ -54,18 +55,18 @@ Required for readiness:
54
55
  - `daemon !== null`
55
56
  - `status === "active"`
56
57
  - `recovery.state === "normal"`
57
- - **EXACTLY TWO agents bound** — among `codex`, `claude`, and `ezio`, exactly two
58
- must have `bindingState === "bound"` (the implementer + reviewer pair). **`ezio`
59
- is a replacement role**: it stands in for `codex` or `claude`, so do NOT require
60
- `codex` and `claude` specifically. A pair of `ezio` + `claude`, `ezio` + `codex`,
61
- or `codex` + `claude` all pass. (The `agents` array may list all three types;
62
- the displaced slot reads `null`/`unbound` and that is expected when `ezio`
63
- replaces it.)
58
+ - **EXACTLY TWO agents bound** — among the supported agent types (`codex`, `claude`,
59
+ `ezio`, `agy`), exactly two must have `bindingState === "bound"` (the implementer +
60
+ reviewer pair). **`ezio` and `agy` are replacement roles**: either stands in for
61
+ `codex` or `claude`, so do NOT require `codex` and `claude` specifically — any
62
+ pair of two distinct supported agents passes. (The `agents` array may list all
63
+ supported types; the displaced slots read `null`/`unbound` and that is expected
64
+ when a replacement agent takes a seat.)
64
65
  - `evaluator.status` is NOT `"missing_anthropic_key"` or `"invalid_config"` (i.e., `ready`, `disabled`, and `unknown` all pass this gate; only the two true-misconfiguration statuses block)
65
66
 
66
67
  If the JSON has `{ "error": "no_collab_for_cwd", ... }`:
67
68
 
68
- > No collab found in this workspace. Mount any **two** agents (e.g. `whisper collab mount ezio` in one terminal and `whisper collab mount codex` — or `claude` — in another), then re-run this skill.
69
+ > No collab found in this workspace. Mount any **two** agents (e.g. `whisper collab mount ezio` in one terminal and `whisper collab mount codex` — or `claude` / `agy` — in another), then re-run this skill.
69
70
 
70
71
  If `recovery.state === "recovery_required"`:
71
72
 
@@ -73,14 +74,14 @@ If `recovery.state === "recovery_required"`:
73
74
 
74
75
  If `recovery.state === "recovered"`:
75
76
 
76
- > The collab has been recovered and still needs reconnect. Run `whisper collab reconnect codex` and `whisper collab reconnect claude`, then re-run this skill.
77
+ > The collab has been recovered and still needs reconnect. Run `whisper collab reconnect <agent>` for each bound agent, then re-run this skill.
77
78
 
78
79
  If FEWER than two agents are bound (count `bindingState === "bound"` across
79
- `codex`/`claude`/`ezio`):
80
+ the supported agent types):
80
81
 
81
82
  > Only <N> agent(s) bound (<list bound agentTypes>). A workflow needs two — an
82
- > implementer and a reviewer. Mount another agent (`whisper collab mount <codex|claude|ezio>`)
83
- > in a separate terminal, then re-run this skill. `ezio` may replace `codex` or `claude`.
83
+ > implementer and a reviewer. Mount another agent (`whisper collab mount <codex|claude|ezio|agy>`)
84
+ > in a separate terminal, then re-run this skill. `ezio` or `agy` may replace `codex` or `claude`.
84
85
 
85
86
  (Do NOT append permission flags — mount already spawns the agent in full-permission mode; passing `--dangerously-skip-permissions` / `--dangerously-bypass-approvals-and-sandbox` again can crash the agent on a duplicate-argument error.)
86
87