groove-dev 0.26.20 → 0.26.22

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.
@@ -75,8 +75,14 @@ export class Introducer {
75
75
  lines.push('');
76
76
  lines.push(`## Coordination Rules`);
77
77
  lines.push('');
78
- lines.push(`- Stay within your file scope. Do NOT modify files owned by other agents.`);
79
- lines.push(`- If you need changes outside your scope, document what you need GROOVE will coordinate.`);
78
+ lines.push(`- Stay within your file scope when other agents are actively running.`);
79
+ lines.push(`- If you are the ONLY active agent, you may edit files outside your scope if needed to complete your task.`);
80
+ lines.push(`- If you need another agent to make changes (e.g., you're a frontend agent and need backend API changes):`);
81
+ lines.push(` Write a handoff file to .groove/handoffs/<role>.md (e.g., .groove/handoffs/backend.md) with:`);
82
+ lines.push(` - What needs to change and why`);
83
+ lines.push(` - Which files to modify`);
84
+ lines.push(` - Expected behavior after the change`);
85
+ lines.push(` GROOVE will automatically wake the target agent and deliver your request.`);
80
86
  lines.push(`- Check AGENTS_REGISTRY.md for the latest team state.`);
81
87
 
82
88
  // Project files section — tell the new agent what exists and what to read
@@ -2,7 +2,7 @@
2
2
  // FSL-1.1-Apache-2.0 — see LICENSE
3
3
 
4
4
  import { spawn as cpSpawn } from 'child_process';
5
- import { createWriteStream, mkdirSync, chmodSync, existsSync, readFileSync, unlinkSync } from 'fs';
5
+ import { createWriteStream, mkdirSync, chmodSync, existsSync, readFileSync, unlinkSync, readdirSync } from 'fs';
6
6
  import { resolve } from 'path';
7
7
  import { getProvider, getInstalledProviders } from './providers/index.js';
8
8
  import { AgentLoop } from './agent-loop.js';
@@ -76,27 +76,28 @@ For best results, apply a slide deck skill from the Marketplace. The skill provi
76
76
  Do NOT write code unless explicitly asked. Use your MCP tools to interact with Home Assistant.
77
77
 
78
78
  `,
79
- planner: `You are a PLANNING ONLY agent. You create plans. You do NOT write code, edit files, or run commands.
79
+ planner: `You are a PLANNING ONLY agent. You create plans and route work to your team. You do NOT write code, edit files, or run commands.
80
80
 
81
81
  ABSOLUTE RULE: Never use the Edit, Write, or Bash tools to modify source code. You ONLY use Read, Glob, and Grep to understand the codebase, then output a written plan. If the user says "build this" or "redesign this", create a PLAN for how other agents should build it — do NOT build it yourself.
82
82
 
83
- Focus on:
84
- - Understanding requirements
85
- - Exploring the codebase to understand current architecture
86
- - Identifying approaches and trade-offs
87
- - Writing structured plans with agent assignments
83
+ YOU HAVE TWO MODES:
88
84
 
89
- After completing your plan, you MUST do two things EVERY TIME, no exceptions:
85
+ MODE 1 TEAM CREATION (first time, no team exists yet):
86
+ Explore the codebase thoroughly, understand the architecture, then recommend a team structure.
90
87
 
91
- 1. Write your team recommendation as a clear summary in your output so the user can review it.
88
+ MODE 2 TASK ROUTING (team already exists):
89
+ Check AGENTS_REGISTRY.md or .groove/recommended-team.json to see your existing team.
90
+ Do NOT re-explore the entire codebase. You already know it from team creation.
91
+ Just read the specific files related to the bug/feature, decide which existing agent should handle it, and write the routing config. This should be FAST — under 5 tool calls.
92
92
 
93
- 2. Save a machine-readable team config to .groove/recommended-team.json using this EXACT format.
94
- ALWAYS write this file, even if the user says "no task yet" or "just building the team."
95
- For team-building without a specific task, use empty prompts ("prompt": "") the agents will wait for instructions.
93
+ HOW TO DETECT WHICH MODE:
94
+ - Read AGENTS_REGISTRY.md. If it lists agents with roles matching your team (frontend, backend, fullstack), you are in MODE 2.
95
+ - If no agents exist or only a planner exists, you are in MODE 1.
96
96
 
97
- For NEW projects (building something from scratch):
97
+ After completing your plan, you MUST write .groove/recommended-team.json — EVERY TIME, no exceptions.
98
+
99
+ For MODE 1 (team creation):
98
100
  {
99
- "projectDir": "my-project-name",
100
101
  "agents": [
101
102
  { "role": "frontend", "phase": 1, "scope": ["src/components/**", "src/views/**"], "prompt": "Build the frontend: [specific tasks]" },
102
103
  { "role": "backend", "phase": 1, "scope": ["src/api/**", "src/server/**"], "prompt": "Build the backend: [specific tasks]" },
@@ -104,35 +105,38 @@ For NEW projects (building something from scratch):
104
105
  ]
105
106
  }
106
107
 
107
- For EXISTING codebases (modifying/extending an existing project):
108
+ For MODE 2 (task routing to existing team):
109
+ Only include the agents that need to do work. Use their EXISTING role — the system will find and reuse them.
108
110
  {
109
111
  "agents": [
110
- { "role": "frontend", "phase": 1, "scope": ["src/components/**"], "prompt": "Update the frontend: [specific tasks]" },
111
- { "role": "fullstack", "phase": 2, "scope": [], "prompt": "QC Senior Dev: Audit all changes, fix issues, run tests, build, commit, and launch." }
112
+ { "role": "frontend", "phase": 1, "prompt": "Fix the bug: [specific description with file paths and what to change]" }
112
113
  ]
113
114
  }
115
+ Do NOT include QC/fullstack in the JSON for task routing — the system auto-triggers the existing QC when work completes.
116
+ Do NOT include agents that have no work to do.
117
+ Do NOT invent new agent names or roles — use the existing team's roles exactly.
118
+
119
+ For NEW projects (team creation only):
120
+ Include "projectDir" with a short kebab-case directory name. All agents spawn inside it.
121
+ For EXISTING codebases: Do NOT include "projectDir".
114
122
 
115
- PROJECT DIRECTORY RULES:
116
- - For NEW projects: ALWAYS include "projectDir" with a short, clean directory name (kebab-case, e.g. "cat-website", "landing-page", "api-service"). All agents will be spawned inside this directory so each project stays isolated.
117
- - For EXISTING codebases: Do NOT include "projectDir". Agents work in the current repo root. You can tell an existing codebase by the presence of package.json, .git, or established source directories.
118
- - NEVER mix projects. Each new project gets its own directory.
123
+ MANDATORY RULES:
119
124
 
120
- MANDATORY RULESNEVER SKIP THESE:
125
+ 1. For team creation: the LAST entry MUST be { "role": "fullstack", "phase": 2 } the QC agent.
126
+ For task routing: do NOT include the QC — it auto-triggers.
121
127
 
122
- 1. The LAST entry in the agents array MUST be: { "role": "fullstack", "phase": 2, ... }
123
- This is the QC Senior Dev. It auto-spawns after all other agents finish.
124
- Its prompt: audit changes, fix issues, run tests, build, commit, launch.
125
- NEVER omit this agent. Every team needs a QC.
128
+ 2. ALL phase 1 agents run in parallel. Do NOT tell agents to wait for each other.
126
129
 
127
- 2. ALL other agents are phase: 1 they run in parallel.
130
+ 3. If the user gave a specific task, write detailed prompts with file paths and what to change.
131
+ If no task was given, use empty prompts ("prompt": "") — agents will await instructions.
128
132
 
129
- 3. Do NOT tell any agent to "wait for" another agent. Phase 2 handles sequencing automatically.
133
+ 4. NEVER create new agent names or custom roles. Use the standard roles: frontend, backend, fullstack.
130
134
 
131
- 4. Set appropriate scopes. If the user gave a specific task, write detailed prompts. If no task was given, use empty prompts ("prompt": "") — the agents will await instructions.
135
+ 5. NEVER instruct agents to delete files from other projects or clean up unrelated code.
132
136
 
133
- 5. NEVER instruct any agent to delete files from other projects or clean up unrelated code. Each agent must ONLY create and modify files relevant to its assigned tasks.
137
+ 6. You MUST always write .groove/recommended-team.json. NEVER skip it.
134
138
 
135
- 6. You MUST always write .groove/recommended-team.json. NEVER skip it. The GUI depends on this file to show the Launch Team modal.
139
+ 7. In MODE 2, be FAST. Read only the files needed to understand the specific task. Do not re-analyze the full codebase.
136
140
 
137
141
  IMPORTANT: Do not use markdown formatting like ** or ### in your output. Write in plain text with clean formatting. Use line breaks, dashes, and indentation for structure.
138
142
 
@@ -373,10 +377,11 @@ For normal file edits within your scope, proceed without review.
373
377
  if (status === 'completed' && this.daemon.journalist) this.daemon.journalist.cycle().catch(() => {});
374
378
  this._checkPhase2(agent.id);
375
379
 
376
- // Auto-trigger idle QC in the same team
380
+ // Auto-trigger idle QC + process cross-scope handoffs
377
381
  if (status === 'completed') {
378
382
  const files = this.daemon.journalist?.getAgentFiles(agent) || [];
379
383
  if (files.length > 0) this._triggerIdleQC(agent);
384
+ this._processHandoffs(agent);
380
385
  }
381
386
  });
382
387
 
@@ -577,6 +582,8 @@ For normal file edits within your scope, proceed without review.
577
582
  if (finalStatus === 'completed') {
578
583
  const files = this.daemon.journalist?.getAgentFiles(agent) || [];
579
584
  if (files.length > 0) this._triggerIdleQC(agent);
585
+ // Process cross-scope handoff requests from this agent
586
+ this._processHandoffs(agent);
580
587
  }
581
588
  });
582
589
 
@@ -765,6 +772,61 @@ For normal file edits within your scope, proceed without review.
765
772
  });
766
773
  }
767
774
 
775
+ /**
776
+ * Process handoff files in .groove/handoffs/.
777
+ * Agents write handoff requests when they need cross-scope work from a teammate.
778
+ * File name = target role (e.g., backend.md). Content = what to do.
779
+ */
780
+ _processHandoffs(sourceAgent) {
781
+ const handoffsDir = resolve(this.daemon.grooveDir, 'handoffs');
782
+ if (!existsSync(handoffsDir)) return;
783
+
784
+ const registry = this.daemon.registry;
785
+ let files;
786
+ try { files = readdirSync(handoffsDir); } catch { return; }
787
+
788
+ for (const file of files) {
789
+ if (!file.endsWith('.md')) continue;
790
+ const targetRole = file.replace(/\.md$/, '');
791
+ const filePath = resolve(handoffsDir, file);
792
+
793
+ let content;
794
+ try { content = readFileSync(filePath, 'utf8').trim(); } catch { continue; }
795
+ if (!content) { try { unlinkSync(filePath); } catch {} continue; }
796
+
797
+ // Find the target agent in the same team
798
+ const target = registry.getAll().find((a) =>
799
+ a.role === targetRole &&
800
+ a.teamId === sourceAgent.teamId &&
801
+ a.id !== sourceAgent.id &&
802
+ (a.status === 'running' || a.status === 'completed')
803
+ );
804
+
805
+ if (!target) {
806
+ console.log(`[Groove] Handoff to ${targetRole} — no matching agent in team`);
807
+ try { unlinkSync(filePath); } catch {}
808
+ continue;
809
+ }
810
+
811
+ // Wake the target agent with the handoff request
812
+ const message = `Cross-scope handoff from ${sourceAgent.name} (${sourceAgent.role}):\n\n${content}`;
813
+ this.daemon.processes.resume(target.id, message).then((newAgent) => {
814
+ this.daemon.audit.log('handoff.routed', {
815
+ from: sourceAgent.name, to: target.name, newId: newAgent.id, role: targetRole,
816
+ });
817
+ this.daemon.broadcast({
818
+ type: 'handoff:routed',
819
+ from: sourceAgent.name, to: target.name, role: targetRole,
820
+ });
821
+ }).catch((err) => {
822
+ console.error(`[Groove] Handoff to ${targetRole} failed: ${err.message}`);
823
+ });
824
+
825
+ // Remove the handoff file
826
+ try { unlinkSync(filePath); } catch {}
827
+ }
828
+ }
829
+
768
830
  /**
769
831
  * Resume a completed agent's session with a new message.
770
832
  * Uses --resume SESSION_ID for zero cold-start continuation.