Install¶
There is no pip install. The sensor has no third-party dependencies, so a checkout plus the python3 macOS already ships is a complete installation.
Requirements¶
| Requirement | Detail |
|---|---|
| Operating system | macOS. Tested on 26.5.2, Apple Silicon. |
| Python | 3.9 or newer. The stock /usr/bin/python3 is fine. |
| Base tooling | ps and lsof from the base system. |
| Plane C additionally | /usr/bin/eslogger (macOS 13+), root, and Full Disk Access. |
| Collector (optional) | OpenTelemetry Collector contrib 0.158.0, downloaded on request. |
Run the host checks¶
install.sh downloads nothing by default. It documents everything that is easy to get wrong on a fresh Mac:
- which Python binary needs Full Disk Access for
--esf - why
sudo python3is often not the same binary aspython3 - the OTLP endpoint choices — Loki direct on
:3100/otlpversus a collector on:4318 - what root versus unprivileged coverage actually includes
| Flag | Effect |
|---|---|
--check |
Report prerequisites and exit without changing anything. |
--with-otelcol |
Also download and verify the OpenTelemetry Collector. |
--skip-otelcol |
Accepted for compatibility; a no-op now that the Collector is opt-in. |
make help lists every one of the 24 Make targets.
Confirm what the host will actually see¶
--self-test reports platform capability, host tooling, whether Endpoint Security will admit this process, and a live acquisition sample. Run it before you commit to a deployment.
python3 -m shadowclaw --self-test
platform
os : macOS (darwin)
plane : inference heartbeat via ps(1)
plane : shadow egress via lsof(8) and tcpdump(1)
plane : agent actions via Endpoint Security (eslogger) (root)
coverage : 3 of 3 planes
host tooling
ps : /bin/ps (ok)
lsof : /usr/sbin/lsof (ok)
eslogger : /usr/bin/eslogger (ok)
euid root : False
endpoint security
status : UNAVAILABLE -- not running as root
re-run under sudo
credential access, identity creation, privilege escalation and launch-item
persistence will NOT be detected on this run
agent-config persistence and public exfil surfaces still work -- they need
no privilege
self-test: DEGRADED
DEGRADED here is the honest answer for an unprivileged run, not a failure. It names which half of the coverage is missing rather than leaving you to infer it.
The OpenTelemetry Collector is optional¶
Loki 3.x accepts OTLP natively at /otlp/v1/logs, so the sensor can post straight to it with nothing in between. The contrib Collector build the shipped pipelines need is a 329 MB download, so it is opt-in:
The download is verified against the upstream SHA-256. You want the Collector only if you need a collector's processing — routing, batching, fan-out to several backends — or if you are running make validate against config/otel-collector.yaml.
Two collectors cannot share a port
DefenseClaw's bundled collector and ShadowClaw's both want 127.0.0.1:4317 and 127.0.0.1:4318. Only one can run at a time. See DefenseClaw integration.
Full coverage needs root¶
Unprivileged, you already see the whole process table but only your own sockets — enough to validate the detector, not enough to police a machine, because attribution needs both halves for the same pid.
Root also unlocks the host plane, --esf, which is where credential access, identity creation and privilege escalation become visible at all.
Full Disk Access¶
Endpoint Security refuses a client that lacks Full Disk Access, with an error that names neither Full Disk Access nor System Settings.
When you run the sensor from a terminal, eslogger(1) checks the terminal application — Terminal, iTerm, Cursor — for FDA, not Python alone.
- Grant Full Disk Access to that app in System Settings → Privacy & Security → Full Disk Access.
- Fully quit and reopen the app. A restart is required; a new window is not enough.
- Confirm with
sudo eslogger exit.
For a launchd daemon, grant FDA to the bundled interpreter named in the plist instead. packaging/README.md covers that case.
--self-test translates the underlying error into this checklist, so use it to confirm rather than guessing.
A Mac with no developer tools¶
packaging/ builds a .pkg inside a .dmg that carries its own Python 3.13 runtime.
The package is unsigned, so the first attempt to open it is refused by Gatekeeper — right-click the .pkg and choose Open. Installing lays down /usr/local/bin/shadowclaw and starts nothing: the root LaunchDaemon is a separate opt-in, and uninstalling deliberately leaves the ledger behind.