Command overview
beacon git records which agent sessions produced a commit, as a git note on the commit.
Command syntax
beacon git setup installs hooks so every new commit in the repository is linked as it is made. beacon git link links one commit by hand, which is also how to link commits made before setup.
A link names a session by its harness and session id, for example beacon:claude_code/0f8e2c1a-…. The note carries identifiers only, never prompts, output, or diffs: notes can be shared with a remote, and the session’s content stays in the local runtime log. beacon handoff export <session-id> reads a linked session back.
How sessions are matched to a commit
Beacon already records every file a supported runtime writes, so matching a commit to its sessions is a read of the local runtime log. No state file is kept and nothing touches the network.- Window. Beacon reads the log from the parent commit’s time up to the commit. The window always covers at least
--min-lookback(2 hours) and never more than--max-lookback(24 hours) before the commit. Events after the commit are ignored, because they cannot have produced it. - Evidence. A session wrote a file when the log has, for that session, a
file.created,file.modifiedorfile.deletedevent, a tool event whosefile.operationis a write, a shell command whose target is plain to read (rm,mv,cp,install,ln,touch,truncate,tee,sed -i,perl -pi,git mv,git rm, output redirection), or anapply_patchenvelope. Reads do not count, and neither does a path that depends on a variable, a glob or a command substitution. - Overlap. Beacon compares those paths with the files the commit changes, counting both sides of a rename. A session that wrote at least one of them is linked. Sessions are ordered by how many of the commit’s files they wrote, then by how recently.
git pull links nothing.
A link is an inference, not an observation. A session that edited a file a person then rewrote by hand is still linked, and a session that wrote nothing the commit kept is not.
beacon git setup
Installs Beacon’s git hooks in the current repository.
Example output
- post-commit links the new commit, exactly as
beacon git linkwould. It reads the local runtime log and writes a git note, typically in tens of milliseconds, and gives up after three seconds rather than hold a commit, recording in the runtime log that it did (see below). It never prints, never touches the network, and never fails a commit. - post-rewrite runs after
git commit --amendandgit rebaseand tidies the note on each rewritten commit, folding the note git copied from the old commit into the one the post-commit hook just wrote. notes.rewriteRefmakes git copy a commit’s links to the commit that replaces it when you amend or rebase.
notes.rewriteRef.
A hook already in place keeps working. Beacon writes its own beacon-post-commit and beacon-post-rewrite scripts and adds a short marked block to the top of the hook that calls them, so a hook ending in exit 0 still runs Beacon’s part. Only shell hooks are edited: if the hook is another language, setup stops and prints the line to add yourself. The scripts call Beacon by the absolute path it had at setup and fall back to beacon on PATH, so a GUI git client without Beacon on its PATH still links commits.
Hooks live in the repository’s shared hooks directory, so one setup covers every linked worktree.
Set
BEACON_GIT_HOOKS=0 to skip the hooks for one command:
Hook managers and core.hooksPath
Tools such as husky and lefthook point core.hooksPath at a directory they own, often one tracked in the repository. setup refuses to write there by default and prints the line to add to that tool’s post-commit hook instead:
--hooks-path to install into that directory anyway.
beacon git status
Shows whether each hook is installed, reports an install that is broken (a hook calling a script that is gone, or the reverse), and says whether notes.rewriteRef is set. The overruns line counts this repository’s hook runs that ran out of time in the last seven days, how many of them were cut short, and the most recent. --json prints the same as JSON, with a top-level installed field and the counts under budget_overruns.
Sharing links with a team
Links start out local. Nothing leaves the machine until you share them, and sharing is off unless you turn it on.- Fetching. Each remote gets a fetch refspec,
+refs/notes/beacon:refs/notes/beacon-remotes/<remote>, so a plaingit fetchorgit pullbrings teammates’ links into a read-only copy.beacon git notesreads that copy alongside your own links. Yourrefs/notes/beaconis never overwritten by a fetch, so links you have not pushed yet are safe. A fetch or pull that names a refspec on the command line, such asgit pull origin main, skips configured refspecs; runbeacon git notes fetchto fetch links then. - Pushing. A
pre-pushhook shares your links whenever yougit push. It fetches the remote’s links, merges them with yours (every line of both is kept), and pushes onlyrefs/notes/beaconto the same remote. It runs with--no-verify, so your other pre-push hooks are not run twice. It gives up after ten seconds and never fails your push: if sharing fails, it prints one line and your code is pushed as usual.
BEACON_GIT_HOOKS=0 git push skips it for one push, and beacon git setup --share-notes=false turns it off.
To share by hand instead, without the hook:
beacon:<harness>/<session-id> lines, optionally followed by the session’s share URL, so sharing a link shares that a session produced the commit (and, when the session was shared, where its trace is), not what happened in it. The session itself stays in the runtime log of the machine that ran it.
Share URLs in notes
A note line can also carry the share URL of a session that was shared to beacon.sh, after the session (beacon:<harness>/<session-id> <url>). Beacon takes these URLs only from local session.shared events in the runtime log, so writing them never touches the network, and it writes or shows only https URLs on beacon.sh or on the Beacon service the CLI is configured for: a note can come from anyone who pushes to the remote, so a URL on any other host is ignored and the link is shown without it. beacon git notes prints the URL after the session, and --json includes it as url.
setup --share-sessions goes further and has the pre-push hook share the sessions linked to pushed commits (at most 100 commits and 10 sessions per push, within the hook’s ten seconds, never failing the push) and write their URLs into the notes. It is off by default, uses the same beacon login sign-in or BEACON_API_KEY as beacon share, shares nothing without one, and is stored in the clone’s own git config (beacon.shareSessions, beacon.shareVisibility). Session sharing is a beacon.sh feature, documented at docs.beacon.sh.
beacon git remove
Removes Beacon’s scripts, its blocks in the hooks, its notes.rewriteRef value, and the fetch refspecs --share-notes added, leaving everything else as it was. A hook that held nothing but Beacon’s block is deleted. Links already written stay in refs/notes/beacon.
beacon git link
Links a commit (default HEAD) and writes the note.
Example output
link again adds only what is new. Links already on the commit, including a teammate’s, are kept, as is any other text in the note.
beacon git notes
Lists recent linked commits reachable from a revision (default HEAD).
Runtime log events
Each new link is also recorded in the runtime log as asession.commit_linked event in the linked session’s own timeline, so the dashboard, beacon endpoint traces, handoff briefs, rules and any forwarding destination see the commit alongside the work that produced it. link and the hook record an event only for a link they add: a dry run, or a commit already linked to the session, records nothing.
Example event (abridged)
event.fidelityisinferred: the link is Beacon’s conclusion from file overlap, not something the runtime reported.vcs.ref.head.nameis the branch HEAD was on at commit time. It is empty for a detached HEAD, or for an older commit linked by hand, whose branch git cannot say.vcs.repository.url.fullis the URL of the remote the branch tracks, ororigin, with any user name, token, or query string removed.- The event carries identifiers and counts only: no file paths, diff, or commit message.
main that one session wrote in full:
Hook runs that run out of time
The hooks hold up a command a person is waiting on, so each gives up when its budget runs out: three seconds for post-commit and post-rewrite, ten for pre-push. Giving up is silent on the terminal, and a post-commit hook that gives up leaves the commit unlinked. So each run that runs out of time writes onegit.hook_budget_exceeded event to the runtime log.
Example event (abridged)
vcs.hook.phaseis the step the hook was in when its time ran out. Post-commit runsopen_repository,attribute(reading the runtime log and writing the note) andrecord_link_event; post-rewrite runsopen_repositoryandnormalize_notes; pre-push runsopen_repository,share_sessions(with--share-sessions) andpush_notes.vcs.hook.elapsed_msis the whole run andvcs.hook.phase_elapsed_msthe part of it spent in that phase, so a slow earlier step shows as the difference. Pre-push holds its share phase to six of its ten seconds, so a share phase that runs out records an elapsed time under the budget.vcs.hook.git_spawnsis how many git processes the run started. Each costs a few milliseconds on macOS and Linux, and can cost far more on a Windows machine that scans every new process.vcs.hook.cut_shortis true when running out of time left work undone: a commit left unlinked, a link event, note or share URL left unrecorded, or the notes ref left unpushed. It is false for a run whose last step finished after the deadline, which is recorded asinforather thanlow.repositoryis empty when the hook ran out before it could resolve the repository.
beacon git status counts these events for the repository, and beacon endpoint doctor for every repository. A commit left unlinked can be linked with beacon git link <commit>.
Note format
Links live underrefs/notes/beacon, one per line:
<harness> is Beacon’s canonical harness name (claude_code, codex_cli, cursor, …). A session id has no whitespace, no control or non-ASCII characters, and at most 256 characters. The first field after whitespace is the session’s share URL when it is an allowed https URL (at most 512 characters); anything else after whitespace is reserved for later fields and ignored. Lines that do not start with beacon: are ignored. When the same link appears with and without a URL (two people’s notes merged), the line with the URL is kept.
Beacon updates the note with a compare-and-swap on the notes ref, so two commits made at the same moment in two worktrees of one repository never lose each other’s links.
To see links in git log, including those fetched from remotes: