Common Mistakes When Building Hive Agents
Critical Errors
Using tools that don't exist — Always verify tools are available in the hive-tools MCP server before assigning them to nodes. Never guess tool names.
Wrong entry_points format — MUST be {"start": "first-node-id"}. NOT a set, NOT {node_id: [keys]}.
Wrong mcp_servers.json format — Flat dict (no "mcpServers" wrapper). cwd must be "../../tools". command must be "uv" with args ["run", "python", ...].
Missing STEP 1/STEP 2 in client-facing prompts — Without explicit phases, the LLM calls set_output before the user responds. Always use the pattern.
Forgetting nullable_output_keys — When a node receives inputs from multiple edges and some inputs only arrive on certain edges (e.g., feedback), mark those as nullable. Without this, the executor blocks waiting for a value that will never arrive.
Creating dead-end nodes in forever-alive graphs — Every node must have at least one outgoing edge. A node with no outgoing edges ends the execution, breaking the loop.
Setting max_node_visits to a non-zero value in forever-alive agents — The framework default is max_node_visits=0 (unbounded). Setting it to any positive value (e.g., 1) means the node stops executing after that many visits, silently breaking the forever-alive loop. Only set max_node_visits > 0 in one-shot agents with feedback loops that need bounded retries.
Missing module-level exports in __init__.py — The runner loads agents via importlib.import_module(package_name), which imports __init__.py. It then reads goal, nodes, edges, entry_node, entry_points, pause_nodes, terminal_nodes, conversation_mode, identity_prompt, loop_config via getattr(). If ANY of these are missing from __init__.py, they default to None or {} — causing "must define goal, nodes, edges" errors or "node X is unreachable" validation failures. ALL module-level variables from agent.py must be re-exported in __init__.py.
Value Errors
Invalid conversation_mode value — Only two valid values: "continuous" (recommended for interactive agents) or omit entirely (for isolated per-node conversations). Values like "client_facing", "interactive", "adaptive" do NOT exist and will cause runtime errors.
Invalid loop_config keys — Only three valid keys: max_iterations (int), max_tool_calls_per_turn (int), max_history_tokens (int). Keys like "strategy", "mode", "timeout" are NOT valid and are silently ignored or cause errors.
Fabricating tools that don't exist — Never guess tool names. Always verify via discover_mcp_tools(). Common hallucinations: csv_read, csv_write, csv_append, file_upload, database_query. If a required tool doesn't exist, redesign the agent to use tools that DO exist (e.g., save_data/load_data for data persistence).
Design Errors
- Too many thin nodes — Hard limit: 2-4 nodes for most agents. Each node boundary serializes outputs to shared memory and loses all in-context information (tool results, intermediate reasoning, conversation history). A node with 0 tools that just does LLM reasoning is NOT a real node — merge it into its predecessor or successor.
Merge when:
- Node has NO tools — pure LLM reasoning belongs in the node that produces or consumes its data
- Node sets only 1 trivial output (e.g.,
set_output("done", "true")) — collapse into predecessor
- Multiple consecutive autonomous nodes with same/similar tools — combine into one
- A "report" or "summary" node that just presents analysis — merge into the client-facing node
- A "schedule" or "confirm" node that doesn't actually schedule anything — remove entirely
Keep separate when:
- Client-facing vs autonomous — different interaction models require separate nodes
- Fundamentally different tool sets (e.g., web search vs file I/O)
- Fan-out parallelism — parallel branches MUST be separate nodes
Bad example (7 nodes — WAY too many):
profile_setup → daily_intake → update_tracker → analyze_progress → generate_plan → schedule_reminders → report
analyze_progress has no tools. schedule_reminders just sets one boolean. report just presents analysis. update_tracker and generate_plan are sequential autonomous work.
Good example (3 nodes):
intake (client-facing) → process (autonomous: track + analyze + plan) → intake (loop back)
One client-facing node handles ALL user interaction (setup, logging, reports). One autonomous node handles ALL backend work (CSV update, analysis, plan generation) with tools and context preserved.
Adding framework gating for LLM behavior — Don't add output rollback, premature rejection, or interaction protocol injection. Fix with better prompts or custom judges.
Not using continuous conversation mode — Interactive agents should use conversation_mode="continuous". Without it, each node starts with blank context.
Adding terminal nodes by default — ALL agents should use terminal_nodes=[] (forever-alive) unless the user explicitly requests a one-shot/batch agent. Forever-alive is the standard pattern. Every node must have at least one outgoing edge. Dead-end nodes break the loop.
Calling set_output in same turn as tool calls — Instruct the LLM to call set_output in a SEPARATE turn from real tool calls.
File Template Errors
Wrong import paths — Use from framework.graph import ..., NOT from core.framework.graph import .... The PYTHONPATH includes core/.
Missing storage path — Agent class must set self._storage_path = Path.home() / ".hive" / "agents" / "agent_name".
Missing mcp_servers.json — Without this, the agent has no tools at runtime.
Bare python command in mcp_servers.json — Use "command": "uv" with args ["run", "python", ...].
Testing Errors
- Using
runner.run() on forever-alive agents — runner.run() calls trigger_and_wait() which blocks until the graph reaches a terminal node. Forever-alive agents have terminal_nodes=[], so runner.run() hangs forever. This is the #1 cause of stuck test suites.
For forever-alive agents, write structural tests instead:
- Validate graph structure (nodes, edges, entry points)
- Verify node specs (tools, prompts, client-facing flag)
- Check goal/constraints/success criteria definitions
- Test that
AgentRunner.load() + _setup() succeeds (skip if no API key)
What NOT to do:
# WRONG — hangs forever on forever-alive agents
result = await runner.run({"topic": "quantum computing"})
Correct pattern for structure tests:
def test_research_has_web_tools(self):
assert "web_search" in research_node.tools
def test_research_routes_back_to_interact(self):
edges_to_interact = [e for e in edges if e.source == "research" and e.target == "interact"]
assert edges_to_interact
Stale tests after agent restructuring — When you change an agent's node count or names (e.g., 4 nodes → 2 nodes), the tests MUST be updated too. Tests referencing old node names (e.g., "review", "report") will fail or hang. Always check that test assertions match the current nodes/__init__.py.
Running full integration tests without API keys — Structural tests (validate, import) work without keys. Full integration tests need ANTHROPIC_API_KEY. Use pytest.skip() in the runner fixture when _setup() fails due to missing credentials.
Forgetting sys.path setup in conftest.py — Tests need exports/ and core/ on sys.path.
Not using auto_responder for client-facing nodes — Tests with client-facing nodes hang without an auto-responder that injects input. But note: even WITH auto_responder, forever-alive agents still hang because the graph never terminates. Auto-responder only helps for agents with terminal nodes.
1---2name: common-mistakes-when-building-hive-agents3description: analyzeprogress has no tools. schedulereminders just sets one boolean. report just presents analysis. updatetracker and generateplan are sequential autonomous work.4---5# Common Mistakes When Building Hive Agents67## Critical Errors891. **Using tools that don't exist** — Always verify tools are available in the hive-tools MCP server before assigning them to nodes. Never guess tool names.10112. **Wrong entry_points format** — MUST be `{"start": "first-node-id"}`. NOT a set, NOT `{node_id: [keys]}`.12133. **Wrong mcp_servers.json format** — Flat dict (no `"mcpServers"` wrapper). `cwd` must be `"../../tools"`. `command` must be `"uv"` with args `["run", "python", ...]`.14154. **Missing STEP 1/STEP 2 in client-facing prompts** — Without explicit phases, the LLM calls set_output before the user responds. Always use the pattern.16175. **Forgetting nullable_output_keys** — When a node receives inputs from multiple edges and some inputs only arrive on certain edges (e.g., feedback), mark those as nullable. Without this, the executor blocks waiting for a value that will never arrive.18196. **Creating dead-end nodes in forever-alive graphs** — Every node must have at least one outgoing edge. A node with no outgoing edges ends the execution, breaking the loop.20217. **Setting max_node_visits to a non-zero value in forever-alive agents** — The framework default is `max_node_visits=0` (unbounded). Setting it to any positive value (e.g., 1) means the node stops executing after that many visits, silently breaking the forever-alive loop. Only set `max_node_visits > 0` in one-shot agents with feedback loops that need bounded retries.22237. **Missing module-level exports in `__init__.py`** — The runner loads agents via `importlib.import_module(package_name)`, which imports `__init__.py`. It then reads `goal`, `nodes`, `edges`, `entry_node`, `entry_points`, `pause_nodes`, `terminal_nodes`, `conversation_mode`, `identity_prompt`, `loop_config` via `getattr()`. If ANY of these are missing from `__init__.py`, they default to `None` or `{}` — causing "must define goal, nodes, edges" errors or "node X is unreachable" validation failures. **ALL module-level variables from agent.py must be re-exported in `__init__.py`.**2425## Value Errors26278. **Invalid `conversation_mode` value** — Only two valid values: `"continuous"` (recommended for interactive agents) or omit entirely (for isolated per-node conversations). Values like `"client_facing"`, `"interactive"`, `"adaptive"` do NOT exist and will cause runtime errors.28299. **Invalid `loop_config` keys** — Only three valid keys: `max_iterations` (int), `max_tool_calls_per_turn` (int), `max_history_tokens` (int). Keys like `"strategy"`, `"mode"`, `"timeout"` are NOT valid and are silently ignored or cause errors.303110. **Fabricating tools that don't exist** — Never guess tool names. Always verify via `discover_mcp_tools()`. Common hallucinations: `csv_read`, `csv_write`, `csv_append`, `file_upload`, `database_query`. If a required tool doesn't exist, redesign the agent to use tools that DO exist (e.g., `save_data`/`load_data` for data persistence).3233## Design Errors343511. **Too many thin nodes** — Hard limit: **2-4 nodes** for most agents. Each node boundary serializes outputs to shared memory and loses all in-context information (tool results, intermediate reasoning, conversation history). A node with 0 tools that just does LLM reasoning is NOT a real node — merge it into its predecessor or successor.3637**Merge when:**38- Node has NO tools — pure LLM reasoning belongs in the node that produces or consumes its data39- Node sets only 1 trivial output (e.g., `set_output("done", "true")`) — collapse into predecessor40- Multiple consecutive autonomous nodes with same/similar tools — combine into one41- A "report" or "summary" node that just presents analysis — merge into the client-facing node42- A "schedule" or "confirm" node that doesn't actually schedule anything — remove entirely4344**Keep separate when:**45- Client-facing vs autonomous — different interaction models require separate nodes46- Fundamentally different tool sets (e.g., web search vs file I/O)47- Fan-out parallelism — parallel branches MUST be separate nodes4849**Bad example** (7 nodes — WAY too many):50```51profile_setup → daily_intake → update_tracker → analyze_progress → generate_plan → schedule_reminders → report52```53`analyze_progress` has no tools. `schedule_reminders` just sets one boolean. `report` just presents analysis. `update_tracker` and `generate_plan` are sequential autonomous work.5455**Good example** (3 nodes):56```57intake (client-facing) → process (autonomous: track + analyze + plan) → intake (loop back)58```59One client-facing node handles ALL user interaction (setup, logging, reports). One autonomous node handles ALL backend work (CSV update, analysis, plan generation) with tools and context preserved.606112. **Adding framework gating for LLM behavior** — Don't add output rollback, premature rejection, or interaction protocol injection. Fix with better prompts or custom judges.626313. **Not using continuous conversation mode** — Interactive agents should use `conversation_mode="continuous"`. Without it, each node starts with blank context.646514. **Adding terminal nodes by default** — ALL agents should use `terminal_nodes=[]` (forever-alive) unless the user explicitly requests a one-shot/batch agent. Forever-alive is the standard pattern. Every node must have at least one outgoing edge. Dead-end nodes break the loop.666715. **Calling set_output in same turn as tool calls** — Instruct the LLM to call set_output in a SEPARATE turn from real tool calls.6869## File Template Errors707116. **Wrong import paths** — Use `from framework.graph import ...`, NOT `from core.framework.graph import ...`. The PYTHONPATH includes `core/`.727317. **Missing storage path** — Agent class must set `self._storage_path = Path.home() / ".hive" / "agents" / "agent_name"`.747518. **Missing mcp_servers.json** — Without this, the agent has no tools at runtime.767719. **Bare `python` command in mcp_servers.json** — Use `"command": "uv"` with args `["run", "python", ...]`.7879## Testing Errors808120. **Using `runner.run()` on forever-alive agents** — `runner.run()` calls `trigger_and_wait()` which blocks until the graph reaches a terminal node. Forever-alive agents have `terminal_nodes=[]`, so **`runner.run()` hangs forever**. This is the #1 cause of stuck test suites.8283**For forever-alive agents, write structural tests instead:**84- Validate graph structure (nodes, edges, entry points)85- Verify node specs (tools, prompts, client-facing flag)86- Check goal/constraints/success criteria definitions87- Test that `AgentRunner.load()` + `_setup()` succeeds (skip if no API key)8889**What NOT to do:**90```python91# WRONG — hangs forever on forever-alive agents92result = await runner.run({"topic": "quantum computing"})93```9495**Correct pattern for structure tests:**96```python97def test_research_has_web_tools(self):98 assert "web_search" in research_node.tools99100def test_research_routes_back_to_interact(self):101 edges_to_interact = [e for e in edges if e.source == "research" and e.target == "interact"]102 assert edges_to_interact103```10410521. **Stale tests after agent restructuring** — When you change an agent's node count or names (e.g., 4 nodes → 2 nodes), the tests MUST be updated too. Tests referencing old node names (e.g., `"review"`, `"report"`) will fail or hang. Always check that test assertions match the current `nodes/__init__.py`.10610722. **Running full integration tests without API keys** — Structural tests (validate, import) work without keys. Full integration tests need `ANTHROPIC_API_KEY`. Use `pytest.skip()` in the runner fixture when `_setup()` fails due to missing credentials.10810923. **Forgetting sys.path setup in conftest.py** — Tests need `exports/` and `core/` on sys.path.11011124. **Not using auto_responder for client-facing nodes** — Tests with client-facing nodes hang without an auto-responder that injects input. But note: even WITH auto_responder, forever-alive agents still hang because the graph never terminates. Auto-responder only helps for agents with terminal nodes.