Skip to content

Quick Start

Terminal window
wardcell run -- curl -sS https://example.com
wardcell: run 0192f0a1 · backend seatbelt
wardcell: logs → ~/Library/Logs/wardcell/runs/0192f0a1….jsonl
wardcell: live tail → wardcell logs show 0192f0a1 -f
curl: (56) Recv failure
wardcell: run 0192f0a1 exited 56 in 0s
wardcell: 1 network request(s) blocked, 1 destination(s):
example.com:443 ×1 allow with: net allow_http "example.com"
wardcell: full log → wardcell logs show 0192f0a1

Nothing is granted by default, so the connection is refused. The summary names what was blocked and the rule that would allow it; every request and decision is in the run’s log.

Terminal window
wardcell policy draft -- curl -sS https://example.com

draft runs the same command in learn mode — every rule still evaluates, but a refusal is recorded and passed through instead of blocking — then prints a fragment built from what it observed:

fragment "curl-draft" {
schema_version = 1
net {
allow_http "example.com" {
allow_requests [
"GET /",
]
}
}
}

Save that as a fragment in your policy root, tightening it as you go:

/etc/wardcell/policies/tools/curl-example.sbx
fragment "curl-example" {
selects_on = { commands = ["curl"] }
net {
allow_http "example.com" {
allow_requests ["GET /**"] # narrowed by hand from the observed "GET /"
}
}
}

selects_on means this fragment applies whenever the command is curl.

Terminal window
wardcell run -- curl -sS https://example.com # works
wardcell run -- curl -sS https://evil.example # still refused
wardcell runrun a command under the policy
wardcell policy draftrun in learn mode, get a fragment back
wardcell policy explainshow every effective rule and where it came from