Feature · 2026-06-10

The Agent Sandbox With a Review Loop

Letting an agent work unattended is two bets at once: that it can't reach anything it shouldn't, and that you can tell, afterward, what it actually did. h5i's env makes those one reviewable unit: an isolated git worktree under a pinned policy, where every run is captured as evidence and the change reaches your branch only when you apply it.

Key takeaways
  • An env is a triple fusion of a code branch, a reasoning branch, and a pinned policy manifest, not just a worktree.
  • The lifecycle is human-gated: create, run, diff, propose, apply; apply is the only verb that touches your branch, and it refuses an unproposed env.
  • propose is a mediated commit (a canonicalized path allowlist), every run is a secret-redacted evidence capture, and compare is the arena.

A coding agent has crossed a line that autocomplete never did: it runs unattended. It installs packages, runs builds, edits files across a tree, and reaches the network, for minutes or hours, with whatever access your shell has, while you do something else. When you come back, the question is no longer "is this line correct." It's two harder questions at once. What could this process have touched that wasn't the task, your ~/.ssh, your tokens, an arbitrary host, if a poisoned dependency or a prompt-injected README nudged it off course? And separately: can you actually tell, after the fact, what it did do?

Those two questions, blast radius and reviewability, are usually handled by two different tools that don't know about each other. A git worktree isolates the checkout. A container isolates the process. Neither, on its own, gives you the thing autonomy actually needs: a single unit you can hand an agent, that confines it, records what it did, and then makes its output reach your real branch only when a human says so. That unit, the confinement-and-provenance core of an auditable workspace, is what h5i calls an env.

An environment is more than a branch

You already know the worktree half of the story: git worktree add gives a branch its own checkout so an agent can't trample your working tree. What it doesn't give you is confinement (the agent still runs with your filesystem and your network), provenance (why each change was made), or a gate (the branch merges like any other). An env fuses three things under one name to close all three gaps:

That triple of code, reasoning, and policy is the whole point. It is the difference between "the agent made a branch" and "the agent worked inside a confined, self-documenting box whose output I can review as one thing." Everything below is the lifecycle of that box.

A worked lifecycle: create → run → propose → apply

The env lifecycle is create → run → propose → apply | abort → gc. Here is the whole arc on one screen; each verb is unpacked below.

~/my-project
$ h5i env create fix-auth           # freeze base, fork code + reasoning branch, pin policy
  created env · isolation: supervised · profile: agent-claude · worktree under .git/.h5i/…

$ h5i env shell fix-auth            # hand the box to an agent (or work in it yourself)
box$ cargo build && cargo test      # every command here is confined + captured
box$ exit

$ h5i env diff fix-auth             # the change, vs the frozen starting point
$ h5i env propose fix-auth          # mediated commit + review brief (apply refuses without it)
$ h5i env apply fix-auth            # merge onto your branch — only when you choose to

create freezes the base commit, forks the code and reasoning branches, and pins the policy. With no --profile it auto-picks the creating runtime's agent-in-box profile where the host can enforce it, else a fail-closed build/test profile; --from <rev> bases it somewhere other than HEAD, and --isolation requests a specific tier (more on that below).

shell drops you, or the agent, into the box with a real, inherited terminal, so every command the session spawns is confined by the box, not only the ones someone remembered to wrap. For a single non-interactive command, h5i env run fix-auth -- cargo build does the same confined execution and captures the output. The distinction matters for autonomy: shell is how you let an agent live in the box and run an open-ended sequence of commands under one policy.

diff (add --stat for a summary) shows the work against the frozen base: the proposed change, before it touches anything real. propose commits the worktree through a path-checked mediation step and writes a review brief; it never writes the parent branch. apply is the only verb that touches your branch, and it refuses to run on an env that hasn't been proposed. It merges by default (fast-forward when it can) or squashes with --patch. If the work is a dead end, abort parks the env (manifest and workspace preserved for forensics) and gc later reclaims the worktree; rm removes an env entirely. The asymmetry is deliberate: producing a change is cheap and reversible; landing one is an explicit, human-gated act.

Why propose is a mediated commit, not git commit

It would be simpler to let the agent git commit in the worktree and call that the proposal. h5i doesn't, because a commit is an attack surface: a worktree is just a directory, and a directory can contain a nested .git, a symlink that points out of the tree, or a .. path that resolves to your real repo. propose runs the commit through a canonicalized path allowlist rooted at the worktree ($WORK). It rejects a nested .git, refuses symlinked-directory escapes and .. traversal, and will not accept an agent-introduced or re-pointed gitlink unless it round-trips a registered base submodule unchanged, with the same path and the same object id as the env-branch tip. Anything that resolves outside the box fails closed. The result is that the bytes you review in diff are the bytes that get committed, with no path trickery in between.

Isolation is a tier, and the post is honest about it

"Confined" means different things on different machines, so the policy names an isolation tier and h5i env create with no flag picks the strongest one the host can actually enforce. Crucially, an explicit tier fails closed: ask for a level the host can't provide and create refuses rather than running with less. A bits-present check isn't enough, either: create runs a functional self-test before it trusts a kernel tier (on some hosts, e.g. AppArmor-restricted user namespaces on CI, the bits exist but confined exec doesn't work).

TierWhat confines the codeNetwork
workspacegit worktree only, no process confinement, for trusted codehost (unrestricted)
processLandlock filesystem allowlist + a seccomp syscall deny-list + user/mount/pid/net namespaces + rlimits, all rootlessoff, or full host
supervisedthe process tier + a live seccomp socket gateoff, or an L3/L4 egress allowlist
containerrootless Podman, --cap-drop=ALL, no-new-privileges, read-only rootfs, no docker socketan L7 egress allowlist (CONNECT proxy)

h5i env probe prints exactly what your host supports. The two egress mechanisms are different, and worth choosing between: the container tier runs an HTTP/HTTPS CONNECT proxy and points the box at it: honest L7 scoping that blocks proxy-respecting tooling but not a program that opens a raw socket to a permitted IP; the supervised tier installs a default-drop nftables ruleset in the box's own network namespace over a rootless slirp4netns uplink, which stops the packet at L3/L4 regardless of how the program tries to connect. None of this needs root or a VM, and h5i is clear that it is strong containment for ordinary and opportunistic threats, not a hardware boundary against a determined kernel exploit. The full mechanism (Landlock allowlists, the seccomp deny-list, the egress internals, and the microVM tier h5i doesn't pretend to ship yet) is the subject of its own post: Sandboxing AI Agents, Part 4: h5i's design.

Every run is evidence; compare is the arena

Confinement decides what the code can do; the captured record tells you what it did. Every run in an env is a tagged, secret-redacted evidence capture stored in git refs and stamped with the env id and the policy digest that was in force, so a run can never be read apart from the rules that governed it. Blocked accesses are recorded too, not silently swallowed.

~/my-project
$ h5i env status fix-auth             # lifecycle, enforced policy, evidence, base drift
$ h5i recall objects --env fix-auth   # this env's captures
$ h5i env inspect fix-auth --capture <id>  # one run's full structured record
$ h5i env compare a b c               # rank parallel attempts side by side

Because the evidence is content-addressed and lives under refs/h5i/env, the whole env travels with h5i share push / pull. A pulled env has no local worktree, so diff falls back to base..branch-tip (the proposed state) and apply works straight from the branch, which is what makes the cross-agent loop real: one agent proposes a change on its clone, and a teammate or another agent reviews and applies it on theirs, with the full evidence in hand.

compare is where this pays off for autonomy at scale. Spin up several envs on the same frozen base, with different agents and different approaches, let each work sealed, and rank them side by side: the changes each made and the results of each one's last run, in one table. This "arena" is the substrate the h5i team ensemble builds on, where the same task is run across personas and a neutral verifier replays each candidate before any verdict is applied. The shared, hashed base is what makes the comparison fair.

Failure modes worth knowing

Conclusion: the unit of safe autonomy

The reason an agent is worth confining is the same reason its output is worth reviewing: you didn't watch it work. h5i's answer is to make those one object instead of two. An env is an isolated worktree, a record of the agent's reasoning, and a pinned policy, bound together so that the box that confined the work is the same box that produced the evidence and the same box you propose and apply from. Nothing reaches your base branch by accident. apply is a deliberate human act on a change you have already diffed, with the policy that governed it hashed into the record.

That is a narrower promise than "a sandbox," and a more useful one. It doesn't ask you to trust the agent, and it doesn't ask you to babysit it either. It asks for one decision, at the end, with the evidence in front of you, which is exactly the decision you wanted to keep.

FAQ

How is an h5i env different from just running an agent in a git worktree?

A worktree isolates the checkout but not the process, since the agent still has your filesystem and network, and the branch merges like any other. An env adds a fail-closed policy, captured evidence, and an explicit apply gate, so confinement, provenance, and review are one reviewable unit rather than three loose pieces.

Is the agent actually confined, or just isolated in a branch?

It depends on the tier you can run. workspace is a worktree with no process confinement; process and supervised add kernel confinement (Landlock, a seccomp deny-list, namespaces, rlimits), with supervised adding an L3/L4 egress allowlist; container uses rootless Podman with an L7 egress proxy. h5i env probe reports what your host can enforce, and create refuses a tier the host can't satisfy instead of downgrading silently.

Why can't an env's commit step write outside its worktree?

propose is a mediated commit. It enforces a canonicalized path allowlist rooted at the worktree, rejecting a nested .git, symlinked-directory escapes, and .. traversal, and refusing an agent-introduced gitlink unless it round-trips a registered base submodule unchanged. Paths that resolve outside the box fail closed.

Can another person or agent review and apply an env on a different clone?

Yes. Env state lives under refs/h5i/env and travels with h5i share push / pull. A pulled env has no local worktree, so diff falls back to base..branch-tip and apply works from the branch, so one agent proposes on its clone, another reviews and applies on theirs, with the full evidence.

Give your agents a box, not your shell

Try h5i on your next AI-assisted branch: create a sandboxed workspace, capture the run, and post a review-ready PR brief.

Star on GitHub Back to docs