# How Strix Sub-Agents Communicate and Share State in Multi-Agent Workflows

> Discover how Strix sub-agents communicate and share state using a message bus and graph structure for efficient multi-agent workflows. Learn about loose coupling and tight coordination.

- Repository: [Strix/strix](https://github.com/usestrix/strix)
- Tags: internals
- Published: 2026-03-26

---

**Strix sub-agents communicate through a thread-safe message bus and shared graph structure while maintaining isolated AgentState objects, enabling both loose coupling and tight coordination in multi-agent workflows.**

The `usestrix/strix` repository implements a dynamic multi-agent framework where parent agents spawn specialized sub-agents to handle delegated tasks. Understanding how Strix sub-agents communicate and share state is essential for building reliable orchestration workflows that coordinate concurrent agent execution.

## Agent Isolation and the Shared Coordination Graph

Strix implements a hybrid state management model that balances **agent isolation** with **global coordination**. Each running agent maintains its own private `AgentState` object containing its unique ID, task description, parent ID, iteration counters, and message history. These states are stored in the `_agent_states` dictionary and are never directly accessed by other agents.

However, all agents participate in a shared **agents-graph** that tracks relationships, message flows, and execution status. This graph structure, maintained in [`strix/tools/agents_graph/agents_graph_actions.py`](https://github.com/usestrix/strix/blob/main/strix/tools/agents_graph/agents_graph_actions.py), enables loose coupling—agents only need their own state to function—while still allowing tight coordination through the global `_agent_messages` queue and `_agent_graph` registry.

## The Agent Lifecycle: From Creation to Completion

### Spawning Sub-Agents with `create_agent`

When a parent agent needs to delegate work, it invokes the `create_agent` tool. In [`strix/tools/agents_graph/agents_graph_actions.py`](https://github.com/usestrix/strix/blob/main/strix/tools/agents_graph/agents_graph_actions.py), this function constructs a new `AgentState`, registers it in `_agent_states`, and starts the agent in its own thread via `_run_agent_in_thread`.

The new agent receives its own isolated state but can optionally **inherit the parent's conversation context** through the `inherit_context` parameter, ensuring the sub-agent starts with necessary background information without direct state sharing.

```python

# Inside a running Strix agent (LLM generated tool call)

result = create_agent(
    agent_state=state,          # current AgentState supplied automatically

    task="Analyze the log files in /workspace/logs",
    name="Log Analyzer",
    inherit_context=True,       # include parent conversation history

    skills="file_read,regex_search"
)
print(result["agent_id"])

```

### Message Passing via `send_message_to_agent`

Agents exchange data through the `send_message_to_agent` function, which implements the core communication protocol. This function creates a message record in the global `_agent_messages` dictionary, creates a graph edge of type `"message"` in `_agent_graph`, and marks the message as delivered.

```python

# Assume this runs inside Agent A's tool execution

send_message_to_agent(
    agent_state=state,
    target_agent_id="agent_4f3b2a1c",
    message="I have finished parsing the CSV. Here are the top 5 rows.",
    message_type="information",
    priority="high"
)

```

### Polling and Processing with `_check_agent_messages`

Each agent's main execution loop in [`strix/agents/base_agent.py`](https://github.com/usestrix/strix/blob/main/strix/agents/base_agent.py) calls `_check_agent_messages` on every iteration. This method queries the shared `_agent_messages` dictionary for entries addressed to the current agent, injects them into the agent's private `AgentState.messages` list as user-role messages, and clears the waiting flag if the agent was paused.

```python

# No explicit code – the BaseAgent loop calls this automatically

# When a new message is placed in _agent_messages, the next iteration runs:

self._check_agent_messages(self.state)

```

### Pausing Execution with `wait_for_message`

Agents can explicitly yield control using the `wait_for_message` tool. This function sets the agent's `AgentState.waiting_for_input` flag, updates the graph node status to `"waiting"`, and notifies the telemetry tracer that the agent is idle. The agent automatically resumes when a message arrives or when the timeout threshold is reached.

```python

# Agent B decides it needs input from another agent or the user

wait_for_message(agent_state=state, reason="Awaiting data export from Log Analyzer")

```

### Reporting Results with `agent_finish`

When a sub-agent completes its delegated task, it calls `agent_finish` to update the agents-graph with its final status. The function records the result in `_agent_graph`, optionally sends a structured XML report back to the parent via `_agent_messages`, and removes the sub-agent from the running `_agent_instances` pool.

```python
agent_finish(
    agent_state=state,
    result_summary="Log analysis completed successfully.",
    findings=["Error spike at 03:00 UTC", "No critical failures"],
    success=True,
    report_to_parent=True,
    final_recommendations=["Increase log rotation frequency"]
)

```

## Shared State Mechanics Reference

The communication architecture relies on three core data structures defined in [`strix/tools/agents_graph/agents_graph_actions.py`](https://github.com/usestrix/strix/blob/main/strix/tools/agents_graph/agents_graph_actions.py):

- **`AgentState`** – Defined in [`strix/agents/state.py`](https://github.com/usestrix/strix/blob/main/strix/agents/state.py), these unique per-agent objects contain IDs, task definitions, message lists, and context dictionaries. They are passed as the `state` argument to tools and stored in `_agent_states`.
- **`_agent_graph`** – A global dictionary tracking all agents, their parent-child relationships, and status edges. It updates when agents are created, finish, or send messages.
- **`_agent_messages`** – A thread-safe dictionary acting as a message queue where `send_message_to_agent` appends entries and `_check_agent_messages` consumes them per agent.

## Summary

- **Strix sub-agents maintain isolated state** through individual `AgentState` objects while coordinating via a shared in-memory graph and message bus.
- **The `create_agent` function** in [`agents_graph_actions.py`](https://github.com/usestrix/strix/blob/main/agents_graph_actions.py) spawns sub-agents with optional context inheritance, registering them in global registries.
- **Message passing** occurs through `send_message_to_agent`, which writes to the global `_agent_messages` dictionary and creates traceable graph edges.
- **Automatic message polling** via `_check_agent_messages` in [`base_agent.py`](https://github.com/usestrix/strix/blob/main/base_agent.py) injects external messages into private agent state and handles resume logic.
- **Explicit synchronization** is available through `wait_for_message`, which pauses agents until specific inputs arrive.

## Frequently Asked Questions

### How do parent agents pass context to sub-agents in Strix?

Parent agents pass context using the `inherit_context=True` parameter in `create_agent`. When enabled, the parent’s conversation history is copied into the new agent’s `AgentState`, providing background information without requiring direct state access or message passing after creation.

### What happens when a Strix sub-agent is waiting for a message?

When an agent invokes `wait_for_message`, its status changes to `"waiting"` in the agents-graph and its `AgentState.waiting_for_input` flag is set. The agent loop pauses execution until `_check_agent_messages` detects a new entry in `_agent_messages`, at which point the message is injected into the agent’s private state and execution resumes.

### How does Strix ensure thread safety when multiple agents communicate?

Thread safety is maintained through the global `_agent_messages` dictionary and `_agent_states` registry in [`agents_graph_actions.py`](https://github.com/usestrix/strix/blob/main/agents_graph_actions.py), which are accessed by agent threads in a coordinated manner. The `_check_agent_messages` method consumes messages atomically, preventing race conditions during message delivery and state updates.

### Can sub-agents communicate directly with siblings, or only through parents?

Sub-agents can communicate directly with any other agent using `send_message_to_agent` by specifying the target's `agent_id`. While hierarchical parent-child relationships are tracked in `_agent_graph`, the messaging system supports direct peer-to-peer communication without requiring message routing through parent agents.