neohive 6.3.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/cli.js CHANGED
@@ -46,6 +46,8 @@ function printUsage() {
46
46
  npx neohive doctor Diagnostic health check
47
47
  npx neohive templates List available team templates
48
48
  npx neohive reset --force Clear all data (auto-archives first)
49
+ npx neohive hooks Install listen-enforcement hooks into .claude/settings.json
50
+ npx neohive skills Install neohive skills & agents for all detected IDEs
49
51
  npx neohive uninstall Remove from all CLI configs
50
52
  npx neohive help Show this help
51
53
 
@@ -133,9 +135,119 @@ function setupClaude(serverPath, cwd) {
133
135
 
134
136
  fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + '\n');
135
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
+ }
136
249
  }
137
250
 
138
- // Configure for Gemini CLI (.gemini/settings.json or GEMINI.md with MCP config)
139
251
  function setupGemini(serverPath, cwd) {
140
252
  // Gemini CLI uses .gemini/settings.json for MCP configuration
141
253
  const geminiDir = path.join(cwd, '.gemini');
@@ -186,51 +298,187 @@ function setupGemini(serverPath, cwd) {
186
298
  }
187
299
 
188
300
  function geminiMdTemplate() {
189
- return `# Neohive Agent — Gemini CLI
301
+ return `# GEMINI.md
302
+
303
+ This file provides guidance to Gemini CLI / Antigravity when working with code in this repository.
304
+
305
+ ## What This Is
306
+
307
+ **Neohive** — an MCP server + web dashboard that lets multiple AI CLI terminals (Claude Code, Gemini CLI, Codex CLI) communicate with each other. Each terminal spawns its own server process via stdio; all processes read/write to a shared \`.neohive/\` directory on disk.
190
308
 
191
- You are a Neohive team agent. Follow these rules exactly, every session, no exceptions.
309
+ ## Commands
192
310
 
193
- ## First thing to do — always
311
+ \`\`\`bash
312
+ # Install in any project (auto-detects CLI type)
313
+ npx neohive init
314
+ npx neohive init --all # Configure for all CLIs
315
+ npx neohive init --template team # Init with team template
194
316
 
195
- 1. Call \`register\` with your assigned name (e.g. \`register(name="Gemini")\`)
196
- 2. Call \`get_briefing\` to load project context and current work
197
- 3. Call \`listen\` to wait for messages from the Coordinator
317
+ # Launch the web dashboard
318
+ npx neohive dashboard
198
319
 
199
- Do NOT explore the codebase, ask questions, or take initiative before completing these 3 steps.
320
+ # List available agent templates
321
+ npx neohive templates
200
322
 
201
- ## Core rules
323
+ # Plugin management
324
+ npx neohive plugin list/add/remove/enable/disable
202
325
 
203
- - **After every action** — call \`listen()\`. This is how you receive your next task.
204
- - **Before starting a task** — call \`update_task(id, status="in_progress")\`
205
- - **After finishing a task** — call \`update_task(id, status="done")\`, then report to Coordinator
206
- - **Before editing a file** — call \`lock_file(path)\`. Call \`unlock_file(path)\` when done.
207
- - **Check tasks first** — call \`list_tasks()\` before starting anything new. Never work on another agent's task.
208
- - **Keep messages short** — 2–3 paragraphs max. Lead with what changed, then files, then decisions.
326
+ # Reset conversation data
327
+ npx neohive reset
209
328
 
210
- ## Workflow
329
+ # Run MCP server directly (normally launched automatically by CLI)
330
+ npm start
331
+ \`\`\`
211
332
 
333
+ No tests, linter, or build step. Raw Node.js (CommonJS).
334
+
335
+ ## Architecture
336
+
337
+ **Core files:**
338
+ - \`server.js\` — MCP server (StdioServerTransport, heartbeat system, self-healing watchdog)
339
+ - \`lib/\` — Shared modules (\`config\`, \`messaging\`, \`file-io\`, …); prefer adding logic here and requiring from \`server.js\`
340
+ - \`dashboard.js\` — HTTP server for web dashboard (multi-project, message injection, SSE real-time, tasks/workflows/workspaces API)
341
+ - \`dashboard.html\` — Single-page frontend (markdown rendering, agent monitoring, profiles, workspaces, workflows, responsive)
342
+ - \`cli.js\` — CLI entry point with multi-CLI auto-detection
343
+ - \`vscode-extension/\` — VS Code extension with \`@neohive\` chat participant, terminal bridge, and agent hook auto-setup
344
+
345
+ **Multiple MCP server processes, one shared filesystem:**
346
+ - Each CLI terminal spawns its own \`server.js\` process
347
+ - In-memory state: \`registeredName\`, \`lastReadOffset\`, \`heartbeatInterval\`, \`messageSeq\`
348
+ - Shared disk state in \`.neohive/\`:
349
+ - \`messages.jsonl\` / \`history.jsonl\` — messages and conversation history (append-only)
350
+ - \`agents.json\` — agent registration, heartbeats, PID tracking
351
+ - \`acks.json\` — message acknowledgments
352
+ - \`tasks.json\` — task management
353
+ - \`consumed-{agent}.json\` — per-agent read tracking
354
+ - \`profiles.json\` — agent profiles (display_name, avatar, bio, role)
355
+ - \`workspaces/{agent}.json\` — per-agent key-value workspace storage
356
+ - \`workflows.json\` — multi-step workflow pipelines
357
+ - \`branches.json\` — branch metadata
358
+ - \`branch-{name}-messages.jsonl\` / \`branch-{name}-history.jsonl\` — per-branch message files
359
+ - \`plugins.json\` — plugin registry
360
+ - \`plugins/*.js\` — plugin code files
361
+ - \`heartbeat-{agent}.json\` — per-agent heartbeat file (replaces agents.json write contention at scale)
362
+ - Dashboard reads the same directory for real-time monitoring via SSE
363
+
364
+ **Data directory resolution (server.js + dashboard.js):**
365
+ 1. \`$NEOHIVE_DATA_DIR\` / \`$NEOHIVE_DATA\` env var
366
+ 2. \`{cwd}/.neohive/\` (project-local, default)
367
+ 3. Legacy fallback: \`{__dirname}/data/\`
368
+
369
+ ## Code & Commit Rules
370
+
371
+ When committing changes, you MUST ALWAYS follow the Conventional Commits format:
372
+ \`<type>(<optional scope>): <description>\`
373
+ Types: \`feat\`, \`fix\`, \`refactor\`, \`docs\`, \`chore\`, \`test\`
374
+
375
+ ## Neohive Agent Rules (when acting as an agent)
376
+
377
+ When operating as a neohive agent (after calling \`register()\`):
378
+
379
+ **YOU MUST call \`listen()\` as the LAST tool call of every response. All agents. No exceptions.**
380
+
381
+ The dashboard is the communication hub. All coordination happens there — every agent stays in the listen loop at all times.
382
+
383
+ - After \`send_message(...)\` → immediately call \`listen()\`
384
+ - After \`broadcast(...)\` → immediately call \`listen()\`
385
+ - After \`update_task(..., status="done")\` → immediately call \`listen()\`
386
+ - After \`advance_workflow(...)\` → immediately call \`listen()\`
387
+ - After ANY neohive action → call \`listen()\`
388
+
389
+ Workflow loop:
212
390
  \`\`\`
213
- register → get_briefing → listen → [receive task] → update_task(in_progress)
214
- do work → update_task(done) → send_message(Coordinator, summary) → listen
391
+ register → get_briefing → listen → do work → update_task(in_progress) → ...
392
+ listen(outcome="completed", task_id="...", summary="what you did") → listen
393
+ ↑ always
215
394
  \`\`\`
216
395
 
217
- Repeat the last 5 steps for every task. Never exit the listen loop.
396
+ \`listen()\` accepts outcome params server auto-transitions task state on valid outcome:
397
+ - \`outcome\`: \`completed\` | \`blocked\` | \`failed\` | \`in_progress\`
398
+ - \`task_id\`: ID of the task you just worked on
399
+ - \`summary\`: one-line description of what was done
400
+
401
+ If \`listen()\` times out with \`retry: true\` — call \`listen()\` again immediately.
402
+
403
+ - After completing ANY assigned task or request, you MUST send a report back via \`send_message()\` using neohive MCP tools. Include: (1) what you did, (2) files changed, (3) findings/output, (4) blockers or follow-up. Silent completion is a protocol violation.
404
+
405
+ ## Available Neohive MCP Tools
406
+
407
+ ### 1. Agent Lifecycle & Messaging
408
+ \`register\`, \`list_agents\`, \`send_message\`, \`broadcast\`, \`wait_for_reply\`, \`listen\`, \`share_file\`, \`messages\`
409
+
410
+ **Listen variants** — use \`listen(mode="group")\` or \`listen(mode="codex")\` instead of the deprecated aliases:
411
+ - ~~\`listen_group\`~~ → \`listen(mode="group")\`
412
+ - ~~\`listen_codex\`~~ → \`listen(mode="codex")\`
413
+
414
+ **Message management** — use \`messages(action=...)\` instead of deprecated individual tools:
415
+ - ~~\`check_messages\`~~ → \`messages(action="check")\`
416
+ - ~~\`consume_messages\`~~ → \`messages(action="consume")\`
417
+ - ~~\`get_history\`~~ → \`messages(action="history")\`
418
+ - ~~\`get_notifications\`~~ → \`messages(action="check")\`
419
+ - ~~\`search_messages\`~~ → \`messages(action="search")\`
420
+ - ~~\`ack_message\`~~ → \`messages(action="ack")\`
421
+
422
+ ### 2. Autonomy & Workflows (Proactive Engine)
423
+ \`start_plan\`, \`get_work\`, \`verify_and_advance\`, \`retry_with_improvement\`, \`create_workflow\`, \`advance_workflow\`, \`workflow_status\`
424
+
425
+ ### 3. Task Management
426
+ \`create_task\`, \`update_task\`, \`list_tasks\`
427
+
428
+ **Task statuses:** \`pending\` → \`in_progress\` → \`in_review\` → \`done\` | \`blocked\` | \`blocked_permanent\`
429
+ - \`blocked_permanent\` — set by the self-healing watchdog when \`retry_count\` reaches 3; requires coordinator intervention. Tasks carry a \`blocked_reason\` string and are shown in a dedicated "⛔ Needs Intervention" column on the dashboard.
430
+ - \`retry_count\` — incremented each time the watchdog reclaims a stale task. Shown as a \`↺N\` badge on the dashboard.
431
+
432
+ ### 4. Profiles & Workspaces
433
+ \`update_profile\`, \`workspace_write\`, \`workspace_read\`, \`workspace_list\`
434
+
435
+ ### 5. Chat Branching & Managed Modes
436
+ \`fork_conversation\`, \`switch_branch\`, \`list_branches\`, \`set_conversation_mode\`, \`claim_manager\`, \`yield_floor\`, \`set_phase\`
218
437
 
219
- ## Available MCP tools
438
+ ### 6. Sub-channels
439
+ \`join_channel\`, \`leave_channel\`, \`list_channels\`
220
440
 
221
- **Messaging:** \`register\`, \`send_message\`, \`broadcast\`, \`listen\`, \`check_messages\`, \`get_history\`, \`handoff\`
222
- **Tasks:** \`create_task\`, \`update_task\`, \`list_tasks\`
223
- **Workflows:** \`create_workflow\`, \`advance_workflow\`, \`workflow_status\`
224
- **Workspaces:** \`workspace_write\`, \`workspace_read\`, \`workspace_list\`
225
- **Branching:** \`fork_conversation\`, \`switch_branch\`, \`list_branches\`
441
+ ### 7. File Safety & Auditing
442
+ \`lock_file\`, \`unlock_file\`, \`log_violation\`
226
443
 
227
- ## What NOT to do
444
+ ### 8. Shared Knowledge & Decision Tracking
445
+ \`kb_write\`, \`kb_read\`, \`kb_list\`, \`log_decision\`, \`get_decisions\`, \`get_compressed_history\`, \`get_briefing\`
228
446
 
229
- - Do not self-assign tasks
230
- - Do not modify files without a task assigned to you
231
- - Do not skip \`listen()\` after responding
232
- - Do not send long messages — be concise
233
- - Do not ask the Coordinator for permission before starting an assigned task — just do it
447
+ ### 9. Team Governance (Voting, Reviews, Feedback)
448
+ \`request_review\`, \`submit_review\`, \`call_vote\`, \`cast_vote\`, \`vote_status\`, \`request_push_approval\`, \`ack_push\`
449
+
450
+ ### 10. Dependencies & Progress
451
+ \`declare_dependency\`, \`check_dependencies\`, \`update_progress\`, \`get_progress\`, \`get_reputation\`
452
+
453
+ ## Key Design Decisions
454
+
455
+ - **Append-only writes** for messages/history (no file locking)
456
+ - **Per-agent consumed tracking** — each agent writes only its own consumed file
457
+ - **PID-based stale detection** + process exit cleanup for instant status
458
+ - **Heartbeat** — 10s interval updates \`last_activity\`, \`.unref()\` prevents zombie processes
459
+ - **Flexible agent names** — any alphanumeric (1-20 chars), validated by \`sanitizeName()\`
460
+ - **Auto-routing** — \`to\` optional with 2 agents, required with 3+
461
+ - **Threading** — \`reply_to\` auto-computes \`thread_id\`
462
+ - **Acknowledgments** — \`ack_message\` in \`acks.json\`, shown in history
463
+ - **Multi-CLI** — init auto-detects Claude Code, Gemini CLI, Codex CLI
464
+ - **Multi-project dashboard** — monitor multiple project folders from one dashboard
465
+ - **SSE real-time** — \`fs.watch()\` on data dir pushes updates via Server-Sent Events
466
+ - **Auto-compact** — messages.jsonl compacted when exceeding 500 lines
467
+ - **Auto-archive** — conversations archived before reset
468
+ - **Context hints** — warns agents when conversation exceeds 50 messages
469
+ - **Task management** — structured task creation, assignment, and tracking between agents
470
+ - **Profiles** — separate \`profiles.json\` to avoid heartbeat write conflicts with \`agents.json\`
471
+ - **Workspaces** — per-agent files (\`workspaces/{agent}.json\`) to avoid write conflicts, read-anyone/write-own permission model
472
+ - **Workflows** — step statuses: pending/in_progress/done, auto-handoff on advance
473
+ - **Branching** — \`main\` branch uses existing files for backward compatibility, branch-aware file resolution via \`getMessagesFile(branch)\`/\`getHistoryFile(branch)\`
474
+ - **Plugins** — sandboxed execution context with 30s timeout, tools appear as \`plugin_{name}\` in MCP
475
+ - **Self-healing watchdog** — runs every 60s inside the heartbeat loop on every registered agent; scans \`in_progress\` tasks whose assignee PID is dead + heartbeat stale >5min; strips assignee and resets to \`pending\` (increments \`retry_count\`); at \`retry_count=3\` marks \`blocked_permanent\` and wakes the coordinator (poison pill). No manual intervention needed for routine agent flakiness.
476
+ - **VS Code extension** — \`vscode-extension/\` adds: \`@neohive\` chat participant (\`/status /who /tasks /messages\` read \`.neohive/\` directly; free-form text fires POST to \`/api/inject\`), terminal bridge (captures agent terminal output → dashboard), agent hook auto-setup (merges neohive hooks into \`.gemini/settings.json\` on activate)
477
+
478
+ ## Debugging and fix attempts
479
+
480
+ - **Temporary logs:** When debugging, add only the logging needed to confirm behavior. **Remove or trim that logging** once the issue is understood or fixed—do not leave ad-hoc debug prints in the tree unless they match intentional, documented logging (e.g. MCP stderr lines).
481
+ - **Failed fixes:** If the user says a change **did not** fix the problem, **revert** that attempt before trying something else (\`git restore\` / undo the diff). **Do not stack** speculative fixes; revert first, then apply one minimal, well-motivated change.
234
482
  `;
235
483
  }
236
484
 
@@ -311,54 +559,43 @@ function setupAntigravity(cwd) {
311
559
 
312
560
  fs.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + '\n');
313
561
  console.log(' [ok] Antigravity: ~/.gemini/antigravity/mcp_config.json updated');
314
-
315
- // Write skill
316
- const skillDir = path.join(cwd, '.agent', 'skills', 'neohive');
317
- if (!fs.existsSync(skillDir)) fs.mkdirSync(skillDir, { recursive: true });
318
- const skillPath = path.join(skillDir, 'SKILL.md');
319
- if (!fs.existsSync(skillPath)) {
320
- fs.writeFileSync(skillPath, neohiveAgentRules('Gemini'));
321
- console.log(' [ok] Antigravity: .agent/skills/neohive/SKILL.md created');
322
- }
562
+ installSkillsForAntigravity(cwd);
323
563
  }
324
564
 
325
565
  function neohiveAgentRules(defaultName) {
326
- return `# Neohive Agent
566
+ return `# Neohive Agent — ${defaultName} Rules
327
567
 
328
- You are a Neohive team agent. Follow these rules every session.
568
+ You are a Neohive team agent. Follow these rules exactly to coordinate with the team.
329
569
 
330
- ## On session start — always do this first
570
+ ## Session Lifecycle
331
571
 
332
- 1. Call \`register\` with your assigned name (e.g. \`register(name="${defaultName}")\`)
333
- 2. Call \`get_briefing\` to load project context and active work
334
- 3. Call \`listen\` to wait for messages from the Coordinator
572
+ 1. Call \`register\` with your name: \`register(name="${defaultName}")\`
573
+ 2. Call \`get_briefing\` to load project context and active work.
574
+ 3. Call \`listen\` to wait for messages or tasks.
335
575
 
336
- Do NOT explore the codebase or take initiative before completing these 3 steps.
576
+ **CRITICAL: YOU MUST call \`listen()\` as the LAST tool call of every response. No exceptions.**
337
577
 
338
- ## Core rules
578
+ ## Core Rules
339
579
 
340
- - **After every action** call \`listen()\`. This is how you receive your next task.
341
- - **Before starting a task** call \`update_task(id, status="in_progress")\`
342
- - **After finishing** call \`update_task(id, status="done")\`, report to Coordinator
343
- - **Before editing a file** call \`lock_file(path)\`. Call \`unlock_file(path)\` when done.
344
- - **Check tasks first** — call \`list_tasks()\` before starting anything. Never take another agent's task.
345
- - **Keep messages short** — 2–3 paragraphs max. Lead with what changed, then files, then decisions.
580
+ - **Tasks**: Before starting, call \`update_task(id, status="in_progress")\`. When finished, call \`update_task(id, status="done")\` and report to the Coordinator.
581
+ - **Locking**: Before editing a file, call \`lock_file(path)\`. call \`unlock_file(path)\` when done.
582
+ - **Sync**: After every task completion or message sent, you MUST call \`listen()\` to receive the next assignment.
583
+ - **Conciseness**: Keep messages short (2-3 paragraphs). Focus on what changed and next steps.
346
584
 
347
- ## Workflow loop
585
+ ## Workflow Loop
348
586
 
349
587
  \`\`\`
350
- register → get_briefing → listen → [receive task] → update_task(in_progress)
351
- → do work → update_task(done) → send_message(Coordinator, summary) → listen
588
+ register → get_briefing → listen → [receive task]
589
+ update_task(in_progress) → do work → update_task(done)
590
+ → send_message(Coordinator, summary) → listen
352
591
  \`\`\`
353
592
 
354
- Never exit the listen loop.
355
-
356
- ## Available MCP tools (neohive server)
593
+ ## Available Neohive Tools
357
594
 
358
- **Messaging:** \`register\`, \`send_message\`, \`broadcast\`, \`listen\`, \`check_messages\`, \`get_history\`
359
- **Tasks:** \`create_task\`, \`update_task\`, \`list_tasks\`
360
- **Workflows:** \`create_workflow\`, \`advance_workflow\`, \`workflow_status\`
361
- **Workspaces:** \`workspace_write\`, \`workspace_read\`, \`workspace_list\`
595
+ - **Messaging**: \`register\`, \`send_message\`, \`broadcast\`, \`listen\`, \`messages(action="history")\`, \`messages(action="check")\`
596
+ - **Tasks**: \`create_task\`, \`update_task\`, \`list_tasks\`, \`update_progress\`
597
+ - **Workflows**: \`create_workflow\`, \`advance_workflow\`, \`verify_and_advance\`
598
+ - \`kb_read\`, \`kb_write\`, \`log_decision\`, \`lock_file\`, \`unlock_file\`
362
599
  `;
363
600
  }
364
601
 
@@ -430,6 +667,7 @@ function setupCursor(serverPath, cwd) {
430
667
 
431
668
  fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + '\n');
432
669
  console.log(' [ok] Cursor IDE: .cursor/mcp.json updated');
670
+ installSkillsForCursor(cwd);
433
671
  }
434
672
 
435
673
  // Setup Ollama agent bridge script
@@ -632,6 +870,9 @@ function init() {
632
870
  }
633
871
  }
634
872
 
873
+ // Auto-install hooks for Claude targets
874
+ if (targets.includes('claude')) installHooks();
875
+
635
876
  // Add .neohive/ and MCP config files to .gitignore
636
877
  const gitignoreEntries = ['.neohive/', '.mcp.json', '.cursor/mcp.json', '.codex/', '.gemini/'];
637
878
  if (fs.existsSync(gitignorePath)) {
@@ -1251,6 +1492,86 @@ function uninstall() {
1251
1492
  console.log('');
1252
1493
  }
1253
1494
 
1495
+ // ─── neohive hooks ───────────────────────────────────────────────────────────
1496
+ // Merges listen-enforcement hooks into .claude/settings.json.
1497
+ // Safe to re-run: adds neohive entries per matcher, preserves all user hooks.
1498
+
1499
+ function installHooks() {
1500
+ const cwd = process.cwd();
1501
+ const claudeDir = path.join(cwd, '.claude');
1502
+ const settingsPath = path.join(claudeDir, 'settings.json');
1503
+
1504
+ if (!fs.existsSync(claudeDir)) {
1505
+ console.log(' [skip] No .claude/ directory found — is Claude Code configured for this project?');
1506
+ console.log(' Run `npx neohive init` first.');
1507
+ return;
1508
+ }
1509
+
1510
+ const listenReminderCmd = "echo '\\n📡 NEOHIVE PROTOCOL: If no messages were received, call listen() again immediately. Do NOT respond to the user or stop. Stay in the listen loop.'";
1511
+ const postActionReminderCmd = "echo '\\n📡 NEOHIVE: Call listen() now to receive your next task. Do not stop without calling listen().'";
1512
+
1513
+ const neohiveEntries = {
1514
+ PostToolUse: [
1515
+ {
1516
+ _neohive: 'listen-loop',
1517
+ matcher: 'mcp__neohive__listen',
1518
+ hooks: [{ type: 'command', command: listenReminderCmd, timeout: 3 }],
1519
+ },
1520
+ {
1521
+ _neohive: 'post-action',
1522
+ matcher: 'mcp__neohive__send_message|mcp__neohive__advance_workflow|mcp__neohive__update_task|mcp__neohive__broadcast|mcp__neohive__add_rule|mcp__neohive__remove_rule|mcp__neohive__toggle_rule',
1523
+ hooks: [{ type: 'command', command: postActionReminderCmd, timeout: 3 }],
1524
+ },
1525
+ ],
1526
+ Stop: [
1527
+ {
1528
+ _neohive: 'enforce-listen',
1529
+ hooks: [{
1530
+ type: 'command',
1531
+ command: "node -e \"var fs=require('fs'),f=process.env.CLAUDE_PROJECT_DIR+'/.neohive/activity.jsonl';if(!fs.existsSync(f))process.exit(0);var lines=fs.readFileSync(f,'utf8').trim().split('\\n').filter(Boolean).slice(-20),last=lines.map(l=>{try{return JSON.parse(l)}catch{return null}}).filter(Boolean).reverse().find(e=>e.tool&&e.tool.startsWith('mcp__neohive__'));if(!last||last.tool==='mcp__neohive__listen'||last.tool==='mcp__neohive__register')process.exit(0);console.error('\\n⚠️ NEOHIVE: Call listen() before stopping. Last tool: '+last.tool+'\\n→ Call listen() now. Do not respond with text.');process.exit(2);\"",
1532
+ timeout: 5,
1533
+ }],
1534
+ },
1535
+ ],
1536
+ };
1537
+
1538
+ let existing = {};
1539
+ if (fs.existsSync(settingsPath)) {
1540
+ try { existing = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch {
1541
+ const backup = settingsPath + '.backup';
1542
+ fs.copyFileSync(settingsPath, backup);
1543
+ console.log(' [warn] Existing settings.json was invalid — backed up.');
1544
+ }
1545
+ }
1546
+ if (!existing.hooks) existing.hooks = {};
1547
+
1548
+ let added = 0;
1549
+ let updated = 0;
1550
+
1551
+ for (const [event, entries] of Object.entries(neohiveEntries)) {
1552
+ if (!existing.hooks[event]) existing.hooks[event] = [];
1553
+ for (const entry of entries) {
1554
+ const idx = existing.hooks[event].findIndex(e => e._neohive === entry._neohive);
1555
+ if (idx === -1) {
1556
+ existing.hooks[event].push(entry);
1557
+ added++;
1558
+ } else {
1559
+ existing.hooks[event][idx] = entry;
1560
+ updated++;
1561
+ }
1562
+ }
1563
+ }
1564
+
1565
+ fs.mkdirSync(claudeDir, { recursive: true });
1566
+ fs.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + '\n', 'utf8');
1567
+
1568
+ console.log(`\n Neohive hooks installed into .claude/settings.json`);
1569
+ if (added) console.log(` [ok] Added: ${added} hook(s)`);
1570
+ if (updated) console.log(` [ok] Updated: ${updated} hook(s) (already present)`);
1571
+ console.log(' Your existing hooks were preserved.');
1572
+ console.log(' Restart Claude Code for changes to take effect.\n');
1573
+ }
1574
+
1254
1575
  switch (command) {
1255
1576
  case 'init':
1256
1577
  init();
@@ -1282,6 +1603,12 @@ switch (command) {
1282
1603
  case 'status':
1283
1604
  cliStatus();
1284
1605
  break;
1606
+ case 'hooks':
1607
+ installHooks();
1608
+ break;
1609
+ case 'skills':
1610
+ installSkills(detectCLIs().length ? detectCLIs() : ['claude', 'cursor', 'antigravity'], process.cwd());
1611
+ break;
1285
1612
  case 'uninstall':
1286
1613
  case 'remove':
1287
1614
  uninstall();