How Apache Maka's Bash Tool Works: A Deep Dive into Shell Execution

Apache Maka's Bash tool is a configurable managed tool that executes shell commands either foreground (blocking with optional timeout) or background (non-blocking as a runtime task), with built-in support for PTY allocation, sandbox boundary enforcement, and host-customizable hooks.

The Bash tool sits at the core of Maka's ability to let AI agents interact with the underlying operating system. In packages/runtime/src/shell-tools.ts, the buildManagedBashTool factory constructs a MakaTool instance that bridges high-level tool calls from the model to concrete shell process execution. This article breaks down the complete execution flow, parameter schema, timeout handling, and extension points you need to understand to work with or extend Maka's Bash capabilities.

Tool Definition and Parameter Schema

Maka defines the Bash tool programmatically rather than through static configuration. The buildManagedBashTool function creates a tool named Bash with activity kind command and a Zod-validated parameter schema.

Core Parameters

The parameter schema in shell-tools.ts lines 31-36 accepts:

  • command (string, required): The shell command to execute
  • timeout_ms (number, optional): Explicit timeout in milliseconds
  • run_in_background (boolean, optional): Run as non-blocking background task
  • pty (boolean, optional): Allocate pseudo-terminal (PTY mode)
  • boundary_intent and required_boundary (conditional): Sandbox boundary declarations when declareSandboxBoundary is enabled

Validation enforces that PTY mode requires run_in_background=true, and foreground timeouts are clamped to MAX_FOREGROUND_BASH_TIMEOUT_MS.

// From shell-tools.ts L31-L36 - the Zod schema structure
const bashParamsSchema = z.object({
  command: z.string(),
  timeout_ms: z.number().optional(),
  run_in_background: z.boolean().optional(),
  pty: z.boolean().optional(),
  // boundary fields added conditionally based on host configuration
});

Execution Flow: From Tool Call to Shell Process

When a model invokes the Bash tool, the runtime follows a predictable dispatch pipeline in shell-tools.ts lines 88-133:

  1. Parameter extraction – Parse and validate incoming arguments
  2. Sandbox resolution – Resolve declared boundary via preflightDeclaredSandboxBoundary
  3. Command transformation – Apply optional transformCommand hook
  4. Timeout calculation – Clamp to host and built-in limits
  5. Execution dispatch – Route to runForegroundBash or runBackgroundBash
  6. Result processing – Emit output, invoke afterResult hook, convert to model format

Timeout Handling Logic

The timeout calculation in shell-tools.ts lines 102-108 implements tiered defaults:

// Foreground: use explicit, or host default, or built-in default
// Then clamp to MAX_FOREGROUND_BASH_TIMEOUT_MS
const effectiveTimeout = Math.min(
  params.timeout_ms ?? host.defaultTimeoutMs?.(params.command) ?? DEFAULT_BASH_TIMEOUT_MS,
  MAX_FOREGROUND_BASH_TIMEOUT_MS
);

// Background: no default timeout unless explicitly provided
// If provided, clamp to MAX_SHELL_RUN_TIMEOUT_MS

These constants are defined in packages/runtime/src/shell-run-contract.js.

Foreground vs. Background Execution

Maka's Bash tool supports two fundamentally different execution modes, selected by the run_in_background parameter.

Foreground Execution (runForegroundBash)

  • Blocking: Returns only after command completion
  • Timeout enforced: Hard limit via MAX_FOREGROUND_BASH_TIMEOUT_MS
  • Simpler result: Direct terminal output, no task reference

Background Execution (runBackgroundBash)

  • Non-blocking: Returns immediately with a task reference like maka://runtime/background-tasks/abc123
  • PTY support: Required for interactive programs (editors, REPLs)
  • Lifecycle management: Tracked by ShellRunLauncher, completion via onCompletion callback

The background task completion handler in shell-tools.ts lines 55-64 attaches a one-time callback:

// Simplified from shell-tools.ts L55-L64
const onCompletion = (result: ShellRunResult) => {
  const success = result.exitCode === 0;
  reportBackgroundTaskCompletion(taskRef, success, result);
};

PTY Mode and Interactive Shell Sessions

The pty parameter triggers pseudo-terminal allocation, essential for programs that require termcap detection or raw terminal I/O. Key constraints enforced by the schema:

  • PTY requires run_in_background=true (enforced at validation)
  • Background PTY tasks can be interacted with via subsequent WriteStdin and Read tool calls
  • The task reference returned allows multi-turn session management

Example background PTY invocation:

{
  "type": "tool_call",
  "toolName": "Bash",
  "args": {
    "command": "vim /tmp/file.txt",
    "run_in_background": true,
    "pty": true
  }
}

Sandbox Boundary Enforcement

When the host enables declareSandboxBoundary, the schema expands to include boundary_intent and required_boundary fields. The runtime validates these through two helper functions:

  • preprocessBashBoundaryDeclaration – Initial validation and normalization
  • refineBashBoundaryDeclaration – Final resolution before execution

The resolved boundary is passed to the shell runner, enabling hosts to implement filesystem, network, or resource isolation policies without modifying core Maka code.

Result Conversion and Model Output

Raw terminal output contains fields unsuitable for durable model context—particularly the original cmd string which may include secrets or excessive length. The bashToolResultToModelOutput function in packages/runtime/src/bash-model-output.ts lines 24-42 sanitizes results:

// From bash-model-output.ts L24-L42
export function bashToolResultToModelOutput(result: TerminalResult): ModelBashOutput {
  // Strip 'cmd' field, preserve stdout/stderr/exitCode
  const { cmd, ...safeFields } = result;
  return {
    ...safeFields,
    // Additional normalization for model consumption
  };
}

This ensures that:

  • Command history in context windows stays compact
  • Potentially sensitive command arguments aren't persisted
  • The model receives canonical, structured output

Host Customization Hooks

The buildManagedBashTool factory accepts configuration options that let hosts inject policy without forking:

Hook/Option Purpose Called When
defaultTimeoutMs Per-command timeout fallback Timeout not explicitly specified
transformCommand Modify command before execution After validation, before dispatch
afterResult Post-execution side effects After result conversion
declareSandboxBoundary Enable boundary schema fields Tool construction

Example host configuration:

import { buildManagedBashTool } from '@maka/runtime/src/shell-tools.js';

export const bash = buildManagedBashTool(launcher, {
  declareSandboxBoundary: true,
  
  defaultTimeoutMs: (cmd) => {
    // Longer timeout for known slow commands
    if (cmd.includes('npm install')) return 300_000;
    if (cmd.includes('git clone')) return 180_000;
    return 60_000;
  },
  
  afterResult: async (input, result, ctx) => {
    await auditLog.record({
      command: input.command,
      exitCode: result.exitCode,
      duration: result.durationMs,
      sessionId: ctx.sessionId,
    });
  },
});

Registration and Built-in Integration

The Bash tool is registered alongside other built-ins in packages/runtime/src/builtin-tools.ts. This registration layer connects the managed tool implementation to Maka's runtime initialization, ensuring the Bash tool name resolves correctly in tool calls from the model.

Key Source Files Reference

File Lines Responsibility
packages/runtime/src/shell-tools.ts 77-88 buildManagedBashTool factory
packages/runtime/src/shell-tools.ts 31-36 Parameter schema definition
packages/runtime/src/shell-tools.ts 88-100 Option handling and transformation
packages/runtime/src/shell-tools.ts 102-108 Timeout calculation logic
packages/runtime/src/shell-tools.ts 109-114 Execution dispatch
packages/runtime/src/shell-tools.ts 115-133 Result handling pipeline
packages/runtime/src/shell-tools.ts 55-64 Background completion callback
packages/runtime/src/shell-tools.ts 71-86 Sandbox boundary processing
packages/runtime/src/bash-model-output.ts 24-42 Result sanitization
packages/runtime/src/shell-run-contract.js — Timeout constants
packages/runtime/src/builtin-tools.ts — Tool registration
packages/runtime/src/shell-run-detect.ts — Model guidance strings

Summary

  • Apache Maka's Bash tool is implemented via buildManagedBashTool in shell-tools.ts, creating a configurable bridge between model tool calls and operating system shell execution.
  • Two execution modes: Foreground (blocking, timeout-capped) and background (non-blocking, PTY-capable, referenced for lifecycle management).
  • Parameter schema validates command, optional timeout_ms, run_in_background, pty, and conditional sandbox boundary fields with strict enforcement of PTY-background coupling.
  • Timeout handling applies tiered defaults and clamps to MAX_FOREGROUND_BASH_TIMEOUT_MS or MAX_SHELL_RUN_TIMEOUT_MS depending on execution mode.
  • Result sanitization via bashToolResultToModelOutput strips the original command for safe, compact model context while preserving execution output.
  • Host extensibility through defaultTimeoutMs, transformCommand, and afterResult hooks without core code modification.

Frequently Asked Questions

What is the maximum timeout for foreground Bash commands in Maka?

Foreground Bash commands are clamped to MAX_FOREGROUND_BASH_TIMEOUT_MS as defined in packages/runtime/src/shell-run-contract.js. Even if the host's defaultTimeoutMs or an explicit timeout_ms parameter exceeds this value, the runtime enforces this hard ceiling for blocking operations.

Can I run interactive programs like vim or node repl through Maka's Bash tool?

Yes, but you must set both run_in_background: true and pty: true. PTY allocation requires background mode because interactive programs need persistent process state across multiple turns. The runtime returns a task reference that subsequent WriteStdin and Read tools use to interact with the session.

How does Maka prevent sensitive commands from persisting in model context?

The bashToolResultToModelOutput function in packages/runtime/src/bash-model-output.ts deliberately removes the cmd field from terminal results before they enter durable storage or model context. This prevents accidental exposure of passwords, tokens, or verbose command strings while preservingstdout, stderr, and exit status for model reasoning.

What happens if I declare a sandbox boundary but the command violates it?

The runtime validates boundary_intent and required_boundary through preprocessBashBoundaryDeclaration and refineBashBoundaryDeclaration before execution. Actual enforcement depends on the host's ShellRunLauncher implementation—these declarations provide structured policy input that the host's execution layer can use to apply filesystem, network, or resource constraints.

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 →