groove-dev 0.27.2 → 0.27.3

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,21 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.27.3 — Planner sees ready-to-resume teammates (2026-04-12)
4
+
5
+ Fixes a Mode 1 / Mode 2 detection bug where a planner spawned duplicate agents instead of routing work to existing teammates.
6
+
7
+ **The bug**
8
+ When a team is created with empty prompts (the "spawn the team first, then assign tasks" pattern), the builders complete in a few seconds (no task to do → return). Their status flips to `completed`. Later, when the planner spawns and looks at its intro context, the team section only listed `running`/`starting` agents — so the planner saw "you are the only agent on this project right now" and went Mode 1, spawning duplicates instead of routing to the existing ready-to-resume team.
9
+
10
+ Not a regression from v0.27.x — this has been brittle for any empty-prompt team flow. Surfaced now.
11
+
12
+ **Fix**
13
+ - Introducer's team section now includes **recent completed teammates** alongside active ones, scoped to the same `teamId` with a 1-hour freshness window. Shown as "ready to resume" with an explicit note: *"Teammates marked 'ready' are part of your team. They finished their last task and will resume their session when assigned new work. If you're a planner, route new tasks to them by role — do NOT spawn duplicates."*
14
+ - Planner role prompt (`process.js`) updated: Mode 2 detection now references the intro context's Team section directly, not just `AGENTS_REGISTRY.md`. Explicitly instructs: *"Teammates listed as 'ready to resume' are REAL agents. They WILL pick up new work when routed. NEVER spawn a new agent of a role that already exists."*
15
+
16
+ **What this means for you**
17
+ The flow that felt perfect — spawn the team, then iterate with the planner task-by-task — now works regardless of whether the builders are actively running or resting between tasks.
18
+
3
19
  ## v0.27.2 — Drop velocity trigger (2026-04-12)
4
20
 
5
21
  Following up on v0.27.1: the role-multiplier fix addressed the planner but left the same false-positive class live for any agent doing heavy exploration on a large codebase. Dropping velocity-based rotation entirely rather than papering over it further.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/cli",
3
- "version": "0.27.2",
3
+ "version": "0.27.3",
4
4
  "description": "GROOVE CLI \u2014 manage AI coding agents from your terminal",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/daemon",
3
- "version": "0.27.2",
3
+ "version": "0.27.3",
4
4
  "description": "GROOVE daemon — agent orchestration engine",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -16,10 +16,30 @@ export class Introducer {
16
16
  generateContext(newAgent, options = {}) {
17
17
  const { taskNegotiation } = options;
18
18
  const agents = this.daemon.registry.getAll();
19
- // Only include ACTIVE agents — not completed/killed ones from previous sessions
20
- // Completed agents' work is captured in the journalist's project map, not here
21
- const others = agents.filter((a) => a.id !== newAgent.id &&
22
- (a.status === 'running' || a.status === 'starting'));
19
+
20
+ // Team awareness must include completed teammates, not just running ones.
21
+ // Agents that finished an empty-prompt standup (common pattern: spawn the
22
+ // team upfront, then direct them task-by-task) sit in `completed` status
23
+ // until resumed. Hiding them from the new agent's context makes planners
24
+ // falsely conclude "I'm alone" and spawn duplicate roles.
25
+ //
26
+ // Scope to the same team so one team's agents don't leak into another's
27
+ // context. Completed teammates get a 1-hour freshness cutoff so truly
28
+ // stale ones don't clutter the intro.
29
+ const COMPLETED_WINDOW_MS = 60 * 60 * 1000;
30
+ const sameTeam = (a) =>
31
+ a.id !== newAgent.id &&
32
+ (!newAgent.teamId || a.teamId === newAgent.teamId);
33
+ const activeOthers = agents.filter((a) =>
34
+ sameTeam(a) && (a.status === 'running' || a.status === 'starting')
35
+ );
36
+ const recentCompleted = agents.filter((a) => {
37
+ if (!sameTeam(a)) return false;
38
+ if (a.status !== 'completed') return false;
39
+ const ts = a.lastActivity ? new Date(a.lastActivity).getTime() : 0;
40
+ return Date.now() - ts < COMPLETED_WINDOW_MS;
41
+ });
42
+ const others = [...activeOthers, ...recentCompleted];
23
43
 
24
44
  const lines = [
25
45
  `# GROOVE Agent Context`,
@@ -42,8 +62,17 @@ export class Introducer {
42
62
  if (others.length === 0) {
43
63
  lines.push('You are the only agent on this project right now.');
44
64
  } else {
45
- lines.push(`## Team (${others.length} other agent${others.length > 1 ? 's' : ''})`);
65
+ const activeCount = activeOthers.length;
66
+ const readyCount = recentCompleted.length;
67
+ const parts = [];
68
+ if (activeCount > 0) parts.push(`${activeCount} active`);
69
+ if (readyCount > 0) parts.push(`${readyCount} ready to resume`);
70
+ lines.push(`## Team (${others.length} teammate${others.length > 1 ? 's' : ''} — ${parts.join(', ')})`);
46
71
  lines.push('');
72
+ if (readyCount > 0) {
73
+ lines.push(`**Teammates marked "ready" are part of your team.** They finished their last task and will resume their session when assigned new work. If you're a planner, route new tasks to them by role — do NOT spawn duplicates.`);
74
+ lines.push('');
75
+ }
47
76
 
48
77
  // Collect all files created by teammates for the project files section
49
78
  const allTeamFiles = [];
@@ -51,7 +80,8 @@ export class Introducer {
51
80
  for (const other of others) {
52
81
  const scope = other.scope?.length > 0 ? other.scope.join(', ') : 'unrestricted';
53
82
  const dir = other.workingDir ? ` — dir: ${other.workingDir}` : '';
54
- lines.push(`- **${other.name}** (${other.role}) scope: ${scope}${dir} ${other.status}`);
83
+ const statusLabel = other.status === 'completed' ? 'ready to resume' : other.status;
84
+ lines.push(`- **${other.name}** (${other.role}) — scope: ${scope}${dir} — ${statusLabel}`);
55
85
 
56
86
  // Get files this agent created/modified
57
87
  const files = this.daemon.journalist?.getAgentFiles(other) || [];
@@ -196,8 +196,10 @@ Do NOT re-explore the entire codebase. You already know it from team creation.
196
196
  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.
197
197
 
198
198
  HOW TO DETECT WHICH MODE:
199
- - Read AGENTS_REGISTRY.md. If it lists agents with roles matching your team (frontend, backend, fullstack), you are in MODE 2.
200
- - If no agents exist or only a planner exists, you are in MODE 1.
199
+ - Check the Team section of YOUR intro context (above this prompt). If it lists any teammates active OR ready-to-resume you are in MODE 2.
200
+ - If no teammates exist or only a planner exists, you are in MODE 1.
201
+ - Teammates listed as "ready to resume" are REAL agents on your team. They finished their last task and await new instructions. They WILL pick up new work when you route it to them via recommended-team.json. Do NOT treat them as absent.
202
+ - NEVER spawn a new agent of a role that already exists in your team. A second backend when a backend already exists is always a bug.
201
203
 
202
204
  After completing your plan, you MUST write .groove/recommended-team.json — EVERY TIME, no exceptions.
203
205
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/gui",
3
- "version": "0.27.2",
3
+ "version": "0.27.3",
4
4
  "description": "GROOVE GUI — visual agent control plane",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "groove-dev",
3
- "version": "0.27.2",
3
+ "version": "0.27.3",
4
4
  "description": "Open-source agent orchestration layer — the AI company OS. Local model agent engine (GGUF/Ollama/llama-server), HuggingFace model browser, MCP integrations (Slack, Gmail, Stripe, 15+), agent scheduling (cron), business roles (CMO, CFO, EA). GUI dashboard, multi-agent coordination, zero cold-start, infinite sessions. Works with Claude Code, Codex, Gemini CLI, Ollama, any local model.",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "author": "Groove Dev <hello@groovedev.ai> (https://groovedev.ai)",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/cli",
3
- "version": "0.27.2",
3
+ "version": "0.27.3",
4
4
  "description": "GROOVE CLI \u2014 manage AI coding agents from your terminal",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/daemon",
3
- "version": "0.27.2",
3
+ "version": "0.27.3",
4
4
  "description": "GROOVE daemon — agent orchestration engine",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -16,10 +16,30 @@ export class Introducer {
16
16
  generateContext(newAgent, options = {}) {
17
17
  const { taskNegotiation } = options;
18
18
  const agents = this.daemon.registry.getAll();
19
- // Only include ACTIVE agents — not completed/killed ones from previous sessions
20
- // Completed agents' work is captured in the journalist's project map, not here
21
- const others = agents.filter((a) => a.id !== newAgent.id &&
22
- (a.status === 'running' || a.status === 'starting'));
19
+
20
+ // Team awareness must include completed teammates, not just running ones.
21
+ // Agents that finished an empty-prompt standup (common pattern: spawn the
22
+ // team upfront, then direct them task-by-task) sit in `completed` status
23
+ // until resumed. Hiding them from the new agent's context makes planners
24
+ // falsely conclude "I'm alone" and spawn duplicate roles.
25
+ //
26
+ // Scope to the same team so one team's agents don't leak into another's
27
+ // context. Completed teammates get a 1-hour freshness cutoff so truly
28
+ // stale ones don't clutter the intro.
29
+ const COMPLETED_WINDOW_MS = 60 * 60 * 1000;
30
+ const sameTeam = (a) =>
31
+ a.id !== newAgent.id &&
32
+ (!newAgent.teamId || a.teamId === newAgent.teamId);
33
+ const activeOthers = agents.filter((a) =>
34
+ sameTeam(a) && (a.status === 'running' || a.status === 'starting')
35
+ );
36
+ const recentCompleted = agents.filter((a) => {
37
+ if (!sameTeam(a)) return false;
38
+ if (a.status !== 'completed') return false;
39
+ const ts = a.lastActivity ? new Date(a.lastActivity).getTime() : 0;
40
+ return Date.now() - ts < COMPLETED_WINDOW_MS;
41
+ });
42
+ const others = [...activeOthers, ...recentCompleted];
23
43
 
24
44
  const lines = [
25
45
  `# GROOVE Agent Context`,
@@ -42,8 +62,17 @@ export class Introducer {
42
62
  if (others.length === 0) {
43
63
  lines.push('You are the only agent on this project right now.');
44
64
  } else {
45
- lines.push(`## Team (${others.length} other agent${others.length > 1 ? 's' : ''})`);
65
+ const activeCount = activeOthers.length;
66
+ const readyCount = recentCompleted.length;
67
+ const parts = [];
68
+ if (activeCount > 0) parts.push(`${activeCount} active`);
69
+ if (readyCount > 0) parts.push(`${readyCount} ready to resume`);
70
+ lines.push(`## Team (${others.length} teammate${others.length > 1 ? 's' : ''} — ${parts.join(', ')})`);
46
71
  lines.push('');
72
+ if (readyCount > 0) {
73
+ lines.push(`**Teammates marked "ready" are part of your team.** They finished their last task and will resume their session when assigned new work. If you're a planner, route new tasks to them by role — do NOT spawn duplicates.`);
74
+ lines.push('');
75
+ }
47
76
 
48
77
  // Collect all files created by teammates for the project files section
49
78
  const allTeamFiles = [];
@@ -51,7 +80,8 @@ export class Introducer {
51
80
  for (const other of others) {
52
81
  const scope = other.scope?.length > 0 ? other.scope.join(', ') : 'unrestricted';
53
82
  const dir = other.workingDir ? ` — dir: ${other.workingDir}` : '';
54
- lines.push(`- **${other.name}** (${other.role}) scope: ${scope}${dir} ${other.status}`);
83
+ const statusLabel = other.status === 'completed' ? 'ready to resume' : other.status;
84
+ lines.push(`- **${other.name}** (${other.role}) — scope: ${scope}${dir} — ${statusLabel}`);
55
85
 
56
86
  // Get files this agent created/modified
57
87
  const files = this.daemon.journalist?.getAgentFiles(other) || [];
@@ -196,8 +196,10 @@ Do NOT re-explore the entire codebase. You already know it from team creation.
196
196
  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.
197
197
 
198
198
  HOW TO DETECT WHICH MODE:
199
- - Read AGENTS_REGISTRY.md. If it lists agents with roles matching your team (frontend, backend, fullstack), you are in MODE 2.
200
- - If no agents exist or only a planner exists, you are in MODE 1.
199
+ - Check the Team section of YOUR intro context (above this prompt). If it lists any teammates active OR ready-to-resume you are in MODE 2.
200
+ - If no teammates exist or only a planner exists, you are in MODE 1.
201
+ - Teammates listed as "ready to resume" are REAL agents on your team. They finished their last task and await new instructions. They WILL pick up new work when you route it to them via recommended-team.json. Do NOT treat them as absent.
202
+ - NEVER spawn a new agent of a role that already exists in your team. A second backend when a backend already exists is always a bug.
201
203
 
202
204
  After completing your plan, you MUST write .groove/recommended-team.json — EVERY TIME, no exceptions.
203
205
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/gui",
3
- "version": "0.27.2",
3
+ "version": "0.27.3",
4
4
  "description": "GROOVE GUI — visual agent control plane",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",