# How ClawTalk Orchestrates Message Routing Between Subagents in ClosedClaw

> Discover how ClawTalk orchestrates message routing between Research, System, Code, and Memory subagents in ClosedClaw. Learn about its role as an inter-agent bus for intelligent prompt parsing and classification.

- Repository: [aSafeLobotomy/closedclaw](https://github.com/asafelobotomy/closedclaw)
- Tags: internals
- Published: 2026-02-25

---

**ClawTalk acts as an inter-agent bus that parses incoming prompts, classifies intent, and injects the correct subagent profile—Research, System, Code, or Memory—into the next execution context.**

ClawTalk is the central routing layer in the `asafelobotomy/closedclaw` repository. It transforms raw user messages into structured routing decisions that determine which specialized subagent handles a given task. By combining an intent classifier, a static directory of agent capabilities, and a runtime hook, ClawTalk ensures that requests like "search the web" reach the Research agent while "refactor this function" trigger the Code agent.

## The Three Core Components of ClawTalk Routing

The orchestration relies on three tightly-coupled modules defined in `src/agents/clawtalk/`:

| Component | Responsibility | Source File |
|-----------|----------------|-------------|
| **Encoder** | Parses raw text into a `ClawTalkMessage`, extracts intent and confidence scores. | [`src/agents/clawtalk/encoder.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/encoder.ts) |
| **Directory** | Maintains `SUBAGENT_PROFILES` for Research, System, Code, Memory, and others; matches intent to the best profile. | [`src/agents/clawtalk/directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/directory.ts) |
| **Hook** | Entry point called by the Claw engine via `before_agent_start`. Runs the encoder, queries the Directory, handles escalation, and injects the chosen subagent’s configuration into the runtime. | [`src/agents/clawtalk/clawtalk-hook.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/clawtalk-hook.ts) |

## Step-by-Step Message Routing Flow

When a user prompt enters the system, `clawtalkBeforeAgentStartHandler` in [`clawtalk-hook.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/clawtalk-hook.ts) executes the following pipeline:

1. **Intent Classification**  
   The hook calls `routeMessage()`, which invokes `encode(userMessage)` from [`encoder.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/encoder.ts). This returns an `EncodedMessage` containing:
   - `intent`: A string like `"web_search"` or `"code_generate"`
   - `confidence`: A 0–1 score
   - `wire`: The raw CT/1 protocol string

2. **Directory Lookup**  
   The hook fetches a singleton `Directory` via `getDirectory()` (lines 94–98). It then calls `directory.routeMessage(encoded.message, encoded.intent)` (lines 102–104).  
   The Directory scans `SUBAGENT_PROFILES` (defined in [`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts) lines 14–41, 60–91, and 95–119), filters for profiles whose `capabilities` array includes the detected intent, and sorts by `priority`. If no match exists, it falls back to `CONVERSATION_PROFILE` (lines 92–94).

3. **Escalation Check**  
   `shouldEscalate()` (lines 106–112) evaluates whether to switch to a cloud model based on `confidence`, message length, and the `escalationThreshold` defined in [`types.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/types.ts) (line 107).

4. **TPC Transport Decision**  
   For agent-to-agent communication (`isAgentToAgent()` at lines 46–48), the hook determines whether to enable the Tonal Pulse Communication (TPC) runtime (lines 115–138). If the TPC runtime is ready and `runtime.shouldFallbackToText()` returns false, the message is encoded as a tonal pulse; otherwise, it falls back to text if `allowTextFallback` is enabled (config lines 129–130).

5. **Build Routing Result**  
   A `ClawTalkRouting` object (lines 56–81) is constructed containing:
   - `agentId`: The chosen subagent identifier (e.g., `"research"`, `"code"`, `"memory"`)
   - `systemPrompt`: The profile’s prompt to be injected
   - `tools`: The allow-listed tools for that subagent
   - `modelOverride`: Set only if escalation occurred
   - `tpc`: Boolean flag for TPC usage

6. **Inject into Agent Context**  
   The hook returns a `PluginHookBeforeAgentStartResult` (lines 93–110) that prepends `systemPrompt` to the context, restricts available tools to the `toolAllowlist`, and optionally overrides the model. The Claw runtime then launches the selected subagent with these parameters.

## How Specific Subagents Are Selected

The `SUBAGENT_PROFILES` array in [`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts) maps intents to specialized handlers:

| Subagent | Handled Intents | Profile Location | Example Trigger |
|----------|----------------|------------------|-----------------|
| **Research** | `web_search`, `summarize`, `browse` | [`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts) lines 16–20 | "Find the latest news about quantum computing" |
| **System** | `read_file`, `write_file`, `run_command` | [`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts) lines 34–38 | "Read the file README.md" |
| **Code** | `code_generate`, `code_review`, `code_debug`, `code_refactor` | [`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts) lines 60–64 | "Refactor this function to use async/await" |
| **Memory** | `remember`, `recall` | [`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts) lines 78–82 | "Remember my favorite color is blue" |
| **Browser** | `browser_automate` | [`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts) lines 95–99 | "Take a screenshot of example.com" |
| **Automation** | `schedule_task` | [`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts) lines 124–128 | "Set a reminder for tomorrow 9am" |
| **Conversation** | `conversation`, `unknown` (fallback) | [`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts) lines 44–48 | General chat not matching other intents |

When the Directory receives an intent like `code_refactor`, it filters the array for profiles where `capabilities.includes("code_refactor")` is true, finds the Code profile, and returns it to the hook for injection.

## Code Examples

### Manually Invoking the Router

You can test the routing logic directly by importing `routeMessage` from the hook file:

```typescript
import { routeMessage } from "./clawtalk-hook";
import { DEFAULT_CONFIG } from "./types";

// Example research query
const prompt = "Summarize the key points of the Wikipedia article on quantum computing.";

// Simulate an agent-to-agent call
const routing = routeMessage(prompt, { agentToAgent: true });

console.log(`Chosen sub-agent: ${routing.agentId}`);
console.log(`System prompt injected:\n${routing.systemPrompt}`);
console.log(`Allowed tools: ${routing.tools.join(", ")}`);

```

This outputs `routing.agentId` as `"research"` and includes the Research profile’s system prompt and tool allow-list.

### Hook Handler Implementation

The `clawtalkBeforeAgentStartHandler` function in [`clawtalk-hook.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/clawtalk-hook.ts) demonstrates how the routing result is applied to the agent context:

```typescript
export function clawtalkBeforeAgentStartHandler(
  event: PluginHookBeforeAgentStartEvent,
  ctx: PluginHookAgentContext,
): PluginHookBeforeAgentStartResult | void {
  // ... intent classification and directory lookup ...
  const routing = routeMessage(prompt, { agentToAgent });

  const result: PluginHookBeforeAgentStartResult = {};

  // Inject sub-agent system prompt
  if (routing.systemPrompt) {
    result.prependContext = routing.systemPrompt;
  }

  // Restrict to sub-agent's tool allowlist
  if (routing.tools.length) {
    result.toolAllowlist = routing.tools;
  }

  // Override model on escalation
  if (routing.modelOverride) {
    result.modelOverride = routing.modelOverride;
  }

  return result;
}

```

The returned `result` is merged into the next agent execution, effectively routing the conversation to the selected subagent with the correct tools and context.

## Key Files and Implementation Details

| File | Role | Link |
|------|------|------|
| [`src/agents/clawtalk/clawtalk-hook.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/clawtalk-hook.ts) | Entry point that performs encoding, directory lookup, escalation, and TPC decisions. | [clawtalk-hook.ts](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/clawtalk-hook.ts) |
| [`src/agents/clawtalk/directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/directory.ts) | Holds `SUBAGENT_PROFILES` and implements `route()` / `routeMessage()`. | [directory.ts](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/directory.ts) |
| [`src/agents/clawtalk/types.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/types.ts) | Core type definitions including `EncodedMessage`, `ClawTalkRouting`, and config thresholds. | [types.ts](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/types.ts) |
| [`src/agents/clawtalk/encoder.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/encoder.ts) | Turns raw user strings into `ClawTalkMessage` objects with intent and confidence. | [encoder.ts](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/encoder.ts) |
| [`src/agents/clawtalk/escalation.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/escalation.ts) | Logic that decides when to switch to a cloud model based on confidence thresholds. | [escalation.ts](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/escalation.ts) |
| [`src/agents/clawtalk/tpc/index.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/tpc/index.ts) | Implements the Tonal Pulse Communication runtime for agent-to-agent encoding. | [tpc/index.ts](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/tpc/index.ts) |
| [`docs/concepts/clawtalk.md`](https://github.com/asafelobotomy/closedclaw/blob/main/docs/concepts/clawtalk.md) | Human-readable specification of the ClawTalk protocol and CT/1 wire format. | [clawtalk.md](https://github.com/asafelobotomy/closedclaw/blob/main/docs/concepts/clawtalk.md) |

These files collectively demonstrate how ClawTalk turns plain user requests into routed, context-aware subagent executions, ensuring that each specialized handler receives exactly the tools and prompts it needs to complete its task.

## Summary

- **ClawTalk** serves as the inter-agent bus in `closedclaw`, routing every user prompt to the correct specialized subagent.
- The **Encoder** ([`encoder.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/encoder.ts)) extracts intent and confidence from raw text, producing an `EncodedMessage` with a CT/1 wire format.
- The **Directory** ([`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts)) maintains `SUBAGENT_PROFILES` for Research, System, Code, Memory, and others, matching intents to the best profile by capability and priority.
- The **Hook** ([`clawtalk-hook.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/clawtalk-hook.ts)) orchestrates the flow: it classifies input, queries the Directory, checks escalation thresholds, optionally enables TPC for agent-to-agent communication, and injects the chosen subagent’s system prompt, tool allowlist, and model override into the next execution context.
- Subagents are selected based on intent filters (e.g., `code_refactor` routes to Code, `web_search` routes to Research), with a fallback to the Conversation profile for unmatched intents.

## Frequently Asked Questions

### How does ClawTalk decide which subagent handles a request?

ClawTalk uses the **Encoder** to classify the user prompt into an intent (such as `web_search` or `code_generate`) with a confidence score. The **Directory** then scans `SUBAGENT_PROFILES` in [`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts) to find a profile whose `capabilities` array includes that intent, sorting by priority and returning the best match. If no profile matches, it falls back to the `CONVERSATION_PROFILE`.

### What is the role of the TPC runtime in message routing?

The **Tonal Pulse Communication (TPC)** runtime, implemented in [`src/agents/clawtalk/tpc/index.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/src/agents/clawtalk/tpc/index.ts), handles agent-to-agent encoding when `isAgentToAgent()` returns true. The hook checks `runtime.shouldFallbackToText()` to decide whether to transmit the message as a tonal pulse or fall back to plain text. This allows specialized subagents to communicate via compressed audio-like signals rather than text when appropriate.

### Can ClawTalk escalate to a cloud model during routing?

Yes. The `shouldEscalate()` function in [`clawtalk-hook.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/clawtalk-hook.ts) (lines 106–112) evaluates whether to override the local model with a cloud-based alternative. It considers the confidence score from the Encoder, message length, and the `escalationThreshold` defined in [`types.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/types.ts). When triggered, the routing result includes a `modelOverride` field that the Claw runtime applies to the next agent execution.

### How are tools restricted when routing to a specific subagent?

Each subagent profile in [`directory.ts`](https://github.com/asafelobotomy/closedclaw/blob/main/directory.ts) defines a `tools` array listing exactly which capabilities that agent may use (for example, the Research profile includes `web_search`, `fetch_url`, and `current_time`). When the hook builds the `ClawTalkRouting` result, it copies this array into `routing.tools`. The returned `PluginHookBeforeAgentStartResult` then sets `result.toolAllowlist` to this array, ensuring the downstream agent can only invoke the tools relevant to its assigned role.