Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/hunvreus/heypi/llms.txt

Use this file to discover all available pages before exploring further.

The runtime is heypi’s command, file, and search API. When the agent calls bash, read, write, grep, or any other core tool, those calls go through the configured runtime. The runtime enforces the scoped workspace root, path containment, file size limits, and (for just-bash) network isolation. Custom tools can also use the runtime explicitly through ctx.runtime when they need sandboxed command or file work.

Built-in Runtimes

just-bash

Default. Runs commands in a subprocess with network disabled by default and strict path containment. The safe choice for team-facing agents.

guarded-bash

Host bash with regex guardrails. Useful for dev or trusted environments. Not a sandbox — runs directly on the host.

host-bash

Unrestricted host bash. For admin or developer-only agents. Do not use with untrusted users.

Basic Configuration

import { workspace } from "@hunvreus/heypi";

runtime: {
  root: workspace("./workspace"),
  // scope: "user", // optional; defaults to the top-level scope
}
workspace() resolves the given path relative to process.cwd(). Use it to get an absolute path for the runtime root. Set runtime.name only when choosing guarded-bash or host-bash; just-bash is the default and does not need an explicit name.

just-bash Network Configuration

Network access is disabled by default in just-bash. Without explicit network config, commands like curl and wget are unavailable even if commandConfirm() would allow them.
Enable access only to the URLs your agent needs:
runtime: {
  root: workspace("./workspace"),
  justBash: {
    network: {
      allowedUrlPrefixes: ["https://docs.example.com"],
    },
  },
}

File and Search Limits

File and search tools enforce size and traversal limits. Configure them under runtime.limits:
OptionDefaultDescription
maxFileBytesMaximum bytes that read will inline
maxScanBytesMaximum bytes that grep will scan
maxEntriesMaximum entries that find and ls will return

Docker Runtime

@hunvreus/heypi-runtime-docker is an experimental preview. Its API and operational behavior may change before heypi 1.0.
The Docker runtime runs heypi’s bash, read, write, edit, grep, find, and ls tools inside a scoped Docker container.

Requirements

  • Docker CLI on PATH
  • Running Docker daemon
  • A Linux image with bash and standard POSIX utilities: sh, find, awk, wc, sed, cat, head

Install

npm install @hunvreus/heypi-runtime-docker

Configuration

import { dockerRuntime } from "@hunvreus/heypi-runtime-docker";

runtime: {
  root: workspace("./workspace"),
  scope: "channel",
  provider: dockerRuntime({
    image: "debian:bookworm-slim",
    network: "none",
    idleMs: 10 * 60 * 1000,
    timeoutMs: 120_000,
    env: { NODE_ENV: "production" },
    labels: { "com.example.app": "ops-agent" },
    user: "1000:1000",
    extraRunArgs: ["--cpus", "1"],
    limits: {
      maxFileBytes: 1_000_000,
      maxScanBytes: 5_000_000,
      maxEntries: 10_000,
    },
  }),
}

Behavior

  • One warm container is kept per runtime scope.
  • The scoped runtime root is bind-mounted at /workspace inside the container.
  • Commands run with docker exec inside the container.
  • File and search tools run shell scripts inside the container — they do not read or write through host filesystem shortcuts.
  • Containers stop after idleMs with no use. Set idleMs: false to keep them until app shutdown.
  • Network defaults to "none". Set network: "bridge" or another Docker network only when the agent needs network access.
  • Containers are labeled with heypi.runtime=docker and scope metadata for local inspection.

Management Hooks

const provider = dockerRuntime({ image: "debian:bookworm-slim" });
const [status] = (await provider.status?.()) ?? [];

if (status) await provider.restart?.(status.scope);
if (status) await provider.stop?.(status.scope);
await provider.cleanup?.();
Docker itself is trusted host infrastructure. Anyone who can control the Docker daemon can control the host.

Gondolin VM Runtime

@hunvreus/heypi-runtime-gondolin is an experimental preview. Its API and operational behavior may change before heypi 1.0.
The Gondolin runtime runs heypi’s tools inside a lightweight QEMU-backed VM. No daemon, auth token, or hosted service is required.

Requirements

  • Node.js 23.6 or newer
  • QEMU installed:
# macOS
brew install qemu

# Debian / Ubuntu
sudo apt install qemu-system-arm
Internet access is needed on first run so Gondolin can download and cache its Alpine guest image.

Install

npm install @hunvreus/heypi-runtime-gondolin

Configuration

import { gondolinRuntime } from "@hunvreus/heypi-runtime-gondolin";

runtime: {
  root: workspace("./workspace"),
  scope: "channel",
  provider: gondolinRuntime({
    idleMs: 10 * 60 * 1000,
    timeoutMs: 120_000,
    env: { NODE_ENV: "production" },
    mounts: {
      "/shared": "./shared",
    },
    secrets: {
      EXAMPLE_API_KEY: {
        value: process.env.EXAMPLE_API_KEY!,
        hosts: ["api.example.com"],
      },
    },
    limits: {
      maxFileBytes: 1_000_000,
      maxScanBytes: 5_000_000,
      maxEntries: 10_000,
    },
  }),
}

Behavior

  • One warm VM is kept per runtime scope.
  • The scoped runtime root is mounted at /workspace.
  • VM egress is open by default. Use secrets with per-host hosts restrictions to limit where credentials can flow.
  • Secrets are exposed through HTTP hooks inside the VM — the agent never sees raw secret values.
  • VMs stop after idleMs with no use. Set idleMs: false to keep them until app shutdown.
  • Extra host directories can be mounted with mounts.
  • Timed out, cancelled, or crashed VM executions close the VM; the next call starts a fresh one.

Management Hooks

const provider = gondolinRuntime();
const [status] = (await provider.status?.()) ?? [];

if (status) await provider.restart?.(status.scope);
if (status) await provider.stop?.(status.scope);
await provider.cleanup?.();

Cold Start Behavior

When a managed runtime (Docker or Gondolin) is starting up, heypi emits a progress event rendered as runtimeStarting. This defaults to "Preparing runtime..." and can be customized or disabled:
messages: {
  runtimeStarting: "Spinning up sandbox...", // or false to use default progress text
  runtimeFailed: "Runtime failed. Ask an admin to check the server logs.",
}

Attachment Handling

Inbound attachments are stored in a scoped tree separate from the runtime workspace. When heypi inlines an attachment:
Attachment typeHandling
Text-like filesInlined as text into the prompt
ImagesPassed to Pi as image inputs
PDFs / Office documentsConverted to Markdown (optional)
Unsupported binariesKept as attachment references

Optional Document Conversion

Enable PDF and Office document conversion:
attachments: { process: { documents: true } }
The bundled heypi-convert-document wrapper uses Microsoft MarkItDown through Python. Prewarm it during deploy to avoid first-run latency:
heypi-convert-document --setup
Document conversion requires Python 3 plus either uv or MarkItDown already installed in your Python environment.

Build docs developers (and LLMs) love