neohive 6.4.1 → 6.4.2

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 CHANGED
@@ -144,7 +144,7 @@ npx neohive init --claude
144
144
 
145
145
  `init` handles MCP config, hooks, and skills in one step. For the smoothest experience:
146
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.
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. Also available on [Open VSX](https://open-vsx.org/extension/alionix/neohive).
148
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
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
150
 
@@ -368,7 +368,7 @@ The [Neohive extension](https://marketplace.visualstudio.com/items?itemName=alio
368
368
  | **`@neohive` Chat** | Query agent status, tasks, and messages directly from Copilot Chat |
369
369
  | **Auto MCP Setup** | Configures MCP and hooks automatically on activation — no manual config needed |
370
370
 
371
- **Install:** [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=alionix.neohive) — or search "Neohive" in the Extensions panel.
371
+ **Install:** [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=alionix.neohive) · [Open VSX](https://open-vsx.org/extension/alionix/neohive) — or search "Neohive" in the Extensions panel.
372
372
 
373
373
  <br />
374
374
 
@@ -407,8 +407,7 @@ Full details: [SECURITY.md](SECURITY.md)
407
407
  | MCP tools (full) | [docs/reference/tools.md](../docs/reference/tools.md) |
408
408
  | AI onboarding (repo map) | [docs/ai-onboarding.md](../docs/ai-onboarding.md) |
409
409
  | MCP tools (high-level tour) | [docs/mcp-tools-documentation.md](../docs/mcp-tools-documentation.md) |
410
- | Documentation audit / doc debt | [docs/documentation-audit.md](../docs/documentation-audit.md) |
411
- | Vision & Roadmap | [VISION.md](../VISION.md) |
410
+ | Roadmap | [ROADMAP.md](../ROADMAP.md) |
412
411
  | Security Policy | [SECURITY.md](SECURITY.md) |
413
412
  | Contributing Guide | [CONTRIBUTING.md](../CONTRIBUTING.md) |
414
413
  | Changelog | [CHANGELOG.md](CHANGELOG.md) · [root CHANGELOG](../CHANGELOG.md) |
package/SECURITY.md CHANGED
@@ -1,60 +1,15 @@
1
- # Security Policy
1
+ # Neohive Security Policy (npm package)
2
2
 
3
- ## Supported Versions
3
+ The **complete, canonical** security policy — supported versions, data model, full protections table, LAN access details — is in the repository:
4
4
 
5
- | Version | Supported |
6
- | ------- | --------- |
7
- | **6.x.x** | Yes — current major line |
8
- | **5.x.x** | Best-effort security fixes only |
9
- | **< 5.0** | No |
5
+ **[github.com/fakiho/neohive SECURITY.md](https://github.com/fakiho/neohive/blob/master/SECURITY.md)**
10
6
 
11
- Older **3.x / 2.x** lines are **not** supported; upgrade via `npx neohive init` and npm.
7
+ ---
12
8
 
13
- ## Reporting a Vulnerability
9
+ ## Reporting a vulnerability
14
10
 
15
- If you discover a security vulnerability in Neohive, please report it responsibly.
11
+ **Do not open a public GitHub issue.**
16
12
 
17
- **Do NOT open a public GitHub issue for security vulnerabilities.**
13
+ Email **contact@alionix.com** or use [GitHub private vulnerability reporting](https://github.com/fakiho/neohive/security/advisories/new).
18
14
 
19
- Instead, please email **contact@alionix.com** or use [GitHub's private vulnerability reporting](https://github.com/fakiho/neohive/security/advisories/new).
20
-
21
- ### What to include
22
-
23
- - Description of the vulnerability
24
- - Steps to reproduce
25
- - Potential impact
26
- - Suggested fix (if any)
27
-
28
- ### Response timeline
29
-
30
- - **Acknowledgment**: Within 48 hours
31
- - **Initial assessment**: Within 1 week
32
- - **Fix release**: As soon as possible, typically within 2 weeks
33
-
34
- ## Security Model
35
-
36
- Neohive is a **local message broker** — it passes text messages between CLI terminals via shared files on your local machine.
37
-
38
- ### What it does NOT do
39
-
40
- - Does not give agents filesystem access (they already have it via their CLI)
41
- - Does not expose anything to the internet by default (dashboard binds to `127.0.0.1`; **`dashboard --lan` / `NEOHIVE_LAN`** binds more broadly — use the generated LAN token)
42
- - Does not store or transmit API keys
43
- - Does not run any cloud services
44
- - Does not execute remote code
45
-
46
- ### Built-in protections
47
-
48
- - **CORS restriction** — dashboard only accepts requests from localhost
49
- - **XSS prevention** — all user inputs are escaped before rendering
50
- - **Path traversal protection** — agents cannot read files outside the project directory
51
- - **Symlink protection** — follows symlinks and validates the real path
52
- - **Origin enforcement** — POST/DELETE requests require valid localhost origin
53
- - **SSE connection limits** — prevents connection exhaustion
54
- - **Input validation** — agent names, branch names, and file paths are validated
55
- - **Message size limits** — 1MB max per message
56
- - **Plugin sandboxing** — plugins run with a 30-second timeout
57
-
58
- ### LAN mode
59
-
60
- When using `--lan` mode, the dashboard is exposed to your local network only. It is never accessible from the internet.
15
+ Include a description, reproduction steps, impact, and a suggested fix if you have one. We acknowledge within 48 hours and aim to release a fix within 2 weeks.
package/dashboard.html CHANGED
@@ -4591,7 +4591,7 @@
4591
4591
  </div>
4592
4592
  </div>
4593
4593
  <div class="app-footer">
4594
- <span>Neohive v6.4.1</span>
4594
+ <span>Neohive v6.4.2</span>
4595
4595
  </div>
4596
4596
  <div class="profile-popup" id="profile-popup" onclick="event.stopPropagation()">
4597
4597
  <div class="profile-popup-header">
package/lib/audit.js CHANGED
@@ -10,8 +10,8 @@ const crypto = require('crypto');
10
10
  // Configuration
11
11
  const AUDIT_MAX_SIZE = parseInt(process.env.NEOHIVE_AUDIT_MAX_SIZE) || 10485760; // 10MB
12
12
  const AUDIT_RETENTION_DAYS = parseInt(process.env.NEOHIVE_AUDIT_RETENTION_DAYS) || 30;
13
- const AUDIT_ARGS_MAX_LENGTH = parseInt(process.env.NEOHIVE_AUDIT_ARGS_MAX_LENGTH) || 500;
14
- const AUDIT_RESULT_MAX_LENGTH = parseInt(process.env.NEOHIVE_AUDIT_RESULT_MAX_LENGTH) || 1000;
13
+ const AUDIT_ARGS_MAX_LENGTH = parseInt(process.env.NEOHIVE_AUDIT_ARGS_MAX_LENGTH) || 50000;
14
+ const AUDIT_RESULT_MAX_LENGTH = parseInt(process.env.NEOHIVE_AUDIT_RESULT_MAX_LENGTH) || 10000;
15
15
  const AUDIT_LEVEL = process.env.NEOHIVE_AUDIT_LEVEL || 'standard';
16
16
 
17
17
  // Tool categories for classification
@@ -201,12 +201,14 @@ function logToolCall(agent, toolName, args, result, durationMs, context = {}) {
201
201
  }
202
202
  };
203
203
 
204
- // Truncate large args/results
205
- if (entry.args) {
206
- entry.args = JSON.parse(truncateContent(JSON.stringify(entry.args), AUDIT_ARGS_MAX_LENGTH));
204
+ // Truncate large args/results only when serializing (never parse truncated JSON)
205
+ const argsStr = JSON.stringify(entry.args);
206
+ if (argsStr && argsStr.length > AUDIT_ARGS_MAX_LENGTH) {
207
+ entry.args = { _truncated: true, preview: argsStr.substring(0, AUDIT_ARGS_MAX_LENGTH) };
207
208
  }
208
- if (entry.result) {
209
- entry.result = JSON.parse(truncateContent(JSON.stringify(entry.result), AUDIT_RESULT_MAX_LENGTH));
209
+ const resultStr = JSON.stringify(entry.result);
210
+ if (resultStr && resultStr.length > AUDIT_RESULT_MAX_LENGTH) {
211
+ entry.result = { _truncated: true, preview: resultStr.substring(0, AUDIT_RESULT_MAX_LENGTH) };
210
212
  }
211
213
 
212
214
  // Add to pending writes for batch processing
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "neohive",
3
+ "version": "6.0.2",
4
+ "description": "Multi-agent collaboration layer. Turn Claude Code into a team — agents communicate, delegate tasks, and build together. Adds /neohive:launch-team, /neohive:status, /neohive:send, /neohive:plan commands.",
5
+ "author": {
6
+ "name": "Alionix",
7
+ "url": "https://github.com/fakiho"
8
+ },
9
+ "homepage": "https://github.com/fakiho/neohive",
10
+ "repository": "https://github.com/fakiho/neohive",
11
+ "license": "SEE LICENSE IN LICENSE",
12
+ "keywords": [
13
+ "multi-agent",
14
+ "collaboration",
15
+ "team",
16
+ "communication",
17
+ "mcp",
18
+ "neohive"
19
+ ],
20
+ "skills": "./skills/",
21
+ "agents": "./agents/",
22
+ "hooks": "./hooks/hooks.json",
23
+ "mcpServers": "./.mcp.json"
24
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "mcpServers": {
3
+ "neohive": {
4
+ "command": "npx",
5
+ "args": ["-y", "neohive"],
6
+ "env": {
7
+ "NEOHIVE_DATA_DIR": "${CLAUDE_PROJECT_DIR}/.neohive"
8
+ }
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,55 @@
1
+ # Neohive Plugin for Claude Code
2
+
3
+ Turn Claude Code into a multi-agent team. Agents communicate, delegate tasks, and build together.
4
+
5
+ ## Skills (Slash Commands)
6
+
7
+ | Command | Description |
8
+ |---------|-------------|
9
+ | `/neohive:launch-team [template]` | Launch a team from a template (pair, team, review, managed, debate) |
10
+ | `/neohive:status` | Show agent status, active tasks, and workflow progress |
11
+ | `/neohive:send [agent] [message]` | Send a quick message to another agent |
12
+ | `/neohive:plan [description]` | Create a workflow plan from a natural language description |
13
+
14
+ ## Hooks
15
+
16
+ - **SessionStart** -- Detects Neohive projects and reminds agents to register
17
+ - **PreToolUse** -- Warns when editing files locked by another agent
18
+ - **PostToolUse** -- Tracks MCP tool usage for activity analytics
19
+
20
+ ## Subagents
21
+
22
+ - **coordinator** -- Project coordinator that plans, delegates, and tracks work (never writes code)
23
+
24
+ ## Installation
25
+
26
+ ### From GitHub (recommended)
27
+ ```
28
+ /plugin install neohive
29
+ ```
30
+
31
+ ### Manual
32
+ 1. Copy the `neohive-plugin/` directory to your Claude Code plugins folder
33
+ 2. Restart Claude Code
34
+
35
+ ### Via npm
36
+ ```bash
37
+ npx neohive init --plugin
38
+ ```
39
+
40
+ ## Gemini CLI
41
+
42
+ For Gemini CLI, use the instructions and config in `gemini-extension/`:
43
+ ```bash
44
+ npx neohive init --gemini
45
+ ```
46
+
47
+ ## Requirements
48
+
49
+ - Claude Code v1.0+
50
+ - Node.js 18+
51
+ - neohive npm package (`npx neohive` must work)
52
+
53
+ ## License
54
+
55
+ See LICENSE file.
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: coordinator
3
+ description: A project coordinator subagent that plans work, creates tasks, and delegates to team agents. Use when you need to orchestrate a multi-agent workflow.
4
+ model: sonnet
5
+ effort: high
6
+ maxTurns: 30
7
+ disallowedTools: Edit, Write, Bash
8
+ skills:
9
+ - neohive:launch-team
10
+ - neohive:status
11
+ - neohive:plan
12
+ - neohive:conventions
13
+ ---
14
+
15
+ You are a project coordinator. Your job is to plan, delegate, and track work — you NEVER write code.
16
+
17
+ Your tools: `register`, `get_briefing`, `send_message`, `broadcast`, `create_task`, `update_task`, `list_tasks`, `create_workflow`, `advance_workflow`, `workflow_status`, `distribute_prompt`, `start_plan`, `messages`, `kb_write`, `kb_read`, `log_decision`, `get_decisions`, `listen`.
18
+
19
+ Workflow:
20
+ 1. Call `register(name="Coordinator")` then `get_briefing()` to load context
21
+ 2. Break the user's request into research tasks and coding tasks
22
+ 3. Create tasks with `create_task` and assign to available agents
23
+ 4. Use `distribute_prompt` to dispatch task instructions to agents
24
+ 5. Call `messages(action="check")` to check for agent updates (non-blocking)
25
+ 6. Process reports, advance workflows with `advance_workflow`, assign next tasks
26
+ 7. Synthesize results and present to user
27
+ 8. **Always call `listen()` as the last tool call of every response**
@@ -0,0 +1,24 @@
1
+ # Neohive Multi-Agent Collaboration
2
+
3
+ You are part of a Neohive multi-agent team. Use the neohive MCP tools to communicate with other agents.
4
+
5
+ ## Getting Started
6
+ 1. Call `register` with your name to join the team
7
+ 2. Call `get_briefing` for project context and active work
8
+ 3. Call `listen` to wait for messages from other agents
9
+
10
+ ## Conventions
11
+ - Always call `listen()` after every action -- this is how you receive messages
12
+ - Update task status: `update_task(in_progress)` when starting, `update_task(done)` when finishing
13
+ - Lock files before editing: `lock_file()` before, `unlock_file()` after
14
+ - Report completions to the Coordinator with: what changed, files modified, decisions made
15
+ - Keep messages to 2-3 paragraphs max
16
+ - Use `kb_write()` for findings, `kb_read()` to check team knowledge
17
+ - Never work on another agent's task -- check `list_tasks()` first
18
+
19
+ ## Available Tools
20
+ - **Messaging:** register, send_message, broadcast, listen, messages, handoff
21
+ - **Tasks:** create_task, update_task, list_tasks
22
+ - **Workflows:** create_workflow, advance_workflow, workflow_status
23
+ - **Knowledge:** kb_write, kb_read, kb_list, log_decision
24
+ - **Coordination:** lock_file, unlock_file, update_progress, get_briefing
@@ -0,0 +1,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "neohive": {
4
+ "command": "npx",
5
+ "args": ["-y", "neohive"],
6
+ "env": {
7
+ "NEOHIVE_DATA_DIR": ".neohive"
8
+ },
9
+ "timeout": 30
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,87 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "matcher": "startup",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "${CLAUDE_PLUGIN_ROOT}/scripts/auto-register.sh",
10
+ "timeout": 10,
11
+ "statusMessage": "Checking Neohive team status..."
12
+ }
13
+ ]
14
+ }
15
+ ],
16
+ "UserPromptSubmit": [
17
+ {
18
+ "hooks": [
19
+ {
20
+ "type": "command",
21
+ "command": "${CLAUDE_PLUGIN_ROOT}/scripts/before-prompt.sh",
22
+ "timeout": 5,
23
+ "statusMessage": "Loading Neohive team context..."
24
+ }
25
+ ]
26
+ }
27
+ ],
28
+ "PreToolUse": [
29
+ {
30
+ "matcher": "Edit|Write",
31
+ "hooks": [
32
+ {
33
+ "type": "command",
34
+ "command": "${CLAUDE_PLUGIN_ROOT}/scripts/enforce-locks.sh",
35
+ "timeout": 5,
36
+ "statusMessage": "Checking file locks..."
37
+ }
38
+ ]
39
+ }
40
+ ],
41
+ "PostToolUse": [
42
+ {
43
+ "matcher": "mcp__neohive__.*",
44
+ "hooks": [
45
+ {
46
+ "type": "command",
47
+ "command": "${CLAUDE_PLUGIN_ROOT}/scripts/track-activity.sh",
48
+ "async": true,
49
+ "timeout": 5
50
+ }
51
+ ]
52
+ },
53
+ {
54
+ "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",
55
+ "hooks": [
56
+ {
57
+ "type": "command",
58
+ "command": "echo '\\n📡 NEOHIVE: Call listen() now to receive your next task. Do not stop without calling listen().'",
59
+ "timeout": 3
60
+ }
61
+ ]
62
+ },
63
+ {
64
+ "matcher": "Edit|Write|MultiEdit|mcp__neohive__update_task",
65
+ "hooks": [
66
+ {
67
+ "type": "command",
68
+ "command": "${CLAUDE_PLUGIN_ROOT}/scripts/post-tool-use.sh",
69
+ "async": true,
70
+ "timeout": 5
71
+ }
72
+ ]
73
+ }
74
+ ],
75
+ "Stop": [
76
+ {
77
+ "hooks": [
78
+ {
79
+ "type": "command",
80
+ "command": "${CLAUDE_PLUGIN_ROOT}/scripts/enforce-listen.sh",
81
+ "timeout": 5
82
+ }
83
+ ]
84
+ }
85
+ ]
86
+ }
87
+ }
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+ # SessionStart hook: check if Neohive is active for this project.
3
+ # Outputs a dynamic context message — no hardcoded agent names.
4
+
5
+ NEOHIVE_DIR="${CLAUDE_PROJECT_DIR}/.neohive"
6
+
7
+ if [ -d "$NEOHIVE_DIR" ]; then
8
+ # Count registered agents
9
+ AGENT_COUNT=0
10
+ AGENT_NAMES=""
11
+ if [ -f "$NEOHIVE_DIR/agents.json" ]; then
12
+ AGENT_COUNT=$(jq 'length' "$NEOHIVE_DIR/agents.json" 2>/dev/null || echo "0")
13
+ # List alive agent names (dynamic — no hardcoding)
14
+ AGENT_NAMES=$(jq -r '[to_entries[] | select(.value.alive == true) | .key] | join(", ")' \
15
+ "$NEOHIVE_DIR/agents.json" 2>/dev/null || echo "")
16
+ fi
17
+
18
+ # Count active workflows
19
+ WF_COUNT=0
20
+ if [ -f "$NEOHIVE_DIR/workflows.json" ]; then
21
+ WF_COUNT=$(jq '[.[] | select(.status == "active")] | length' \
22
+ "$NEOHIVE_DIR/workflows.json" 2>/dev/null || echo "0")
23
+ fi
24
+
25
+ # Count pending tasks
26
+ PENDING_TASKS=0
27
+ if [ -f "$NEOHIVE_DIR/tasks.json" ]; then
28
+ PENDING_TASKS=$(jq '[.[] | select(.status == "pending" or .status == "in_progress")] | length' \
29
+ "$NEOHIVE_DIR/tasks.json" 2>/dev/null || echo "0")
30
+ fi
31
+
32
+ # Build the names hint (show only if agents are online)
33
+ NAMES_HINT=""
34
+ if [ -n "$AGENT_NAMES" ]; then
35
+ NAMES_HINT=" Online agents: $AGENT_NAMES."
36
+ fi
37
+
38
+ cat <<EOF
39
+ {
40
+ "hookSpecificOutput": {
41
+ "hookEventName": "SessionStart"
42
+ },
43
+ "systemMessage": "Neohive is active ($AGENT_COUNT agents registered, $WF_COUNT active workflows, $PENDING_TASKS pending/in-progress tasks).$NAMES_HINT\n\nTo join: call register() with the name you were assigned, then get_briefing(), then listen(). Do NOT invent a name — the user or Coordinator will tell you which name to use."
44
+ }
45
+ EOF
46
+ fi
47
+
48
+ exit 0
@@ -0,0 +1,47 @@
1
+ #!/bin/bash
2
+ # UserPromptSubmit hook: inject live neohive team context before every prompt.
3
+ # No hardcoded names — all data read dynamically from .neohive/ files.
4
+ # Exit 0 always (never blocks the prompt).
5
+
6
+ NEOHIVE_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}/.neohive"
7
+
8
+ # Not a neohive project — nothing to inject
9
+ [ -d "$NEOHIVE_DIR" ] || exit 0
10
+
11
+ # Agents: list alive agents with their roles (dynamic, no hardcoded names)
12
+ AGENTS_ONLINE=""
13
+ if [ -f "$NEOHIVE_DIR/agents.json" ]; then
14
+ AGENTS_ONLINE=$(jq -r '
15
+ [to_entries[]
16
+ | select(.value.alive == true)
17
+ | "\(.key)(\(.value.role // "agent"))"]
18
+ | join(", ")
19
+ ' "$NEOHIVE_DIR/agents.json" 2>/dev/null || echo "")
20
+ fi
21
+
22
+ # Task counts
23
+ PENDING_COUNT=0
24
+ IN_PROGRESS_COUNT=0
25
+ if [ -f "$NEOHIVE_DIR/tasks.json" ]; then
26
+ PENDING_COUNT=$(jq '[.[] | select(.status == "pending")] | length' \
27
+ "$NEOHIVE_DIR/tasks.json" 2>/dev/null || echo "0")
28
+ IN_PROGRESS_COUNT=$(jq '[.[] | select(.status == "in_progress")] | length' \
29
+ "$NEOHIVE_DIR/tasks.json" 2>/dev/null || echo "0")
30
+ fi
31
+
32
+ # Only inject if there is an active team
33
+ [ -z "$AGENTS_ONLINE" ] && exit 0
34
+
35
+ # Escape for JSON
36
+ AGENTS_ESCAPED=$(printf '%s' "$AGENTS_ONLINE" | sed 's/"/\\"/g')
37
+
38
+ cat <<EOF
39
+ {
40
+ "hookSpecificOutput": {
41
+ "hookEventName": "UserPromptSubmit"
42
+ },
43
+ "systemMessage": "Neohive team status: $AGENTS_ESCAPED | Tasks: $PENDING_COUNT pending, $IN_PROGRESS_COUNT in-progress. Reminder: call listen() after every action."
44
+ }
45
+ EOF
46
+
47
+ exit 0
@@ -0,0 +1,72 @@
1
+ #!/bin/bash
2
+ # Stop hook: block agent from stopping if last neohive action wasn't listen()
3
+ # Also auto-reports to coordinator via /api/inject when blocking.
4
+ # Exit 2 = block stop (forces Claude to continue and call listen)
5
+ # Exit 0 = allow stop
6
+
7
+ NEOHIVE_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}/.neohive"
8
+ ACTIVITY_FILE="$NEOHIVE_DIR/activity.jsonl"
9
+ SESSION="${CLAUDE_SESSION_ID:-}"
10
+ NEOHIVE_URL="${NEOHIVE_SERVER_URL:-http://localhost:4321}"
11
+
12
+ # Allow exit: no tool calls this session (user cancelled before any tools ran)
13
+ LOOP_COUNT="${CLAUDE_LOOP_COUNT:-0}"
14
+ [ "$LOOP_COUNT" = "0" ] && exit 0
15
+
16
+ # Allow exit: user aborted — agent had no chance to call listen()
17
+ STOP_STATUS="${CLAUDE_STOP_HOOK_STATUS:-}"
18
+ [ "$STOP_STATUS" = "aborted" ] && exit 0
19
+
20
+ # Not a neohive project — allow stop
21
+ [ -f "$ACTIVITY_FILE" ] || exit 0
22
+
23
+ # Get the last neohive tool used in THIS session
24
+ LAST_TOOL=$(tail -100 "$ACTIVITY_FILE" 2>/dev/null | jq -r --arg session "$SESSION" '
25
+ select(.session == $session or $session == "") | .tool
26
+ ' | grep "^mcp__neohive__" | tail -1)
27
+
28
+ # No neohive tools used in this session — allow stop
29
+ [ -z "$LAST_TOOL" ] && exit 0
30
+
31
+ # Look up agent name from the last activity
32
+ AGENT_NAME=$(tail -100 "$ACTIVITY_FILE" 2>/dev/null | jq -r --arg session "$SESSION" '
33
+ select(.session == $session or $session == "") | .agent
34
+ ' | tail -1)
35
+ AGENT="${AGENT_NAME:-unknown}"
36
+
37
+ # All roles must call listen() — no exemptions
38
+
39
+ # Last action was listen/register/rules management — allow stop
40
+ case "$LAST_TOOL" in
41
+ mcp__neohive__listen|\
42
+ mcp__neohive__register|\
43
+ mcp__neohive__add_rule|mcp__neohive__remove_rule|mcp__neohive__toggle_rule)
44
+ exit 0
45
+ ;;
46
+ esac
47
+
48
+ # Last neohive action was something other than listen — report + block
49
+
50
+ # Auto-report to coordinator via neohive /api/inject (HTTP equivalent of send_message)
51
+ # Fire-and-forget: don't fail if dashboard isn't running
52
+ PAYLOAD=$(printf '{"from":"%s","to":"__user__","content":"[STOP HOOK] %s attempted to stop without calling listen(). Last tool: %s. Blocking stop — agent will be prompted to call listen() now.","priority":"normal"}' \
53
+ "$AGENT" "$AGENT" "$LAST_TOOL")
54
+ curl -s -X POST "${NEOHIVE_URL}/api/inject" \
55
+ -H "Content-Type: application/json" \
56
+ -d "$PAYLOAD" \
57
+ --max-time 2 \
58
+ > /dev/null 2>&1 || true
59
+
60
+ cat <<'EOF'
61
+
62
+ ⚠️ NEOHIVE — REQUIRED ACTION BEFORE STOPPING:
63
+
64
+ Your last neohive action was not listen(). You MUST call listen() before stopping.
65
+ This keeps you in the receive loop for your next task.
66
+ Your coordinator has been notified via the dashboard.
67
+
68
+ → Call: listen()
69
+
70
+ Do not respond with text. Call listen() now.
71
+ EOF
72
+ exit 2
@@ -0,0 +1,34 @@
1
+ #!/bin/bash
2
+ # PreToolUse hook: check if the file being edited is locked by another agent
3
+ # Input: JSON via stdin with tool_input.file_path or tool_input.file
4
+ # Exit 0 = allow (with optional context), Exit 2 = block
5
+
6
+ INPUT=$(cat)
7
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.file // empty' 2>/dev/null)
8
+ NEOHIVE_DIR="${CLAUDE_PROJECT_DIR}/.neohive"
9
+ LOCKS_FILE="$NEOHIVE_DIR/locks.json"
10
+
11
+ # No file path or no locks file — allow
12
+ if [ -z "$FILE_PATH" ] || [ ! -f "$LOCKS_FILE" ]; then
13
+ exit 0
14
+ fi
15
+
16
+ # Normalize: make path relative to project dir for matching
17
+ REL_PATH="${FILE_PATH#$CLAUDE_PROJECT_DIR/}"
18
+
19
+ # Check if file is locked (check both absolute and relative paths)
20
+ LOCKED_BY=$(jq -r --arg fp "$FILE_PATH" --arg rp "$REL_PATH" '(.[$fp].agent // .[$rp].agent) // empty' "$LOCKS_FILE" 2>/dev/null)
21
+
22
+ if [ -n "$LOCKED_BY" ]; then
23
+ # File is locked — soft enforcement (warn but don't block)
24
+ cat <<EOF
25
+ {
26
+ "hookSpecificOutput": {
27
+ "hookEventName": "PreToolUse",
28
+ "additionalContext": "WARNING: File '$REL_PATH' is locked by agent '$LOCKED_BY'. Consider coordinating with them or using lock_file() first to claim ownership."
29
+ }
30
+ }
31
+ EOF
32
+ fi
33
+
34
+ exit 0
@@ -0,0 +1,119 @@
1
+ #!/bin/bash
2
+ # PostToolUse hook — three jobs:
3
+ # 1. send_message → __user__: echo message content as a systemMessage in chat,
4
+ # and send the last assistant chat turn as report context to the dashboard.
5
+ # 2. File edits: fire-and-forget report to dashboard.
6
+ # 3. Task updates: fire-and-forget report to dashboard.
7
+ #
8
+ # Works with both Claude Code (mcp__neohive__*) and Cursor (MCP:*) tool name formats.
9
+
10
+ INPUT=$(cat)
11
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // "unknown"' 2>/dev/null)
12
+ NEOHIVE_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}/.neohive"
13
+ NEOHIVE_URL="${NEOHIVE_SERVER_URL:-http://localhost:4321}"
14
+
15
+ [ -d "$NEOHIVE_DIR" ] || exit 0
16
+
17
+ # Normalize: strip "MCP:" or "mcp__<server>__" prefix → bare tool name
18
+ BARE=$(echo "$TOOL_NAME" | sed 's/^MCP://; s/^mcp__[^_]*__//')
19
+
20
+ # Resolve agent name from response or env
21
+ AGENT=$(echo "$INPUT" | jq -r '.tool_response.from // empty' 2>/dev/null)
22
+ [ -z "$AGENT" ] && AGENT="${CLAUDE_AGENT_NAME:-unknown}"
23
+
24
+ # ── Helper: extract last assistant text turn from the transcript JSONL ────────
25
+ last_chat_text() {
26
+ local transcript
27
+ transcript=$(echo "$INPUT" | jq -r '.transcript_path // empty' 2>/dev/null)
28
+ [ -z "$transcript" ] && return
29
+ [ -f "$transcript" ] || return
30
+
31
+ # Use python3 (always available on macOS/Linux) to walk backward through the
32
+ # JSONL and find the last assistant turn that has a text content block.
33
+ # role is at the top level; content is inside .message.content or .content.
34
+ python3 - "$transcript" <<'PYEOF'
35
+ import sys, json
36
+
37
+ path = sys.argv[1]
38
+ with open(path, 'rb') as f:
39
+ lines = f.read().splitlines()
40
+
41
+ for line in reversed(lines):
42
+ try:
43
+ obj = json.loads(line)
44
+ except Exception:
45
+ continue
46
+ role = obj.get('role') or (obj.get('message') or {}).get('role', '')
47
+ if role != 'assistant':
48
+ continue
49
+ content = (obj.get('message') or {}).get('content') or obj.get('content') or []
50
+ if not isinstance(content, list):
51
+ continue
52
+ for block in content:
53
+ if isinstance(block, dict) and block.get('type') == 'text':
54
+ text = block.get('text', '').strip()
55
+ if text:
56
+ # Truncate to 500 chars so the JSON payload stays manageable
57
+ print(text[:500], end='')
58
+ sys.exit(0)
59
+ PYEOF
60
+ }
61
+
62
+ case "$BARE" in
63
+ # ── send_message to __user__ ────────────────────────────────────────────────
64
+ send_message)
65
+ TO=$(echo "$INPUT" | jq -r '.tool_input.to // ""' 2>/dev/null)
66
+ CONTENT=$(echo "$INPUT" | jq -r '.tool_input.content // ""' 2>/dev/null)
67
+
68
+ if [ "$TO" = "__user__" ] && [ -n "$CONTENT" ]; then
69
+ # Inject into chat as systemMessage
70
+ CONTENT_ESC=$(echo "$CONTENT" | sed 's/"/\\"/g; s/$/\\n/' | tr -d '\n')
71
+ printf '{"hookSpecificOutput":{"hookEventName":"PostToolUse"},"systemMessage":"[Neohive → you] %s"}\n' \
72
+ "$CONTENT_ESC"
73
+
74
+ # Also send last chat turn as context to the dashboard
75
+ LAST_CHAT=$(last_chat_text)
76
+ if [ -n "$LAST_CHAT" ]; then
77
+ LAST_ESC=$(printf '%s' "$LAST_CHAT" | sed 's/"/\\"/g')
78
+ REPORT="[REPORT] ${AGENT} sent message. Last chat turn: ${LAST_ESC}"
79
+ REPORT_ESC=$(printf '%s' "$REPORT" | sed 's/"/\\"/g')
80
+ curl -s -X POST "${NEOHIVE_URL}/api/inject" \
81
+ -H "Content-Type: application/json" \
82
+ -d "{\"from\":\"${AGENT}\",\"to\":\"__user__\",\"content\":\"${REPORT_ESC}\",\"priority\":\"normal\"}" \
83
+ --max-time 2 \
84
+ > /dev/null 2>&1 || true
85
+ fi
86
+ fi
87
+ exit 0
88
+ ;;
89
+
90
+ # ── File edits ───────────────────────────────────────────────────────────────
91
+ Edit|Write|MultiEdit)
92
+ FILE=$(echo "$INPUT" | jq -r \
93
+ '.tool_input.file_path // .tool_input.file // "unknown"' 2>/dev/null)
94
+ FILE="${FILE#$CLAUDE_PROJECT_DIR/}"
95
+ MSG="[POST-TOOL] ${AGENT} edited: ${FILE}"
96
+ ;;
97
+
98
+ # ── Task status updates ──────────────────────────────────────────────────────
99
+ update_task)
100
+ TASK_ID=$(echo "$INPUT" | jq -r '.tool_input.task_id // "?"' 2>/dev/null)
101
+ STATUS=$(echo "$INPUT" | jq -r '.tool_input.status // "?"' 2>/dev/null)
102
+ MSG="[POST-TOOL] ${AGENT} updated task ${TASK_ID} → ${STATUS}"
103
+ ;;
104
+
105
+ *)
106
+ exit 0
107
+ ;;
108
+ esac
109
+
110
+ [ -z "$MSG" ] && exit 0
111
+
112
+ MSG_ESCAPED=$(printf '%s' "$MSG" | sed 's/"/\\"/g')
113
+ curl -s -X POST "${NEOHIVE_URL}/api/inject" \
114
+ -H "Content-Type: application/json" \
115
+ -d "{\"from\":\"${AGENT}\",\"to\":\"__user__\",\"content\":\"${MSG_ESCAPED}\",\"priority\":\"normal\"}" \
116
+ --max-time 2 \
117
+ > /dev/null 2>&1 || true
118
+
119
+ exit 0
@@ -0,0 +1,23 @@
1
+ #!/bin/bash
2
+ # PostToolUse hook: log Neohive MCP tool calls for activity analytics
3
+ # Runs async — does not block tool execution
4
+ # Input: JSON via stdin with tool_name, tool_input, tool_response
5
+
6
+ INPUT=$(cat)
7
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // "unknown"' 2>/dev/null)
8
+ NEOHIVE_DIR="${CLAUDE_PROJECT_DIR}/.neohive"
9
+ ACTIVITY_FILE="$NEOHIVE_DIR/activity.jsonl"
10
+
11
+ # Only log if neohive data dir exists
12
+ if [ -d "$NEOHIVE_DIR" ]; then
13
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
14
+ INPUT_SIZE=$(echo "$INPUT" | jq -r '.tool_input | tostring | length' 2>/dev/null || echo "0")
15
+ OUTPUT_SIZE=$(echo "$INPUT" | jq -r '.tool_response | tostring | length' 2>/dev/null || echo "0")
16
+
17
+ # Extract agent name from tool response if available
18
+ AGENT=$(echo "$INPUT" | jq -r '.tool_response.from // .tool_input.name // empty' 2>/dev/null)
19
+
20
+ echo "{\"tool\":\"$TOOL_NAME\",\"timestamp\":\"$TIMESTAMP\",\"input_size\":$INPUT_SIZE,\"output_size\":$OUTPUT_SIZE,\"agent\":\"${AGENT:-unknown}\",\"session\":\"${CLAUDE_SESSION_ID:-unknown}\"}" >> "$ACTIVITY_FILE"
21
+ fi
22
+
23
+ exit 0
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: conventions
3
+ description: Neohive multi-agent collaboration conventions. Automatically loaded when working in a multi-agent team to ensure proper tool usage, communication patterns, and workflow management.
4
+ user-invocable: false
5
+ ---
6
+
7
+ ## Neohive Collaboration Conventions
8
+
9
+ When working as part of a Neohive multi-agent team:
10
+
11
+ 1. **Register and get briefing first** — call `register()` then `get_briefing()` before any other action
12
+ 2. **Always call `listen()` as the LAST tool call of every response** — no exceptions, all agents
13
+ 3. **Handle `retry: true`** — if `listen()` returns `{retry: true}`, call `listen()` again immediately
14
+ 4. **Use `listen()` to complete tasks** — pass outcome params instead of a separate update_task call:
15
+ - `listen(outcome="completed", task_id="...", summary="one line of what was done")`
16
+ - `listen(outcome="blocked", task_id="...", summary="what is blocking you")`
17
+ 5. **Update task to in_progress when starting** — call `update_task(id, status="in_progress")` when you pick up a task
18
+ 6. **Lock files before editing** — call `lock_file(path)` before editing, `unlock_file(path)` after
19
+ 7. **Report completions via send_message** — after finishing a task send the coordinator: what changed, files modified, decisions made
20
+ 8. **Use KB for shared knowledge** — `kb_write()` for findings and decisions, `kb_read()` before starting work to avoid duplication
21
+ 9. **Never work on another agent's task** — check `list_tasks()` first
22
+ 10. **Keep messages concise** — 2–3 paragraphs max
23
+
24
+ ### listen() outcome loop
25
+
26
+ ```
27
+ register → get_briefing → listen → pick up task → update_task(in_progress)
28
+ → do work → send_message(coordinator, report) → listen(outcome="completed", task_id, summary)
29
+ ↑ always last
30
+ ```
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: launch-team
3
+ description: Launch a multi-agent team from a template. Lists available templates and generates prompts for each agent. Use when starting a new multi-agent collaboration, team session, or when the user says "launch team" or "start agents".
4
+ argument-hint: [template-name]
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ Launch a multi-agent team using Neohive templates.
9
+
10
+ 1. Call `list_agents` to see who's already online
11
+ 2. Call `workflow_status` to check if there's an active workflow
12
+ 3. If $ARGUMENTS is provided, use it as the template name
13
+ 4. If no template specified, list available templates:
14
+ - **pair** — 2 agents for brainstorming or Q&A
15
+ - **team** — Coordinator + Researcher + Coder for complex features
16
+ - **review** — Author + Reviewer for code review pipeline
17
+ - **managed** — Manager with floor control for structured sessions with large teams
18
+ - **debate** — Pro vs Con structured debate between two agents
19
+ 5. For the chosen template, generate the launch prompt for each agent role
20
+ 6. Each prompt must instruct the agent to:
21
+ - Call `register(name="<AgentName>")` first
22
+ - Call `get_briefing()` to load context
23
+ - Call `listen()` to enter the listen loop
24
+ 7. Display the prompts and instruct the user to paste each into a separate terminal running `claude` (or the relevant CLI)
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: plan
3
+ description: Create a multi-agent workflow plan from a natural language description. Breaks down the task into steps, assigns to agents, and creates the workflow. Use when the user describes a feature or task they want the team to build.
4
+ argument-hint: [task description]
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ Create a workflow plan for the multi-agent team.
9
+
10
+ 1. Call `list_agents` to see available agents and their roles/skills
11
+ 2. Call `kb_read` to check for existing decisions or context relevant to this task
12
+ 3. Analyze $ARGUMENTS to identify the steps needed
13
+ 4. Assign each step to the best-suited agent based on their skills
14
+ 5. Call `create_workflow` with the plan:
15
+ - name: derived from the task description
16
+ - steps: array of `{description, assignee, depends_on}`
17
+ - autonomous: true if all agents are online and no human checkpoints needed, false to let Coordinator manage step-by-step
18
+ 6. Call `create_task` for each step that can start immediately (no unresolved dependencies)
19
+ 7. Call `distribute_prompt` to dispatch task instructions to assigned agents
20
+ 8. Call `log_decision` to record the plan breakdown
21
+ 9. Display the created workflow in a clean format showing steps, assignees, and dependencies
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: send
3
+ description: Send a message to another agent or broadcast to all agents via Neohive. Use when the user wants to communicate with a specific agent or the whole team.
4
+ argument-hint: [agent-name|all] [message]
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ Send a message to an agent or the entire team.
9
+
10
+ 1. Parse $ARGUMENTS — first word is agent name (or `all`), rest is the message
11
+ 2. If no agent specified, call `list_agents` and ask the user which agent to target
12
+ 3. If agent is `all`, call `broadcast(content=<message>)`
13
+ 4. Otherwise call `send_message(to=<agent>, content=<message>)`
14
+ 5. Call `listen()` after sending to stay in the listen loop
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: status
3
+ description: Show the current status of the Neohive multi-agent team — who's online, active tasks, workflow progress, and recent messages. Use when the user asks about agent status, team progress, or "what's happening".
4
+ ---
5
+
6
+ Check the status of the multi-agent team:
7
+
8
+ 1. Call `list_agents` to see who's online/offline with their roles
9
+ 2. Call `list_tasks` to see all tasks and their statuses
10
+ 3. Call `workflow_status` to see workflow progress and current step
11
+ 4. Call `messages(action="check")` to surface any unread messages
12
+ 5. Call `get_decisions` to show recent decisions logged by the team
13
+ 6. Summarize in a clean format:
14
+ - **Agents:** name, status (online/offline), role, current task
15
+ - **Tasks:** title, assignee, status (`pending` / `in_progress` / `in_review` / `done` / `blocked`)
16
+ - **Workflows:** name, progress, current step, autonomous or managed
17
+ - **Recent decisions:** logged rationale from `get_decisions`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neohive",
3
- "version": "6.4.1",
3
+ "version": "6.4.2",
4
4
  "description": "The MCP collaboration layer for AI CLI tools. Turn Claude Code, Gemini CLI, and Codex CLI into a team.",
5
5
  "main": "server.js",
6
6
  "bin": {
@@ -24,6 +24,7 @@
24
24
  "design-system.css",
25
25
  "design-system.html",
26
26
  "cli.js",
27
+ "neohive-plugin/",
27
28
  "lib/",
28
29
  "tools/",
29
30
  "templates/",
package/server.js CHANGED
@@ -6498,7 +6498,7 @@ function toolSubmitReview(reviewId, status, feedback) {
6498
6498
 
6499
6499
  review.status = status;
6500
6500
  review.reviewer = registeredName;
6501
- review.feedback = (feedback || '').substring(0, 2000);
6501
+ review.feedback = feedback || '';
6502
6502
  review.reviewed_at = new Date().toISOString();
6503
6503
 
6504
6504
  // Review → retry loop: track review rounds, auto-route feedback, auto-approve after 2 rounds