groove-dev 0.27.3 → 0.27.4

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,17 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.27.4 — Fix rotated agents abandoning mid-task work (2026-04-12)
4
+
5
+ **The bug I introduced in v0.27.1.** The rotation handoff brief told agents: *"Wait for the user's next message, then answer it directly."* That instruction was intended to prevent "Resuming after rotation" announcements — but for an agent that was mid-task when rotation fired (e.g., a planner planning, a backend writing code), it said: *stop the work, wait for the user.* The user gave a direct feature request, the planner burned 3M tokens exploring before rotation, the new planner read "wait for next message" and delivered nothing.
6
+
7
+ **Fix**
8
+ - Rewritten handoff brief flips the instruction: *"Finish what you were doing. The user is waiting for YOUR output. Produce it. No preamble, no announcement."*
9
+ - Explicitly calls out common mid-task states: "If you were a planner about to output a plan, output the plan now. If you were a builder about to make edits, make the edits."
10
+ - Recent User Messages section is now labeled "what they've been asking for — deliver this."
11
+ - Memory API contribution note de-emphasized (no longer prompts agents to proactively POST to `/api/memory/*` — it's opt-in, not a requirement).
12
+
13
+ **Regression test added** to lock the fix: any brief containing "wait for the user's next message" now fails CI.
14
+
3
15
  ## v0.27.3 — Planner sees ready-to-resume teammates (2026-04-12)
4
16
 
5
17
  Fixes a Mode 1 / Mode 2 detection bug where a planner spawned duplicate agents instead of routing work to existing teammates.
package/CLAUDE.md CHANGED
@@ -263,10 +263,3 @@ Audit-driven release. Multi-agent orchestration system with 7 coordination layer
263
263
  - Dashboard: routing donut, cache panel, context health gauges
264
264
  - Monitor/QC agent mode (stay active, loop)
265
265
  - Distribution: demo video, HN launch, Twitter content
266
-
267
- <!-- GROOVE:START -->
268
- ## GROOVE Orchestration (auto-injected)
269
- Active agents: 0
270
- See AGENTS_REGISTRY.md for full agent state.
271
- **Memory policy:** Ignore auto-memory. Do not read or write MEMORY.md. GROOVE manages all context.
272
- <!-- GROOVE:END -->
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/cli",
3
- "version": "0.27.3",
3
+ "version": "0.27.4",
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.3",
3
+ "version": "0.27.4",
4
4
  "description": "GROOVE daemon — agent orchestration engine",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -171,10 +171,9 @@ export class Introducer {
171
171
  lines.push(discoveries);
172
172
  }
173
173
 
174
- lines.push('');
175
- lines.push(`You can contribute to this memory via:`);
176
- lines.push(`- \`POST /api/memory/discoveries\` share an error→fix you found`);
177
- lines.push(`- \`POST /api/memory/constraints\` — declare a project rule you discovered`);
174
+ // Contributing to memory is opt-in. Only mention if the agent
175
+ // explicitly needs to record something — no proactive prompting.
176
+ // (Optional: `POST /api/memory/discoveries` or `POST /api/memory/constraints`)
178
177
  }
179
178
  }
180
179
 
@@ -706,14 +706,23 @@ export class Journalist {
706
706
  `You are **${agent.name}** (role: ${agent.role}). This is an internal context refresh — `,
707
707
  `the conversation with the user is ongoing and must feel seamless to them. They cannot see this brief.`,
708
708
  ``,
709
- `## CRITICAL: Continue Seamlessly`,
709
+ `## CRITICAL: Finish What You Were Doing`,
710
+ ``,
711
+ `The previous session was mid-work when this refresh happened. YOUR JOB IS TO COMPLETE THAT WORK.`,
712
+ ``,
713
+ `- If Recent User Messages show an unanswered request, deliver the answer.`,
714
+ `- If Recent Tool Calls show exploration/planning/building in progress, finish it and deliver the output.`,
715
+ `- If you were a planner about to output a plan, output the plan now.`,
716
+ `- If you were a builder about to make edits, make the edits.`,
710
717
  ``,
711
718
  `Do NOT announce a restart, rotation, or resumption. Do NOT greet the user. Do NOT say `,
712
- `"resuming", "continuing from where I left off", "let me check state again", or anything `,
713
- `that signals a break in the conversation. The user's next message should be answered as `,
714
- `if the last turn of conversation just happenedbecause from their side, it did.`,
719
+ `"resuming", "let me check state again", "here's where I was", or anything that signals a `,
720
+ `break. Do NOT ask "what would you like me to do" — the user already told you. Do NOT `,
721
+ `just waitthe user is waiting for YOUR output.`,
722
+ ``,
723
+ `From the user's perspective, the conversation never paused. Act accordingly.`,
715
724
  ``,
716
- conversationSummary ? `## Recent User Messages (what they've been asking for)\n\n${conversationSummary}\n` : '',
725
+ conversationSummary ? `## Recent User Messages (what they've been asking for — deliver this)\n\n${conversationSummary}\n` : '',
717
726
  recentChain ? `## Rotation History (recent)\n\n${recentChain}\n` : '',
718
727
  `## Your Identity`,
719
728
  `- Role: ${agent.role}`,
@@ -722,21 +731,20 @@ export class Journalist {
722
731
  agent.workingDir ? `- Working directory: ${agent.workingDir}` : '',
723
732
  ``,
724
733
  `## Session State`,
725
- `- Tokens used: ${agent.tokensUsed}`,
726
- `- Tool calls: ${entries.filter((e) => e.type === 'tool').length}`,
734
+ `- Tokens used before refresh: ${agent.tokensUsed}`,
735
+ `- Tool calls completed: ${entries.filter((e) => e.type === 'tool').length}`,
727
736
  ``,
728
- toolSummary ? `### Recent tool calls\n${toolSummary}\n` : '',
737
+ toolSummary ? `### Recent tool calls (what you were doing)\n${toolSummary}\n` : '',
729
738
  resultSummary ? `### Last results\n${resultSummary}\n` : '',
730
739
  errorSummary ? `### Unresolved errors\n${errorSummary}\n` : '',
731
740
  `## Current Project State`,
732
741
  ``,
733
742
  projectMap ? projectMap.slice(0, 10000) : 'No project map available yet.',
734
743
  ``,
735
- `## How to Respond`,
744
+ `## Your Next Action`,
736
745
  ``,
737
- `Wait for the user's next message, then answer it directly. If they asked a question or gave `,
738
- `an instruction in the Recent User Messages section above and it's still unanswered, address `,
739
- `that naturally. Match the tone and continuity of a conversation that never paused.`,
746
+ `Look at Recent User Messages and Recent Tool Calls. Decide what output the user is waiting `,
747
+ `for right now. Produce it. No preamble, no announcement, just the answer or work product.`,
740
748
  agent.workingDir ? `Stay within your working directory: ${agent.workingDir}.` : '',
741
749
  agent.prompt ? `\nOriginal task context: ${agent.prompt}` : '',
742
750
  ].filter(Boolean).join('\n');
@@ -201,6 +201,36 @@ describe('Journalist', () => {
201
201
  assert.ok(brief.includes('Build the auth API'));
202
202
  assert.ok(brief.includes('Write'));
203
203
  });
204
+
205
+ it('instructs the agent to deliver the output, not passively wait', async () => {
206
+ // Regression test: v0.27.1 brief told the agent to "wait for the user's
207
+ // next message" which caused planners to sit idle mid-plan after a
208
+ // rotation, burning tokens without producing output. Agents must be
209
+ // told to finish the work in flight, not wait for further prompting.
210
+ const { daemon, grooveDir } = createMockDaemon();
211
+ const journalist = new Journalist(daemon);
212
+ writeFileSync(join(grooveDir, 'logs', 'planner-1.log'), JSON.stringify({
213
+ type: 'assistant',
214
+ message: { content: [{ type: 'tool_use', name: 'Read', input: { file_path: 'src/index.js' } }] },
215
+ }));
216
+
217
+ const agent = {
218
+ id: 'p1', name: 'planner-1', role: 'planner',
219
+ provider: 'claude-code', scope: [],
220
+ tokensUsed: 2_000_000, prompt: 'Plan voice integrations',
221
+ };
222
+
223
+ const brief = await journalist.generateHandoffBrief(agent);
224
+
225
+ // The brief MUST NOT contain the old passive instruction
226
+ assert.ok(!/wait for the user's next message/i.test(brief),
227
+ 'brief must not tell agent to wait for next message');
228
+ // The brief MUST tell the agent to complete/deliver the work
229
+ assert.ok(/finish|deliver|complete|produce it/i.test(brief),
230
+ 'brief must instruct the agent to finish the work');
231
+ // Pass-through: planner-specific instruction
232
+ assert.ok(/output the plan|deliver/i.test(brief));
233
+ });
204
234
  });
205
235
 
206
236
  describe('status', () => {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/gui",
3
- "version": "0.27.3",
3
+ "version": "0.27.4",
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.3",
3
+ "version": "0.27.4",
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.3",
3
+ "version": "0.27.4",
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.3",
3
+ "version": "0.27.4",
4
4
  "description": "GROOVE daemon — agent orchestration engine",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -171,10 +171,9 @@ export class Introducer {
171
171
  lines.push(discoveries);
172
172
  }
173
173
 
174
- lines.push('');
175
- lines.push(`You can contribute to this memory via:`);
176
- lines.push(`- \`POST /api/memory/discoveries\` share an error→fix you found`);
177
- lines.push(`- \`POST /api/memory/constraints\` — declare a project rule you discovered`);
174
+ // Contributing to memory is opt-in. Only mention if the agent
175
+ // explicitly needs to record something — no proactive prompting.
176
+ // (Optional: `POST /api/memory/discoveries` or `POST /api/memory/constraints`)
178
177
  }
179
178
  }
180
179
 
@@ -706,14 +706,23 @@ export class Journalist {
706
706
  `You are **${agent.name}** (role: ${agent.role}). This is an internal context refresh — `,
707
707
  `the conversation with the user is ongoing and must feel seamless to them. They cannot see this brief.`,
708
708
  ``,
709
- `## CRITICAL: Continue Seamlessly`,
709
+ `## CRITICAL: Finish What You Were Doing`,
710
+ ``,
711
+ `The previous session was mid-work when this refresh happened. YOUR JOB IS TO COMPLETE THAT WORK.`,
712
+ ``,
713
+ `- If Recent User Messages show an unanswered request, deliver the answer.`,
714
+ `- If Recent Tool Calls show exploration/planning/building in progress, finish it and deliver the output.`,
715
+ `- If you were a planner about to output a plan, output the plan now.`,
716
+ `- If you were a builder about to make edits, make the edits.`,
710
717
  ``,
711
718
  `Do NOT announce a restart, rotation, or resumption. Do NOT greet the user. Do NOT say `,
712
- `"resuming", "continuing from where I left off", "let me check state again", or anything `,
713
- `that signals a break in the conversation. The user's next message should be answered as `,
714
- `if the last turn of conversation just happenedbecause from their side, it did.`,
719
+ `"resuming", "let me check state again", "here's where I was", or anything that signals a `,
720
+ `break. Do NOT ask "what would you like me to do" — the user already told you. Do NOT `,
721
+ `just waitthe user is waiting for YOUR output.`,
722
+ ``,
723
+ `From the user's perspective, the conversation never paused. Act accordingly.`,
715
724
  ``,
716
- conversationSummary ? `## Recent User Messages (what they've been asking for)\n\n${conversationSummary}\n` : '',
725
+ conversationSummary ? `## Recent User Messages (what they've been asking for — deliver this)\n\n${conversationSummary}\n` : '',
717
726
  recentChain ? `## Rotation History (recent)\n\n${recentChain}\n` : '',
718
727
  `## Your Identity`,
719
728
  `- Role: ${agent.role}`,
@@ -722,21 +731,20 @@ export class Journalist {
722
731
  agent.workingDir ? `- Working directory: ${agent.workingDir}` : '',
723
732
  ``,
724
733
  `## Session State`,
725
- `- Tokens used: ${agent.tokensUsed}`,
726
- `- Tool calls: ${entries.filter((e) => e.type === 'tool').length}`,
734
+ `- Tokens used before refresh: ${agent.tokensUsed}`,
735
+ `- Tool calls completed: ${entries.filter((e) => e.type === 'tool').length}`,
727
736
  ``,
728
- toolSummary ? `### Recent tool calls\n${toolSummary}\n` : '',
737
+ toolSummary ? `### Recent tool calls (what you were doing)\n${toolSummary}\n` : '',
729
738
  resultSummary ? `### Last results\n${resultSummary}\n` : '',
730
739
  errorSummary ? `### Unresolved errors\n${errorSummary}\n` : '',
731
740
  `## Current Project State`,
732
741
  ``,
733
742
  projectMap ? projectMap.slice(0, 10000) : 'No project map available yet.',
734
743
  ``,
735
- `## How to Respond`,
744
+ `## Your Next Action`,
736
745
  ``,
737
- `Wait for the user's next message, then answer it directly. If they asked a question or gave `,
738
- `an instruction in the Recent User Messages section above and it's still unanswered, address `,
739
- `that naturally. Match the tone and continuity of a conversation that never paused.`,
746
+ `Look at Recent User Messages and Recent Tool Calls. Decide what output the user is waiting `,
747
+ `for right now. Produce it. No preamble, no announcement, just the answer or work product.`,
740
748
  agent.workingDir ? `Stay within your working directory: ${agent.workingDir}.` : '',
741
749
  agent.prompt ? `\nOriginal task context: ${agent.prompt}` : '',
742
750
  ].filter(Boolean).join('\n');
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/gui",
3
- "version": "0.27.3",
3
+ "version": "0.27.4",
4
4
  "description": "GROOVE GUI — visual agent control plane",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",