How ClawTalk Orchestrates Message Routing Between Subagents in ClosedClaw

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
Directory Maintains SUBAGENT_PROFILES for Research, System, Code, Memory, and others; matches intent to the best profile. 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

Step-by-Step Message Routing Flow

When a user prompt enters the system, clawtalkBeforeAgentStartHandler in clawtalk-hook.ts executes the following pipeline:

  1. Intent Classification
    The hook calls routeMessage(), which invokes encode(userMessage) from 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 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 (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 maps intents to specialized handlers:

Subagent Handled Intents Profile Location Example Trigger
Research web_search, summarize, browse directory.ts lines 16–20 "Find the latest news about quantum computing"
System read_file, write_file, run_command directory.ts lines 34–38 "Read the file README.md"
Code code_generate, code_review, code_debug, code_refactor directory.ts lines 60–64 "Refactor this function to use async/await"
Memory remember, recall directory.ts lines 78–82 "Remember my favorite color is blue"
Browser browser_automate directory.ts lines 95–99 "Take a screenshot of example.com"
Automation schedule_task directory.ts lines 124–128 "Set a reminder for tomorrow 9am"
Conversation conversation, unknown (fallback) 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:

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 demonstrates how the routing result is applied to the agent context:

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 Entry point that performs encoding, directory lookup, escalation, and TPC decisions. clawtalk-hook.ts
src/agents/clawtalk/directory.ts Holds SUBAGENT_PROFILES and implements route() / routeMessage(). directory.ts
src/agents/clawtalk/types.ts Core type definitions including EncodedMessage, ClawTalkRouting, and config thresholds. types.ts
src/agents/clawtalk/encoder.ts Turns raw user strings into ClawTalkMessage objects with intent and confidence. encoder.ts
src/agents/clawtalk/escalation.ts Logic that decides when to switch to a cloud model based on confidence thresholds. escalation.ts
src/agents/clawtalk/tpc/index.ts Implements the Tonal Pulse Communication runtime for agent-to-agent encoding. tpc/index.ts
docs/concepts/clawtalk.md Human-readable specification of the ClawTalk protocol and CT/1 wire format. 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) extracts intent and confidence from raw text, producing an EncodedMessage with a CT/1 wire format.
  • The Directory (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) 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 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, 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 (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. 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →