- A
verifieragent persona in your tenant catalog that encodes the verification discipline. - A GitHub Actions workflow that runs one persistent verifier per PR — spawned on open, re-driven on every push, killed on close — using the composite actions at
prassoai/murmur-actions.
Why a verifier, not another test job
A test suite asserts intent; a verifier confirms reality. The persona’s core rules:- Exercise, don’t inspect. Reading the diff and concluding “looks right” is not verification. The verifier brings up the real system and drives the actual behavior a user or caller would see.
- One verdict. Every run ends in exactly one of three verdicts —
CONFIRMED CORRECT,CONFIRMED INCORRECT, orNOT LOCALLY TESTABLE— never “probably works.” - Evidence or it didn’t happen. A verdict carries the commands, inputs, and outputs that prove it, so anyone can re-run the steps and see the same thing.
- One comment per PR. The verifier upserts a single marker-tagged comment instead of stacking a new comment on every push.
How it works
The workflow maps PR lifecycle events onto one long-lived agent with a stable slug,verify-<repo-id>-pr-<number>, built from the repository ID and the PR number:
Cancelling a superseded verification lives in the agent (via preempt), not in CI job concurrency. The CI jobs stay thin calls that return in seconds; the long-running work is the agent’s. Because the agent persists, it keeps its context across commits and updates one verdict comment in place.
Prerequisites
- A workspace whose repos include the repository you want verified — the agent checks out the PR head inside its VM. See the admin quickstart.
- Permission to create a service profile and API key in your organization, and admin access to the GitHub repository (to add a secret and the workflow file).
Step 1: Author the verifier persona
The persona is the standing discipline — verdict rules, evidence rules, boundaries — plus the project-specific knowledge of how to bring your system up. Create it withmurmur set agent-persona, piping Markdown with YAML frontmatter:
NOT LOCALLY TESTABLE verdicts you get.
The persona holds the reusable discipline; the per-PR facts (PR number, head SHA, which comment to upsert) arrive in the spawn prompt from the workflow in step 3. Editing the persona affects future spawns only — see agent persona lifecycle.
murmur get agent-persona verifier.
Step 2: Set up credentials
The workflow authenticates to Murmur with a service profile API key, so verifier runs belong to a bot identity rather than a person.- Create a service profile (e.g.
pr-verifier) — see Create a service profile. - Create an API key against that profile — see API keys. The key is shown once, in the form
mur_…. - Store the key as a repository (or organization) secret named
MURMUR_API_KEY:
Step 3: Add the workflow
Create.github/workflows/verify-pr.yml in the repository. Replace my-workspace with your workspace name, and adjust the numbered protocol in the prompt to your project:
The slug uses
github.event.repository.id because it works for any repository: the ID is unique and stable across repositories, needs no per-repository editing — the same file drops into every repository unchanged — and, because it is numeric, always satisfies the slug grammar ^[a-z][a-z0-9-]{0,62}$ (start with a lowercase letter; lowercase letters, digits, and hyphens only; max 63 characters). If you prefer the more readable github.event.repository.name, it works only when the repository’s name already fits that grammar — names like socket.io, my_project, React, or 2048 produce an invalid slug and the spawn fails. If your name doesn’t fit, sanitize it or keep the ID.murmur spawn, murmur queue add --preempt, and murmur kill you can run by hand. Their full inputs and outputs are documented in the murmur-actions repository.
Six details in the workflow are worth understanding before you adapt it:
- The slug carries a repository discriminator. A slug identifies the agent within the workspace, not within the repository, and PR numbers repeat across repositories — with a bare
verify-pr-42, two repositories in one workspace would resolve their PR #42 events to the same agent. The repository ID keeps the slugs distinct however many repositories share the workspace, and thepurposefield keeps the human-readable repository name visible on the dashboard. - The same-repo gate. Every job requires
github.event.pull_request.head.repo.full_name == github.repository. Fork PRs receive no repository secrets, so on a fork runMURMUR_API_KEYis empty and every call fails — the gate keeps fork events from running the jobs at all. Because a fork PR never spawns an agent, it also has nothing to re-verify or tear down. needs: reverifywithalways(). Thespawnjob waits onreverifyso the synchronize recovery path can read itsdeliveredoutput.always()keepsspawnrunning on open/reopen, where the synchronize-onlyreverifyjob is skipped.- The concurrency group drops stale pending runs — safely. GitHub queues at most one pending run per concurrency group: with
cancel-in-progress: falsea running job always finishes, and when a newer event arrives while another run is already pending, GitHub cancels the older pending run and the newer one takes the pending slot. The newest event always survives, and the jobs are shaped so a dropped older event never matters: a re-verify is latest-wins by design, a pending spawn displaced by a re-verify is recovered through the deliver-or-spawn path, a pending teardown displaced by a reopen is covered byforce-new: "true", and the kill tolerates an agent that is already gone. - The prompt is the single source of per-PR truth. PR-context values flow through the action’s
with:inputs — never a runner shell step — so a PR-author-controlled value like a branch name cannot inject script into the CI job. The prompt’sghsnippet runs later, inside the agent, not on the runner. - The verdict comment carries
<!-- MURMUR_IGNORE -->. Murmur delivers PR comments to subscribed agents as events; a comment whose body contains this marker wakes no agent. Stamping it on the verdict keeps the verifier’s own machine-generated comment from arriving as apr_commentfollow-up to an agent working the PR. It is separate from<!-- pr-verifier -->, which the upsert step searches for.
Step 4: Pin the actions to a commit SHA
Thespawn, reverify, and teardown jobs all carry MURMUR_API_KEY, so follow the standard practice for secret-bearing jobs: pin uses: to a full commit SHA rather than a moving tag or branch, so the action code your jobs run only changes when you change it. Look at the murmur-actions repository and pin its head commit, keeping a trailing comment naming the ref you resolved (# murmur-actions main) so the human-readable version stays visible.
Resolve the head commit:
uses: lines, and bump it deliberately when you want to roll the actions forward.
Open a pull request
Push the workflow, then open a PR against the repository. On open, thespawn job returns within seconds and the agent appears on your dashboard as verify-<repo-id>-pr-<number>. When it finishes, the PR carries one comment:
murmur ls.
Between commits the agent sleeps rather than terminating. You can talk to it like any other agent —
murmur queue add to ask it to re-check something, murmur status to see what it’s doing.