macOS standalone deployment
Install the standalone DefenseClaw enterprise LaunchDaemons on Apple silicon Macs from the pkg or the payload tarball, check the result, and remove them.
The standalone macOS profile installs DefenseClaw machine-wide under
/opt/cisco/defenseclaw, with LaunchDaemons labeled
com.cisco.defenseclaw.* and a hidden service account, _defenseclaw. It is
separate from the Cisco Secure Client module
(/opt/cisco/secureclient/defenseclaw) and refuses to install beside it.
Standard users cannot stop the daemons or change the config, and the hook
guardian restores DefenseClaw's hooks if a user removes them. For the terms
used on this page, see Concepts.
Deploying with an MDM?
This page installs on one Mac from an administrator shell. To deploy with Jamf Pro, Kandji, Intune, Workspace ONE or another MDM, start with Install with an MDM. It uses the same pkg and the same config.
Requirements
| Requirement | Detail |
|---|---|
| macOS | macOS 13.0 or later. The pkg refuses older versions. |
| Hardware | Apple silicon only. The pkg is arm64-only, and releases build no Intel macOS binaries, so neither the pkg nor the tarball runs on an Intel Mac. |
| Privileges | root, through sudo or an MDM agent. Only enterprise macos status works without root. |
| Other profiles | No Secure Client DefenseClaw module. The pkg's pre-install script refuses when /opt/cisco/secureclient/defenseclaw or a com.cisco.secureclient.defenseclaw* LaunchDaemon exists. |
| Gatekeeper | Only the pkg can be Developer ID-signed and notarized. It is signed only when the release pipeline has Apple signing credentials, and notarized only when it also has notary credentials, so a release can be signed but not notarized. The tarball's binaries are never Developer ID-signed. On Macs that require notarized software, use the pkg and check it first with spctl --assess --type install --verbose=2 <pkg>. |
Layout
All paths are under /opt/cisco/defenseclaw unless shown in full.
| Item | Path | Owner and mode |
|---|---|---|
| Binaries | bin: defenseclaw-gateway, defenseclaw-hook, defenseclaw-sensor-helper, and defenseclaw-acp when present | root, 0755 |
| Managed OpenCode plugin | share/opencode/defenseclaw.js | root, 0644 |
| Config | etc/config.yaml | root:_defenseclaw, 0640 |
| Policies | etc/policies | root:_defenseclaw, 0750 |
| Secrets | etc/secrets | Directory root:_defenseclaw 0750, files 0640 |
| Target manifest | etc/hook-guardian/targets.yaml, written by the enumerator | Directory root:_defenseclaw, 0750 |
| Runtime descriptor | etc/managed-runtime.json, the non-secret settings that hooks read | root, 0644 |
| Machine-policy summary | etc/machine-policy.json | Readable by users |
| Lifecycle state | lifecycle, including last-package-result.json, last-activation-failure.log, the last applied config and a rejected one | root, 0700 |
| Gateway data | runtime | _defenseclaw, 0700 (the device identity key needs a private directory) |
| Authorization ledger | hook-guardian-state, with each enrolled user's latest AI Discovery scan in ai-discovery/ | root:_defenseclaw, 0750 |
| Hook socket | run/hook.sock | Directory _defenseclaw, 0755 |
| Logs | /Library/Logs/Cisco/DefenseClaw, with the gateway's logs in gateway/ | root, 0755; gateway/ is _defenseclaw, 0750 |
| LaunchDaemons | /Library/LaunchDaemons/com.cisco.defenseclaw.*.plist | root, 0644 |
The daemons:
| Label | Runs as | What it does |
|---|---|---|
com.cisco.defenseclaw.gateway | _defenseclaw | Policy engine and hook API. Binds 127.0.0.1:18970 and run/hook.sock. |
com.cisco.defenseclaw.hook-guardian | root | Always running. Reconciles each user's hooks every minute (enterprise hooks watch --interval 1m), through a worker that runs as each user. The same worker runs each enrolled user's AI Discovery scan (Per-user scans). It does not repair machine policy, including the Claude Code version floor: ensure, repair and reconcile do. |
com.cisco.defenseclaw.hook-enumerator | root | Rewrites the target manifest every five minutes (in the default auto enrollment mode) |
com.cisco.defenseclaw.sensor-helper | root | Answers the gateway's fixed AI Discovery requests |
com.cisco.defenseclaw.apply | root | Runs ensure --reason path when etc/config.yaml, etc/secrets or etc/policies changes |
com.cisco.defenseclaw.verify | root | Runs verify every day at 03:17 local time |
See Threat model for what each zone may do.
Install
Stage the config first, then install the pkg or the tarball. The lifecycle
picks its config in this order: --config, then
/opt/cisco/defenseclaw/etc/config.yaml, then a built-in default. The
default runs observe mode with no connectors, so it protects nothing.
1. Get and check the release
Download from the same GitHub release:
defenseclaw-enterprise-<version>-darwin-arm64.pkg, or the tarballdefenseclaw-enterprise-<version>-darwin-arm64.tar.gz;checksums.txtandchecksums.txt.bundle.
Check the signature on checksums.txt with
cosign, then
the file against it, then the pkg's own signature:
VERSION=1.4.0 # the release you deploy
cosign verify-blob --bundle checksums.txt.bundle \
--certificate-identity "https://github.com/cisco-ai-defense/defenseclaw/.github/workflows/release.yaml@refs/heads/main" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
checksums.txt
grep " defenseclaw-enterprise-${VERSION}-darwin-arm64.pkg\$" checksums.txt | shasum -a 256 -c
pkgutil --check-signature "defenseclaw-enterprise-${VERSION}-darwin-arm64.pkg"pkgutil reports "no signature" for a pkg built without Apple credentials.
Such a pkg does not satisfy Gatekeeper on Macs that require notarization.
2. Stage the config
This example protects Codex and Claude Code in observe mode. The lifecycle
requires config_version: 8, deployment_mode: managed_enterprise,
enterprise.profile: standalone and
data_dir: /opt/cisco/defenseclaw/runtime. If you set gateway.api_bind or
gateway.api_port, they must be 127.0.0.1 and 18970.
config_version: 8
deployment_mode: managed_enterprise
data_dir: /opt/cisco/defenseclaw/runtime
policy_dir: /opt/cisco/defenseclaw/etc/policies
enterprise:
profile: standalone
gateway:
api_bind: 127.0.0.1
api_port: 18970
guardrail:
enabled: true
mode: observe
connectors:
codex: {}
claudecode: {}Each key under guardrail.connectors turns on protection for that agent. See
Choose the agents to protect
and the settings reference.
Put it where the lifecycle reads it. A config staged before the install is used as is; it does not count as an unmanaged layout:
sudo install -d -o root -g wheel -m 0755 /opt/cisco/defenseclaw/etc
sudo install -o root -g wheel -m 0640 config.yaml /opt/cisco/defenseclaw/etc/config.yamlThe lifecycle re-owns the file to root:_defenseclaw 0640 when it installs.
3a. Install the pkg
VERSION=1.4.0 # the release you deploy
sudo installer -pkg "defenseclaw-enterprise-${VERSION}-darwin-arm64.pkg" -target /
sudo cat /opt/cisco/defenseclaw/lifecycle/last-package-result.jsonThe pkg installs the binaries in /opt/cisco/defenseclaw/bin, and its
post-install script runs
enterprise macos ensure --from-package --reason package --json. That
creates _defenseclaw, validates the config, lays out the files, writes the
LaunchDaemons, starts them in order, verifies, and rolls back on any failure.
A failed apply fails the pkg install, so installer and your MDM report it.
The result is in last-package-result.json. The pkg receipt is
com.cisco.defenseclaw.enterprise.
If you did not stage a config, the pkg installs the default, which protects
nothing. Apply your config afterward. Either copy it to
/opt/cisco/defenseclaw/etc/config.yaml, and the apply daemon runs ensure
for you, or run ensure yourself and read the result:
sudo /opt/cisco/defenseclaw/bin/defenseclaw-gateway enterprise macos ensure \
--from-package --config "$PWD/config.yaml" --json3b. Or install from the tarball
The payload folder and its binaries must be owned by root and not writable by group or others:
VERSION=1.4.0 # the release you deploy
PAYLOAD="/var/root/defenseclaw-enterprise-${VERSION}"
sudo install -d -o root -g wheel -m 0700 "$PAYLOAD"
sudo tar -xzf "defenseclaw-enterprise-${VERSION}-darwin-arm64.tar.gz" \
-C "$PAYLOAD" --no-same-owner --no-same-permissions
sudo chmod -R go-w "$PAYLOAD"
sudo "$PAYLOAD/defenseclaw-gateway" enterprise macos ensure --payload "$PAYLOAD" --jsonensure installs when nothing is installed, applies a payload that differs
from the installed one, re-applies a changed config, repairs a deployment
that fails verification, and otherwise does nothing. Add
--config <absolute path> to install a config from another location, and
--no-start to stage the deployment with the daemons stopped. If the Mac
already has a hand-built DefenseClaw layout, the install stops with
unmanaged_layout_present. Add --adopt-existing to back it up and take it
over.
Exit codes:
| Code | Meaning |
|---|---|
0 | Success, or nothing to do |
1 | Failure. A failed install, upgrade or repair is rolled back, and a refusal before any change leaves the computer as it was. For status and verify, 1 means the deployment is unhealthy. |
2 | Invalid arguments |
75 | Another lifecycle run holds the lock. Retry later. |
4. Add the AI Defense key
Without a key, the local policy engine decides alone. To add Cisco AI Defense, set these keys in the config:
enterprise:
profile: standalone
inspection:
ai_defense:
enabled: true
credential: ai-defense-api-keyThen store the key. Install first: the command needs the _defenseclaw
account, and it runs ensure right after it writes the key, so it fails on
a Mac with nothing installed.
sudo /opt/cisco/defenseclaw/bin/defenseclaw-gateway enterprise secret set \
--name ai-defense-api-key --from-file /var/root/ai-defense.key --json
sudo rm /var/root/ai-defense.keySee AI Defense key for rotation and removal.
Verify the install
sudo /opt/cisco/defenseclaw/bin/defenseclaw-gateway enterprise macos status --json
sudo /opt/cisco/defenseclaw/bin/defenseclaw-gateway enterprise macos verify --json
pkgutil --pkg-info com.cisco.defenseclaw.enterprise # pkg installs onlystatus reports the state. verify also checks every file, permission,
service and readiness check, and exits 1 when anything fails. Look for:
| Field | Healthy value |
|---|---|
ok | true |
installed, installed_version | true and the version you deployed |
readiness | gateway, guardian, enumerator and sensor_helper all true |
coverage_complete | true: the gateway, guardian and enumerator are ready |
security_complete | true: coverage is complete, the sensor helper is ready, and there are no errors |
enrollment.targets | The number of per-user targets in the manifest. Connectors published through machine policy (Codex, Claude Code, Cursor, GitHub Copilot) have no per-user targets unless enterprise.enrollment.unenrolled_users is deny, so 0 is normal when you enable only those. For per-user connectors, 0 means nobody is enrolled yet. |
errors | Empty |
When the config enables no agent under guardrail.connectors while there
are users to enroll, status and verify warn no_connectors_enabled and
security_complete is false. Otherwise neither field checks that the
users you expect are enrolled, so check enrollment too. The
enumerator enrolls accounts with a uid of 501 or higher by default. See
Enrollment. To reconcile at once instead of
waiting for the next minute, run
sudo /opt/cisco/defenseclaw/bin/defenseclaw-gateway enterprise macos reconcile --json.
See Status and verify and Logs and events for monitoring.
Per-user installs
On a Mac with /opt/cisco/defenseclaw/etc/managed-runtime.json, the
per-user product refuses to run:
| Per-user action | What happens |
|---|---|
install.sh | Refuses and changes nothing |
defenseclaw upgrade | Refuses |
| Per-user gateway | Refuses to start |
Nothing migrates a per-user install automatically. Before you deploy, have
each user remove their per-user install with defenseclaw uninstall --binaries --yes.
Add --all to also delete ~/.defenseclaw. See
Uninstall.
Remove
| Goal | Command |
|---|---|
| Stop and remove the deployment and its binaries. Keep the config, secrets, data and logs. | defenseclaw-gateway enterprise macos uninstall --json |
| Also remove the config, secrets, data, logs and lifecycle state | defenseclaw-gateway enterprise macos uninstall --purge --json |
Also delete the _defenseclaw account | defenseclaw-gateway enterprise macos uninstall --purge --remove-service-account --json |
Run these as root from /opt/cisco/defenseclaw/bin. Uninstall removes each
user's DefenseClaw hook registrations and DefenseClaw's own machine-policy
entries first. Administrator entries in those files stay as they were.
With --purge it also removes each enrolled user's ~/.defenseclaw, except
inert hook stubs. See Uninstall.
A pkg has no uninstaller, so the lifecycle removes the binaries itself. For
a pkg install it also runs pkgutil --forget com.cisco.defenseclaw.enterprise,
so the pkg receipt is gone afterward.
Upgrades and changes
- Upgrade. Install the newer pkg, or run
ensurewith the newer tarball. An older pkg is refused before any file changes unless the root-owned rollback marker/opt/cisco/defenseclaw/lifecycle/allow-downgradeexists; the lifecycle refuses an older tarball unless you pass--allow-downgrade. See Upgrade and Roll back. - Change the config. Replace
/opt/cisco/defenseclaw/etc/config.yaml. The apply daemon runsensure, which validates the new file and applies it, or rolls back. See Change the config. - Failures. See Lifecycle error codes.
The service account
_defenseclaw is a hidden account and group. The lifecycle creates it with
dscl, using the highest free id from 300 to 499 (the range macOS reserves
for daemons), with shell /usr/bin/false and home /var/empty. The
gateway runs as _defenseclaw. Everything else runs as root.
Privacy prompts
The packaging ships no PPPC (Privacy Preferences Policy Control) profile.
The guardian works only in hidden dot-directories inside each user's home,
such as ~/.claude, ~/.codex and ~/.config. macOS privacy controls (TCC)
do not protect those folders, so no profile is needed.
The per-user AI Discovery scan also walks the home for package manifests. Without a profile, macOS keeps it out of TCC-protected folders, and it skips them.
If your organization moves agent configuration into a TCC-protected folder,
such as Desktop, Documents or iCloud Drive, deploy a PPPC profile that grants
Full Disk Access (SystemPolicyAllFiles) to
/opt/cisco/defenseclaw/bin/defenseclaw-gateway. That one binary runs the
gateway, the guardian (enterprise hooks watch) and the enumerator. Identify
it by its Developer ID code requirement, which needs a signed build.
Machine policy
For Codex, Claude Code, Cursor, GitHub Copilot and OpenCode, DefenseClaw adds its hooks to the vendor's machine policy files:
| Connector | File |
|---|---|
| Codex | /etc/codex/requirements.toml |
| Claude Code | /Library/Application Support/ClaudeCode/managed-settings.d/ |
| Cursor | /Library/Application Support/Cursor/hooks.json |
| GitHub Copilot | /etc/github-copilot/policy.d/ |
| OpenCode | /Library/Application Support/opencode/opencode.json, which loads the managed plugin |
An MDM configuration profile outranks these files: a Codex profile for
com.openai.codex with requirements_toml_base64, or a Claude Code profile
for com.anthropic.claudecode. enterprise policy show reports such a
profile as a higher-precedence source. Export DefenseClaw's entries in plist
form and add them to your profile:
sudo DEFENSECLAW_CONFIG=/opt/cisco/defenseclaw/etc/config.yaml \
/opt/cisco/defenseclaw/bin/defenseclaw-gateway enterprise policy show
sudo DEFENSECLAW_CONFIG=/opt/cisco/defenseclaw/etc/config.yaml \
/opt/cisco/defenseclaw/bin/defenseclaw-gateway enterprise policy export --connector codex --format plistUse --connector claudecode --format plist for Claude Code. The policy
commands only read. See Machine policy
for ownership, conflicts and the foreign-hook guard.
Linux standalone deployment
Install the standalone DefenseClaw enterprise services on Linux from the deb or rpm package or the payload tarball, check the result, and remove them.
Install with any MDM
The contract every MDM recipe follows to deliver, run, detect, upgrade, reconfigure and remove the standalone DefenseClaw enterprise deployment on Windows, Linux and macOS.