Run powerful agent harnesses inside explicit, temporary, auditable permission boundaries — on your own machine.
Whizzard wraps an agent harness — a tool that drives an LLM through real work (Hermes today; Claude Code, Cursor, and others to follow) — in a hardened, time-bounded Docker sandbox. Inside it, the agent reaches only the files you mounted and the network you allowed. It never holds your model or service credentials; those stay on your machine. And you stay in the loop: capabilities only narrow after launch, any escalation needs your approval, and every session leaves an audit trail you can read back.
Status: v0.1.0 OSS launch in preparation. Jump to Quickstart.
Tip
Launch a session on the safe profile — network off, nothing mounted:
whiz run --harness hermes --profile safeInside that sandbox the agent has no network (no DNS, no outbound anything) and can see none of your files — not ~/.ssh, not your other projects, not your password manager — only the paths you explicitly mounted (here, none). Its credentials aren't in there either — your real keys stay on your machine and never enter the sandbox. When the session ends — or its time cap fires — the container is gone, and ~/.whizzard/logs/ holds a log of exactly what ran, with what access, and what the agent asked for mid-session.
That's the whole idea: whatever the agent does, it can only do it within a capability surface you declared and can read back later.
flowchart LR
you([you]) --> whiz["whiz CLI<br/>profiles, mounts, time caps"]
creds[("your credentials<br/>env / OneCLI / keychain")]
mounts["declared mounts<br/>= filesystem permission"]
subgraph net["per-session isolated network (no route out)"]
sandbox["sandbox<br/>the agent runs here<br/>holds only a placeholder"]
broker["credential broker"]
gw["OneCLI gateway"]
end
whiz -->|"launch: scoped, hardened, time-bounded"| sandbox
mounts -. "only these paths" .-> sandbox
creds -->|"real key, on your machine only"| broker
sandbox -->|model calls| broker -->|injects credential| provider([model provider])
sandbox -->|service calls| gw -->|injects credential| services([GitHub, Slack, tools])
sandbox -.->|"needs more? asks you"| whiz
The sandbox is the untrusted boundary. It never shares a network with anything holding a raw secret, never sees a credential value, and cannot widen its own permissions — it can only ask, and you decide. Full treatment in docs/architecture.md and the visual overview.
- Filesystem is opt-in. The agent reaches only the paths you mounted — no parent-directory traversal, symlink, or glob trick reaches your home directory. The mount list is the permission model. Closes the whole "an agent ran
find ~ -name '*.pem'" class. - Credentials never enter the sandbox. A credential broker on your machine holds your real model key/login and attaches it only when forwarding to the model provider; the sandbox never sees the real value. If you use OneCLI, every service credential (GitHub, Slack, tool APIs) is injected on your machine too. A fully-compromised agent can neither read nor exfiltrate a secret it never holds. → Credential privacy
- Network is a per-profile choice.
off= nothing (no DNS, no HTTP);open= full outbound access;native/onecli/hybrid= on, but outbound is routed so credentials stay out of the sandbox (see Credential privacy).offcloses data exfiltration entirely. - The container is hardened. Non-root user, all Linux capabilities dropped, read-only container root,
no-new-privileges, Docker socket unreachable. A vulnerable tool the agent invokes gets no root, no host, no escape hatch. - Escalation is one-way, and you decide. Permissions only narrow after launch. An agent that needs more surfaces a request to a file-mailbox you monitor; you approve or deny. No silent self-upgrade.
- Sessions are time-bounded. Every session carries a duration cap and an idle cap; when they fire, the container stops. Blast radius is the declared window.
- Everything is audited. An append-only log records what launched, with what profile and mounts, what was requested, how it resolved, and why it ended — and the sandbox can't reach the log to tamper with it.
No credential of any kind ever enters the sandbox — not your model key, not your service tokens. Whatever the agent uses, the real value stays on your machine and is attached to a request only as it leaves the sandbox for its real destination; inside the container there is only a placeholder. A fully-compromised agent cannot read or exfiltrate a secret it never holds.
You choose how credentials are handled, based on how you sign in. Pick one of three — whiz init walks you through it, or set it per session with --credential-handling:
native— the default, no extra tools. Whizzard keeps your model credential out of the sandbox. Choose this if you don't need the agent to use service tokens (GitHub, Slack, tool APIs).onecli— OneCLI keeps every credential out of the sandbox, model and services alike. Choose this if you use OneCLI and sign in to your model provider with an API key.hybrid— Choose this if you sign in to your model provider with OAuth (a subscription login rather than an API key). OneCLI can't handle OAuth logins, so Whizzard covers your model login while OneCLI covers your service tokens — both kept out of the sandbox.
OneCLI is opt-in — the way to extend the guarantee to your service tokens, not a requirement. If it's ever unavailable, a session still runs model-only with --credential-handling native. (The off and open profiles deliberately skip credential mediation — for untrusted work, or when you want broad, unmediated access.)
See the decision log for the full credential-privacy rationale, and the threat model.
- macOS or Linux (Windows in pre-release verification), Python 3.11+, and a running Docker daemon.
- A supported agent harness installed and configured first — today that's Hermes. Whizzard sandboxes a harness you provide; it doesn't install one for you.
pip install whizzard==0.1.0
whiz initwhiz init walks five short steps, builds the sandbox images (~2 min first time), asks how to keep your credentials out of the sandbox, and writes config to ~/.whizzard/config/. About five minutes total. If a Hermes profile exists at ~/.hermes/, the wizard clones it (read-only, auth excluded) into a Whizzard profile; if not, it explains the setup and you run whiz hermes profile create main once Hermes is configured.
whiz # what's running + what you have set up
whiz r hermes # launch a Hermes session (default: native, credential-private)
whiz --help # every commandBundled profiles (customize during whiz init or edit ~/.whizzard/config/profiles.json):
| Profile | Network | Credentials | Time cap | For |
|---|---|---|---|---|
default |
on | native (key stays out of the sandbox) | none | everyday baseline |
build |
on | native | 2 h | development, long compiles |
power |
on (open) | full outbound, no mediation | 1 h | capability-heavy, broad access |
safe |
off | n/a | 30 min | running something you don't trust |
quarantine |
off | n/a | 30 min | untrusted, read-only folders only |
whiz init can set the default to onecli or hybrid if you use OneCLI.
Whizzard reduces risk; it does not eliminate it. It bounds an agent at runtime — what it can reach while executing — a containment layer, not a complete security solution. In v0.1.0 it deliberately does not address:
- Deferred-execution via writable mounts — an agent with write access can plant files (
.git/hooks/, lockfiles, post-install scripts) that run later on the host. Mitigation: review diffs before commit; opt-in--strict-overlayreview gate planned for v1.0 (ROADMAP goal 10). - DNS-based exfiltration when network is
on— the on/off boolean doesn't gate DNS independently. Mitigation: use a network-offprofile (safe/quarantine) for high-stakes work; per-profile constrained DNS under consideration (ROADMAP goal 11). - Behavioral analysis, container escape, and supply-chain attacks on Whizzard itself — out of scope; Whizzard relies on Docker / container-runtime boundaries and standard repo hardening, not novel sandboxing or third-party audit.
The full threat model gives the complete treatment with trust boundaries. This list names the gaps most likely to surprise someone who assumes "it's in Docker, so it's isolated." Found one that isn't listed? Please open an issue.
None. No analytics, no crash reporting, no phone-home — nothing leaves your machine except the network traffic your agent sessions make under the policy you set. The only files Whizzard writes are your local config and audit log. There is no analytics dependency in the codebase.
Early (0.1.x), solo-maintained, and deliberately narrow: it sandboxes one harness (Hermes), pinned to a tested build. Support is best-effort with no SLA. For sensitive work, use the pinned-version install and read Scope and limitations.
The engineering rationale is documented in the open, in an append-only decision log (docs/decisions.md, D-1 → D-191).
- docs/vision_and_strategy.md — what this is, who it's for, where it's going
- docs/reference/architecture-at-a-glance.html — visual overview (open in a browser)
- docs/threat_model.md — threat model and trust boundaries
- docs/architecture.md — system structure, safety policy, adapter contract
- docs/decisions.md — append-only decision log
- ROADMAP.md — v1.0 goals + post-launch sequencing
git clone https://github.com/BuckG71/whizzard && cd whizzard
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
make check # lint + typecheck + test in one shotIndividual targets: make test, make lint, make fmt, make typecheck, make validate-decisions. Pre-commit hooks: pip install pre-commit && pre-commit install. See CONTRIBUTING.md.
Whizzard is the project; whiz is the short CLI alias — both invoke the same tool.