# How Mako Runtime Implements Bash, Read, and Write Built-In Tools

> Discover how Mako runtime implements Bash, Read, and Write built-in tools within sandboxed environments. Learn about MakaTool objects and execution context enforcement.

- Repository: [The Apache Software Foundation/maka](https://github.com/apache/maka)
- Tags: internals
- Published: 2026-09-06

---

**Mako’s runtime registers Bash, Read, and Write as `MakaTool` objects via the `buildBuiltinTools` factory in [`packages/runtime/src/builtin-tools.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/builtin-tools.ts), where each tool executes within sandboxed filesystem and shell boundaries enforced by the active execution context.**

The Apache Mako project provides a runtime environment for LLM-driven agents that interact with the filesystem and shell through strictly defined built-in tools. Understanding how Mako implements **Bash**, **Read**, and **Write** at the runtime level reveals the architecture behind its secure, sandboxed execution model. This article examines the source code in `apache/maka` to explain the factory pattern, schema validation, and security boundaries that govern these core utilities.

## Tool Registration Architecture

The runtime initializes its built-in toolkit through the `buildBuiltinTools` function located at [lines 94-122 of [`packages/runtime/src/builtin-tools.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/builtin-tools.ts)](https://github.com/apache/maka/blob/main/packages/runtime/src/builtin-tools.ts#L94-L122). This factory creates and returns an array of `MakaTool` objects, always including the three core file-system tools—**Read**, **Write**, and **Edit**—alongside the **Bash** command tool.

```typescript
import { buildBuiltinTools } from '@maka/runtime';

const tools = buildBuiltinTools({
  permissionProfile: myPermissionProfile,
});

```

The function wires in auxiliary services—including the workspace executor, sandbox manager, and permission profile—ensuring every tool invocation runs inside a controlled execution boundary. Each tool conforms to the `MakaTool` interface, which describes its metadata, Zod-based input schema, and asynchronous implementation.

## Read Tool Implementation

The **Read** tool, defined at [lines 350-449](https://github.com/apache/maka/blob/main/packages/runtime/src/builtin-tools.ts#L350-L449), serves a dual purpose: reading text files from the sandboxed filesystem or retrieving whole runtime resources referenced by a `ref` identifier.

### Input Schema and Validation

The tool accepts a Zod schema that enforces mutual exclusivity between a `path` property (with optional `offset` and `limit` parameters) and a `ref` property. The schema is pre-processed to ensure only one input type is provided, then exposed to the provider as a JSON schema.

### Execution Logic

When invoked, the implementation branches based on the input type:

- **Resource References**: If a `ref` is supplied, the tool resolves the reference via `runtimeResources` or `attachmentResources`.
- **Filesystem Paths**: If a `path` is supplied, the request forwards to the sandboxed filesystem worker through `filesystem.execute({ kind: 'read', … })`.

The result can be a plain text payload, an image snapshot handled via `snapshotImage`, or an error wrapped by `internalFilesystemReadFailure`.

```typescript
await tools.find(t => t.name === 'Read')!.impl({
  path: 'docs/README.md',
  offset: 0,
  limit: 20,
}, {
  cwd: '/home/user/project',
  sessionId: 'sess-123',
  abortSignal: new AbortController().signal,
});

```

## Write Tool Implementation

The **Write** tool, found at [lines 450-473](https://github.com/apache/maka/blob/main/packages/runtime/src/builtin-tools.ts#L450-L473), persists string content to a specified file path within the sandboxed environment.

### Schema and Operation

The tool uses a simple Zod object schema requiring `{ path: string, content: string }`. The implementation calls the filesystem worker with `operation: { kind: 'write', path, content }` via the shared `filesystem.execute` helper at [lines 635-645](https://github.com/apache/maka/blob/main/packages/runtime/src/builtin-tools.ts#L635-L645).

### Result Handling

On success, the tool returns either a file diff (`kind: 'file_diff'`) or a plain write acknowledgment (`kind: 'file_write'`). Errors are captured and wrapped by `internalFilesystemWriteFailure` to ensure consistent error reporting to the LLM.

```typescript
await tools.find(t => t.name === 'Write')!.impl({
  path: 'tmp/out.txt',
  content: 'Hello, Mako!',
}, {
  cwd: '/home/user/project',
  sessionId: 'sess-123',
  abortSignal: new AbortController().signal,
});

```

## Bash Tool Implementation

The **Bash** tool provides arbitrary shell command execution within the session’s current working directory. Its construction and execution logic spans [lines 494-511](https://github.com/apache/maka/blob/main/packages/runtime/src/builtin-tools.ts#L494-L511) for tool creation and [lines 558-750](https://github.com/apache/maka/blob/main/packages/runtime/src/builtin-tools.ts#L558-L750) for the executor implementation.

### Tool Construction Strategy

The runtime selects between two construction strategies:

- **Managed Bash**: Built via `buildManagedBashTool` when a custom `ShellRunLauncher` is supplied.
- **Simple Executor**: Built via `buildExecutorBashTool` for direct executor-driven execution.

### Schema and Validation

The tool schema combines `bashBoundaryIntentSchema` and `sandboxBoundaryExpansionSchema` to express sandbox-boundary intent and optional timeout parameters.

### Execution Flow

Before execution, the command undergoes validation via `throwIfShellSetupFailed` and potential transformation by the sandbox manager through `sandboxCommand`. The runtime then delegates execution to `executor.exec`, which spawns the command using the detected `defaultShellPlan`. Results are wrapped by `shapeTerminalResult` and returned as a `TerminalResult` object.

```typescript
await tools.find(t => t.name === 'Bash')!.impl({
  command: 'ls -l *.ts',
  timeout_ms: 30_000,
}, {
  cwd: '/home/user/project',
  sessionId: 'sess-123',
  abortSignal: new AbortController().signal,
  emitOutput: (output) => console.log(output),
});

```

## Sandbox Boundaries and Security

All three tools operate within the active **execution boundary** (`ctx.executionBoundary`) enforced by the `filesystem.execute` method. For Bash commands, additional sandbox transformations occur via `sandboxCommand`, which may rewrite commands, adjust environment variables, or reject execution if the permission profile demands an unavailable sandbox configuration. This architecture ensures that filesystem and shell operations remain confined to the permitted workspace scope.

## Model Output Conversion

Both **Read** and **Write** expose a `toModelOutput` hook that maps raw tool results into LLM-compatible formats. The Bash tool utilizes conversion logic in [[`bash-model-output.ts`](https://github.com/apache/maka/blob/main/bash-model-output.ts)](https://github.com/apache/maka/blob/main/packages/runtime/src/bash-model-output.ts), while file operations rely on [[`file-tool-model-output.ts`](https://github.com/apache/maka/blob/main/file-tool-model-output.ts)](https://github.com/apache/maka/blob/main/packages/runtime/src/file-tool-model-output.ts). These hooks transform internal results—such as `TerminalResult` or file diff objects—into deterministic, JSON-compatible structures via functions like `bashToolResultToModelOutput` and `fileWriteToolResultToModelOutput`.

## Summary

- **Central Registry**: Mako defines all built-in tools in [`packages/runtime/src/builtin-tools.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/builtin-tools.ts) via the `buildBuiltinTools` factory (lines 94-122), which returns `MakaTool` objects for Read, Write, and Bash.
- **Schema Enforcement**: Each tool uses Zod schemas to validate inputs, with Read supporting mutually exclusive `path` or `ref` parameters, while Write requires `path` and `content`.
- **Sandboxed Execution**: Filesystem operations route through `filesystem.execute` (lines 635-645) with active permission profiles, while Bash commands undergo `sandboxCommand` transformation before `executor.exec` spawns them.
- **Result Normalization**: Tools convert raw results to LLM-friendly formats via `toModelOutput` hooks located in dedicated model-output modules.

## Frequently Asked Questions

### How does the Mako runtime register its built-in tools?

The runtime calls the `buildBuiltinTools` factory function in [`packages/runtime/src/builtin-tools.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/builtin-tools.ts) (lines 94-122), which instantiates `MakaTool` objects for Read, Write, Edit, and Bash. This factory injects required services like the sandbox manager and permission profile to ensure controlled execution boundaries.

### What security mechanisms protect Bash tool execution?

The Bash tool implements multiple security layers: input validation via `throwIfShellSetupFailed`, command transformation through `sandboxCommand`, and execution confinement within the `ctx.executionBoundary`. The tool also checks against the active permission profile and may reject commands requiring unsupported sandbox features.

### How does the Read tool differentiate between filesystem paths and runtime resources?

The Read tool uses a Zod schema enforced at lines 350-449 that accepts either a `path` string or a `ref` identifier, but never both simultaneously. When `ref` is provided, the tool queries `runtimeResources` or `attachmentResources`; when `path` is provided, it delegates to the sandboxed `filesystem.execute` method.

### What determines the output format returned to the LLM model?

The output format is determined by the `toModelOutput` hook implemented on each tool. Read and Write use converters in [`file-tool-model-output.ts`](https://github.com/apache/maka/blob/main/file-tool-model-output.ts), while Bash uses [`bash-model-output.ts`](https://github.com/apache/maka/blob/main/bash-model-output.ts). These hooks transform internal results into deterministic, JSON-compatible structures via functions like `bashToolResultToModelOutput`.