Skip to main content

Overview

beacon-sandbox is a testing tool for Beacon contributors. It starts a throwaway Linux machine in the cloud, installs your local Beacon build on it, runs a real Claude Code session inside it, and then checks whether Beacon recorded what the agent actually did. You would use it when you have changed something about how Beacon captures telemetry and you want proof that it still works against a live agent — not just that the unit tests pass. Nothing runs on your own machine, so your local Beacon setup is untouched, and the machine is destroyed when the test finishes.
This is a tool for working on Beacon. It is not part of Beacon itself, it is not included in any release, and installing Beacon does not install this. Beacon’s own telemetry collection stays local and offline as always.

Why A Sandbox Instead Of Unit Tests

Beacon’s unit tests feed it example telemetry and check the output. That catches a lot, but it cannot answer the question that matters most: when a real agent runs a real command, does Beacon record it? Real agents produce messier telemetry than any handwritten example. A field can quietly stop being filled in, and every unit test still passes because none of them ever saw what the live agent actually sends. The catch is that AI sessions are not repeatable. Ask an agent to run a command twice and you get two slightly different sessions, so there is no fixed expected output to compare against. The tool works around this with markers rather than exact comparison:
  • Each test puts a random one-off string into the prompt, then checks that string appears in Beacon’s log. Since the tool invented the string, a match cannot be coincidence.
  • The agent is also asked to write that string into a file. If the file is there, the agent definitely did the work — so if Beacon has no record of it, that is Beacon’s problem and not the model having a lazy day.
That second part is what makes the results trustworthy. Without it, “Beacon missed the event” and “the agent never ran the command” look exactly the same.

Before You Start

You need two accounts, and neither can be set up for you: You also need Go installed, and you should be working inside a clone of this repository.

Setup

1

Install and sign in to Modal

modal token new opens your browser to sign in, then saves credentials to ~/.modal.toml. You only do this once.
2

Provide your Anthropic API key

The simplest way is an environment variable. See other options if you would rather not put it there.
3

Run the setup check

doctor looks at everything else the tool needs and tells you exactly what to do about anything missing. --fix downloads what it can for you.
One-time setup
When everything is ready, doctor finishes with the command to run next:
If something is missing, doctor prints the fix beside it. Run the fix, then run doctor again.
doctor is worth running any time a test behaves strangely. Most confusing failures turn out to be a missing or outdated build artifact, and it will tell you.

Keeping Your API Key Out Of Your Shell

Three ways to supply the key, in the order the tool looks for them: To create the Modal secret: modal secret create my-anthropic-key ANTHROPIC_API_KEY=sk-ant-...
The Modal secret option keeps the key furthest from your machine, but it comes with one small trade-off: because the tool never sees the key itself, it cannot double-check that the key never leaked into the collected logs. It will say so in the results rather than quietly skipping that check.

Your First Test

Build Beacon for Linux, then run a single test:
Run one test
This takes about three minutes and costs a few cents. You will see the sandbox start, the agent session run, and then a result:
PASS means Beacon recorded everything this test looked for.

Understanding The Results

Every test ends in one of three states: A FAIL tells you which expectation broke and why that expectation exists:
Read it from the top. The agent demonstrably did the work, so the missing event is a real gap. The event counts then hint at where it went — seven events landed under a different name, which points at a labelling problem rather than a dropped event.

Warnings Mean “Could Not Check”

Alongside pass and fail, you may see [WARN] lines. These are not failures, but they are not clean results either — each one means a check could not run: If you are reporting results to someone else, mention these. Silence from this tool is meant to mean “checked and clean”, so a warning is worth passing on.

A Failure Is Not Always A Beacon Bug

Tests encode what Beacon should do. When Beacon’s behaviour legitimately improves, an old expectation can become out of date and start failing. Before concluding you have found a bug:
  1. Read the failing expectation’s why and compare it against the event counts in the output. Did the event move somewhere else rather than disappear?
  2. If your change touched collector-builder/, check that you rebuilt it — see the warning below.
  3. Only then treat it as a gap in Beacon.
If your change is in collector-builder/, rebuild it before testing. Telemetry processing lives in a separate binary from the beacon command, so a test run will happily use an older copy and pass without ever exercising your change. doctor warns about this, and it is the single most common way to waste a test run.

The Tests You Can Run

Use one test while you are iterating. Run all of them before opening a pull request.

Commands

verify is worth knowing about. Every run saves its output under runs/, and verify re-checks that saved output without starting a sandbox or calling the API. If you are adjusting what a test expects, use verify rather than paying for another run.

Writing Your Own Test

Tests are YAML files in beacon-sandbox/scenarios/:
A minimal test
  • {{canary}} becomes the random one-off string for that run. {{sentinel}} and {{workdir}} are also substituted.
  • sentinel is the file the agent must leave behind. It has to contain the canary, so a file created by setup does not count.
  • why is required on every expectation — a failure nobody can interpret is not useful.
  • optional: true records an expectation without failing the run, for something known to be missing.
Check your file without spending anything:

Checking That The Checks Work

A test that cannot fail is worse than no test, so you can deliberately damage a saved run and confirm the tool notices:
Confirm a PASS can become a FAIL
Other options are drop-commands, drop-action:<action>, and plant-secret. Each should turn a PASS into a FAIL. The tool’s own unit tests do this automatically and need no accounts, no API key, and no cost:

Limitations

Modal only provides Linux machines, so this cannot test the macOS build. Anything macOS-specific — launchd, the signed installer, notarization — is out of reach.
  • It tests one collection path. Specifically the temporary-collector path Beacon uses in CI and cloud agents, not a permanently installed Beacon.
  • It checks presence, not completeness. It confirms the thing it planted was recorded. It cannot tell you whether Beacon missed something it never knew to look for.
  • Linux x86 only. Modal does not offer a choice of processor architecture.
  • It costs money and takes minutes. Each test is a real API session.
  • Occasional flakiness is normal. Telemetry arrives asynchronously, so the tool waits for activity to settle rather than a fixed delay. Use --repeat 3 to tell a flaky result from a broken one.
  • The agent version is pinned. Claude Code’s behaviour changes between releases, so the sandbox installs a fixed version. Updating it is a deliberate change.

Contributing

Building Beacon, running the test suites, and opening a pull request.

Validate a local install

Checking Beacon on your own machine, rather than testing Beacon itself.

beacon ci exec

The collection path these tests exercise.

Event schema

The fields tests can check.