How the Apache Maka Tool Runtime Handles Tool Execution and Sandboxing

The Apache Maka Tool Runtime (ToolRuntime class) executes tools through a deterministic pipeline that validates arguments, emits structured events, and isolates untrusted operations via sandbox boundary requests and denial flags.

The Tool Runtime is the core execution engine inside the apache/maka repository that mediates every tool invocation during a Maka session. It enforces strict sandboxing rules, prevents infinite retry loops, and ensures the host system remains protected from unsafe tool behavior while maintaining a deterministic execution log.

ToolRuntime Initialization and Sandbox State

The ToolRuntime class is constructed from a ToolRuntimeInput bundle defined in packages/runtime/src/tool-runtime.ts. During initialization, the runtime validates that a readExecutionBoundary function is present and verifies that hosted session IDs align with the current turn.

// packages/runtime/src/tool-runtime.ts#L6-L18
const toolRuntime = new ToolRuntime({
  sessionId: 'sess-123',
  turnId: 'turn-5',
  readExecutionBoundary: async () => {/* fetch from host */},
  createSandboxBoundaryRequest: async (req) => {/* send to host */},
  settleSandboxBoundaryRequest: async (settlement) => {/* send to host */},
});

The runtime immediately seeds a sandbox denial flag (sandboxBoundaryDenied) from input.inheritedSandboxBoundaryDenied. When this flag is true, the runtime short-circuits any further sandbox boundary requests for the entire turn, returning a SANDBOX_BOUNDARY_DENIED_FOR_TURN error without forwarding the request to the host.

The Tool Execution Pipeline

Tool execution flows through ToolRuntime.settleToolCall(), which delegates to the private executeTool() method. This pipeline performs several deterministic steps before invoking the actual tool implementation:

  1. Argument snapshotting – Captures raw arguments via snapshotToolArgs to prevent mutation during execution.
  2. Pre-flight validation – Checks for direct-only nesting violations, tool-availability gating, schema validation, and sandbox availability for the request_sandbox_boundary tool.
  3. Permission projection – Derives optional permission arguments for permission prompts.
  4. Event emission – Queues a tool_start event and optional diagnostic traces via eventSink.
  5. Implementation call – Invokes tool.impl with the validated context.
  6. Result handling – Applies result projection, enforces size limits, and converts errors.

The implementation in packages/runtime/src/tool-runtime.ts (lines 95-140) guarantees exactly one tool_start event per call and handles abort signals gracefully.

Sandbox Boundary Request Handling

When a tool requires expanded privileges (typically via the request_sandbox_boundary tool), the runtime invokes context.requestSandboxBoundary(). This registers a pending request in the sandboxBoundaryRequests registry—an AwaitRegistry instance that tracks the asynchronous conversation with the host.

// Sandbox request lifecycle
sandboxBoundaryRequests.register(requestId, promise);
// Host responds via:
await toolRuntime.respondToSandboxBoundaryResponse({
  requestId: 'req-7',
  decision: 'allow', // or 'deny'
});

The respondToSandboxBoundaryResponse() method (lines 37-44) resolves the pending registry entry and persists the settlement via input.settleSandboxBoundaryRequest. If the request belongs to a hosted interaction, the runtime throws a runtime invariant error to preserve host-side continuity.

To prevent infinite negotiation loops, the runtime enforces a SANDBOX_BOUNDARY_FAILURE_ROUND_LIMIT. Once reached, or if sandboxBoundaryDenied is set, forceSandboxBoundaryFinalization() stops further sandbox expansion attempts for that turn.

Safety Mechanisms and Loop-Gate Protection

The Tool Runtime implements a loop-gate mechanism to block infinite retries on identical failing calls. It maintains two pieces of state:

  • lastFailedToolCallSignature – A hash of the last failed call's identity.
  • failedToolCallStreak – A counter tracking consecutive identical failures.

If the same signature fails LOOP_GATE_IDENTICAL_THRESHOLD (3) times consecutively, the runtime blocks the call before the tool implementation executes again. This logic resides in recordLoopGateOutcome (lines 112-124) and protects against resource exhaustion from misbehaving agents.

Turn Lifecycle and Cleanup

When a turn completes—whether successfully or aborted—the host invokes ToolRuntime.endTurn(). This method performs critical cleanup:

  • Pending request settlement – Automatically denies any embedded sandbox requests that remain unanswered by calling settleSandboxBoundaryRequest with a denial.
  • Registry closure – Closes the AwaitRegistry instances for sandbox boundaries, user questions, and forms, rejecting any pending promises.
  • State reset – Clears internal counters, admission limits for sub-agents, and the loop-gate state (lastFailedToolCallSignature, failedToolCallStreak).
  • Inflight synchronization – Waits for activeToolSettlements to complete before returning, ensuring no dangling async operations survive the turn boundary.

The implementation spans lines 22-35 in packages/runtime/src/tool-runtime.ts.

Summary

  • The ToolRuntime class in packages/runtime/src/tool-runtime.ts orchestrates all tool execution within Apache Maka, providing deterministic event emission and result projection.
  • Sandboxing is enforced through an explicit request/response flow using sandboxBoundaryRequests (an AwaitRegistry) and the sandboxBoundaryDenied flag, with hard limits on retry rounds.
  • Loop-gate protection blocks tool calls that fail identically three times in a row, preventing infinite retry storms.
  • Turn finalization via endTurn() guarantees cleanup of pending promises, registry closure, and reset of safety counters.

Frequently Asked Questions

What happens when a sandbox boundary request is denied?

When a host denies a sandbox request through respondToSandboxBoundaryResponse(), the runtime sets the sandboxBoundaryDenied flag to true. Subsequent sandbox requests in the same turn immediately return a SANDBOX_BOUNDARY_DENIED_FOR_TURN error without contacting the host, effectively freezing the sandbox state for the remainder of the turn.

How does the loop-gate prevent infinite tool call retries?

The runtime tracks the signature of the last failed tool call and increments a failedToolCallStreak counter when identical failures repeat. Once the streak reaches three (LOOP_GATE_IDENTICAL_THRESHOLD), the runtime blocks the call before execution, breaking potential infinite loops from deterministic failures.

What is the difference between settleToolCall() and executeTool()?

settleToolCall() is the public entry point that receives a ResolvedMakaToolCall and manages the high-level settlement promise, while executeTool() is the private implementation containing the actual execution logic: pre-flight checks, event queuing, tool implementation invocation, and result handling.

Which source files define the sandbox boundary schema and contracts?

The Zod schema for sandbox boundary expansions lives in packages/runtime/src/sandbox-boundary-declaration.ts, the tool definition is in packages/runtime/src/sandbox-boundary-tool.ts, and the core type contracts (CreateSandboxBoundaryRequest, SandboxBoundarySettlement) are defined in packages/core/src/sandbox-boundary.ts.

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 →