How Subagent Interception Controls Background Task Execution in free-claude-code

Subagent interception in free-claude-code forces synchronous execution of Task tools by rewriting run_in_background to false at the provider layer while the transcript system tracks sub-agent lifecycle to suppress unrelated output.

The free-claude-code repository implements a strict subagent interception mechanism to ensure Task tools execute deterministically in the foreground. This system treats every Task tool call as the beginning of a nested conversational flow, requiring precise control over execution timing and UI rendering. By forcing run_in_background to false regardless of client requests, the architecture guarantees predictable behavior across all provider endpoints.

The Three-Layer Interception Architecture

Subagent interception operates across three distinct components to guarantee that Task tools never run in the background, even when clients explicitly request run_in_background: true.

messaging/transcript.py – Sub-Agent Stack Management

The transcript subsystem in messaging/transcript.py (lines 226-344) maintains an internal stack to track active sub-agents. When a Task tool is detected, the _subagent_push() method (around line 250) pushes the tool's tool_use_id onto the _subagent_stack.

While the stack is non-empty, the _in_subagent() method returns True, causing the transcript renderer to suppress all non-tool content. This ensures the UI displays only the sequential flow of "Task → tool calls → result" without interleaved thinking bubbles or background task indicators. When the tool result arrives, _subagent_pop() (line 267) matches the result's ID with the stack top and resumes normal output rendering.

providers/common/sse_builder.py – SSE Argument Sanitization

Before streaming requests to the LLM, the SSE builder sanitizes tool arguments in _maybe_fix_background() (lines 98-116). The code performs an explicit check:

if args_json.get("run_in_background") is not False:
    args_json["run_in_background"] = False

This mutation occurs in-place, guaranteeing that the flag is false before the provider receives the request. The enforcement happens regardless of the client's original value, ensuring synchronous scheduling through the normal streaming channel.

providers/openai_compat.py – OpenAI-Compatible Wrapper

The OpenAI-compatible provider wrapper applies identical sanitization at two entry points: the regular tool call path (lines 257-267) and the chunked tool call path (lines 341-350). Both locations execute the same conditional rewrite:

if tool_use["input"].get("run_in_background") is not False:
    tool_use["input"]["run_in_background"] = False

This dual-path coverage ensures consistency whether the request arrives as a standard API call or via streaming chunks.

Execution Flow of a Task Tool

When a Task tool initiates a sub-agent, the system processes the request through six deterministic stages:

  1. Client submits Task tool – The request includes arguments such as {"run_in_background": true, "prompt": "..."}.

  2. Transcript detects sub-agentmessaging/transcript.py calls _subagent_push() to stack the Task's tool_use_id, activating sub-agent mode.

  3. SSE builder sanitizes arguments – The request passes through providers/common/sse_builder.py, where _maybe_fix_background() rewrites the flag to false.

  4. OpenAI wrapper confirms sanitizationproviders/openai_compat.py performs the same rewrite for both regular and chunked paths (lines 257-267 and 341-350).

  5. Provider executes synchronously – With run_in_background forced to false, the provider schedules the task in the foreground and returns results via the standard streaming channel.

  6. Stack cleanup – Upon receiving the tool result, _subagent_pop() removes the task from the stack, allowing the transcript renderer to resume normal output.

Code Implementation Details

The sub-agent stack management in messaging/transcript.py handles Task identification and lifecycle tracking:


# messaging/transcript.py – pushing a sub-agent

def _subagent_push(self, tool_id: str, seg: SubagentSegment) -> None:
    tool_id = str(tool_id or "").strip() or f"__task_{len(self._subagent_stack) + 1}"
    self._subagent_stack.append(tool_id)
    self._subagent_segments.append(seg)

Provider-layer enforcement occurs in the SSE builder's sanitization logic:


# providers/common/sse_builder.py – sanitising run_in_background

if args_json.get("run_in_background") is not False:
    args_json["run_in_background"] = False

The OpenAI-compatible provider implements identical checks for cross-endpoint consistency:


# providers/openai_compat.py – same rewrite for OpenAI-compatible endpoint

if tool_use["input"].get("run_in_background") is not False:
    tool_use["input"]["run_in_background"] = False

Why Background Execution Must Be Disabled

Forcing synchronous execution provides three critical guarantees:

  • Predictable UI rendering – Users see ordered transcripts without interleaved "thinking" bubbles that would appear for background tasks, as the transcript renderer filters non-tool content while _in_subagent() returns True.
  • Resource management – Background workers defined in messaging/limiter.py are never spawned for sub-agents, preventing stray async tasks from lingering after sub-agent completion.
  • Security consistency – The rewrite prevents malicious clients from hiding long-running work in background threads, ensuring rate limits and logging apply to all Task tool executions.

Verification and Testing

The interception logic is verified through targeted test suites:

Summary

  • Subagent interception forces synchronous execution of Task tools by rewriting run_in_background to false at the provider layer.
  • The transcript stack in messaging/transcript.py tracks active sub-agents to suppress non-tool UI output during Task execution.
  • Sanitization occurs in both providers/common/sse_builder.py and providers/openai_compat.py to cover all API entry points.
  • This architecture ensures predictable rendering, prevents resource leaks, and maintains security by blocking background execution attempts.

Frequently Asked Questions

What is subagent interception in free-claude-code?

Subagent interception is the mechanism that detects Task tool calls and forces them to execute synchronously by rewriting the run_in_background argument to false. According to the free-claude-code source code, this ensures nested conversational flows remain deterministic and UI output stays clean while the sub-agent is active.

How does the transcript system know when to suppress output?

The transcript subsystem uses an internal stack (_subagent_stack) managed by _subagent_push() and _subagent_pop() in messaging/transcript.py. When _in_subagent() returns True because the stack is non-empty, the renderer filters out non-tool content, showing only the Task invocation and its results.

Can clients bypass the background execution block?

No. The rewrite happens at the provider layer in providers/common/sse_builder.py and providers/openai_compat.py before requests reach the execution engine. Because the code checks if args_json.get("run_in_background") is not False and forces the value to false, clients cannot override this behavior regardless of their initial payload.

Which components handle the run_in_background flag rewrite?

Three components enforce this behavior: messaging/transcript.py manages the sub-agent lifecycle and UI suppression, providers/common/sse_builder.py sanitizes SSE arguments, and providers/openai_compat.py applies identical rewrites for both regular and chunked OpenAI-compatible endpoints.

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 →