Skip to main content
This guide takes you from no Beacon on your Macs to every Mac in a Jamf pilot sending its AI agent activity to one Microsoft Sentinel table. Follow the steps in order. A Homebrew install on one Mac is only for looking at events locally. It does not include Vector, and it writes a per-user log. The Macs in the pilot use the signed package, which writes /var/log/beacon-agent/runtime.jsonl and ships Vector at /opt/beacon/bin/vector.

What you’ll set up

When you finish, each Mac in the pilot has:
  • Beacon installed under /opt/beacon, with its collector running as the LaunchDaemon com.beacon.endpoint.collector.
  • Claude Code, Codex CLI, and Cursor reporting to that collector for the user who is logged in at the Mac.
  • Agent activity written to /var/log/beacon-agent/runtime.jsonl.
  • A forwarder (Vector, shipped in the package) posting each new line to the Azure Monitor Logs Ingestion API.
Those lines land in the custom Log Analytics table BeaconRuntime_CL, which is the table Sentinel hunts over. Azure Monitor Agent does not run on macOS, so this guide uses Vector. Linux hosts can use Azure Monitor Agent and still fill the same table. See Microsoft Sentinel forwarding.

Before you start

The Macs do not need Beacon installed beforehand. Jamf installs it in Policy 1.
Claude Desktop chat is not part of this rollout. Beacon does not collect that app. Claude Code is the claude CLI and the Claude Code extension. Codex is the Codex CLI. Cursor is the Cursor app.

1. Look at Beacon on one Mac (optional)

A Homebrew install lets you see what a session looks like before Jamf is involved. It stays on that Mac:
Check it with beacon endpoint status and beacon endpoint doctor. A fresh install reports one warning, harness_observed, until an agent actually runs. Start a new Claude Code or Codex session and the events are in ~/.beacon/endpoint/logs/runtime.jsonl. Leave this Mac as it is. The pilot Macs get the package in Policy 1, and they forward a different log.

2. Prepare Sentinel

Do this once, in Azure. The same workspace then receives every pilot Mac. On the Mac from step 1, generate the content pack with the system log path filled in. --system is what makes vector.toml tail /var/log/beacon-agent/runtime.jsonl:
The pack contains the table schema, both Data Collection Rule templates, vector.toml, the KQL transform, starter hunting queries, and a sample event. Full portal steps are in Microsoft Sentinel forwarding. For these Macs, finish these four things:
  1. Create the custom table. Name it BeaconRuntime. Azure adds _CL, so the table you query is BeaconRuntime_CL. Upload sample-event.jsonl and paste dcr-transform.kql in the schema step.
  2. Create a Data Collection Endpoint in the same region as the workspace. Copy its logs ingestion URL. It looks like https://<dce>.<region>.ingest.monitor.azure.com.
  3. Deploy dcr-logs-ingestion-template.json with the workspace resource ID and the Data Collection Endpoint resource ID. Copy the rule’s immutableId. It starts with dcr-.
  4. Register an app in Microsoft Entra ID, create a client secret, and grant that app the Monitoring Metrics Publisher role on the Data Collection Rule. Role assignment can take several minutes.
Each Mac needs outbound HTTPS to login.microsoftonline.com and to the Data Collection Endpoint hostname. Nothing else. Beacon never stores the tenant ID, client secret, workspace ID, or ingestion URL. Those stay in the forwarder’s environment file on the Mac, written by Policy 2.

3. Set up Jamf

Create four policies, in this order, scoped to the pilot Smart Group. A person has to be logged in at the Mac for policies 3 and 4. At the login window those two exit with an error, which is expected.

Policy 1: install the package

Download the signed package for the release you are piloting. The asset name is BeaconEndpointAgent-<version>-arm64.pkg, attached to the GitHub release with a .sha256. Check the checksum before uploading it to Jamf. In Jamf Pro, upload the package and add it to a policy named Beacon - Install Package with the install action. The package installs:
It also starts the collector LaunchDaemon and, when someone is logged in during install, points that person’s Claude Code and Codex settings at the collector. Policy 3 does that again on purpose, so a Mac that was at the login window during install still gets configured.

Policy 2: forward to Sentinel

Add a script named Beacon - Configure Sentinel Forwarding. It writes Vector’s config, a root-owned environment file, a small wrapper, and a LaunchDaemon, then starts it. Jamf script parameters: Deliver the secret with Jamf’s own secret mechanism if you have one. A script parameter is visible to Jamf administrators.
Vector starts reading at the end of the log. Lines already in the file are not uploaded. That is what you want on a pilot: only activity from the moment forwarding starts. The client secret lives only in sentinel-vector.env, mode 0600, owned by root. It is not in Beacon’s config.json.

Policy 3: Claude Code and Codex

Add a script that runs the helper shipped in the package:
Run it while someone is logged in. The helper repairs the system endpoint for Claude Code and Codex, then installs Claude Code hooks for that person, writing events to /var/log/beacon-agent/runtime.jsonl. Codex sends prompts, tools, and token usage over OTLP to 127.0.0.1:4317. Its SessionStart hook adds the OS user, which the OTLP spans do not carry. Claude Code sends prompts, tools, approvals, and token usage over the same OTLP endpoint. Its hooks add session start and end, file activity, command output, and subagent lifecycle, which Claude Code’s OTLP export does not carry. After the policy, that person quits Claude Code and Codex completely, reopens them, and starts a new session. A session that was already open keeps the old settings.

Policy 4: Cursor

Add a script that runs the other helper shipped in the package:
This also has to run while someone is logged in. It installs Cursor hooks for that person and points them at the system runtime log. Quit Cursor and start a new agent session afterward.

What each harness sends

Events from these three are rows in the same table. Filter with HarnessName. Other local agents are installed the same way, one policy per harness, with beacon endpoint hooks install or that runtime’s own setup. The runtime list is the catalog. This pilot does not turn on Claude Cowork. Cowork is an org-admin OTLP export, documented on Claude Cowork, and it is a different harness name (claude_cowork).

4. Check one Mac

On a pilot Mac, after all four policies and a new session in each agent:
Service: loaded=true running=true means the collector is up. Run the two hooks checks as the person who is logged in. They read that person’s home, the same place Policies 3 and 4 wrote: Claude Code should say hooks are installed at that person’s ~/.claude/settings.json, and Cursor at that person’s ~/.cursor/hooks.json. The forwarder print should show state = running. Write a known event after the forwarder is running, so Vector is already watching the end of the file:
Then in the Log Analytics workspace:
A real session shows up next to it:
If the validation query is empty, read /Library/Logs/Beacon/com.beacon.endpoint.sentinel-forwarder.err on the Mac. An authentication error there is the Entra app or the Monitoring Metrics Publisher role. A path error means Vector is not reading /var/log/beacon-agent/runtime.jsonl. Rows in the local file with no matching rows in the table mean the forwarder started before those lines were written: Vector only ships lines appended after it starts.

Microsoft Sentinel forwarding

Table setup, both ingestion paths, and the content pack.

macOS

Package install, launchd, and the system log path.

Jamf

Package deployment, Extension Attributes, and validation.

Anthropic, OpenAI, and Cursor

The same three harnesses, forwarding to S3 instead of Sentinel.