Installing the poison0 agent: complete reference
The poison0 agent is a small daemon on each device that watches your agents' memory files locally. This page documents the installer end to end: the quick-install commands, every environment variable, the data directory per operating system, the service that runs the daemon, and how to roll it out unattended.
Overview
What the installer does, in order:
- Downloads the matching daemon binary from
https://poisonzero.com/dl/latest(Linux/macOS/Windows,amd64orarm64). - Verifies its SHA-256 checksum against the published
SHA256SUMS; aborts on any mismatch. - Installs a privileged service and, optionally, enrolls the device using an install code from the console.
sudo) on Linux/macOS, an Administrator PowerShell on Windows. Use PZ_FETCH_ONLY=1 to only download and verify.Requirements, checked before install:
- x86-64: AVX2 (Intel Haswell/2013+, AMD Zen+).
- ARM64: i8mm (Apple M2+; Apple M1 not supported).
- Windows: data directory on an NTFS volume.
Quick install
Create an install code in the console (or use a legacy per-device code), then run the command for your platform:
curl -fsSL https://poisonzero.com/install.sh | sudo \ PZ_ENROLL_CODE="your-code" sh
$env:PZ_ENROLL_CODE="your-code" irm https://poisonzero.com/install.ps1 | iex
- No code pre-set: the installer prompts for the install code (plus acceleration/tier and headless choices on a real terminal); an app ID is only asked for the legacy per-device pairing.
- An install code is multi-use up to its redemption cap; a legacy per-device code stays single-use.
- Already enrolled, re-run without a new code = upgrade: swaps the binary, restarts the service, keeps your credentials.
Install codes
Create an install code in the console, under Install keys. It is the recommended way to enroll devices:
- Multi-use: one code enrolls devices up to the redemption cap you set when you create it; each enrollment counts against that cap.
- Shown once: copy it when you create it - the console does not display it again.
- Revocable: revoke it in the console to stop further redemptions immediately; already-enrolled devices keep working.
- No app ID needed: the backend assigns each device its identity at redemption.
Environment variables
Pin any option through an environment variable to run the install non-interactively:
| Variable | Values | Default | Effect |
|---|---|---|---|
PZ_ENROLL_CODE | install code | none | The install code from the console. Required for a fresh enrollment; on its own it is enough, since the backend assigns the device identity. Passing a fresh one again on an enrolled device forces a deliberate re-enroll. |
PZ_APP_ID | app id | none | Legacy and optional: only needed together with an older per-device code minted before install codes. Ignored on its own. |
PZ_HEADLESS | none, standard, strict | none | Pins the user confirmation-prompt handling on a machine with no desktop user to answer prompts. none auto-detects from the logged-in user; standard/strict write a headlessmode file the daemon reads. |
PZ_BACKEND | cpu, gpu | cpu | Acceleration backend. CPU-only is the recommended, most secure default. GPU is opt-in and prints a security disclaimer; the GPU engine is not released yet. |
PZ_TIER | enterprise, ultra | enterprise | Product tier. ultra implies GPU and is fail-closed with no CPU fallback; enterprise with GPU falls back to a working CPU-only install. |
PZ_FETCH_ONLY | 1 | unset | Download and verify the binary only, then exit. No service is installed, so no elevated rights are needed. |
PZ_FETCH_DEST | path | ./poisonzero (.\poisonzero.exe on Windows) | Destination path for the verified binary when PZ_FETCH_ONLY=1. |
PZ_SETUP_AGENTS | comma list, e.g. claude,codex | unset | Wires the local /poisonzero stats command into the listed agents (Claude Code, Codex, Gemini, Cursor). Fully local, opt-in. |
PZ_SETUP_STATUSLINE | 1 | unset | Adds the poison0 agent's status line to Claude Code (~/.claude/settings.json). An existing status line is never replaced. |
PZ_DRY_RUN | 1 | unset | Prints the resolved mode (fresh/re-enroll/upgrade) and exits before any side effect. Useful for testing automation. |
POISONZERO_DATA_DIR | path | per-OS default (see below) | Overrides the data directory the daemon and installer use. |
--headless none|standard|strict flag (wins over PZ_HEADLESS); the Windows deploy script takes -Headless.Data directory and files
Binary: /usr/local/bin/poisonzero (Linux/macOS), <ProgramFiles>\PoisonZero\poisonzero.exe (Windows). Data directory per OS:
| OS | Data directory | Owner |
|---|---|---|
| Linux | /var/lib/poisonzero (enroll file at /etc/poisonzero/enroll) | poisonzero:poisonzero |
| macOS | /Library/Application Support/PoisonZero | root:wheel |
| Windows | <ProgramData>\PoisonZero | SYSTEM / Administrators |
Files inside the data directory:
credentials- stored device token; its presence marks the device as enrolled and is never overwritten on upgrade.enroll- one-time enrollment input (the install code, plusappIdfor the legacy pairing) consumed bypoisonzero enrollon first start.headlessmode- present only whenstandard/strictwas pinned; absent or empty = auto-detect.vault/- quarantine store for reverted content.
Service / daemon
Runs as a privileged background service, one mechanism per OS:
| OS | Type | Name & status command |
|---|---|---|
| Linux | systemd unit (root) | poisonzero.service · systemctl status poisonzero |
| macOS | launchd LaunchDaemon | com.poisonzero.daemon · launchctl print system/com.poisonzero.daemon |
| Windows | Scheduled Task (SYSTEM, at boot) | PoisonZero · Get-ScheduledTask -TaskName PoisonZero |
- Windows uses a Scheduled Task, not a Windows Service: the Go binary loads its model on first start and would miss the Service Control Manager start timeout.
- A desktop notifier runs in each user session for the user confirmation prompt: XDG autostart (Linux), per-user LaunchAgent (macOS), Run-key VBS wrapper (Windows).
Unattended install (Intune / SCCM)
Set the install code in the environment, then run the same one-liner; with the code present and no terminal, it runs prompt-free:
PZ_ENROLL_CODE="your-code" \ sh -c "$(curl -fsSL https://poisonzero.com/install.sh)"
$env:PZ_ENROLL_CODE="your-code" irm https://poisonzero.com/install.ps1 | iex
PZ_DRY_RUN=1 to print the resolved mode (fresh/re-enroll/upgrade) and exit before any change.Download and verify only
PZ_FETCH_ONLY=1 downloads, verifies the SHA-256 checksum and writes the binary without installing a service (no elevated rights):
curl -fsSL https://poisonzero.com/install.sh | PZ_FETCH_ONLY=1 sh # writes ./poisonzero (override with PZ_FETCH_DEST)
$env:PZ_FETCH_ONLY="1"; irm https://poisonzero.com/install.ps1 | iex # writes .\poisonzero.exe (override with $env:PZ_FETCH_DEST)
Verify the device
- Confirm the service is running with the status command for your OS (table above).
- Open the console: the enrolled device appears in your device list with its status.
- To move a device to a fresh install code, re-run the installer with a new
PZ_ENROLL_CODE- it re-enrolls cleanly.
Uninstall
One command removes everything: first the exec0 file managed-settings.d/50-poisonzero-exec0.json and the Claude Code hooks of every user, then the service, the program and the data directory. If the exec0 file cannot be removed, the uninstall stops and the program stays installed. Run it as administrator (root). Never delete the program by hand: hooks that point to a missing program block every tool call in Claude Code.
curl -fsSL https://poisonzero.com/install.sh | sudo sh -s -- --uninstall
& ([scriptblock]::Create((irm https://poisonzero.com/install.ps1))) -Uninstall
# .deb / .rpm sudo apt remove poisonzero # or: sudo dnf remove poisonzero # Homebrew poison0 remove-agent-integration && brew uninstall poisonzero # Scoop scoop uninstall poisonzero
exec0 hooks in Claude Code
exec0 hooks into Claude Code with three hooks: UserPromptSubmit, PreToolUse and PostToolUse. Where they are registered depends on the type of installation:
| Installation | Location of the exec0 hooks |
|---|---|
| System installation: install.sh, install.ps1, .deb/.rpm (program in a folder only administrators can change) | Claude Code's managed settings, separate file managed-settings.d/50-poisonzero-exec0.json |
| User installation: Homebrew under a user-owned prefix, Scoop in the user profile | The user's ~/.claude/settings.json |
| OS | Managed settings folder |
|---|---|
| macOS | /Library/Application Support/ClaudeCode/ |
| Linux, WSL | /etc/claude-code/ |
| Windows | C:\Program Files\ClaudeCode\ |
- PoisonZero never changes your
managed-settings.jsonand never changes other files inmanaged-settings.d/. - Folders PoisonZero creates are writable only by administrators and readable by everyone.
Effect
| Case | Result |
|---|---|
A user or agent removes the entry or sets "disableAllHooks": true in user or project settings or via --settings | The exec0 hooks keep running. |
You set allowManagedHooksOnly | The exec0 hooks keep running; hooks from user and project settings do not. |
You set "disableAllHooks": true in the managed settings | The exec0 hooks are off as well; poison0 doctor reports it. |
| Device with an older installation | The entry in ~/.claude/settings.json stays as a fallback until the PoisonZero service sees Claude Code call the managed entry for that user. Then the service removes the user entry. If both run until then, each tool call is still checked only once. |
Policies already delivered centrally
If you already deliver Claude Code policies through one of the following sources, Claude Code by default applies only the highest source and ignores 50-poisonzero-exec0.json:
| Source | Location |
|---|---|
| Server-managed settings | claude.ai admin console |
| MDM profile (macOS) | Domain com.anthropic.claudecode |
| Group Policy or Intune (Windows) | HKLM\SOFTWARE\Policies\ClaudeCode |
| Fix | How |
|---|---|
| Merge the sources (Claude Code 2.1.242 or later) | Set "managedSourcesBehavior": "merge" in the highest source. |
| Deliver through your own source | Copy the content of managed-settings.d/50-poisonzero-exec0.json from an installed device into that source. |
| Check | poison0 doctor, poison0 exec0 status or the PoisonZero console show whether Claude Code really calls the hook, and name the source. |
Turn exec0 off and on for Claude Code
Requires administrator rights. On Windows, run it in a terminal as administrator.
# turn off sudo poison0 setup-claude --toolgate-off # turn on sudo poison0 setup-claude --toolgate
# turn off poison0 setup-claude --toolgate-off # turn on poison0 setup-claude --toolgate