Skip to main content
Use this guide to install Beacon on your Macs with Jamf Pro and send the AI agent activity it records to a Cloud Storage bucket you own. People using the Macs don’t have to do anything.

What you’ll have

Every Mac in scope gets:
  • Beacon, installed from the signed package, recording what Claude Code, Codex, and Cursor do for the person logged in: prompts, commands and their output, tool and MCP calls, file edits, approvals, and token usage, where each agent exposes them.
  • An inventory of the Mac’s AI agents, MCP servers, and skills, taken every six hours.
  • A forwarder that uploads both to your bucket with a key that can only add new objects below your prefix:
Each object is newline-delimited JSON, one event per line, with the fields in the telemetry schema. Agent activity reaches the bucket within five minutes. Nothing else leaves the Mac, and the agents’ hooks never use the network.

Before you start

To see what Beacon records before you roll it out, download the package as in step 3 and install it on one Mac with sudo installer -pkg BeaconEndpointAgent-<version>-arm64.pkg -target /.

1. Set up Google Cloud

Pick a root prefix such as beacon-prod. Beacon adds runtime/ and inventory/ below it, so don’t put either in the prefix.
Beacon’s Terraform module creates a new bucket just for Beacon, a writer service account that can only create objects below your prefix, and a read-only service account. Create a main.tf in a new directory and change the project, location, bucket name, and prefix:
main.tf
Review the plan and type yes. It’s working when the apply ends with Apply complete! Resources: 7 added, 0 changed, 0 destroyed. and prints the four outputs.Save the values for the next steps:
For your own Cloud KMS key, object expiry, and other settings, see the module’s options.

2. Create the writer key

The forwarder on each Mac signs in to Google Cloud with a key for the writer service account:
It’s working when gcloud prints created key [...]. Keep the file for step 3, and don’t commit it or share it in chat or email.
If gcloud says Key creation is not allowed on this service account, your Google Cloud organization blocks service-account keys, which new organizations do by default. Ask someone with the Organization Policy Administrator role to allow keys in this project only:
The rest of your organization still blocks keys. The change takes a minute or two to apply, and then the command above works. To manage this exception with Terraform, see Allow service-account keys.

3. Build the packages

Jamf installs two packages on each Mac: Beacon’s signed package, and a small package you build that holds the key. Download Beacon’s package and check its checksum and Apple signature:
Download and verify
It’s working when pkgutil prints Status: signed by a developer certificate issued by Apple for distribution. Package the key. The package installs it at /Library/Application Support/Your Organization/Secrets/beacon-gcs-writer.json, owned by root and readable only by root. Replace Your Organization and com.yourorg with your own names, and use the same path in step 5:
Build the key package
It’s working when pkgbuild prints Wrote package to beacon-gcs-writer-key-1.pkg. Keep the key out of /opt/beacon and /Library/Application Support/Beacon, because Beacon upgrades and repairs replace those directories. Anyone who can download this package from Jamf can read the key. The key can only add new objects below your prefix. It can’t list, read, change, or delete anything in the bucket.

4. Add them to Jamf Pro

Upload both packages. In Jamf Pro, go to Settings > Computer management > Packages, click New, and upload BeaconEndpointAgent-<version>-arm64.pkg. Do the same for beacon-gcs-writer-key-1.pkg. Add the forwarding script. Go to Settings > Computer management > Scripts, click New, name it Beacon - Forward to GCS, and paste:
Beacon - Forward to GCS
On the Options tab, label the parameters:

5. Create the policies

Go to Computers > Policies and create two policies. Beacon - Install installs Beacon and the key, starts the forwarder, and sets up the agents for whoever is logged in: Beacon - Set up agents at login sets up the agents for each person who logs in later, including on Macs that were at the login window when Beacon installed: Running it at every login is safe. It also puts back Beacon’s settings if an agent update removed them. The Login trigger needs login events turned on in Settings > Computer management > Check-in (Check for policies triggered by login).

6. Confirm on the pilot Mac

  1. Log in to the pilot Mac and run the policy now instead of waiting for the next check-in:
  2. Check that the forwarder is running:
    It should print state = running.
  3. Start a new session in Claude Code and in Codex, and quit and reopen Cursor. Give each one a small task, such as running echo hello in the terminal.
  4. Write a test event:
  5. Wait five minutes. Then, on your own Mac, count the events in the bucket by agent:
    You should see each agent you used, and test_harness for the test event:
    Inventory arrives as soon as the forwarder starts. gcloud storage ls "gs://${BEACON_GCS_BUCKET}/${BEACON_GCS_PREFIX}/inventory/**" should list at least one object.
These commands use your own Google identity, which needs read access to the bucket, such as Storage Object Viewer. To read as the beacon-endpoint-reader service account instead, give yourself Service Account Token Creator on it and add --impersonate-service-account "$BEACON_GCS_READER_EMAIL" to the command. A new grant can take a few minutes to work.

7. Roll out

Widen the scope of both policies to the Macs you want covered. Each Mac installs Beacon at its next check-in. Ask people to start new agent sessions and to quit and reopen Cursor.

Rotate the writer key

  1. Create a new key as in step 2, and package it as in step 3 with --version 2 and the file name beacon-gcs-writer-key-2.pkg. Keep the same install location.
  2. Upload the new package to Jamf, and swap it for the old one in Beacon - Install so Macs that enroll later get the new key.
  3. Create a policy named Beacon - Rotate GCS key, triggered by Recurring Check-in, Once per computer, and scoped to every Mac with Beacon. Add the new key package and the Beacon - Forward to GCS script with the same parameters as before. The script restarts the forwarder with the new key.
  4. When the policy logs show that every Mac has run it, delete the old key:

Add other agents

Beacon supports more agents than these three. To add one, put its name in the --harness list in both the script and the login command, for example claude,codex,cursor,gemini. Agent Harness Integrations lists the agents Beacon supports.

Remove Beacon

Run this as root on each Mac, for example from a Jamf policy script. It removes Beacon’s LaunchDaemons, including the forwarder, /opt/beacon, Beacon’s config and logs, and Beacon’s entries in the Claude Code, Codex, and Cursor settings of every local user, whether or not anyone is logged in. Then it removes the key:
To delete the bucket and service accounts too, see Remove for Terraform. Deleting the writer service account also deletes its keys.

Troubleshooting

The output of both helpers is in the Jamf policy log. On the Mac, the forwarder’s own log is /Library/Logs/Beacon/com.beacon.endpoint.gcs-forwarder.err:
The key package didn’t install, or parameter 6 doesn’t match the path it installs to. Check the file:
It should exist with mode -rw------- and owner root.
Google rejects a brand-new key for up to a minute, and never accepts a deleted or disabled key. If the key is new, flush the policy’s log so it runs again. Otherwise create a new key and follow Rotate the writer key.
Check that the bucket and prefix in the policy match your Google Cloud setup exactly, and that the key belongs to beacon-endpoint-writer. The writer can only create objects below <prefix>/. If the bucket uses your own Cloud KMS key, the Cloud Storage service agent needs roles/cloudkms.cryptoKeyEncrypterDecrypter on it.
Beacon sets up an agent for the person logged in when the script or login policy runs. With that person logged in, run the login command by hand:
Then start a new session in the agent, or quit and reopen Cursor. sudo /opt/beacon/bin/beacon endpoint status --system should list telemetry=enabled for Claude Code and Codex CLI.
The forwarder starts at the end of the activity log, so it uploads only what happens after it starts. It uploads the whole inventory log.
That’s expected. The writer can only create objects. Read the bucket with your own identity or the reader service account.

Reference

What the policies put on each Mac: Earlier versions of this guide ran /opt/beacon/jamf/claude/gcs/repair-hooks-and-forwarder.sh. Macs set up that way keep forwarding. That helper sets up only Claude Code’s hooks and fails on a Mac where nobody is logged in, so use the script above for new rollouts.

Google Cloud Storage with Terraform

The bucket and service accounts on their own, with every module option.

Jamf Pro

Package deployment, policy scripts, validation, and Extension Attributes.

Object storage forwarding

Forward to S3, Cloud Storage, or both from one Mac.

Event schema

The fields in each uploaded event.