Skip to main content

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.

The yard starts with zero credentials: no ~/.ssh, no tokens, no credential helpers. With no posture declared there are no keys to push with and nothing to lift — and access is never baked in: it's opt-in, scoped, and TTL-bound (thesis 2). A malicious npm/PyPI package wakes up with no ambient credentials to lift and no push access; any access it is granted is injected at a host-side proxy, so the token itself never enters the yard.

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; your machine — keys, browser profile, other repos — stays outside the fence.

Three theses

  1. Stack colocation. The unit of isolation is the project, not the agent. Agent sandboxes are plentiful; isolated dev environments exist (Devcontainers, Codespaces, Gitpod, Coder). What's genuinely missing is an environment that gives the agent — or just you — the real compose stack, real e2e loop, and real services by container name inside the same boundary that holds zero credentials.

  2. Secretless by default, posture on demand. The yard starts with zero credentials. When real access is needed, you declare a posture (foldyard mode gcp=logs github=app) and host-side daemons — running 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 itself. Emergency rungs are TTL-bound and auto-revert. No daemon running ⇒ no credential flows, whatever any file inside the yard says.

  3. Isolation without hiding. Safety comes from the VM moat + rootless Podman

    • restricted mounts: a container escape lands the attacker inside the disposable Linux VM, not on your machine — there is no host filesystem mounted to reach even at VM level, and the nsenter escape test is refused. Because the boundary doesn't depend on concealment, nothing needs to be nested or hidden: Podman Desktop shows every container, and foldyard verify asserts the machine exposes only the repo (no stray $HOME bind-mount — the one default that would quietly break everything) 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.)

Before you adopt: a clean repo

Secretless is a precondition foldyard relies on, not a transformation it performs. The yard mounts only your repo, so the guarantee holds precisely when that repo carries config, not credentials — env vars that point at services, not the keys to them. foldyard can mount a clean repo; it can't clean a dirty one.

So step one is a scan, not an install. Run gitleaks or TruffleHog across your history first, and move anything they surface into a posture. Re-run the scan as part of your routine (folding it into foldyard verify is on the roadmap) so the precondition can't silently rot back into the repo.

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 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 the repo it can already see (which the clean-repo prerequisite keeps boring). The box's egress routes through the host-side proxy: every destination is logged (SNI-only by default, full decrypt-and-log with capture=on), and an opt-in default-deny egress wall ([proxy] default_deny + live host grants) refuses any host you haven't allowed. One honesty note: that routing rides proxy env vars, which cooperative software honors and malware may not — [machine].wall = true (what foldyard init writes) closes it by provisioning a fail-closed firewall into the VM itself, making the proxy the only way out. Mind the one overlap: declaring a posture while running an untrusted install step is the window where install-time code and a live token coincide.

Shape

  • Core: machine lifecycle · compose-stack runner (worktree-namespaced projects, shared caches) with declarative posture overlays ([[overlay]]: layer a -f file when the mode matches, config only) · long-lived dev box (multi-session, shadow volumes, IDE-attachable) · verify isolation battery (mount audit + escape tests + posture checks) · mode/posture substrate with TTLs and host-side supervisor · credential-injecting egress proxy with capture logging, an opt-in default-deny egress wall, and VM-level fail-closed forcing ([machine].wall) · 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).

One Python CLI (uv tool install foldyard; also aliased as fyfy <verb> == foldyard <verb>), one foldyard.toml in your repo, host state in ~/.foldyard/. Project-specific task runners (just, npm scripts) stay yours — foldyard runs under them, not instead of them.

Getting started in any repo (docs/quickstart.md is the walkthrough): foldyard init scaffolds a foldyard.toml that is live for an isolated box-only VM (no compose stack, no agents) with everything else — agents, editor attach, stack wiring — present as commented blocks you uncomment to opt in; it also fences foldyard's box-generated dirs into your .gitignore. Then foldyard box up. Projects with no custom image use foldyard's packaged generic box (engine client + git + uv); to grow it into a tuned image, install foldyard skill install bootstrap-devbox and run the skill.

Each project gets its own rootless VM, scoped by project name. The default backend is Lima (brew install lima), because it runs the per-project VMs side by side — so a 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 above. You'll also need podman on the host: the backend creates the VM, podman drives the socket it hands out. Other backends, and when to pick them, are in docs/configuration.md.

Status

The engine runs daily in production. The user guides live under docs/ (start at the docs map); the "why" behind each design call in docs/adrs/.

Host platform: macOS is what's validated. There is no platform branching in the package — no sys.platform, no Darwin test — and [machine].backend = "native" exists for Linux and WSL2 hosts, but that path is unexercised and much of the prose still says "Mac" where it means "the machine running fy host". Treat Linux and WSL2 as untested, not unsupported. The box is Linux either way.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

foldyard-0.0.1.tar.gz (951.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

foldyard-0.0.1-py3-none-any.whl (567.3 kB view details)

Uploaded Python 3

File details

Details for the file foldyard-0.0.1.tar.gz.

File metadata

  • Download URL: foldyard-0.0.1.tar.gz
  • Upload date:
  • Size: 951.2 kB
  • 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

Hashes for foldyard-0.0.1.tar.gz
Algorithm Hash digest
SHA256 1af37b182839e7267689bf5436f0d11e470e0ff741ceda77ca22dc024e399d60
MD5 c99d6db966e0e1562cd9bf7d16e87fc7
BLAKE2b-256 1ebb4b096302de29b1aac91b3c2eaa7f1934a80eebb6b28c5164eaf3eda3c913

See more details on using hashes here.

File details

Details for the file foldyard-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: foldyard-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 567.3 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

Hashes for foldyard-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e5cbd1c98ef09dd0acb8877fc455ec95fab1aa7a0e73a0c28465688490fe3af1
MD5 10ef026e517fad9b1b94de1857545109
BLAKE2b-256 adcd59b9dcd049e9952eb98ddcd10f6ecfb241bcd321779598ceabc33bcceb53

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.1

2 files

0.2.0

2 files

0.1.0

2 files

This release

0.0.1 This release

2 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