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:
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 asbeacon-prod. Beacon adds runtime/ and inventory/ below it, so don’t put either in the prefix.
- Terraform
- gcloud
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 Review the plan and type For your own Cloud KMS key, object expiry, and other settings, see the module’s options.
main.tf in a new directory and change the project, location, bucket name, and prefix:main.tf
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:2. Create the writer key
The forwarder on each Mac signs in to Google Cloud with a key for the writer service account:created key [...]. Keep the file for step 3, and don’t commit it or share it in chat or email.
If gcloud says 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.
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: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
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
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 uploadBeaconEndpointAgent-<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
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
-
Log in to the pilot Mac and run the policy now instead of waiting for the next check-in:
-
Check that the forwarder is running:
It should print
state = running. -
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 helloin the terminal. -
Write a test event:
-
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_harnessfor 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.
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
-
Create a new key as in step 2, and package it as in step 3 with
--version 2and the file namebeacon-gcs-writer-key-2.pkg. Keep the same install location. - 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.
-
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 GCSscript with the same parameters as before. The script restarts the forwarder with the new key. -
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:
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:
Google credentials file is not readable, or must be owned by root
Google credentials file is not readable, or must be owned by root
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.Invalid JWT Signature
Invalid JWT Signature
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.
Uploads fail with 403
Uploads fail with 403
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.No events from one agent
No events from one agent
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.Activity from before the rollout is missing
Activity from before the rollout is missing
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.
gcloud storage commands fail with the writer's key
gcloud storage commands fail with the writer's key
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.
Related
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.