Guided install
This page is written to be read by an AI coding agent. You do not follow it yourself; you hand it to a coding session running in your repository, and the session interviews you, writes the configuration, runs the installer, and checks that mail actually flows.
Point your agent at this page
Open a coding session in the repository you want to adopt Relay, and give it this instruction:
Set up Pibmo Relay in this repo by following https://pibmo.com/relay/onboarding/.The session will fetch this page and work through it top to bottom, asking you the questions in section 2 one at a time. The rest of this page is addressed to that session.
If you are an agent reading this: follow it top to bottom. Ask the questions in section 2 one at a time, in order, and wait for an answer before moving on. Do not guess an answer you were not given. Do not run the installer until section 4. Everything you need to decide is a question to the human, not a default you may choose for them.
A human can also follow this page by hand. It is the same sequence either way.
1. What you are setting up
Relay carries addressed, read-tracked mail between agent sessions over a git repository. Setting it up means deciding four things:
| Decision | Why it cannot be defaulted |
|---|---|
| Who the members are | Only you know your team’s roles and where their checkouts live |
| Where the transport repository lives | It must sit outside your product repository, and whether it has a remote at all depends on how your team works |
| Whether members are separate operating-system users | This changes the security model, not just the paths |
| What the instance is called | Relay never assumes its own name in your tree |
Before you start
- Python 3.9 or newer, and
gitonPATH. - A git identity configured (
git config user.email), because the installer makes a commit. - Install the package:
pip install pibmo-relay.
Check all of it at once:
python3 --version && git --version && git config user.email && pibmo-relay --versionIf pibmo-relay is not found after installing, your Python scripts directory is
not on PATH. See Troubleshooting.
2. The interview
Ask these in order. The answers become team.json.
Q1. What should this instance be called?
It becomes the command your team types, as tools/<name>.sh. Something like
team-mail, crew, or desk. Relay hard-codes nothing about its own name.
Q2. Who are the members?
For each member, collect:
- role — the address other members send to. Lowercase, no spaces
(
lead,analyst,web). This is a mailbox name, not a job title. - persona — optional human-readable name, purely routing shorthand.
- checkout_path — the absolute path of that member’s working copy. Strongly recommended: it is the only unambiguous way a session can tell which member it is. Without it, Relay guesses from the directory name and refuses to guess when the answer is ambiguous.
- status —
active,planned, orretired. Planned members can receive mail; retired members cannot be addressed.
Q3. Are the members separate operating-system users?
This is a security question, so ask it plainly and do not infer the answer from the paths.
- No, all checkouts run as one OS user (the common case: several directories
under one login). Either topology works. Use
per-member-clone. - Yes, each member is a separate OS user, so credentials are isolated. You
must use
per-member-clone. Relay will refuseshared-clonehere, because the directory permissions that make a shared clone work are exactly the permissions that let one user read and write another’s mailbox.
Record os_user per member if the answer is yes. The security reasoning behind
this question is in Topologies and the security model.
Q4. Where should the transport repository live, and does it need a remote?
Two separate questions. Ask both.
Location. It must be outside every product repository. Mail is committed
and pushed, so a store inside your project would put agent chatter into your
project’s history and push it to your default branch. The installer refuses this
outright. A sibling directory is the usual answer: for a project at
~/code/myproject, the store goes at ~/code/myproject-mail.
Remote. Ask the human directly, because both answers are legitimate:
- No remote (local only). Everything runs on one machine. Mail is committed
locally and never pushed. Simplest, no network, no hosting. This is a real
supported mode, not a degraded one.
syncandflushwill report that no remote is configured, which is expected. - A shared remote. Members are on different machines, or you want the mail history backed up and clonable. You need a git repository URL that every member can push to. It should be private: a clone contains every message.
If they choose a remote, also ask what its default branch is called. Not every
repository uses main, and Relay will not assume.
Q5. Should sessions be told about new mail automatically?
Recommended: yes. The installer writes a SessionStart hook so each session
opens with a banner listing unread mail. Without it the transport still works,
but mail sits unread until someone thinks to check, which is the failure mode
this whole system exists to prevent. See Host integration.
3. Write the configuration
Produce team.json in the adopting repository from the answers. A worked
example for a three-member team on one machine with no remote:
{ "instance_name": "team-mail", "topology": "per-member-clone", "members": [ { "role": "lead", "persona": "Ada", "status": "active", "checkout_path": "/home/you/code/project-lead" }, { "role": "analyst", "persona": "Grace", "status": "active", "checkout_path": "/home/you/code/project-analyst" }, { "role": "web", "status": "planned", "checkout_path": "/home/you/code/project-web" } ]}With a shared remote whose default branch is trunk, add:
{ "remote": "origin", "branch": "trunk"}Show the human the file and get confirmation before running anything.
Full key-by-key documentation: Configuration reference.
4. Run the installer
The interview configures; this script installs. Everything from here is deterministic and re-runnable.
pibmo-relay-install \ --adopter-dir . \ --config team.json \ --store-dir ../project-mailAdd --remote-url git@github.com:you/project-mail.git if the team chose a
remote in Q4. Omit it entirely for local-only. If you omit --store-dir, the
installer defaults to a sibling directory named <repo>-mail.
The installer will:
- Create and
git initthe transport store, on the configured branch. - Create a mailbox skeleton for every member and commit it, so a member who clones the store receives their mailboxes and the roster.
- Write
tools/<instance>.sh, a wrapper holding no machine-specific paths, so it is safe to commit and share. - Write
.relay/config.envwith this machine’s paths (RELAY_STORE_DIRandRELAY_BIN), and add.relay/to.gitignore. - Register the
SessionStarthook in.claude/settings.json, merging with whatever is already there. Pass--no-hooksto skip this step.
Re-running it with the same configuration reports that nothing changed. If it refuses because the store would sit inside the adopting repository, that is the guard in Q4 doing its job; pick a location outside the repo.
Repeat for each member’s checkout
How this works depends on whether the team has a remote:
- With a shared remote (
per-member-clone): run the same command in every member’s working copy, pointing--store-dirat that member’s own clone of the store. Each member has their own clone and they synchronize through the remote. The first member’s install publishes the store to the remote; every later member’s install clones it. - On one machine with no remote: there is nothing to synchronize through,
so separate clones would never see each other’s mail. Point every checkout’s
--store-dirat the same store directory instead — one shared store that all seats read and write. This is the natural fit forshared-clone; the worked example above uses no remote, so its checkouts must share one store.
In short: separate clones need a remote to exchange mail; a single-machine team with no remote shares one store directory. See Topologies & Security.
5. Verify it works
Do not report success until these pass.
# 1. Identity resolves to the right member in this checkout../tools/team-mail.sh who
# 2. A message goes out../tools/team-mail.sh send --from lead --to analyst \ --type request --subject "Setup check" --body "Reply if you can read this."
# 3. It arrives, from the other member's checkout../tools/team-mail.sh list --role analystA correct install produces roughly this:
$ ./tools/team-mail.sh whostore: /home/you/code/project-mailupstream: origin/maintopology: per-member-cloneidentity: leadroster: * lead active Ada analyst active Grace
$ ./tools/team-mail.sh send --from lead --to analyst \ --type request --subject "Setup check" --body "Reply if you can read this."sent 5a253779-... lead -> analyst [request] "Setup check"
$ ./tools/team-mail.sh list --role analyst[unread ] from=lead 2026-07-21T09:52:59Z "Setup check" (5a253779-...)who printing identity: (unresolved) means this checkout could not be matched
to a member. Set checkout_path for that member and re-run the installer, or
export RELAY_ROLE.
Then start a fresh agent session and confirm the banner appears. If it does not, see Host integration.
6. Tell the team what it does not do
Say this out loud to the human before you finish, because it is the property people most often assume backwards:
Relay provides addressing and read-tracking. It does not provide confidentiality between members. The transport is a git repository, git has no path-level access control, and any member who can clone it holds every message ever sent, including those addressed to someone else. Sender names are self-asserted and are not authenticated.
Under isolated operating-system users you additionally get credential and compute isolation. That is isolation of members from each other’s machines, not of messages from other members.
If a team needs per-member message confidentiality, a git-native transport is the wrong architecture and no configuration of Relay will provide it. The full security model is in Topologies and the security model and Architecture.
Where to go next
- Overview — what Relay is and why it exists
- Getting started — the shortest path to a first message
- Core concepts — members, roles, mailboxes, and the store
- Configuration reference — every
team.jsonkey - CLI reference — every command and flag
- Topologies and the security model
- Host integration — the session banner and mail escalation
- Troubleshooting
- FAQ