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.

Our default recommendation

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.

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

manifest
agentstack.toml
apply --write
renders config
.mcp.json
written to disk
Claude Code
reads at launch

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

manifest
one source of truth
apply --write
compiles each format
native config
claude-code · codex
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

${ }
manifest
holds ${GH_PAT} only
🔑
OS keychain
secret set — real value
per call
gateway injects it
server
gets the token

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

profile: backend
github, kibana + sql-review
use backend
--write
loaded
just backend's set
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

1
init
configs → manifest
2
bootstrap
what's missing?
3
apply
preview → write
4
doctor
verify + fix
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
Two habits worth keeping

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

agent
calls a tool
gateway
[policy.tools]
decision
✓ get_issue
✗ 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

machine policy
your standing rules
repo policy
can only add, not loosen
=
effective
never more permissive
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

[ ]
[policy]
require / forbid / sources
doctor --ci · add
validation gate
build
✓ passes / ✗ fails
a running agent
NOT consulted

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

clone
inert — nothing spawns
👁
trust .
review, then pin bytes
firewalled
servers serve live
audited
every call logged

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.

Keep what the task actually used

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

+
lib add
content-scanned first
~/.agentstack/lib
machine-wide
by name
project A · B · C
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

container
no host route, no net
egress sidecar
[policy.egress]
per host
✓ api.github.com
✗ 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

{ }
TS program
exact tool grant
sandbox
no net, no creds
gateway
re-checks each call
result
attributed in report

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

install --locked
fail on source drift
doctor --ci
policy · unsafe content
build
✓ green / ✗ blocked
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.