foldyard
Bring your whole dev stack into the fold. Secretless by default.
Foldyard is a laptop-local, isolated development environment 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 optionally your coding agent all run together inside a throwaway Linux VM running rootless Podman — one that mounts only the repo, and nothing else.
TL;DR
brew install uv lima podman # lima creates the VM; podman drives the socket it hands out
uv tool install "foldyard[host]" # puts `foldyard` on your PATH, with `fy` as shorthand
cd your-repo
foldyard init # writes foldyard.toml: a locked-down, stack-less box, with
# agents / stack / editor attach as commented opt-ins
fy box up # VM + dev box; egress fail-closed through a host-side proxy
fy box shell # you're in the yard
No custom image required — foldyard ships a Debian box (engine client, git, uv). To grow it
into one tuned for your repo: foldyard skill install bootstrap-devbox, then run the skill.
An agent inside the box (fy claude/fy codex) is told what fy is and how to edit the
config, so you can let them help you. The config changes won't apply automatically, but
instead you'll see the changes and have to approve on the next fy box up. This way the
agent inside the box can't sneak changes in, but you can still share the config with your team.
One prerequisite: a clean repo. The yard mounts only your repo, so the zero-credential guarantee holds exactly when that repo carries config, not credentials. Scan your history with gitleaks or TruffleHog first and move anything that surfaces into a posture. Foldyard can mount a clean repo; it can't clean a dirty one.
The walkthrough is docs/quickstart.md — and the whole manual ships
with the install, offline and version-matched: fy docs.
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 machine — 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 genuinely missing is one boundary that holds the real compose stack, the real e2e loop and real services by container name and zero credentials. → prior-art.md
Secretless by default, posture on demand. The yard starts with no ~/.ssh, no tokens, no
credential helpers — nothing to lift, and no keys to push with. When you need real access you
declare a posture (fy mode gcp=logs github=app), and host-side daemons outside the blast
radius mint short-lived scoped tokens and inject them at the egress proxy — so the token
reaches the upstream API but never the yard. Emergency rungs are TTL-bound and auto-revert. No
daemon running ⇒ no credential flows, whatever a file inside the yard says.
→ modes.md
Isolation without hiding. A container escape lands the attacker inside the disposable VM,
not on your machine — there is no host filesystem mounted 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 exercises a battery of
known escapes on demand. (It tests the escapes we know about — it raises assurance, it doesn't
prove a negative.) → security.md
Who it's for
Agent users — hand Claude Code (or any agent) the in-VM machine socket: full stack autonomy, bounded to the repo and the containers inside the VM. The socket controls the machine from within the moat, not your host. 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
yard, and the worm wakes up with no ambient credentials and no push access, its reach bounded
to a repo the clean-repo prerequisite keeps boring. Egress routes through the host-side proxy:
every destination logged (SNI-only by default, full decrypt-and-log under capture=on), with
an opt-in default-deny wall and live host grants. → networking.md
Two honesty notes. Proxy routing rides proxy env vars, which cooperative software honours and
malware may not — [machine].wall = true (what foldyard init writes) closes that by
provisioning a fail-closed firewall into the VM itself, making the proxy the only way out.
And declaring a posture while running an untrusted install step is the one window where
install-time code and a live token coincide.
Shape
One Python CLI, one foldyard.toml in your repo, host state in ~/.foldyard/. Your own task
runners (just, npm scripts) stay yours — foldyard runs under them, not instead of them.
- Core — machine lifecycle · compose-stack runner (worktree-namespaced projects, shared
caches) with declarative posture overlays · long-lived dev box
(multi-session, shadow volumes, IDE-attachable) ·
verifyisolation battery · mode/posture substrate with TTLs and a host-side supervisor · credential-injecting egress proxy with capture logging, a default-deny wall and VM-level fail-closed forcing · doctor · TUI. - Plugins — credential minters (GCP metadata emulator, GitHub App header injection, generic header/query-param-auth APIs) · editor attach (VS Code) · agents (Claude Code and Codex, keyless: the proxy injects your key host-side, a dummy lives in the box).
Each project gets its own rootless VM, scoped by project name. The default backend is Lima
because it runs the per-project VMs side by side — so one project's open box shell / code
session survives while you work in another — and because it's the backend that can be
provisioned with the fail-closed wall. Other backends, and when to pick them, are in
configuration.md.
Status
The engine runs daily on Macs with a production project, but has only been lightly tested on other repos, treat it as alpha quality for now. Other platforms (Linux and WSL2) are planned, but currently not supported. Brave testers and issues very welcome!
More info
Start at the docs map; the "why" behind each design call is in docs/adrs/.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file foldyard-0.2.0.tar.gz.
File metadata
- Download URL: foldyard-0.2.0.tar.gz
- Upload date:
- Size: 1.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
adf22f132a4874899d0bb9b54d91adb3e874d53f8567cd7b3b0dd0f46c8eda14
|
|
| MD5 |
ed1bdf50e74f26eb2cd25ba28e7a9f75
|
|
| BLAKE2b-256 |
e5385d21c98b1facfdac08a813716f26ec2563274cef5399ffe493512edde80a
|
File details
Details for the file foldyard-0.2.0-py3-none-any.whl.
File metadata
- Download URL: foldyard-0.2.0-py3-none-any.whl
- Upload date:
- Size: 588.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","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}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30cabfbd2d638a334394eea35f1ddc18a8c824123726fd0c683948f361c96305
|
|
| MD5 |
66d138744e6a26fee4d0129e8d55ae53
|
|
| BLAKE2b-256 |
51c342e3f023699ad72a3ba35d149d56626a1634df7bcb1a7b841c48fe20e6cc
|