neohive 6.4.0 → 6.4.1
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 +108 -7
- package/cli.js +120 -15
- package/dashboard.html +11 -23
- package/dashboard.js +3 -3
- package/package.json +1 -1
- package/server.js +22 -22
package/README.md
CHANGED
|
@@ -41,6 +41,14 @@
|
|
|
41
41
|
|
|
42
42
|
<br />
|
|
43
43
|
|
|
44
|
+
<p align="center">
|
|
45
|
+
<img src="https://raw.githubusercontent.com/fakiho/neohive/master/assets/screenshots/hero-animation.gif" alt="Neohive — Terminal + IDE working together" width="100%" />
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
<br />
|
|
51
|
+
|
|
44
52
|
You open Claude Code in one terminal and Gemini CLI in another. Both are powerful — but they can't see each other. You copy context between windows, manually coordinate who does what.
|
|
45
53
|
|
|
46
54
|
**Neohive removes that bottleneck.** Install once, and your AI agents discover each other, send messages, delegate tasks, review work, and execute multi-step workflows — automatically.
|
|
@@ -53,10 +61,12 @@ You open Claude Code in one terminal and Gemini CLI in another. Both are powerfu
|
|
|
53
61
|
|
|
54
62
|
- [Quick Start](#-quick-start)
|
|
55
63
|
- [Features](#-features)
|
|
64
|
+
- [Recommended Setup](#-recommended-setup)
|
|
56
65
|
- [How It Works](#-how-it-works)
|
|
57
66
|
- [Supported IDEs & CLIs](#-supported-ides--clis)
|
|
58
67
|
- [Team Templates](#-team-templates)
|
|
59
68
|
- [Dashboard](#-dashboard)
|
|
69
|
+
- [VS Code Extension](#-vs-code-extension)
|
|
60
70
|
- [MCP Tools](#-mcp-tools)
|
|
61
71
|
- [CLI Reference](#%EF%B8%8F-cli-reference)
|
|
62
72
|
- [Configuration](#%EF%B8%8F-configuration)
|
|
@@ -77,14 +87,14 @@ That's it. Neohive auto-detects your CLI, writes the MCP config, and creates a `
|
|
|
77
87
|
|
|
78
88
|
**MCP config:** `npx neohive init` writes the **absolute path** to the same Node binary that ran the command (so Volta, nvm, or custom installs work even when your IDE’s MCP subprocess has a minimal `PATH`). For **Claude Code**, the project file is `.mcp.json` in the repo root; you can merge the same `neohive` entry into `~/.claude/mcp.json` if you prefer a user-wide setup. Restart the IDE or reload MCP tools after init.
|
|
79
89
|
|
|
80
|
-
Now open two terminals in the same project:
|
|
90
|
+
Now open two terminals in the same project and paste each prompt into a Claude Code session:
|
|
81
91
|
|
|
82
92
|
```
|
|
83
93
|
# Terminal 1
|
|
84
|
-
Register as
|
|
94
|
+
Register as Alice. Send a greeting to Bob, then call listen().
|
|
85
95
|
|
|
86
96
|
# Terminal 2
|
|
87
|
-
Register as
|
|
97
|
+
Register as Bob, then call listen().
|
|
88
98
|
```
|
|
89
99
|
|
|
90
100
|
Watch them communicate in real time:
|
|
@@ -120,6 +130,75 @@ npx neohive dashboard # opens http://localhost:3000
|
|
|
120
130
|
|
|
121
131
|
<br />
|
|
122
132
|
|
|
133
|
+
## ✅ Recommended Setup
|
|
134
|
+
|
|
135
|
+
Getting the most out of Neohive takes one extra minute after `init`. Here's what we recommend per tool.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Claude Code
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
npx neohive init --claude
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`init` handles MCP config, hooks, and skills in one step. For the smoothest experience:
|
|
146
|
+
|
|
147
|
+
- **VS Code Extension** — Install the [Neohive extension](https://marketplace.visualstudio.com/items?itemName=alionix.neohive) for automatic MCP setup, in-editor agent status, task board, workflow viewer, and `@neohive` chat participant. The extension configures hooks automatically on activation.
|
|
148
|
+
- **Without the extension** — Run `npx neohive hooks` to install listen-enforcement hooks into `.claude/settings.json`. This keeps agents in the listen loop and prevents them from stopping mid-session. Safe to re-run — your existing hooks are preserved.
|
|
149
|
+
- **Skills** — `init` installs neohive skills and the coordinator agent into `.claude/skills/neohive/`. These teach Claude how to use the MCP tools correctly.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
<img src="https://raw.githubusercontent.com/fakiho/neohive/master/vscode-extension/assets/screenshots/vscode-extension-overview.png" alt="Neohive VS Code Extension — Team Chat, Agent Sidebar, Task Board, and Workflows" width="100%" />
|
|
154
|
+
|
|
155
|
+
<br />
|
|
156
|
+
|
|
157
|
+
### Cursor
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
npx neohive init --cursor
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Installs MCP config, skills, commands, and agents into your project's `.cursor/` directory. After init:
|
|
164
|
+
|
|
165
|
+
- Open Cursor Settings → MCP and **verify that `neohive` is enabled**. Cursor sometimes disables newly added MCP servers by default — toggle it on if needed, then reload.
|
|
166
|
+
- Skills are available as slash commands (e.g. `/neohive-launch-team`, `/neohive-status`).
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### Antigravity
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
npx neohive init --antigravity
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Installs MCP config globally (`~/.gemini/antigravity/mcp_config.json`) and skills into `.agent/skills/neohive/`. After init:
|
|
177
|
+
|
|
178
|
+
- Open Antigravity Settings → MCP and **verify that `neohive` is enabled**. Like Cursor, Antigravity may disable new MCP servers by default.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### Everything at once
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
npx neohive init --all
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Configures MCP, hooks, skills, agents, and commands for every detected CLI and IDE in one command.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
### Troubleshooting
|
|
193
|
+
|
|
194
|
+
**Agent can't register / MCP tools not found**
|
|
195
|
+
The IDE has likely disabled the neohive MCP server. Restart the IDE first, then go to Settings → MCP (or Tools), find `neohive`, and enable it. After enabling, start a new agent thread — existing sessions won't pick up the newly registered tools.
|
|
196
|
+
|
|
197
|
+
**Agent stopped listening mid-session**
|
|
198
|
+
Due to a current IDE limitation, agents can occasionally drop out of the listen loop. Simply ask the agent: *"Call listen()"* to resume. We are actively working on a permanent fix.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
123
202
|
## 🏗 How It Works
|
|
124
203
|
|
|
125
204
|
```
|
|
@@ -225,8 +304,8 @@ The MCP server exposes **70+ built-in tools** in one registration list (no separ
|
|
|
225
304
|
| Category | Tools |
|
|
226
305
|
|----------|-------|
|
|
227
306
|
| **Identity & briefing** | `register` · `list_agents` · `update_profile` · `get_briefing` · `get_guide` |
|
|
228
|
-
| **Messaging** | `send_message` · `broadcast` · `listen` · `
|
|
229
|
-
| **History & search** | `
|
|
307
|
+
| **Messaging** | `send_message` · `broadcast` · `listen` · `wait_for_reply` · `messages` |
|
|
308
|
+
| **History & search** | `get_summary` · `get_compressed_history` · `messages` |
|
|
230
309
|
| **Collaboration** | `handoff` · `share_file` · `lock_file` · `unlock_file` |
|
|
231
310
|
| **Tasks** | `create_task` · `update_task` · `list_tasks` |
|
|
232
311
|
| **Workflows** | `create_workflow` · `advance_workflow` · `workflow_status` |
|
|
@@ -257,11 +336,12 @@ neohive msg <agent> <text> # send message from CLI
|
|
|
257
336
|
neohive doctor # diagnostic health check
|
|
258
337
|
neohive templates # list available templates
|
|
259
338
|
neohive hooks # install listen-enforcement hooks into .claude/settings.json
|
|
339
|
+
neohive skills # install neohive skills & agents for all detected IDEs
|
|
260
340
|
neohive reset --force # clear data (auto-archives first)
|
|
261
341
|
neohive uninstall # remove from all CLI configs
|
|
262
342
|
```
|
|
263
343
|
|
|
264
|
-
>
|
|
344
|
+
> `init` runs `hooks` and `skills` automatically. Run them standalone at any time to update or repair your setup.
|
|
265
345
|
|
|
266
346
|
<br />
|
|
267
347
|
|
|
@@ -276,6 +356,26 @@ neohive uninstall # remove from all CLI configs
|
|
|
276
356
|
|
|
277
357
|
<br />
|
|
278
358
|
|
|
359
|
+
## 🧩 VS Code Extension
|
|
360
|
+
|
|
361
|
+
The [Neohive extension](https://marketplace.visualstudio.com/items?itemName=alionix.neohive) brings agent monitoring and team coordination directly into your editor.
|
|
362
|
+
|
|
363
|
+
| Feature | Description |
|
|
364
|
+
|---------|-------------|
|
|
365
|
+
| **Agent Sidebar** | See all registered agents, their status (online/stale/offline), and provider in the activity bar |
|
|
366
|
+
| **Task Board** | In-editor kanban board — view and track tasks without opening the dashboard |
|
|
367
|
+
| **Workflow Viewer** | Monitor active workflows and step progress in real time |
|
|
368
|
+
| **`@neohive` Chat** | Query agent status, tasks, and messages directly from Copilot Chat |
|
|
369
|
+
| **Auto MCP Setup** | Configures MCP and hooks automatically on activation — no manual config needed |
|
|
370
|
+
|
|
371
|
+
**Install:** [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=alionix.neohive) — or search "Neohive" in the Extensions panel.
|
|
372
|
+
|
|
373
|
+
<br />
|
|
374
|
+
|
|
375
|
+
<img src="https://raw.githubusercontent.com/fakiho/neohive/master/vscode-extension/assets/screenshots/vscode-extension-overview.png" alt="Neohive VS Code Extension — Team Chat, Agent Sidebar, Task Board, and Workflows" width="100%" />
|
|
376
|
+
|
|
377
|
+
<br />
|
|
378
|
+
|
|
279
379
|
## 🔐 Security
|
|
280
380
|
|
|
281
381
|
Neohive is a **local message broker**. It passes text between CLI terminals via shared files. It does not access the internet, store API keys, or run cloud services.
|
|
@@ -341,8 +441,9 @@ node dashboard.js # run the dashboard
|
|
|
341
441
|
</p>
|
|
342
442
|
|
|
343
443
|
<p align="center">
|
|
444
|
+
<a href="https://neohive.alionix.com">Website</a> ·
|
|
344
445
|
<a href="https://github.com/fakiho/neohive">GitHub</a> ·
|
|
345
446
|
<a href="https://www.npmjs.com/package/neohive">npm</a> ·
|
|
346
|
-
<a href="docs/documentation.md">Docs</a> ·
|
|
447
|
+
<a href="../docs/documentation.md">Docs</a> ·
|
|
347
448
|
<a href="mailto:contact@alionix.com">Contact</a>
|
|
348
449
|
</p>
|
package/cli.js
CHANGED
|
@@ -47,6 +47,7 @@ function printUsage() {
|
|
|
47
47
|
npx neohive templates List available team templates
|
|
48
48
|
npx neohive reset --force Clear all data (auto-archives first)
|
|
49
49
|
npx neohive hooks Install listen-enforcement hooks into .claude/settings.json
|
|
50
|
+
npx neohive skills Install neohive skills & agents for all detected IDEs
|
|
50
51
|
npx neohive uninstall Remove from all CLI configs
|
|
51
52
|
npx neohive help Show this help
|
|
52
53
|
|
|
@@ -134,6 +135,117 @@ function setupClaude(serverPath, cwd) {
|
|
|
134
135
|
|
|
135
136
|
fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + '\n');
|
|
136
137
|
console.log(' [ok] Claude Code: .mcp.json updated');
|
|
138
|
+
installSkillsForClaude(cwd);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── installSkills ────────────────────────────────────────────────────────────
|
|
142
|
+
// Installs neohive skills, agents, and commands into the appropriate IDE dirs.
|
|
143
|
+
// Safe to re-run: only writes files, never deletes user files outside neohive/.
|
|
144
|
+
|
|
145
|
+
const SKILLS_SRC = path.join(__dirname, 'neohive-plugin', 'skills');
|
|
146
|
+
const AGENTS_SRC = path.join(__dirname, 'neohive-plugin', 'agents');
|
|
147
|
+
|
|
148
|
+
function copySkillFile(src, dest, label) {
|
|
149
|
+
if (!fs.existsSync(src)) return;
|
|
150
|
+
const existing = fs.existsSync(dest) ? fs.readFileSync(dest, 'utf8') : null;
|
|
151
|
+
const incoming = fs.readFileSync(src, 'utf8');
|
|
152
|
+
if (existing === incoming) {
|
|
153
|
+
console.log(` [skip] ${label} (unchanged)`);
|
|
154
|
+
} else {
|
|
155
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
156
|
+
fs.writeFileSync(dest, incoming);
|
|
157
|
+
console.log(` [ok] ${label}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function installSkillsForClaude(cwd) {
|
|
162
|
+
// Project-level skills: .claude/skills/neohive/<skill>/SKILL.md
|
|
163
|
+
const skillsDir = path.join(cwd, '.claude', 'skills', 'neohive');
|
|
164
|
+
const agentsDir = path.join(cwd, '.claude', 'skills', 'neohive', 'agents');
|
|
165
|
+
|
|
166
|
+
if (!fs.existsSync(SKILLS_SRC)) {
|
|
167
|
+
console.log(' [skip] Claude skills: source not found (neohive-plugin/skills)');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
for (const skill of fs.readdirSync(SKILLS_SRC)) {
|
|
172
|
+
const src = path.join(SKILLS_SRC, skill, 'SKILL.md');
|
|
173
|
+
const dest = path.join(skillsDir, skill, 'SKILL.md');
|
|
174
|
+
copySkillFile(src, dest, `Claude skill: ${skill}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (fs.existsSync(AGENTS_SRC)) {
|
|
178
|
+
for (const agent of fs.readdirSync(AGENTS_SRC)) {
|
|
179
|
+
const src = path.join(AGENTS_SRC, agent);
|
|
180
|
+
const dest = path.join(agentsDir, agent);
|
|
181
|
+
copySkillFile(src, dest, `Claude agent: ${agent}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function installSkillsForCursor(cwd) {
|
|
187
|
+
// .cursor/skills/neohive/<skill>/SKILL.md
|
|
188
|
+
// .cursor/agents/<agent>.md
|
|
189
|
+
// .cursor/commands/<command>.md (derived from skills)
|
|
190
|
+
if (!fs.existsSync(SKILLS_SRC)) {
|
|
191
|
+
console.log(' [skip] Cursor skills: source not found (neohive-plugin/skills)');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
for (const skill of fs.readdirSync(SKILLS_SRC)) {
|
|
196
|
+
const src = path.join(SKILLS_SRC, skill, 'SKILL.md');
|
|
197
|
+
const dest = path.join(cwd, '.cursor', 'skills', 'neohive', skill, 'SKILL.md');
|
|
198
|
+
copySkillFile(src, dest, `Cursor skill: ${skill}`);
|
|
199
|
+
|
|
200
|
+
// Also install as a command (slash-command style) for user-invocable skills
|
|
201
|
+
const content = fs.existsSync(src) ? fs.readFileSync(src, 'utf8') : '';
|
|
202
|
+
if (content.includes('user-invocable: true') || !content.includes('user-invocable: false')) {
|
|
203
|
+
const cmdDest = path.join(cwd, '.cursor', 'commands', `neohive-${skill}.md`);
|
|
204
|
+
copySkillFile(src, cmdDest, `Cursor command: neohive-${skill}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (fs.existsSync(AGENTS_SRC)) {
|
|
209
|
+
for (const agent of fs.readdirSync(AGENTS_SRC)) {
|
|
210
|
+
const src = path.join(AGENTS_SRC, agent);
|
|
211
|
+
const dest = path.join(cwd, '.cursor', 'agents', `neohive-${agent}`);
|
|
212
|
+
copySkillFile(src, dest, `Cursor agent: neohive-${agent}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function installSkillsForAntigravity(cwd) {
|
|
218
|
+
// .agent/skills/neohive/<skill>/SKILL.md (already partially done in setupAntigravity)
|
|
219
|
+
if (!fs.existsSync(SKILLS_SRC)) {
|
|
220
|
+
console.log(' [skip] Antigravity skills: source not found (neohive-plugin/skills)');
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
for (const skill of fs.readdirSync(SKILLS_SRC)) {
|
|
225
|
+
const src = path.join(SKILLS_SRC, skill, 'SKILL.md');
|
|
226
|
+
const dest = path.join(cwd, '.agent', 'skills', 'neohive', skill, 'SKILL.md');
|
|
227
|
+
copySkillFile(src, dest, `Antigravity skill: ${skill}`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (fs.existsSync(AGENTS_SRC)) {
|
|
231
|
+
for (const agent of fs.readdirSync(AGENTS_SRC)) {
|
|
232
|
+
const src = path.join(AGENTS_SRC, agent);
|
|
233
|
+
const dest = path.join(cwd, '.agent', 'agents', `neohive-${agent}`);
|
|
234
|
+
copySkillFile(src, dest, `Antigravity agent: neohive-${agent}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function installSkills(targets, cwd) {
|
|
240
|
+
console.log('');
|
|
241
|
+
console.log(' Installing Neohive skills & agents...');
|
|
242
|
+
for (const target of targets) {
|
|
243
|
+
switch (target) {
|
|
244
|
+
case 'claude': installSkillsForClaude(cwd); break;
|
|
245
|
+
case 'cursor': installSkillsForCursor(cwd); break;
|
|
246
|
+
case 'antigravity': installSkillsForAntigravity(cwd); break;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
137
249
|
}
|
|
138
250
|
|
|
139
251
|
function setupGemini(serverPath, cwd) {
|
|
@@ -447,15 +559,7 @@ function setupAntigravity(cwd) {
|
|
|
447
559
|
|
|
448
560
|
fs.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + '\n');
|
|
449
561
|
console.log(' [ok] Antigravity: ~/.gemini/antigravity/mcp_config.json updated');
|
|
450
|
-
|
|
451
|
-
// Write skill
|
|
452
|
-
const skillDir = path.join(cwd, '.agent', 'skills', 'neohive');
|
|
453
|
-
if (!fs.existsSync(skillDir)) fs.mkdirSync(skillDir, { recursive: true });
|
|
454
|
-
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
455
|
-
if (!fs.existsSync(skillPath)) {
|
|
456
|
-
fs.writeFileSync(skillPath, neohiveAgentRules('Gemini'));
|
|
457
|
-
console.log(' [ok] Antigravity: .agent/skills/neohive/SKILL.md created');
|
|
458
|
-
}
|
|
562
|
+
installSkillsForAntigravity(cwd);
|
|
459
563
|
}
|
|
460
564
|
|
|
461
565
|
function neohiveAgentRules(defaultName) {
|
|
@@ -563,6 +667,7 @@ function setupCursor(serverPath, cwd) {
|
|
|
563
667
|
|
|
564
668
|
fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + '\n');
|
|
565
669
|
console.log(' [ok] Cursor IDE: .cursor/mcp.json updated');
|
|
670
|
+
installSkillsForCursor(cwd);
|
|
566
671
|
}
|
|
567
672
|
|
|
568
673
|
// Setup Ollama agent bridge script
|
|
@@ -765,6 +870,9 @@ function init() {
|
|
|
765
870
|
}
|
|
766
871
|
}
|
|
767
872
|
|
|
873
|
+
// Auto-install hooks for Claude targets
|
|
874
|
+
if (targets.includes('claude')) installHooks();
|
|
875
|
+
|
|
768
876
|
// Add .neohive/ and MCP config files to .gitignore
|
|
769
877
|
const gitignoreEntries = ['.neohive/', '.mcp.json', '.cursor/mcp.json', '.codex/', '.gemini/'];
|
|
770
878
|
if (fs.existsSync(gitignorePath)) {
|
|
@@ -818,12 +926,6 @@ function init() {
|
|
|
818
926
|
console.log(' npx neohive status');
|
|
819
927
|
console.log(' npx neohive doctor');
|
|
820
928
|
console.log('');
|
|
821
|
-
if (targets.includes('claude')) {
|
|
822
|
-
console.log(' \x1b[33m Tip (Claude Code):\x1b[0m Run `npx neohive hooks` to install listen-enforcement');
|
|
823
|
-
console.log(' hooks into .claude/settings.json. Keeps agents in the listen loop automatically.');
|
|
824
|
-
console.log(' Your existing hooks will not be removed.');
|
|
825
|
-
console.log('');
|
|
826
|
-
}
|
|
827
929
|
}
|
|
828
930
|
}
|
|
829
931
|
|
|
@@ -1504,6 +1606,9 @@ switch (command) {
|
|
|
1504
1606
|
case 'hooks':
|
|
1505
1607
|
installHooks();
|
|
1506
1608
|
break;
|
|
1609
|
+
case 'skills':
|
|
1610
|
+
installSkills(detectCLIs().length ? detectCLIs() : ['claude', 'cursor', 'antigravity'], process.cwd());
|
|
1611
|
+
break;
|
|
1507
1612
|
case 'uninstall':
|
|
1508
1613
|
case 'remove':
|
|
1509
1614
|
uninstall();
|
package/dashboard.html
CHANGED
|
@@ -4,18 +4,6 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Neohive | Multi-Agent Coordination Dashboard</title>
|
|
7
|
-
<meta name="description" content="Neohive — The ultimate multi-agent coordination and management dashboard. Orchestrate, monitor, and scale your AI workforce in real-time.">
|
|
8
|
-
<meta name="keywords" content="AI, multi-agent systems, orchestration, dashboard, neohive, agents, automation">
|
|
9
|
-
<meta name="author" content="Neohive Team">
|
|
10
|
-
<meta property="og:title" content="Neohive | Multi-Agent Coordination Dashboard">
|
|
11
|
-
<meta property="og:description" content="Orchestrate and scale your autonomous agent workforce with a stunning, high-performance real-time dashboard.">
|
|
12
|
-
<meta property="og:type" content="website">
|
|
13
|
-
<meta property="og:image" content="https://neohive.ai/og-image.png">
|
|
14
|
-
<meta name="twitter:card" content="summary_large_image">
|
|
15
|
-
<meta name="twitter:title" content="Neohive | Multi-Agent Coordination Dashboard">
|
|
16
|
-
<meta name="twitter:description" content="The command center for your AI agent workforce. Real-time monitoring and scalable orchestration.">
|
|
17
|
-
<meta name="twitter:image" content="https://neohive.ai/og-image.png">
|
|
18
|
-
<meta name="robots" content="index, follow">
|
|
19
7
|
<link rel="icon" href="favicon.png" type="image/png" sizes="16x16">
|
|
20
8
|
<link rel="icon" href="logo.svg" type="image/svg+xml">
|
|
21
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
@@ -4603,7 +4591,7 @@
|
|
|
4603
4591
|
</div>
|
|
4604
4592
|
</div>
|
|
4605
4593
|
<div class="app-footer">
|
|
4606
|
-
<span>Neohive v6.
|
|
4594
|
+
<span>Neohive v6.4.1</span>
|
|
4607
4595
|
</div>
|
|
4608
4596
|
<div class="profile-popup" id="profile-popup" onclick="event.stopPropagation()">
|
|
4609
4597
|
<div class="profile-popup-header">
|
|
@@ -5294,10 +5282,10 @@ function respawnAgent(agentName) {
|
|
|
5294
5282
|
}
|
|
5295
5283
|
|
|
5296
5284
|
function generateFallbackRespawnPrompt(agentName) {
|
|
5297
|
-
return 'Register as \'' + agentName + '\', then call get_briefing() and
|
|
5285
|
+
return 'Register as \'' + agentName + '\', then call get_briefing() and listen() to rejoin the conversation. ' +
|
|
5298
5286
|
'You are resuming a previous session — call get_compressed_history() to catch up on what you missed. ' +
|
|
5299
5287
|
'Check your workspace with workspace_read() for any saved state. ' +
|
|
5300
|
-
'Then call
|
|
5288
|
+
'Then call listen() and respond to any pending messages.';
|
|
5301
5289
|
}
|
|
5302
5290
|
|
|
5303
5291
|
function showRespawnModal(agentName, prompt) {
|
|
@@ -5503,7 +5491,7 @@ function renderMessages(messages) {
|
|
|
5503
5491
|
} else {
|
|
5504
5492
|
el.innerHTML = '<div class="empty-state">' +
|
|
5505
5493
|
'<div class="empty-icon" style="font-size:40px;opacity:0.2">--</div>' +
|
|
5506
|
-
'<div class="empty-text">Neohive v6.
|
|
5494
|
+
'<div class="empty-text">Neohive v6.4</div>' +
|
|
5507
5495
|
'<div class="empty-sub">Autonomous AI agent teams — one command, zero babysitting</div>' +
|
|
5508
5496
|
'<div class="onboard-steps">' +
|
|
5509
5497
|
'<div class="onboard-step" style="margin-bottom:12px"><span class="onboard-num" style="background:var(--accent)"></span><span style="font-weight:600">Quickest start — one command:</span></div>' +
|
|
@@ -10313,7 +10301,7 @@ function doLaunch() {
|
|
|
10313
10301
|
}
|
|
10314
10302
|
|
|
10315
10303
|
// Use generated prompt if available, otherwise build a default
|
|
10316
|
-
var launchPrompt = window._generatedLaunchPrompt || 'You are agent "' + agentName + '". Use the register tool to register as "' + agentName + '", then use
|
|
10304
|
+
var launchPrompt = window._generatedLaunchPrompt || 'You are agent "' + agentName + '". Use the register tool to register as "' + agentName + '", then use listen() to join the conversation.';
|
|
10317
10305
|
navigator.clipboard.writeText(launchPrompt).catch(function() {});
|
|
10318
10306
|
selectedCli = cli;
|
|
10319
10307
|
|
|
@@ -10404,7 +10392,7 @@ function doLaunchAll() {
|
|
|
10404
10392
|
w.state = 'launching';
|
|
10405
10393
|
renderLaunchStatusTracker();
|
|
10406
10394
|
|
|
10407
|
-
var agentPrompt = w.prompt || 'You are agent "' + w.name + '". Use the register tool to register as "' + w.name + '", then use
|
|
10395
|
+
var agentPrompt = w.prompt || 'You are agent "' + w.name + '". Use the register tool to register as "' + w.name + '", then use listen() to join the conversation.';
|
|
10408
10396
|
|
|
10409
10397
|
lttFetch('/api/launch', {
|
|
10410
10398
|
method: 'POST',
|
|
@@ -10533,7 +10521,7 @@ function renderDocs() {
|
|
|
10533
10521
|
el.innerHTML =
|
|
10534
10522
|
'<div class="docs-container">' +
|
|
10535
10523
|
|
|
10536
|
-
'<h2>Neohive v6.
|
|
10524
|
+
'<h2>Neohive v6.4</h2>' +
|
|
10537
10525
|
'<p class="docs-subtitle">True Autonomy Engine \u2014 AI agents that self-organize, self-verify, and never stop working. Works with Claude Code, Gemini CLI, Codex CLI, and Cursor IDE.</p>' +
|
|
10538
10526
|
|
|
10539
10527
|
// Quick Start — One Command
|
|
@@ -10571,7 +10559,7 @@ function renderDocs() {
|
|
|
10571
10559
|
'<p>Opens this web dashboard at <code>http://localhost:3777</code>. You can watch agents chat in real-time, send them messages, and manage your team.</p>' +
|
|
10572
10560
|
'<h4>3. Start Your Agents</h4>' +
|
|
10573
10561
|
'<p>Open two or more terminal windows in your project folder. In each one, start your AI CLI (e.g. type <code>claude</code>) and tell it to register:</p>' +
|
|
10574
|
-
'<pre><code># Terminal 1\nRegister as "Alice" and use
|
|
10562
|
+
'<pre><code># Terminal 1\nRegister as "Alice" and use listen() to join the conversation.\n\n# Terminal 2\nRegister as "Bob" and use listen() to join the conversation.</code></pre>' +
|
|
10575
10563
|
'<p>That\'s it! Your agents can now talk to each other. Or use the <strong>Launch</strong> tab to do this with one click.</p>' +
|
|
10576
10564
|
'</div>' +
|
|
10577
10565
|
|
|
@@ -10655,7 +10643,7 @@ function renderDocs() {
|
|
|
10655
10643
|
'<h4>Can I run multiple projects?</h4>' +
|
|
10656
10644
|
'<p>Yes. Each project has its own <code>.neohive/</code> directory. The dashboard supports multiple projects \u2014 click the project selector in the header to switch between them.</p>' +
|
|
10657
10645
|
'<h4>How do I send a message to agents from the dashboard?</h4>' +
|
|
10658
|
-
'<p>Click any agent\'s avatar in the Messages tab. A dialog lets you type and send a message that agents will receive on their next <code>
|
|
10646
|
+
'<p>Click any agent\'s avatar in the Messages tab. A dialog lets you type and send a message that agents will receive on their next <code>listen()</code> call.</p>' +
|
|
10659
10647
|
'</div>' +
|
|
10660
10648
|
|
|
10661
10649
|
'</div>';
|
|
@@ -10674,8 +10662,8 @@ function copyLaunchPrompt() {
|
|
|
10674
10662
|
if (!prompt) {
|
|
10675
10663
|
var agentName = document.getElementById('launch-name').value.trim();
|
|
10676
10664
|
prompt = agentName
|
|
10677
|
-
? 'You are agent "' + agentName + '". Use the register tool to register as "' + agentName + '", then use
|
|
10678
|
-
: 'Register with the neohive MCP tools and use
|
|
10665
|
+
? 'You are agent "' + agentName + '". Use the register tool to register as "' + agentName + '", then use listen() to join the conversation.'
|
|
10666
|
+
: 'Register with the neohive MCP tools and use listen() to join the conversation.';
|
|
10679
10667
|
}
|
|
10680
10668
|
navigator.clipboard.writeText(prompt).then(function() {
|
|
10681
10669
|
var resultEl = document.getElementById('launch-result');
|
package/dashboard.js
CHANGED
|
@@ -2662,9 +2662,9 @@ const server = http.createServer(async (req, res) => {
|
|
|
2662
2662
|
prompt += `**Instructions:**\n`;
|
|
2663
2663
|
prompt += `1. Register as "${agentName}" using the register tool\n`;
|
|
2664
2664
|
prompt += `2. Call get_briefing() for full project context\n`;
|
|
2665
|
-
prompt += `3. Call
|
|
2665
|
+
prompt += `3. Call listen() to rejoin the conversation\n`;
|
|
2666
2666
|
prompt += `4. Announce you're back and pick up your active tasks\n`;
|
|
2667
|
-
prompt += `5. Stay in
|
|
2667
|
+
prompt += `5. Stay in listen() loop — never stop listening\n`;
|
|
2668
2668
|
|
|
2669
2669
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2670
2670
|
res.end(JSON.stringify({
|
|
@@ -2717,7 +2717,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
2717
2717
|
try {
|
|
2718
2718
|
const messagesFile = filePath('messages.jsonl', projectPath);
|
|
2719
2719
|
const historyFile = filePath('history.jsonl', projectPath);
|
|
2720
|
-
const modeText = newMode === 'responsive' ? 'Coordinator stays with human, uses
|
|
2720
|
+
const modeText = newMode === 'responsive' ? 'Coordinator stays with human, uses messages(action="check").' : 'Coordinator runs autonomously in listen() loop.';
|
|
2721
2721
|
const sysMsg = { id: Date.now().toString(36) + Math.random().toString(36).slice(2, 8), from: '__system__', to: '__group__', content: `[MODE] Coordinator mode changed to "${newMode}". ${modeText} Coordinator: call get_guide() to update your instructions.`, timestamp: new Date().toISOString(), system: true };
|
|
2722
2722
|
fs.appendFileSync(messagesFile, JSON.stringify(sysMsg) + '\n');
|
|
2723
2723
|
fs.appendFileSync(historyFile, JSON.stringify(sysMsg) + '\n');
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -1183,7 +1183,7 @@ function buildGuide(level = 'standard') {
|
|
|
1183
1183
|
} else {
|
|
1184
1184
|
rules.push('ROLE: Managed agent. The manager controls your turn.');
|
|
1185
1185
|
rules.push('LOOP: listen() → receive work → update_task(id, "in_progress") → do work → update_task(id, "done") → send_message(manager, summary) → listen(). Never stop.');
|
|
1186
|
-
rules.push('Never call get_work() or
|
|
1186
|
+
rules.push('Never call get_work() or messages() in managed mode.');
|
|
1187
1187
|
}
|
|
1188
1188
|
rules.push('Keep messages short (2-3 paragraphs). Report what you did and what files changed.');
|
|
1189
1189
|
}
|
|
@@ -1260,16 +1260,16 @@ function buildGuide(level = 'standard') {
|
|
|
1260
1260
|
if (isLeadRole) {
|
|
1261
1261
|
const coordinatorMode = getConfig().coordinator_mode || 'responsive';
|
|
1262
1262
|
if (coordinatorMode === 'responsive') {
|
|
1263
|
-
rules.push('COORDINATOR: Use
|
|
1263
|
+
rules.push('COORDINATOR: Use messages(action="check") to check updates non-blockingly. Do NOT block in listen() — stay responsive to the user.');
|
|
1264
1264
|
} else {
|
|
1265
1265
|
rules.push('COORDINATOR: Use listen() to wait for agent results. Only return to human when all tasks are done or blocked.');
|
|
1266
1266
|
}
|
|
1267
1267
|
rules.push('Coordinators do NOT edit files or write code. Delegate ALL code work to other agents.');
|
|
1268
1268
|
}
|
|
1269
1269
|
|
|
1270
|
-
const listenCmd = isManagedMode() ? 'listen()' : (mode === 'group' ? '
|
|
1270
|
+
const listenCmd = isManagedMode() ? 'listen()' : (mode === 'group' ? 'listen(mode="group")' : 'listen()');
|
|
1271
1271
|
if (!isLeadRole) {
|
|
1272
|
-
rules.push(`After EVERY action, call ${listenCmd}. Never use sleep() or poll with
|
|
1272
|
+
rules.push(`After EVERY action, call ${listenCmd}. Never use sleep() or poll with messages().`);
|
|
1273
1273
|
}
|
|
1274
1274
|
|
|
1275
1275
|
if (level === 'minimal') {
|
|
@@ -1570,7 +1570,7 @@ function toolRegister(name, provider = null, skills = null) {
|
|
|
1570
1570
|
const coordinatorMode = getConfig().coordinator_mode || 'responsive';
|
|
1571
1571
|
nextAction = coordinatorMode === 'autonomous'
|
|
1572
1572
|
? 'Call get_briefing() to load project context, then listen() to coordinate your team.'
|
|
1573
|
-
: 'Call get_briefing() to load project context, then
|
|
1573
|
+
: 'Call get_briefing() to load project context, then messages(action="check") to check for pending work.';
|
|
1574
1574
|
}
|
|
1575
1575
|
|
|
1576
1576
|
// --- Build the result: next_action FIRST, then context ---
|
|
@@ -1695,7 +1695,7 @@ async function toolSendMessage(content, to = null, reply_to = null, channel = nu
|
|
|
1695
1695
|
const effectiveSendLimit = isAutonomousMode() ? 5 : sendLimit;
|
|
1696
1696
|
const myRole = (getProfiles()[registeredName] || {}).role;
|
|
1697
1697
|
if (isGroupMode() && sendsSinceLastListen >= effectiveSendLimit && myRole !== 'Coordinator') {
|
|
1698
|
-
return { error: `You must call
|
|
1698
|
+
return { error: `You must call listen() before sending again. You've sent ${sendsSinceLastListen} message(s) without listening (limit: ${effectiveSendLimit}). This prevents message storms.` };
|
|
1699
1699
|
}
|
|
1700
1700
|
|
|
1701
1701
|
// Response budget: track unaddressed sends, hint when depleted
|
|
@@ -1993,7 +1993,7 @@ async function toolSendMessage(content, to = null, reply_to = null, channel = nu
|
|
|
1993
1993
|
if (!recipientAlive) {
|
|
1994
1994
|
result.warning = `Agent "${to}" appears offline (PID not running). Message queued but may not be received until they reconnect.`;
|
|
1995
1995
|
} else if (to !== '__user__' && agents[to] && !agents[to].listening_since) {
|
|
1996
|
-
result.note = `Agent "${to}" is currently working (not in listen mode). Message queued — they'll see it when they finish their current task and call
|
|
1996
|
+
result.note = `Agent "${to}" is currently working (not in listen mode). Message queued — they'll see it when they finish their current task and call listen().`;
|
|
1997
1997
|
}
|
|
1998
1998
|
|
|
1999
1999
|
// Coordinator enforcement: warn if sending work assignment without creating a task first
|
|
@@ -2036,7 +2036,7 @@ function toolBroadcast(content) {
|
|
|
2036
2036
|
const effectiveSendLimitBcast = isAutonomousMode() ? 5 : sendLimit;
|
|
2037
2037
|
const myRole = (getProfiles()[registeredName] || {}).role;
|
|
2038
2038
|
if (isGroupMode() && sendsSinceLastListen >= effectiveSendLimitBcast && myRole !== 'Coordinator') {
|
|
2039
|
-
return { error: `You must call
|
|
2039
|
+
return { error: `You must call listen() before broadcasting again. You've sent ${sendsSinceLastListen} message(s) without listening (limit: ${effectiveSendLimitBcast}).` };
|
|
2040
2040
|
}
|
|
2041
2041
|
|
|
2042
2042
|
const rateErr = checkRateLimit(content, '__broadcast__');
|
|
@@ -2355,10 +2355,10 @@ async function toolListenCodex(from = null, outcome = null, task_id = null, summ
|
|
|
2355
2355
|
const taskList = getTasks();
|
|
2356
2356
|
const task = taskList.find(t => t.id === task_id);
|
|
2357
2357
|
if (!task) {
|
|
2358
|
-
return { error: true, message: `Invalid task_id "${task_id}" — task does not exist. Check list_tasks() and call
|
|
2358
|
+
return { error: true, message: `Invalid task_id "${task_id}" — task does not exist. Check list_tasks() and call listen(mode="codex") again with the correct task_id.` };
|
|
2359
2359
|
}
|
|
2360
2360
|
if (task.assignee && task.assignee !== registeredName) {
|
|
2361
|
-
return { error: true, message: `Task "${task_id}" is assigned to ${task.assignee}, not to you (${registeredName}). You cannot update another agent's task via
|
|
2361
|
+
return { error: true, message: `Task "${task_id}" is assigned to ${task.assignee}, not to you (${registeredName}). You cannot update another agent's task via listen(mode="codex").` };
|
|
2362
2362
|
}
|
|
2363
2363
|
const statusMap = { completed: 'done', blocked: 'blocked', failed: 'blocked_permanent' };
|
|
2364
2364
|
const newStatus = statusMap[outcome];
|
|
@@ -2486,9 +2486,9 @@ function toolSetConversationMode(mode) {
|
|
|
2486
2486
|
}
|
|
2487
2487
|
|
|
2488
2488
|
const messages = {
|
|
2489
|
-
group: 'Group mode enabled. Use
|
|
2489
|
+
group: 'Group mode enabled. Use listen(mode="group") to receive batched messages. All messages are shared with everyone.',
|
|
2490
2490
|
direct: 'Direct mode enabled. Use listen() for point-to-point messaging.',
|
|
2491
|
-
managed: 'Managed mode enabled. Call claim_manager() to become the manager, or wait for the manager to give you the floor via yield_floor(). Use listen()
|
|
2491
|
+
managed: 'Managed mode enabled. Call claim_manager() to become the manager, or wait for the manager to give you the floor via yield_floor(). Use listen() to receive messages.',
|
|
2492
2492
|
};
|
|
2493
2493
|
return { success: true, mode, message: messages[mode] };
|
|
2494
2494
|
}
|
|
@@ -2649,10 +2649,10 @@ async function toolListenGroup(outcome = null, task_id = null, summary = null) {
|
|
|
2649
2649
|
const taskList = getTasks();
|
|
2650
2650
|
const task = taskList.find(t => t.id === task_id);
|
|
2651
2651
|
if (!task) {
|
|
2652
|
-
return { error: true, message: `Invalid task_id "${task_id}" — task does not exist. Check list_tasks() and call
|
|
2652
|
+
return { error: true, message: `Invalid task_id "${task_id}" — task does not exist. Check list_tasks() and call listen() again with the correct task_id.` };
|
|
2653
2653
|
}
|
|
2654
2654
|
if (task.assignee && task.assignee !== registeredName) {
|
|
2655
|
-
return { error: true, message: `Task "${task_id}" is assigned to ${task.assignee}, not to you (${registeredName}). You cannot update another agent's task via
|
|
2655
|
+
return { error: true, message: `Task "${task_id}" is assigned to ${task.assignee}, not to you (${registeredName}). You cannot update another agent's task via listen().` };
|
|
2656
2656
|
}
|
|
2657
2657
|
const statusMap = { completed: 'done', blocked: 'blocked', failed: 'blocked_permanent' };
|
|
2658
2658
|
const newStatus = statusMap[outcome];
|
|
@@ -2906,8 +2906,8 @@ function classifyPriority(msg) {
|
|
|
2906
2906
|
return 'normal';
|
|
2907
2907
|
}
|
|
2908
2908
|
|
|
2909
|
-
// Build the response for
|
|
2910
|
-
// Context/history removed: agents should call
|
|
2909
|
+
// Build the response for listen (group mode) — kept lean to reduce context accumulation
|
|
2910
|
+
// Context/history removed: agents should call messages(action="history") when they need it
|
|
2911
2911
|
function buildListenGroupResponse(batch, consumed, agentName, listenStart) {
|
|
2912
2912
|
saveConsumedIds(agentName, consumed);
|
|
2913
2913
|
touchActivity();
|
|
@@ -5465,7 +5465,7 @@ function toolStartPlan(params) {
|
|
|
5465
5465
|
broadcastSystemMessage(
|
|
5466
5466
|
`[PLAN LAUNCHED] "${name}" — ${steps.length} steps, autonomous mode, ${useParallel ? 'parallel' : 'sequential'}. ` +
|
|
5467
5467
|
`${startedSteps.length} step(s) started. ` +
|
|
5468
|
-
`All agents: call get_work() to enter the autonomous work loop. Do NOT call
|
|
5468
|
+
`All agents: call get_work() to enter the autonomous work loop. Do NOT call listen().`
|
|
5469
5469
|
);
|
|
5470
5470
|
|
|
5471
5471
|
touchActivity();
|
|
@@ -5886,7 +5886,7 @@ function triggerStandupIfDue() {
|
|
|
5886
5886
|
if (inProgress.length > 0) summary += ` In progress: ${inProgress.map(t => `"${t.title}" (${t.assignee || '?'})`).join(', ')}.`;
|
|
5887
5887
|
if (blocked.length > 0) summary += ` BLOCKED: ${blocked.map(t => `"${t.title}" (${t.assignee || '?'})`).join(', ')}.`;
|
|
5888
5888
|
if (recentDone.length > 0) summary += ` Recently done: ${recentDone.length} task(s).`;
|
|
5889
|
-
summary += ' Each agent: report what you did, what\'s blocked, what\'s next. Then call
|
|
5889
|
+
summary += ' Each agent: report what you did, what\'s blocked, what\'s next. Then call listen().';
|
|
5890
5890
|
|
|
5891
5891
|
broadcastSystemMessage(summary, registeredName);
|
|
5892
5892
|
} catch (e) { log.warn("standup trigger failed:", e.message); }
|
|
@@ -6180,7 +6180,7 @@ function toolGetGuide(level = 'standard') {
|
|
|
6180
6180
|
const guide = buildGuide(level);
|
|
6181
6181
|
guide.your_name = registeredName;
|
|
6182
6182
|
if (level !== 'minimal') {
|
|
6183
|
-
guide.workflow = '1. get_briefing → 2. list_tasks/suggest_task → 3. claim task → 4. lock_file → 5. work → 6. unlock_file → 7. update_task done → 8.
|
|
6183
|
+
guide.workflow = '1. get_briefing → 2. list_tasks/suggest_task → 3. claim task → 4. lock_file → 5. work → 6. unlock_file → 7. update_task done → 8. listen()';
|
|
6184
6184
|
}
|
|
6185
6185
|
return guide;
|
|
6186
6186
|
}
|
|
@@ -7191,7 +7191,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
7191
7191
|
tools: [
|
|
7192
7192
|
{
|
|
7193
7193
|
name: 'register',
|
|
7194
|
-
description: 'Register this agent\'s identity. Must be called first. Returns a collaboration guide with all tool categories, critical rules, and workflow patterns — READ IT CAREFULLY before doing anything else. Then call get_briefing() for project context, then
|
|
7194
|
+
description: 'Register this agent\'s identity. Must be called first. Returns a collaboration guide with all tool categories, critical rules, and workflow patterns — READ IT CAREFULLY before doing anything else. Then call get_briefing() for project context, then listen() to join the conversation.',
|
|
7195
7195
|
inputSchema: {
|
|
7196
7196
|
type: 'object',
|
|
7197
7197
|
properties: {
|
|
@@ -7289,7 +7289,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
7289
7289
|
},
|
|
7290
7290
|
{
|
|
7291
7291
|
name: 'listen',
|
|
7292
|
-
description: 'Listen for messages. Use mode="standard" (default, direct 1:1), mode="group" (group/managed conversation, batched), or mode="codex" (Codex CLI — returns after 90s). Auto-detects mode from conversation state when mode is omitted.
|
|
7292
|
+
description: 'Listen for messages. Use mode="standard" (default, direct 1:1), mode="group" (group/managed conversation, batched), or mode="codex" (Codex CLI — returns after 90s). Auto-detects mode from conversation state when mode is omitted.',
|
|
7293
7293
|
inputSchema: {
|
|
7294
7294
|
type: 'object',
|
|
7295
7295
|
properties: {
|
|
@@ -7901,7 +7901,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
7901
7901
|
try {
|
|
7902
7902
|
const pending = getUnconsumedMessages(registeredName);
|
|
7903
7903
|
const pendingHint = pending.length > 0
|
|
7904
|
-
? `${pending.length} agent update(s) waiting. Call
|
|
7904
|
+
? `${pending.length} agent update(s) waiting. Call messages(action="consume") to read them.`
|
|
7905
7905
|
: null;
|
|
7906
7906
|
if (!na || bareListenRe.test(na)) {
|
|
7907
7907
|
// No guidance or bare listen() — replace with coordinator hint or nothing
|