What’s recorded
One Execution Profile, four surfaces. Jibril, an eBPF sensor, runs alongside your workflow and records process and network activity at the kernel. It captures the process paths that led to each outbound connection, with the workflow step attributed where the runner exposed one.Reading the comment
The screenshot below shows the public comment Garnet posted on garnet-labs/ghaw-garnet-reference#8, with the CI / test job fold open.![Screenshot of the public comment Garnet posted on garnet-labs/ghaw-garnet-reference#8, with the CI / test job fold open to show node reaching storage.googleapis[.]com and the runner tree](https://mintcdn.com/garnetlabs/w2ENCdJ_5q3T906z/images/comment-ghaw-8-open.png?fit=max&auto=format&n=w2ENCdJ_5q3T906z&q=85&s=e1a6102b657802f8ea18eefb0546dbb2)
1 of 1 recorded job changed · 1 new on the runner, outside your steps; node newly reaches storage.googleapis[.]com compared with the PR base main. Runner and GitHub traffic is shown in its own tree and never counts toward workload change. Marker counts mirror rendered +/− workload rows, including removals. Capture is marked best-effort.
Top to bottom:
- Verdict and counts — the heading names the state; the count line names recorded jobs that changed.
- Comparison — one line names the head and comparison source.
- Capture — the comment states whether capture is best-effort or complete.
- Jobs — each job has one fold with workload, then runner and GitHub traffic, followed by the job log and public record.
- Footer — a
How to read thisfold andRecorded by Garnet · Add it to your CI ↗.
How the comparison is chosen
For each recorded job, the baseline is the union of its last 10 recorded runs on the base branch. If fewer runs exist, Garnet names how many it used. With fewer than two, Garnet uses the PR base alone. If the base has no record, Garnet uses the previous push only when that commit belongs to the pull request. A destination counts as new only when no baseline run reached it. Removals never count: a destination present in every baseline run is shown as a− row with that history, and one present in only some runs is annotated with its count. Runner and GitHub traffic never counts toward workload changes. Workflow step labels place chains but are not displayed.
In the #8 example the comment names its comparison: the PR base main.
Attribution
The tree separates your workload from the machinery around it, structurally:
Names, domains, and IPs never classify. Only structure does.
Bracket context
Bracket context
(github infra) marks a GitHub Actions infrastructure host. (Cloud IMDS) marks the cloud metadata address. On a − row, (reached in all of the last N main runs) means a host every baseline run reached and this run did not. (K of the last N main runs) marks an unmarked host reached in some baseline runs. Step labels place chains but are not displayed. Loopback is not shown. Every other name and address renders exactly as recorded, in code.Bold marks a changed job’s row title.
+ and − mark tree rows: + appears only in this commit, − only in the compared run, and an unmarked row appears in both. Recorded strings are in code. Attribution is structural. See Consume the Runtime Review.One comment per PR
One sticky comment, updated in place on every push and as each job’s profile lands, pinned to the head commit it records. The action logs any errors it catches as warnings rather than failing your job. The action records the run.What Garnet sees
GARNET_API_TOKEN is the only repository secret you provision on the token path. With GitHub OIDC (id-token: write, no api_token), there is none. The action also takes github_token, which GitHub supplies as ${{ github.token }} without you storing anything. The action reads no other entry in secrets and never writes to your repository.
- Metadata, not contents — the fields an Execution Profile is built from are execution chains and the destinations they reached: process names, the recorded step, the working directory, domains, IPs, ports, and protocols. It is not a copy of your source, your environment, or your files. Full field list: Security and permissions.
- Observe-only — Jibril reads kernel events rather than modifying them; its eBPF programs pass the kernel verifier before they load. The sensor is not only eBPF: it installs with
sudoand runs as a root systemd service alongside your job. - No pipeline changes — no sidecars, no proxies, no reordering of your steps. On any error the step logs a warning and the job continues.
Why sudo
Why sudo
Attaching eBPF programs requires root, so the install runs under
sudo and the sensor runs as root. ubuntu-latest runners include sudo by default.The public run report
Every job’s permalink opens a stable report page for as long as the record stays published:![Public Execution Profile report showing runtime behavior changed: node newly reaches storage.googleapis[.]com](https://mintcdn.com/garnetlabs/w2ENCdJ_5q3T906z/images/public-run-report-ghaw-8.png?fit=max&auto=format&n=w2ENCdJ_5q3T906z&q=85&s=f36a7da77792b1491a0969f99c2258cd)
The public report for the same job as the posted #8 comment: compared with the PR base main, node newly reaches storage.googleapis[.]com. Open the public report.
?profile=<profile-id>is required and exact. Only a published(run, profile)pair resolves; a wrong or missing selector is a 404, never a silent fallback. Use the published report’s permalink. The stable action’sreport_urloutput is a dashboard link, not this public URL.- There is no run index. Bare
/public/runs/<run-id>— or a?job=query — is the same 404. - A 404 is the same response whatever the reason, so it says nothing about whether a profile exists. What is verified here is the selector contract: a published
(run, profile)pair resolves anonymously, and a bare or wrong selector does not. Which records are published, and how publication is granted or withdrawn for a repository, is controlled in the Garnet dashboard, not by this URL shape. - The page’s canonical and
og:urlare the selector URL, and its copy-link button hands back that URL without theutm_campaign parameters.
app.garnet.ai/api/public/runs/<run-id>?profile=<profile-id>, same selector rules. It is the fuller of the two published views: the rendered comment leaves out fields the JSON carries, PIDs among them. Machine consumption is a preview; the supported path today ends at this report and the comment.
README badge
A published Execution Profile can back a Garnet Runtime Profiled badge. The badge says the run was recorded, links to the report, and carries no verdict:?profile= is the same 404 as any other bare run URL.
Next: Quick start · Consume the Runtime Review (preview)