Our own provenance
RepoOps publishes facts about its own public work to aisourceoftruth.com, a registry RepoOps does not run: one provenance record per merged pull request in a public sellingascode or RepoOps repository, and the head of each repository's transparency log. It never publishes customer repositories, private repositories, forks, telemetry, session content or prompt text.
Watch it
Transcript
The walkthrough is silent. These are its captions, in order. Every value it shows is illustrative.
- 0:00Never customer repositories, private ones, forks, telemetry or prompt text
- 0:06One record per merged PR in a public sellingascode repository
- 0:12The prompt leaves only as a hash, and only when it is long enough
- 0:18Every record waits for a person until its kind is trusted
- 0:24A smaller log head is refused. The log can only grow.
The values in this video are illustrative; no record has been published yet. The fields are the ones the aisot-publish command sends.
How to
The repoops publisher's credentials on the machine that runs RepoOps: AISOT_REGISTRY_CLIENT_ID, AISOT_REGISTRY_CLIENT_SECRET, AISOT_REGISTRY_KEY_ID and a signing key. Publishing is off until AISOT_PUBLISH_MODE is set.
The gh command signed in, because each pass reads the repository's visibility and its merged pull requests from GitHub.
- Turn on a dry run.
Set
AISOT_PUBLISH_MODE=dry-runandAISOT_PUBLISH_KINDS=code_provenance,log_checkpoint. A dry run logs each record and sends nothing. - Run one pass.
Run
repoops aisot-publish --repo <path>in a clone of a public sellingascode or RepoOps repository. It prints what happened per kind. A repository that is not ours, not public or a fork is skipped and says why. The nightly dream pass runs the same pass for every tracked repository. - Read what is waiting.
Run
repoops aisot-publish --list. Each queued record shows its key and the exact JSON that would go: the PR URL, the session id, the prompt hash, the reviewer, the model and the merge time. Check that no record holds prompt text. - Send what you approve.
Switch to
AISOT_PUBLISH_MODE=live, then runrepoops aisot-publish --approve <key>for one record, or--approve-all. Each line reads published with the registry link, or names why it was not sent. The gate checks every record again before it goes. - Skip the queue for a kind you trust.
After a clean dry-run week, list a kind in
AISOT_PUBLISH_AUTO_KINDSand the nightly pass sends its records without waiting for approval. A PR or a head already sent is never sent again.
Use cases
Check who wrote and approved one of our PRs
- Situation
- You read a merged pull request in a public sellingascode or RepoOps repository and want to know how it was made.
- You do
- Look the PR up on aisourceoftruth.com and recompute the artifact digest from your own clone.
- You see
- The record names the Claude Code session that wrote it, a hash of the prompt that started it and the login that approved it, kept by a registry RepoOps does not run.
Check that our transparency log was not rewritten
- Situation
- You kept a log head from an earlier day and want to know the log only grew since.
- You do
- Compare it with the latest log_checkpoint record for that repository.
- You see
- A later head has a larger size. RepoOps refuses to send a smaller head or a different root at the same size, and so does the registry.
Expected outcome
Next step: Set AISOT_PUBLISH_MODE to dry-run or live on the machine that runs RepoOps, and name the kinds in AISOT_PUBLISH_KINDS.
Next step: That is the rule working. Only public, non-fork repositories owned by sellingascode or RepoOps publish provenance, and no setting widens it.
Next step: The gate's scanner found something shaped like a key, a token, an email address or a phone number. Nothing was sent. Read the record with --list and find the field.
Next step: The new head is smaller than the last one sent, or the same size with another root. Nothing was sent. Find out why the log changed before you do anything else.
What else to consider
What never leaves
Customer repositories, private repositories, forks, telemetry, session content and prompt text. The owners are constants, sellingascode and RepoOps, and visibility is read from GitHub on every pass, so a repository that turns private stops publishing.
The prompt leaves only as the sha256 of the session's opening prompt, and only when that prompt is at least 64 characters, because a hash of a short prompt can be found by hashing guesses. The merge commit message is read for its Co-Authored-By trailer, for the model name, and is never sent.
The artifact digest
A PR's artifact is the git tree its merge commit produced. The digest is the sha256 of the JSON object with the keys commit, repo and tree, sorted, with no spaces. Anyone with a clone gets the tree with git rev-parse <commit>^{tree} and recomputes it. The tree names the whole state of the code, where the bytes of a diff depend on the tool that made it.
The private log that still publishes a head
Checkpoints also go out for RepoOps/repo-dashboard, which is private, because its name is already public as the repository of the repoops npm package. A checkpoint holds a size and a root hash, never a leaf.