# Technical Orientation

> What actiond is, its two execution modes (linux-actiond and darwin-actiond serve-vm), the top-level binary layout, the REAPI subset it implements, and how the rest of this reference is organized.

- Repository: hermeticbuild/actiond
- GitHub: https://github.com/hermeticbuild/actiond
- Human wiki: https://grok-wiki.com/public/wiki/hermeticbuild-actiond-796c0ee40e63
- Complete Markdown: https://grok-wiki.com/public/wiki/hermeticbuild-actiond-796c0ee40e63/llms-full.txt

## Source Files

- `README.md`
- `ARCHITECTURE.md`
- `MODULE.bazel`
- `src/root.zig`
- `cmd/darwin_actiond/`
- `cmd/linux_actiond/`
- `cmd/linux_actiond_guest/`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:

- [README.md](README.md)
- [ARCHITECTURE.md](ARCHITECTURE.md)
- [MODULE.bazel](MODULE.bazel)
- [src/root.zig](src/root.zig)
- [src/reapi_dispatch.zig](src/reapi_dispatch.zig)
- [src/host_server.zig](src/host_server.zig)
- [src/darwin_vm_host.zig](src/darwin_vm_host.zig)
- [src/embedded_payload.zig](src/embedded_payload.zig)
- [src/guest_init.zig](src/guest_init.zig)
- [src/grpc_vsock_bridge.zig](src/grpc_vsock_bridge.zig)
- [cmd/darwin_actiond/main.zig](cmd/darwin_actiond/main.zig)
- [cmd/linux_actiond/main.zig](cmd/linux_actiond/main.zig)
- [cmd/linux_actiond_guest/main.zig](cmd/linux_actiond_guest/main.zig)
</details>

# Technical Orientation

`actiond` is a local [Remote Execution API (REAPI)](https://github.com/bazelbuild/remote-apis) worker and cache designed for running Bazel actions inside a hermetic Linux sandbox. Its primary purpose is to let a developer's workstation act as a local remote-execution worker without surrendering normal process access to the build tool.

This page describes what `actiond` is, the two execution backends it provides, how its binaries are laid out and deployed, which REAPI methods it implements, and how the major source modules relate to one another. Deeper per-subsystem detail (filesystem, CAS layout, execution lifecycle, performance) lives in [ARCHITECTURE.md](ARCHITECTURE.md) and in the subsystem-specific pages of this wiki.

---

## What actiond Is

`actiond` accepts standard Bazel REAPI traffic over gRPC/HTTP-2, stores CAS and ActionCache state locally, constructs a fresh Linux execroot with minimal data copies, runs each action under process-level isolation, and returns declared outputs back into the CAS. The shared goal is the same across both execution modes.

The project exists primarily because of the macOS path: Apple Silicon Macs cannot run Linux binaries natively, yet Bazel's default Mac sandbox does not provide a Linux filesystem view. `darwin-actiond serve-vm` fills that gap by booting a tiny Linux VM using Apple's `Virtualization.framework` and routing all execution into it, while the Mac host owns only the TCP listener and VM lifecycle.

Sources: [README.md](), [ARCHITECTURE.md]()

---

## Execution Modes

### `linux-actiond` — Direct Linux Host

`linux-actiond serve` runs actions directly on a Linux host. Isolation is achieved entirely through Linux kernel primitives applied to each action process:

- `chroot` into a per-action work root
- private mount and network namespaces
- loopback-only networking (`lo` only, no outbound interface)
- read-only bind mounts for CAS inputs
- dropped uid/gid, `PR_SET_NO_NEW_PRIVS`
- best-effort cgroup v2 limits

The runtime SquashFS is mounted locally and glibc runtime directories are bind-mounted into the chroot when the action requests a specific `libc` platform property.

Sources: [ARCHITECTURE.md — Sandbox Model: Linux Host](), [src/host_server.zig:68-115]()

### `darwin-actiond serve-vm` — macOS Virtualization.framework VM

`darwin-actiond serve-vm` starts a long-lived arm64 Linux VM and proxies all REAPI traffic into it over `virtio-vsock`. The VM is intentionally minimal:

| Component | Details |
|---|---|
| Kernel | Custom arm64 Linux `Image`, built by `linux.bzl` via Bazel |
| Initramfs | Contains only `linux-actiond-guest` |
| Writable block device (`virtio-blk`) | Guest ext4 disk image mounted at `/cas` — owns CAS, ActionCache, and staged outputs |
| Read-only block device | `runtimes.sqfs` mounted at `/runtimes` |
| Control channel | `virtio-vsock` — carries gRPC payloads and a control protocol |
| Networking | No guest network device; each action gets a Linux network namespace with loopback only |

The VM is started once and reused across all actions. Per-action isolation is Linux-native (chroot, mount namespace, network namespace) inside the guest — not per-action VM cold boots.

Sources: [ARCHITECTURE.md — VM Shape](), [src/guest_init.zig:18-50](), [src/grpc_vsock_bridge.zig:22-58]()

---

## Binary Layout

```text
┌─────────────────────────────────────────────────────────┐
│  darwin-actiond  (macOS Mach-O arm64)                   │
│    cmd: serve-vm → darwin_vm_host.serve()               │
│    embedded: __ACTIOND,__kernel   (Image.zst)           │
│              __ACTIOND,__initramfs (initramfs.cpio.zst) │
│              __ACTIOND,__runtimes  (runtimes-aarch64.sqfs)│
└───────────────────┬─────────────────────────────────────┘
                    │ vsock gRPC bridge
                    ▼
┌─────────────────────────────────────────────────────────┐
│  linux-actiond-guest  (Linux ELF, inside initramfs)     │
│    mode --guest-init  → guest_init.run()  (PID 1)       │
│    mode --guest-worker → guest_worker.run()             │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  linux-actiond  (Linux ELF arm64 or x86_64)             │
│    cmd: serve → host_server.serve()                     │
│    embedded: .actiond.runtimes (ELF section)            │
└─────────────────────────────────────────────────────────┘
```

### `darwin-actiond`

Entry point: [`cmd/darwin_actiond/main.zig`](cmd/darwin_actiond/main.zig). The only supported subcommand is `serve-vm`. Argument parsing is handled by `darwin_vm_host.parseServeVmArgs`; the runtime call is `darwin_vm_host.serve`. The Mach-O binary carries compressed boot artifacts in dedicated sections; at startup these are extracted under `--root` and inflated before `VZLinuxBootLoader` is called.

Key CLI flags:

| Flag | Default | Purpose |
|---|---|---|
| `--listen` | `127.0.0.1:8980` | Public REAPI TCP address |
| `--root` | `/tmp/actiond-vm` | Worker root for extracted artifacts |
| `--cas-image` | `<root>/cas.ext4` | Writable guest ext4 disk image |
| `--kernel` | embedded | Path to raw or `.zst` kernel |
| `--initramfs` | embedded | Path to `.cpio.zst` initramfs |
| `--runtime-image` | embedded | Path to runtime SquashFS |
| `--memory-mib` | 512 | VM RAM |
| `--cpus` | 2 | VM vCPU count |

Sources: [cmd/darwin_actiond/main.zig](), [src/darwin_vm_host.zig:24-67]()

### `linux-actiond`

Entry point: [`cmd/linux_actiond/main.zig`](cmd/linux_actiond/main.zig). The only supported subcommand is `serve`. Calls `host_server.serve`. The standalone binary embeds the runtime SquashFS in the `.actiond.runtimes` ELF section, extracted automatically when neither `--runtime-image` nor `--runtime-root` is supplied.

Key CLI flags:

| Flag | Default | Purpose |
|---|---|---|
| `--listen` | `127.0.0.1:8980` | Public REAPI TCP address |
| `--root` | `/tmp/actiond` | Worker root (CAS, ActionCache, work dirs) |
| `--runtime-image` | embedded | Runtime SquashFS path |
| `--runtime-root` | — | Pre-mounted runtime directory |

Sources: [cmd/linux_actiond/main.zig](), [src/host_server.zig:19-55]()

### `linux-actiond-guest`

Entry point: [`cmd/linux_actiond_guest/main.zig`](cmd/linux_actiond_guest/main.zig). The same binary serves two roles inside the VM, selected by argv:

- If invoked as `init` (or with `--guest-init`): runs `guest_init.run()`, which acts as PID 1. It mounts `proc`, `sysfs`, `cgroup2`, `devtmpfs`, `tmpfs`, scans for virtio block devices to mount the CAS ext4 and runtime SquashFS, then `exec`s itself as `--guest-worker`.
- With `--guest-worker`: runs `guest_worker.run()`, the actual REAPI + execution server loop inside the guest.

Sources: [cmd/linux_actiond_guest/main.zig](), [src/guest_init.zig:47-60]()

---

## REAPI Subset Implemented

The server implements the exact methods Bazel needs for remote execution. The full set of dispatched method paths is declared as constants in [`src/reapi_dispatch.zig`](src/reapi_dispatch.zig):

| Service | Method | gRPC path |
|---|---|---|
| `Capabilities` | `GetCapabilities` | `/build.bazel.remote.execution.v2.Capabilities/GetCapabilities` |
| `ContentAddressableStorage` | `FindMissingBlobs` | `/build.bazel.remote.execution.v2.ContentAddressableStorage/FindMissingBlobs` |
| `ContentAddressableStorage` | `BatchUpdateBlobs` | `/build.bazel.remote.execution.v2.ContentAddressableStorage/BatchUpdateBlobs` |
| `ContentAddressableStorage` | `BatchReadBlobs` | `/build.bazel.remote.execution.v2.ContentAddressableStorage/BatchReadBlobs` |
| `ContentAddressableStorage` | `GetTree` | `/build.bazel.remote.execution.v2.ContentAddressableStorage/GetTree` |
| `ByteStream` | `Read` | `/google.bytestream.ByteStream/Read` |
| `ByteStream` | `Write` | `/google.bytestream.ByteStream/Write` |
| `ActionCache` | `GetActionResult` | `/build.bazel.remote.execution.v2.ActionCache/GetActionResult` |
| `ActionCache` | `UpdateActionResult` | `/build.bazel.remote.execution.v2.ActionCache/UpdateActionResult` |
| `Execution` | `Execute` (server-streaming) | `/build.bazel.remote.execution.v2.Execution/Execute` |
| *(internal)* | `CAS/DeleteBlobs` | `/actiond.internal.v1.CAS/DeleteBlobs` |

All methods run over an HTTP/2 server (`grpc_http2_server.zig`) that dispatches independent streams concurrently. Server-streaming responses use a `body_sink` so large payloads are chunked rather than buffered into a single response frame.

The server does **not** implement resource exhaustion throttling, inter-worker federation, or the optional `WaitExecution` / `CancelOperation` RPCs.

Sources: [src/reapi_dispatch.zig:25-45](), [ARCHITECTURE.md — REAPI Surface]()

---

## Source Module Map

The shared library lives under `src/` and is the single `actiond` Zig module consumed by all three binaries. `src/root.zig` re-exports every module, making them available as `actiond.<module>` in consumers.

```text
src/
├── root.zig                 # Library root – re-exports all modules
│
├── --- Transport / HTTP-2 ---
├── grpc_http2_server.zig    # HTTP/2 accept loop, stream dispatch
├── http2_frame.zig          # Frame read/write
├── http2_header.zig         # Header encoding/decoding
├── http2_hpack.zig          # HPACK compression
├── grpc_record.zig          # gRPC length-prefix framing
├── body_sink.zig            # Chunked response body abstraction
│
├── --- REAPI Dispatch ---
├── reapi_dispatch.zig       # Method router → service handlers
├── reapi.zig                # Protobuf message types (REAPI)
├── protobuf_wire.zig        # Wire-format encoder/decoder
├── capabilities_service.zig
├── cache_service.zig        # CAS FindMissing/BatchUpdate/BatchRead
├── bytestream_service.zig   # ByteStream Read/Write
├── bytestream.zig
├── action_cache_service.zig # ActionCache Get/Update
├── action_cache.zig
├── execution_service.zig    # Execute (server-streaming)
├── tree_service.zig         # GetTree
│
├── --- Storage ---
├── cas.zig                  # Content-addressed blob store
├── staged_cas_index.zig     # actiondfs staged output tracking
│
├── --- Execution ---
├── action_executor.zig      # Per-action fork/exec, namespace setup
├── action_runner.zig        # High-level action dispatch
├── execroot.zig             # Execroot construction (bind mounts / overlayfs)
├── runtime_mount.zig        # SquashFS runtime selection & bind-mount
│
├── --- VM Host (macOS) ---
├── darwin_vm_host.zig       # serve-vm entry, VM lifecycle, vsock bridge setup
├── darwin_vm.zig            # Virtualization.framework wrapper (Zig side)
├── grpc_vsock_bridge.zig    # TCP ↔ vsock raw gRPC byte bridge
├── vsock.zig                # vsock port constants, connect helpers
├── control_protocol.zig     # darwin↔guest control messages
├── control_transport_fd.zig
│
├── --- VM Guest (Linux) ---
├── guest_init.zig           # PID-1 / init: mount filesystems, exec worker
├── guest_worker.zig         # Guest REAPI + execution server
│
├── --- Standalone Packaging ---
├── embedded_payload.zig     # Mach-O section / ELF section payload extraction
│
└── version.zig              # Zig and Bazel version strings
```

Sources: [src/root.zig]()

---

## Build System and Artifact Packaging

The repo is fully Bazelized. All Zig binaries are built by `rules_zig` (version `0.16.0`). The C/Objective-C bridge for `Virtualization.framework` (`vz_bridge.m`) is compiled via the `@llvm` toolchain. The VM kernel is produced by the `linux.bzl` ruleset from the Linux source archive declared in `MODULE.bazel`.

Key build targets:

```bash
# macOS standalone (embeds kernel + initramfs + runtimes)
bazel build //cmd/darwin_actiond:darwin-actiond-standalone

# Linux standalone (embeds runtimes SquashFS)
bazel build //cmd/linux_actiond:linux-actiond-standalone \
  --platforms=//platforms:linux_aarch64

# VM artifacts only
bazel build //vm:linux_kernel_zst //vm:initramfs //runtimes:runtimes_squashfs
```

The Darwin standalone uses Mach-O section embedding (`__ACTIOND,__kernel`, `__ACTIOND,__initramfs`, `__ACTIOND,__runtimes`). The Linux standalone uses ELF section embedding (`.actiond.runtimes`). Both use `embedded_payload.extractFromSelf` at runtime to locate and extract the payload.

The kernel is shipped compressed (`Image.zst`) and inflated once to `root/boot/kernel-<sha256>.Image` before `VZLinuxBootLoader` is invoked, because `VZLinuxBootLoader` requires a raw arm64 `Image` and the arm64 format is not self-decompressing.

Sources: [ARCHITECTURE.md — Build Artifacts, Why the Kernel Is Inflated Before Boot](), [src/embedded_payload.zig:8-18](), [MODULE.bazel:1-14]()

---

## VM Request Routing (Sequence Summary)

```mermaid
sequenceDiagram
    participant Bazel
    participant darwin-actiond (macOS)
    participant grpc_vsock_bridge
    participant linux-actiond-guest (VM)
    participant guest ext4 CAS (/cas)

    Bazel->>darwin-actiond (macOS): gRPC / REAPI (TCP 8980)
    darwin-actiond (macOS)->>grpc_vsock_bridge: forward raw gRPC bytes
    grpc_vsock_bridge->>linux-actiond-guest (VM): virtio-vsock (grpc_port)
    linux-actiond-guest (VM)->>guest ext4 CAS (/cas): CAS / AC reads & writes
    linux-actiond-guest (VM)-->>darwin-actiond (macOS): ExecuteResponse / CAS responses
    darwin-actiond (macOS)-->>Bazel: gRPC response
```

The macOS host holds the public TCP listener and VM lifecycle but does not hold a CAS mirror. All content-addressed storage, ActionCache, and output promotion happen inside the guest against its native ext4 filesystem on the virtio block device.

Sources: [ARCHITECTURE.md — Darwin VM Request Routing](), [src/grpc_vsock_bridge.zig:34-58]()

---

## How This Reference Is Organized

| Page | Contents |
|---|---|
| **Technical Orientation** *(this page)* | What actiond is, execution modes, binary layout, REAPI surface, module map |
| **CAS and Storage** | Content-addressed blob layout, materialization strategies, actiondfs lazy filesystem (VM), output staging and promotion |
| **Execution Lifecycle** | Per-action fork/exec sequence, namespace setup, cgroup limits, runtime selection, input/output handling |
| **VM Infrastructure** | Virtualization.framework integration, kernel inflation, vsock protocol, guest init, disk image management |
| **Build and Packaging** | Bazel targets, standalone embedding, kernel build via linux.bzl, runtime SquashFS construction |
| **Testing** | Unit tests, e2e harness, LLVM smoke test, stress workspace |

---

## Summary

`actiond` is a focused REAPI worker implemented in Zig 0.16 that provides hermetic Linux action execution either directly on a Linux host (`linux-actiond serve`) or through an Apple Virtualization.framework VM on macOS (`darwin-actiond serve-vm`). The three binaries — `darwin-actiond`, `linux-actiond`, and `linux-actiond-guest` — share a single Zig library under `src/` and implement the ten REAPI methods Bazel needs for remote execution. Standalone binaries embed their runtime artifacts (kernel, initramfs, SquashFS) in native executable sections and extract them once at worker startup, keeping distribution and startup self-contained. The VM path is the project's primary motivation: it gives Apple Silicon Mac workstations a local Linux remote-execution worker without exposing host macOS resources to build actions.
