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 executetimeout_ms(number, optional): Explicit timeout in millisecondsrun_in_background(boolean, optional): Run as non-blocking background taskpty(boolean, optional): Allocate pseudo-terminal (PTY mode)boundary_intentandrequired_boundary(conditional): Sandbox boundary declarations whendeclareSandboxBoundaryis 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:
- Parameter extraction – Parse and validate incoming arguments
- Sandbox resolution – Resolve declared boundary via
preflightDeclaredSandboxBoundary - Command transformation – Apply optional
transformCommandhook - Timeout calculation – Clamp to host and built-in limits
- Execution dispatch – Route to
runForegroundBashorrunBackgroundBash - Result processing – Emit output, invoke
afterResulthook, 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 viaonCompletioncallback
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 normalizationrefineBashBoundaryDeclaration– 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
buildManagedBashToolinshell-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, optionaltimeout_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_MSorMAX_SHELL_RUN_TIMEOUT_MSdepending on execution mode. - Result sanitization via
bashToolResultToModelOutputstrips the original command for safe, compact model context while preserving execution output. - Host extensibility through
defaultTimeoutMs,transformCommand, andafterResulthooks 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →