Skip to main content

foldyard

Bring your whole dev stack into the fold. Secretless by default.

Foldyard is an isolated development environment that runs on your own computer, for your project's entire dev stack — not just an agent, not just a shell. Your docker-compose services (databases, emulators, app servers), your dependency installs, your IDE backend and, if you want, your coding agent all run together inside a throwaway Linux VM running rootless Podman. The VM mounts your repo and nothing else.

New to the vocabulary? The glossary defines every term these docs use.

TL;DR

Install the prerequisites. Lima creates the VM; podman talks to the container engine inside it.

# macOS
brew install uv lima podman

# Linux (Debian/Ubuntu shown; x86-64 with KVM)
curl -LsSf https://astral.sh/uv/install.sh | sh
sudo apt-get install qemu-system-x86 qemu-utils ovmf podman
curl -fsSL https://github.com/lima-vm/lima/releases/download/v2.2.0/lima-2.2.0-Linux-x86_64.tar.gz \
  | sudo tar Cxz /usr/local

Then:

uv tool install foldyard           # puts `foldyard` on your PATH, with `fy` as shorthand

cd your-repo
foldyard init                      # writes foldyard.toml: a locked-down box with no stack yet;
                                   # agents, stack and editor attach are commented-out opt-ins
fy box up                          # creates the VM and the dev box; all traffic goes out
                                   # through a proxy on your computer
fy box shell                       # you're in the box

No custom image is needed: foldyard ships a Debian box with the engine client, git and uv. To grow it into one tuned for your repo, run foldyard skill install bootstrap-devbox and then the skill.

An agent inside the box (fy claude, fy codex) is told what fy is and how to edit the config, so it can help you set foldyard up. Its edits don't take effect on their own: the next fy box up shows you the change and asks you to approve it. The agent can't sneak a change in, and you can still share the config with your team.

One prerequisite: a clean repo. The VM mounts only your repo, so the zero-credential guarantee holds exactly when that repo holds config, not credentials. Scan your history with gitleaks or TruffleHog first, and move anything they find out of the repo. Credentials the box really needs are supplied by modes without ever entering the VM. Foldyard can mount a clean repo; it can't clean a dirty one.

The full walkthrough is docs/quickstart.md. The whole manual also ships with the install, offline and matched to your version: fy docs.

Architecture

Everything that holds a credential stays on your computer. The VM gets the repo and nothing else.

Foldyard architecture: your machine runs the foldyard CLI, the supervisor, the credential token services and the egress proxy, and holds the config you approve, the allowlist and the access modes; the VM ("the yard") is a throwaway Linux VM running rootless Podman that mounts only the repo and holds the compose stack, the dev box, the coding agent and worktrees side by side, with fy verify auditing the boundary from inside; traffic from the VM reaches upstream APIs only through the proxy.

Isolation comes in layers, not as one switch. You can harden the same setup one step at a time — from a rootless Podman VM, to Lima with a firewall inside the VM, to gVisor under the dev box, to a second firewall on a Linux host — with egress control as a separate dial alongside. Each step is one line in foldyard.toml, and the credentials never move:

Foldyard isolation layers: four cumulative steps — a rootless Podman VM; Lima with the firewall inside the VM; gVisor under the dev box, reached through a narrowed engine socket; and the host-side firewall on Linux — then the egress dial from open through observe and enforce to fail-closed, and what never moves: the credentials stay on your computer, the engine socket is the one deliberate opening, and fy verify checks the layer you are in.

Which layer carries the weight depends on your operating system — isolation-layers.md.

Why

A fold-yard is the enclosed farmyard where animals are folded (penned) for the night. Same idea here: everything that runs untrusted code lives in the yard, and your computer — keys, browser profile, other repos — stays outside the fence. Three ideas hold it up.

The unit of isolation is the project, not the agent. Agent sandboxes are plentiful, and isolated dev environments exist (Devcontainers, Codespaces, Gitpod, Coder). What's missing is one boundary that holds the real compose stack, the real end-to-end test loop and real services reachable by container name — and zero credentials. → prior-art.md

Secretless by default, credentials on demand. The yard starts with no ~/.ssh, no tokens, no credential helpers: nothing to steal and no keys to push with. When you need real access you switch it on (fy mode gcp=logs github=on). Token services on your computer — outside anything the yard can reach — make short-lived, scoped tokens, and the egress proxy adds them to requests on the way out. The upstream API gets the token; the yard never does. Emergency levels that act as you expire on a timer and switch themselves off. If no token service is running, no credential flows, whatever a file inside the yard says. → modes.md

Isolation without hiding. A container escape lands the attacker inside the throwaway VM, not on your computer — no host filesystem is mounted for it to reach, even at VM level. Because the boundary doesn't depend on concealment, nothing needs to be nested or hidden: Podman Desktop shows every container, and fy verify audits the mounts and tries a set of known escapes on demand. (It tests the escapes we know about: it raises confidence, it can't prove there are none.) → security.md

Who it's for

Agent users. Give Claude Code (or any agent) the container socket inside the VM: full control of the stack, bounded to the repo and the containers in that VM. The socket controls the VM from the inside, not your computer. Safer autonomy, not less of it.

Everyone else. Supply-chain worms (Shai-Hulud and friends) ride npm install and lifecycle scripts on developer laptops. Run installs, dev servers and your IDE backend in the VM, and a worm wakes up with no credentials and no push access, able to reach only a repo the clean-repo rule keeps boring. All traffic out goes through the proxy on your computer: every request is decrypted and logged (except trusted toolchain hosts you mark as passthrough), and an allowlist decides what may go out, with grants you add live. → networking.md

Two honest caveats. Routing through the proxy relies on proxy environment variables, which well-behaved software honours and malware may ignore. [machine] firewall = true (which foldyard init writes) closes that gap: a firewall inside the VM refuses any traffic that doesn't go through the proxy. And switching a credential on while running an untrusted install step is the one window where install-time code and a live token meet.

Shape

One Python CLI, one foldyard.toml in your repo, and state on your computer in ~/.foldyard/. Your own task runners (just, npm scripts) stay yours — foldyard runs under them, not instead of them.

  • Core — VM lifecycle · a compose-stack runner (one namespaced stack per worktree, shared caches) with overlays that change with the mode · a long-lived dev box (several sessions at once, IDE-attachable) · the fy verify isolation self-test · modes with time limits, run by a supervisor on your computer · an egress proxy that adds credentials, logs traffic and enforces the allowlist, backed by the VM firewall · fy doctor · a TUI.
  • Plugins — token services (a GCP metadata emulator; [[inject]] credentials from config alone — static header- or query-parameter tokens, GitHub App installation tokens) · editor attach (VS Code) · agents (Claude Code and Codex, keyless: the box holds a dummy key and the proxy swaps in your real one).

Each project gets its own rootless VM, named after the project. The default backend is Lima: it runs one VM per project side by side, so a fy box shell or fy code session in one project survives while you work in another, and it is the backend that can carry the VM firewall. The alternative, and when to pick it, is in configuration.md.

Status

Alpha. Treat it that way, and expect rough edges.

  • macOS — used daily with a production project. Other repos have only been lightly tested.
  • Linux (x86-64) — CI boots a real Lima VM on an Ubuntu 24.04 runner and drives the real loop on it: fy up, the dev box, worktrees, VM lifecycle, fy verify, and both firewalls. fy tui, fy code and fy open haven't been tried on Linux yet, and some messages still give macOS-only hints (brew install …).
  • WSL2 — the same CI tests pass inside WSL2 on a Windows runner, except the host firewall, which the stock WSL2 kernel can't support. Not yet tried on a real Windows 11 machine.

What has and hasn't been run on Linux is tracked in docs/linux-support.md. Brave testers and issues very welcome!

More info

Start at the docs map. The reasoning behind each design decision is in docs/adrs/.

Metadata

Release files for foldyard 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for foldyard 0.4.0
File Size Uploaded
foldyard-0.4.0.tar.gz 1.6 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for foldyard 0.4.0
File Interpreter ABI Platform
foldyard-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 2.5 MB

Release files / foldyard-0.4.0.tar.gz

Download URL foldyard-0.4.0.tar.gz
Size 1.6 MB
Tags Source
SHA-256 checksum
How to use checksums
a39653ead7198c1d19e877e5cd3494f7ef671f4ccb7389138c363a47aeb4d53d
BLAKE2b-256 checksum
How to use checksums
277686381d0b665b55ad6fe5c78aef592c196ac647d36b2f98c75993c2b831e9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / foldyard-0.4.0-py3-none-any.whl

Download URL foldyard-0.4.0-py3-none-any.whl
Size 832.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8bd33cc7782f669a177b96b27b879c08620b18fbc369d5f35d69040a66ae8e05
BLAKE2b-256 checksum
How to use checksums
fecc4de516aa8dea568bd08d84eac8cc12d3919bc813607f13daa0ecb02b2747
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page