Posthook supports macOS and Linux (Intel and arm64). Windows isn’t supported yet, so skip Windows devices in your scope.
Before you start
1
Get a team install key
In Bilanc, a Owner or Manager goes to Admin → Connections → AI Tools → PostHook and clicks Generate install link. The command shown contains the key after Copy the whole URL. The key is shown once; store it in your MDM’s secrets store or script variables, not in a wiki.The key is org-scoped and write-only — it can send posthook data into your workspace and cannot read anything. One key serves the whole organisation.
apiKey=:2
Decide how you'll pass the engineer's email
Posthook stamps every session with a work email so the dashboard can attribute activity to a person. Interactively, the installer asks for it. Under MDM there is no terminal, so set
POSTHOOK_ENGINEER_EMAIL in the script instead.Most MDM tools expose the assigned user’s email as a script variable — use that. If yours doesn’t, you can leave it out: sessions fall back to the machine’s global git config user.email, and the engineer can set it later with posthook identity --set-email you@company.com.3
Allow the network egress
The installer and the sync daemon need HTTPS to:
Self-hosted Bilanc customers replace
api.bilanc.co with their own API host. The install link your dashboard generates already points at the right place.4
Install agents before posthook, or re-run init after
posthook init installs hooks only for agents it finds on the machine (it looks for ~/.claude, ~/.cursor, and ~/.codex). If Claude Code, Cursor, or Codex is installed later, run posthook init again — it’s idempotent. The simplest way to cover this is to make the install script a recurring policy (see Keep it current).Install script
The install must run as the logged-in user, not root. Everything posthook touches lives in the user’s home directory: the binary in~/.local/bin, the database and config in ~/.posthook, the agent hook files, and the per-user launchd agent or systemd unit. Running it as root installs posthook for root and captures nothing.
Replace <team-key> with your key and <engineer-email> with your MDM’s user-email variable. Both are set as plain shell variables at the top of the script, so MDM parameter substitution (Jamf $4-style parameters, Kandji or Intune variables) works as normal.
- macOS
- Linux
MDM scripts on macOS run as root, so switch to the console user first. This is the same pattern Jamf, Kandji, and Mosyle recommend for per-user installs.If no one is logged in the script exits cleanly so your MDM retries on the next check-in rather than marking the device failed.
What the script does
- Resolves the latest release from GitHub (or the version pinned in
POSTHOOK_VERSION). - Downloads the binary for the machine’s OS and CPU, verifies its SHA-256 checksum, and installs it to
~/.local/bin/posthook. - Downloads the local dashboard bundle to
~/.posthook/dash(optional feature; skipped silently if unavailable). - Writes the team key and endpoint into
~/.posthook/config.jsonand enables sync. - Runs
posthook init: installs hooks for every detected agent, installs thegitshadow symlink next to the binary, and writes a global git template as a fallback. - Records the engineer identity from
POSTHOOK_ENGINEER_EMAILwithout prompting. - Installs and starts the background sync daemon: a launchd user agent named
co.bilanc.posthook-syncon macOS, or aposthook-sync.servicesystemd user unit on Linux. It starts at login, restarts on failure, and flushes new rows every 5 seconds.
init, keeps the existing identity and database, and restarts the daemon so the new binary takes over.
Environment variables
Set these inside the user context, before thecurl … | sh line.
POSTHOOK_API_KEY and POSTHOOK_CLOUD_ENDPOINT are set for you by the install link; you don’t need to set them yourself.
PATH and the git shadow
Commit capture works through agit symlink that the installer places next to the posthook binary. For it to see every commit, ~/.local/bin must come before the real git on PATH in the shells and IDE terminals engineers actually use. The installer checks this and prints a warning if it isn’t, but it never edits shell profiles.
For an MDM rollout, add the path once for everyone:
- macOS
- Linux
Append to
/etc/zshenv (read by every zsh, including non-interactive shells spawned by IDEs and agents):PATH on locked-down machines, capture still works for repositories cloned or created after install, via the global git template posthook sets up. Existing checkouts need posthook track <path> run once each.
Verify the rollout
On any machine, as the engineer:posthook identity is set.
Logs for the daemon are in ~/.posthook/sync.log.
Keep it current
Posthook does not self-update. To keep machines on the latest release, either:- Re-run the install script on a schedule from your MDM (weekly is plenty). The same script upgrades in place and re-detects any newly installed agents.
- Or have engineers run
posthook update, which does the same thing locally.
POSTHOOK_VERSION if you want to control exactly which build ships, and bump it deliberately.
Offboarding a machine
Run as the user:~/.claude/settings.json, ~/.cursor/hooks.json, and ~/.codex/config.toml if those agents remain in use, so they don’t call a binary that’s no longer there.
To cut off sync for every machine at once — for example if the key leaks — revoke the install link from Admin → Connections → PostHook in Bilanc and redeploy with a freshly generated one.
Troubleshooting
Installed, but nothing appears in Bilanc
Installed, but nothing appears in Bilanc
Check in order:
posthook sync --status for a recent successful flush and no auth error; posthook service status to confirm the daemon is loaded; posthook status to confirm hooks were installed for the agents the engineer uses. If the agent shows as not detected, it was installed after posthook — run posthook init.Sessions are attributed to the wrong email or to no one
Sessions are attributed to the wrong email or to no one
The identity wasn’t set at install (no
POSTHOOK_ENGINEER_EMAIL) and the machine’s git email is personal or empty. Fix on the machine with posthook identity --set-email you@company.com. Posthook retro-stamps that machine’s existing unattributed sessions when you do.Commits are missing but agent sessions show up
Commits are missing but agent sessions show up
The
git shadow isn’t first on PATH for the shell the engineer commits from. See PATH and the git shadow, or run posthook track <path> on the affected repositories.The daemon doesn't start on macOS
The daemon doesn't start on macOS
The install ran as root or from a context with no GUI session, so the launchd agent couldn’t be bootstrapped into the user’s session. Re-run the install script while the user is logged in.
launchctl print gui/$(id -u)/co.bilanc.posthook-sync shows the agent’s state.Machines behind an HTTP proxy
Machines behind an HTTP proxy
The installer’s
curl calls honour HTTPS_PROXY. The sync daemon is launched by launchd or systemd and does not inherit shell proxy variables, so egress to api.bilanc.co must be allowed directly. If your network requires a proxy for all outbound traffic, contact support before rolling out.
