Leash: Cedar Policies Around Containerized AI Coding Agents
Leash by StrongDM - take your AI agents for a walk
At a glance
- What is it?
- StrongDM's Leash wraps claude, codex and other coding agents in a container, records filesystem and network activity, and enforces Cedar policies against it. The design is legible and the install path is short, but the enforcement model assumes you accept a container boundary and a manager container sitting next to your agent.
- Who is it for?
- Adopt Leash if you already run coding agents non-interactively and want policy decisions expressed in Cedar rather than in shell wrappers, and if a Docker or Podman dependency on the developer machine is acceptable. Do not adopt it if your agents must run with host-level filesystem semantics, if you cannot run a second container alongside the agent, or if your threat model requires kernel-level isolation rather than a container boundary plus a monitoring sidecar.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 162 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The gap Leash fills between an agent and your home directory
A coding agent running directly on a workstation has the same reach as the person who launched it. It reads the SSH keys, the cloud credentials, the browser profile, and it can open outbound connections to anywhere the host can reach. Most teams respond by writing a wrapper script that sets a working directory and hopes the agent stays inside it. Leash takes a different position: the agent runs in a container, the current directory is bind-mounted so the file tree looks familiar, and a second container watches system calls and evaluates Cedar policies against them. The intended user is someone who already runs claude, codex, gemini, qwen or opencode on a laptop or CI box and wants a declarative answer to the question of what that agent is allowed to touch. Cedar is the interesting part of the bet. Policies are written in a language with a published specification rather than in Go callbacks or regex lists, which means the rules can be reviewed, versioned and reasoned about separately from the wrapper.
Two containers, one bind mount, and a syscall stream
The architecture described in the README splits responsibilities. The agent container runs your command with the current directory bind-mounted, so tools see the same file tree they would on the host. The Leash container monitors system calls, applies Cedar policies, and serves the Control UI at http://localhost:18080. The README calls the telemetry model full monitoring: every filesystem access and network connection initiated by the agent is captured so that policies and audit trails operate on complete data. That phrasing matters. Partial telemetry produces policies that appear to pass because the events never reached the evaluator, and the project is explicit that it is aiming at the complete case instead. Alongside the syscall stream there is an MCP observer that inspects, records and enforces MCP tool calls, and the README states that requests through supported MCP transports are correlated with filesystem and network telemetry. That correlation is the design decision worth noticing: a tool call and the file it touched become one story rather than two log lines, which is what makes a policy like "this MCP tool may read but not write" expressible at all.
Installing and launching an agent under policy
The recommended install is npm: npm install -g @strongdm/leash. On macOS there is also a Homebrew cask, brew tap strongdm/tap followed by brew install --cask leash-app, which the README says installs a helper app enabling experimental native mode and also installs the leash formula. Downloading a release binary directly requires xattr -d com.apple.quarantine leash after extraction. Running an agent is a single command: leash --open claude, or leash --open codex, where --open launches the Control UI in a browser. The default coder image ships claude, codex, gemini, qwen and opencode, and on first use Leash prompts to mount the host's agent config directory, for example ~/.claude, into the container. The answer can be remembered globally, per project, or for one run, and persistent choices are stored at ~/.config/leash/config.toml. Configuration can come from TOML, CLI flags or environment variables. A project entry can set target_image, and a nested volumes table maps host paths to container paths, as in the README's example of "~/devtools" = "/workspace/devtools:rw". The table of overrides covers target_image, TARGET_CONTAINER, --leash-image or LEASH_IMAGE, --policy or LEASH_POLICY_FILE, --listen or LEASH_LISTEN, repeatable -v src:dst[:ro] mounts, and -e KEY=value. Environment forwarding is automatic for the common keys: ANTHROPIC_API_KEY for claude, OPENAI_API_KEY for codex, GEMINI_API_KEY for gemini, DASHSCOPE_API_KEY for qwen. Requirements are Docker, Podman or OrbStack on macOS or Linux, with WSL listed as supported.
Where the container boundary stops being enough
The honest limitation is the one the README implies rather than states. Leash is a container plus a monitoring sidecar, not a virtual machine and not a kernel sandbox. A container boundary is a namespacing and capability boundary, and its strength depends on the runtime underneath it. If your agent needs host-level filesystem semantics, or if it needs to talk to a device or a socket that cannot be forwarded into the container, the bind-mount model becomes friction rather than protection. The second limitation is operational: running an agent under Leash means running two containers, and the manager container has to be able to observe the agent's syscalls. That is a heavier footprint than a shell alias, and it is the kind of thing that breaks quietly on a machine where the container runtime is not the one you tested with. Third, the default posture forwards credentials. The mount prompt exists precisely because forwarding ~/.claude or ~/.codex is a meaningful decision, and the README notes that the answer can be persisted. A persisted yes means every future run in that project forwards the same credentials, which is convenient and also the exact thing a policy layer is supposed to make you think about. If your goal is to stop an agent from reading a specific file on the host, the bind mount is the wrong lever; the right lever is not mounting that path at all.
Cedar versus hand-rolled wrappers and agent-native permission modes
The obvious alternative is the permission system built into the agent itself. Claude Code and Codex both ship their own allow and deny configuration, and those systems are tuned to the tool calls the agent makes. The difference in approach is the layer being governed. An agent-native permission mode sees the agent's own view of its actions and trusts the agent to report them. Leash sits below that, at the syscall and network level, and correlates those events with MCP tool calls. A second alternative is a plain container workflow: docker run with a bind mount and no policy engine. That gets you the isolation and none of the enforcement, and it is a reasonable choice if your rules are simple enough to express as "mount this, not that". The trade Leash asks for is a policy language and a telemetry pipeline in exchange for rules that can reference actual observed behavior. That trade only pays off when the rules are non-trivial. A team whose entire policy is "do not mount ~/.ssh" should write a docker run line and stop there.
Images, upgrades and the Apache-2.0 boundary
The default image is public.ecr.aws/s5i7k8t3/strongdm/coder, and the README gives two extension paths: add packages to Dockerfile.coder and point Leash at the new image, or reuse an existing project image after adding ca-certificates and configuring Leash to launch it. That ca-certificates requirement is not incidental. An image without a CA bundle will fail TLS handshakes, and the failure will look like a network problem rather than a missing package. Upgrades come through whichever channel you installed from: npm for the global package, brew for the cask, or a manual download from the releases page with the quarantine attribute to clear again. Release cadence visible in the repository is roughly monthly, with v1.1.5 in January 2026, v1.1.6 in February and v1.1.7 in March. The project is Apache-2.0, which permits commercial use and modification and requires preservation of notices; the README ships a CONTRIBUTORS.md and a DEVELOPMENT.md, so the contribution path is documented. None of that is legal advice, and the licence text is the authority. The maintenance cost worth budgeting for is policy authoring, not the binary. Cedar snippets are linked from docs/design/CEDAR.md, and someone on the team has to own the policy file that --policy points at, because a stale policy is indistinguishable from a permissive one until an audit asks why an event was allowed.
Verifying the setup before trusting the audit trail
The material supports a small set of concrete checks. Confirm the Control UI is reachable at http://localhost:18080, or at whatever address --listen or LEASH_LISTEN resolves to, since a blank value binds to 127.0.0.1:18080 by default. Confirm that the policy file passed through --policy or LEASH_POLICY_FILE is the one you expect, because the flag and the environment variable are two independent ways to set the same thing and the precedence is not spelled out in the README. Confirm that telemetry is actually arriving rather than merely configured: the project's own framing is that full monitoring is what makes policies meaningful, so an empty event stream is a signal that the manager container is not seeing the agent. The macOS path deserves separate attention, since the cask installs a helper app for experimental native mode and the README points to docs/MACOS.md for the additional capabilities, which suggests the native path and the container path are not identical in behavior. Anyone running Leash on a shared build machine should also decide deliberately whether the mount prompt answer is global, per project or one-off, because that single choice determines whether agent credentials are forwarded on every subsequent invocation.
Editorial conclusion
Adopt Leash if you already run coding agents non-interactively and want policy decisions expressed in Cedar rather than in shell wrappers, and if a Docker or Podman dependency on the developer machine is acceptable. Do not adopt it if your agents must run with host-level filesystem semantics, if you cannot run a second container alongside the agent, or if your threat model requires kernel-level isolation rather than a container boundary plus a monitoring sidecar. Before rolling it out, verify three things against your own setup: that your target image contains ca-certificates and whatever toolchain the agent needs, that the Cedar policy file you pass via --policy actually matches the telemetry fields your policy references, and that the mount prompt behavior for ~/.claude or ~/.codex is what you want, since the persistent answer lands in ~/.config/leash/config.toml and is easy to forget.
Community notes