By example · simplest → most advanced
AgentStack, by example.
Twenty-five copy-paste examples, building from a one-line manifest to
sandboxed, governed execution. Everything you author lives in
one file — .agentstack/agentstack.toml, the
intent, safe to commit. Relative paths anchor at that file's directory;
only cwd anchors at the project root.
For interactive work in an MCP-capable harness: commit the manifest + lock, connect the gateway once, trust each reviewed repo, and open the smallest useful profile as an MCP lease. Choose native rendering only when the harness must read native files; add lockdown when the agent process needs isolation. See why and when to choose differently.
Contents
Choose before copying
Compose primitives; do not ask one boundary to do every job
A profile chooses capabilities. Delivery puts them into a harness. Trust grants local consent. Policy limits authority. Lockdown confines the process. Audit records evidence. They are strongest when composed—and dangerous when confused.
Connected interactive work
Recommended: trust + machine policy + MCP profile lease. You get the smallest live surface and no per-project native artifacts.
Native skills or instructions
Use static use --write, or session start/end when files should exist only temporarily. Harnesses read these files themselves.
High-risk repository code
Use trust + policy + run --sandbox --lockdown. A lease narrows MCP capabilities; it does not isolate arbitrary processes or direct host activity.
CI and reproducibility
Use install --locked + doctor --ci. CI verifies pins and policy; it does not need interactive machine trust.
Full decision table: AgentStack primitives and recommendations.
Basics
Get a server into your tools
1 The smallest manifest
One MCP server, one CLI — the whole thing at its simplest.
how it flows · manifest → your CLI
note → the CLI reads that file once, at launch — change the manifest and re-run apply, then restart the CLI to pick it up.
# .agentstack/agentstack.toml
version = 1
[servers.time]
type = "stdio"
command = "uvx"
args = ["mcp-server-time"]
[targets]
default = ["claude-code"]
agentstack apply --write # writes Claude Code's native .mcp.json for you
Result
Claude Code now has the current official Time reference server, generated from your manifest — you never hand-edited its config.
2 Fan out to several CLIs
The same server, spelled correctly for every tool. Add names to targets.
one manifest · many CLIs
cursor · gemini…
[targets]
default = ["claude-code", "codex", "cursor", "gemini-cli"]
Result
Four CLIs, four native config formats, one source of truth. No drift, no copy-paste. (13 CLIs supported — agentstack adapters list.)
3 Keep secrets out of the file
Never paste a token in. Reference it as ${NAME}; it resolves per machine through the configured secret chain (environment, varlock, OS keychain, then .env).
a secret, resolved at runtime
note → the committed file never contains a real secret; if a ref can't resolve, the write/run is blocked, not left with a placeholder.
[servers.github]
type = "http"
url = "https://api.githubcopilot.com/mcp/"
headers = { Authorization = "Bearer ${GH_PAT}" } # a reference, never the value
agentstack secret set GH_PAT # stored in the OS keychain, not a file
agentstack bootstrap # flags a referenced secret that's missing
Result
The committed manifest is safe to share. A missing secret blocks the write rather than leaking a placeholder into live config. This uses GitHub's current official MCP endpoint, not the archived reference npm server.
4 An HTTP server with auth
Remote MCP servers use type = "http", a url, and headers.
[servers.kibana]
type = "http"
url = "https://kibana-mcp.example.com/mcp"
headers = { Authorization = "Bearer ${KIBANA_TOKEN}" }
agentstack doctor --live # real MCP handshake: name + tool count, or the exact error
5 Per-CLI native passthrough
When one CLI needs a native key another doesn't, pass it through verbatim under extra.<cli>.
[servers.filesystem]
type = "stdio"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "./"]
[servers.filesystem.extra.codex]
startup_timeout_sec = 20 # Codex sees this; the others don't
Structure
Organize capabilities by task
6 Add skills
Skills are reusable instruction/tool bundles. Point at a local directory:
[skills.sql-review]
path = "./skills/sql-review" # lives at .agentstack/skills/sql-review
Skills activate through profiles (next), not apply. Materialize one directly with agentstack use <profile> --write.
7 Task-specific profiles
A profile is a named bundle of servers + skills you switch on for a kind of work.
load only what the task needs
others stay off
why → fewer tools on the wire = fewer tokens billed every turn.
[profiles.backend]
servers = ["github", "kibana"]
skills = ["sql-review"]
[profiles.docs]
servers = ["github"]
skills = ["writing-style"]
agentstack use backend --write # activate the backend profile
Result
Load only what the task needs — fewer tools on the wire means fewer tokens billed every turn (see §21).
8 Instruction files (house rules)
Compile shared instructions into each CLI's native file (CLAUDE.md, AGENTS.md…) from one source.
[instructions.house_rules]
path = "./house-rules.md"
# targets = ["*"] # optional: which CLIs get it (default: all)
9 The everyday loop
The four commands you'll actually run.
the everyday loop
agentstack init # reverse-engineer a manifest from configs you already have
agentstack bootstrap # installed CLIs? missing skills/secrets? pending diff?
agentstack diff # read-only: exactly what would change
agentstack apply # preview only
agentstack apply --write # after review: render the native files
agentstack doctor # verify wiring; every warning names its exact fix
agentstack with no arguments tells you the single next step for the directory you're in. agentstack doctor --ci fails a build on errors, drift, policy, or unsafe content.
Security
Constrain what agents may do
10 The MCP tool firewall
Restrict which tools a server may expose. Plain globs allow; a leading ! denies. Any allow pattern makes the list an allowlist.
the firewall, on every call
✗ list_secrets
enforced → a denied tool is refused before it reaches the server, and hidden from discovery entirely.
[policy.tools]
github = ["get_*", "list_*", "!list_secrets"] # read-only, minus one tool
Result
A denied tool is invisible — filtered from discovery — and refused with the rule named if called anyway. agentstack explain github shows the effective policy.
11 The machine layer — rules no repo can loosen
Your standing rules live in ~/.agentstack/agentstack.toml and are checked before any project's. A call must pass both layers.
policy is an intersection
than the machine layer
# ~/.agentstack/agentstack.toml — applies to every project on this machine
[policy.tools]
"*" = ["!delete_*"] # no server, under any name, may delete_*
github = ["get_*", "list_*"] # servers NAMED github are read-only
Result
The effective policy is always the intersection of machine and repo policy — never more permissive than your machine layer. The "*" key is rename-proof.
12 Governance — require, forbid, allowed sources
Gate where capabilities may come from and what must / mustn't be present — enforced by doctor --ci.
a check, not a runtime firewall
read this carefully → governance fails add / CI. It places no runtime block on anything — that's [policy.tools].
[policy]
allowed_sources = ["git:github.com/acme/*"] # only these origins may be installed
forbid = ["network-broker"] # never allow this capability
13 Zero files: the trust gate
Skip rendered files entirely. Register the gateway once; every trusted repo then serves its own servers live — an unreviewed repo is inert.
clone → inert → trusted → audited
re-gates → edit the manifest or lock and it drops back to inert until you review again.
agentstack connect --all --write # register the gateway with your harnesses (once)
git clone <some-repo> && cd <some-repo>
agentstack mcp --auto-project # an agent asks what's here → nothing (untrusted)
agentstack trust . # SEE what it declares, then authorize
$ agentstack trust .
▶ demo: runs `python3 ./server.py` # exactly what it would run
✓ trusted at sha256:945b4b… # editing the manifest/lock re-gates it
# now its servers serve live, through the firewall:
agent → demo.echo ✓ ok
agent → demo.secret_read ✗ denied [policy.tools]
Any pinned byte changing (manifest, overlay, or lock) re-gates the bundle. Every brokered call lands in ~/.agentstack/audit/calls.jsonl.
Fence one MCP connection to a profile
After trust, the agent can choose a profile without rendering native configs. These are MCP tool calls made inside the agent session—not terminal commands:
# agent → agentstack control plane
agentstack_lease_open({ "profile": "backend" })
agentstack_list_loadable({})
agentstack_load({
"name": "sql-review",
"reason": "review the migration in this task"
})
agentstack_lease_status({})
agentstack_lease_close({})
Result
Only backend servers and skills are reachable on that connection. Loads are recorded in memory, repeat loads do not duplicate the trail, and close/process exit needs no restore because no .mcp.json, skill folder, or sessions.json entry was written.
Call agentstack_lease_freeze({ "name": "backend-observed" }) to propose a normal manifest profile from the observed skill set. Review that edit, then run agentstack lock; freeze never applies or renders the profile. Try the runnable end-to-end fixture.
Scale
Reuse capabilities everywhere
14 The central library
Install a capability once into your machine-wide library (~/.agentstack/lib), then reference it by name from any project.
install once · reference by name
no files copied
agentstack search codex # find shipped skills + registry servers
agentstack lib add sql-review --path ./skills/sql-review --write
# straight from a git repo, including monorepo subdirs:
agentstack lib add improve --git https://github.com/acme/skills \
--subpath skills/improve --write
agentstack lib list # what's installed, with provenance
Then in any profile: skills = ["sql-review"] resolves from the library. Every add is content-scanned (hidden-Unicode / prompt-injection) before it lands.
15 Sync the library across machines
Version the library as a git repo. A fail-closed gate scans every server field and the outgoing commits for secrets before pushing.
agentstack lib sync --init --remote git@github.com:you/agent-lib.git
agentstack lib sync # commit local changes, pull, push
Result
A literal secret in a definition — or a definition it can't parse — blocks the sync rather than slipping through.
16 Versioned vendor packs
Install a pinned bundle of MCP + skills + house-rules in one shot, policy-gated and content-scanned first.
agentstack add from git:github.com/acme/pack@v1.2.0
Upgrading is just the next tag — the lockfile records exactly what you got.
17 Adopt a native plugin
Lift a plugin you installed in one CLI into the manifest so it travels everywhere — skills copied to the library with provenance, servers carried as ${REF}s.
agentstack plugins adopt cloudflare --harness codex --write
agentstack plugins sync --write # generate native packages + marketplaces
agentstack plugins install cloudflare --target claude-code --write
The harness you adopted from stays satisfied by its native install — status/doctor report it up to date and flag drift, never double-installing.
Runtime
Confine, observe, and measure a run
18 Sandboxed runs with egress policy
Run the agent in a container with no host route and no internet — its only way out is the egress-proxy sidecar, which enforces your machine [policy.egress].
the only way out is the proxy
✗ evil.example
topological → ignoring the proxy reaches nothing — it's the network shape, not an honor system. Needs Docker + --features sandbox.
# ~/.agentstack/agentstack.toml — same glob grammar as the tool firewall, over hosts
[policy.egress]
"*" = ["!*"] # deny everything by default
github = ["api.github.com:443"] # a server named github may reach only this
agentstack run claude-code --sandbox --lockdown --profile backend
agentstack report <run-id> # the run's flight recorder: every egress decision
Result
Ignoring the proxy reaches nothing — confinement is topological. It filters by host, requires a TLS connection's SNI to match the dialed host (no domain fronting), and refuses names resolving to loopback/private/link-local/metadata addresses (no SSRF). Needs Docker + --features sandbox.
19 The other policy dimensions
The same two-layer intersection and "*" grammar apply beyond tools and egress.
[policy.secrets]
github = ["GH_*"] # server named github may resolve only GH_* refs
[policy.filesystem] # bundle-global path globs
read = ["./src/**", "./docs/**"]
write = ["./out/**", "!**/.env"] # never write a .env, even under an allowed root
Enforcement depends on execution mode: host/gateway filesystem guards are cooperative harness hooks; sandbox/lockdown use coarse workspace mounts. See the enforcement matrix before making a security claim.
20 See what happened — audit, analyze, report
Every brokered call is recorded (digests and outcomes, never argument values or secrets). Turn that into insight.
agentstack audit --calls --since 7 # recent brokered calls: tool · outcome · latency
agentstack report <run-id> # per-run tree, incl. sandbox egress decisions
agentstack analyze # what you actually call; flags installed-but-unused
agentstack analyze --transcripts # + cross-harness reach from local session logs
21 See what your tools cost
Every tool/server/skill you load is re-billed as input tokens every turn. Measure it with the passive wire proxy — observe only, cache stays warm.
export ANTHROPIC_BASE_URL=http://127.0.0.1:8787
agentstack proxy start # in one shell, then use your agent normally
agentstack proxy report # ranks tokens/turn vs. how often each was called
A server that's expensive but never used is flagged drop / lazy — data-driven pruning that closes the loop with the profiles you manage.
22 Experimental: governed TypeScript
tools_execute lets one bounded TypeScript program call a small, exact set of MCP tools through the gateway — as a non-root process in a read-only, resource-limited Docker container with no workspace, credentials, package install, or direct network. Off by default; only the machine owner enables it.
governed code, sandboxed
experimental → Docker-only, off by default, and never a host-execution fallback.
# ~/.agentstack/agentstack.toml
[experimental]
tools_execute = true
# optional machine-owned ceilings; a request may only narrow them
[experimental.tools_execute_limits]
timeout_ms = 30000
max_calls = 40
max_output_bytes = 131072
Every allowed call is re-checked by the gateway and attributed in agentstack report. Docker-only; never a host-execution fallback.
Operate
CI, extension, and the personal layer
23 The CI trust gate
Two commands make a pipeline fail on drift or unsafe content — or use the pinned Action.
fail the build on drift
agentstack install --locked # fail if sources drifted from the pinned lock
agentstack doctor --ci # fail on errors, drift, policy, unsafe content
steps:
- uses: actions/checkout@v4
- uses: Tarekkharsa/agentstack@v0.10.1 # pin a release tag, not @main
24 Extend it — add a CLI in one file
Support a new CLI with a single YAML descriptor — no rebuild.
cp crates/adapters/descriptors/codex.yaml my-adapter.yaml
# edit it, then:
agentstack adapters validate my-adapter.yaml
cp my-adapter.yaml ~/.agentstack/adapters/ # picked up on next run
agentstack adapters list # marks which adapters are yours
A broken drop-in is skipped with a warning, never fatal.
25 The personal layer & app-owned servers
Machine-wide instructions that merge beneath every project without landing in any repo; and letting an app's own config be the source of truth.
agentstack init --global # a home for your machine-wide rules
[servers.codex-native]
owner = "codex" # codex owns this entry; apply follows it
When the app rewrites its own entry (a self-update), apply refreshes the manifest and fans the fresh values out to every other CLI instead of reverting the app.
Where to go next
Beyond the examples.
Get started · 10 min
The guided walkthrough: take an unfamiliar repo from untrusted to a confined, auditable run — with the exact commands and expected output.
What's enforced where
The compact, code-grounded matrix: for host, gateway, sandbox, and lockdown, exactly which of tools, egress, secrets, filesystem, and audit are enforced.
Central library
Install a skill or server once into your machine-wide library, then reference it by name from any project — every add content-scanned first.
Primitives & recommendations
Choose static, session, lease, trust, policy, or lockdown from the boundary you need—not from one universal mode.
Feature reference
The complete tested inventory: machine-policy presets, vendor packs, the MCP firewall, plugin recipes, live runs, and every command and flag.