The boundary, with the edges named. If any of this turns out not to match what the product does, that is a bug and we want to hear about it. This page is written from the boundary the code enforces.
The path everything takes#
your agent
→ the daemon, on your machine
→ ignore rules (an excluded file is never even named)
→ redaction (secrets masked before the event exists)
→ structured events (never transcripts)
→ your workspace (readable by your workspace alone)
Every publication crosses that path. So does every read: the MCP server, which lets an agent ask for context instead of being handed it, goes through the same gate, not a second one written for the pull case.
Never, under any setting#
- Your repository is never scanned, indexed or uploaded. There is no file scanner and no repo indexer. Neither was ever built.
- Your Git history is never read. Not commits, not branches, not blame.
- A file your agent did not edit is never read. A record of a change is a record of a change.
- A file your ignore rules exclude is never named, by an edit or by a read.
- Extended thinking never crosses. The model's private reasoning is a scratchpad, and no adapter registers for the hooks that carry it.
- Unfiltered absolute paths never cross. Your home directory layout is not your team's business.
- Nothing is written to your repository. The single exception is the Git checkpoint you explicitly create when sharing work, which shows you what it will commit first.
What may cross, and what gates it#
| Thing | Crosses when | Notes |
|---|---|---|
| That a session started, in which repository, with which agent | Always, in a tracked repository | This is what makes overlap warnings possible. |
| Which files your agent edited, by relative path | Always, in a tracked repository | Excluded paths are not named. Filenames only, never contents. |
| Test runs, with pass and fail counts | Always, in a tracked repository | The command is redacted and the output is not uploaded. |
| Your prompt, word for word | What I ask is on | Secrets are masked before the event exists, in every mode. |
| The lines your agent changed | What my agent changed is on | Capped at 4,000 characters a side. |
| Your agent's visible reply for a turn | What my agent changed is on | Carried whole, with a visible mark only when it would not otherwise fit the row. |
Both switches are yours, per person. See The two sharing switches.
Your own sessions stay whole, locally#
Choosing not to share detail with teammates does not blind you to your own
work. Local detail is still written to ~/.relay/detail/, so your
sessions read in full in your own app. The switch is a choice about your
colleagues, not about yourself.
Scoping, enforced rather than promised#
A session is readable by its author's workspace and nobody else, enforced in the database by row-level security rather than by application convention. Every table is workspace-scoped through the same helper, and a table without a policy does not ship.
Counts are reported after the gate#
A small thing that says a lot about how this is built. When a search reports how many records it looked at, that number is computed after the gate has run. "1 record was searched" over a record being withheld would confirm that something exists behind the hold, which is the fact the hold exists to keep.
Where secrets are handled#
On your machine, before the event exists. The redaction list is shared by the daemon and the app from one source, so what the UI marks as redacted and what the daemon strips cannot drift apart.
You can prove this in about ten seconds without publishing anything:
$ echo '{"hook_event_name":"UserPromptSubmit","prompt":"key is sk-ant-xxxx"}' \
| DRY_RUN=1 node ~/.relay/daemon/hooks/claude.js
DRY_RUN=1 prints what would have been published, to stderr, and
writes nothing. The key comes back masked.
What Runi does not know#
Worth being clear about, because it changes how you should read an empty result. Runi knows the sessions it observed and what their authors chose to share. It has no view of your codebase, your issue tracker, your chat or your commits.
An empty search result means Runi has nothing on the subject. It never means nothing happened.
Removing what you have shared#
One entry, one session, or the whole workspace, at any time, and it is gone rather than hidden. See Deleting your data.