A single command to start a coding agent (Claude Code or any other) inside an
isolated, egress-filtered cage on macOS — composed from
agent-safehouse (filesystem + process isolation)
and mitmproxy (TLS-terminating egress allowlist),
configured by one .agent-creance.yaml file.
Status: early development (pre-v0.1). The full design lives in
docs/design.md. What's implemented today is the project skeleton plus theversionanddoctor(prerequisite/version-compatibility) commands.
- Go 1.26+
- macOS (v0.1 is macOS-only)
- For actually running a cage (not yet wired up):
agent-safehouseandmitmproxyonPATH.
agent-creance setup scaffolds a global config at ~/.config/agent-creance.yaml
with the "always-allowed" baseline a caged Claude agent needs — the Claude Code
API/OAuth hosts plus Anthropic's public documentation hosts, so routine "how does
Claude Code X work" lookups don't get soft-denied. setup never modifies an
existing global config; it only writes the file when none is present.
If your global config predates the documentation hosts (added in AC-0048), add
them under network.egress.allow to read Anthropic's docs from inside the cage.
They are credential-free and scoped to GET (code.claude.com to /docs; the
two legacy hosts redirect to the already-allowed platform.claude.com):
network:
egress:
allow:
- host: code.claude.com
mode: intercept
paths: ["/docs/"]
methods: [GET]
- host: docs.anthropic.com
mode: intercept
methods: [GET]
- host: docs.claude.com
mode: intercept
methods: [GET]agent-creance init scaffolds a project .agent-creance.yaml. On an interactive
terminal it also offers to do the tedious allowlist/port wiring for you — each as
its own yes/no prompt, all auto-skipped when there is no TTY (so CI behaves as
before):
- Import allowed web domains from the project's Claude Code settings
(
WebFetch(domain:…)in.claude/settings.json/settings.local.json, plussandbox.network.allowedDomains) as GET-onlyinterceptrules. - Import MCP servers from
.claude/settings*.json,.mcp.json, and~/.claude.json: remote servers becomepassthroughallow rules; an MCP server bound tolocalhostbecomes ahost_servicesport. - Detect dev ports from
docker-compose.yml,package.jsonscripts,Procfile, and.env.
It then shows the resulting config and asks you to confirm before writing.
agent-creance setup does the same for the global baseline, seeding it from your
global ~/.claude config when it first creates ~/.config/agent-creance.yaml.
For everything that can't be inferred statically, init offers to print a prompt
you hand to your agent; the agent writes a config fragment (documentation hosts,
remaining ports) which you review and merge with:
agent-creance import agent-creance.suggested.yaml # add --yes for non-interactive useimport strict-validates the fragment, shows the merged result, and writes only
on confirmation.
make help # list all tasks
make test # fast unit + CLI tests, race detector on
make lint # go vet + golangci-lint (run `make tools` once to install the linter)
make hooks # install the git pre-commit hook (gofmt + vet + tests)
make build # build ./bin/agent-creance with version metadata
make run ARGS="doctor"cmd/agent-creance/— tinymain, just calls intointernal/cli.internal/cli/— cobra command tree and theAppcomposition root.internal/buildinfo/— version metadata + tested-against tool versions.internal/prereq/— prerequisite detection and version-skew classification.internal/sysdep/— interfaces over the OS (the testability seam) and the real implementations;sysdeptest/holds the test fakes.
Logic never touches the OS directly — it goes through internal/sysdep
interfaces so tests inject fakes. Pure logic is covered by table-driven tests,
generated artifacts by golden files (-update to regenerate), and end-to-end
CLI behavior by testscript
.txtar scenarios. Anything that shells out to the real agent-safehouse /
mitmproxy is gated behind the integration build tag (make test-integration).
Apache-2.0.