Skip to content

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:

DecisionWhy it cannot be defaulted
Who the members areOnly you know your team’s roles and where their checkouts live
Where the transport repository livesIt 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 usersThis changes the security model, not just the paths
What the instance is calledRelay never assumes its own name in your tree

Before you start

  • Python 3.9 or newer, and git on PATH.
  • 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:

Terminal window
python3 --version && git --version && git config user.email && pibmo-relay --version

If 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.
  • statusactive, planned, or retired. 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 refuse shared-clone here, 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. sync and flush will 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.

Terminal window
pibmo-relay-install \
--adopter-dir . \
--config team.json \
--store-dir ../project-mail

Add --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:

  1. Create and git init the transport store, on the configured branch.
  2. Create a mailbox skeleton for every member and commit it, so a member who clones the store receives their mailboxes and the roster.
  3. Write tools/<instance>.sh, a wrapper holding no machine-specific paths, so it is safe to commit and share.
  4. Write .relay/config.env with this machine’s paths (RELAY_STORE_DIR and RELAY_BIN), and add .relay/ to .gitignore.
  5. Register the SessionStart hook in .claude/settings.json, merging with whatever is already there. Pass --no-hooks to 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-dir at 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-dir at the same store directory instead — one shared store that all seats read and write. This is the natural fit for shared-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.

Terminal window
# 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 analyst

A correct install produces roughly this:

$ ./tools/team-mail.sh who
store: /home/you/code/project-mail
upstream: origin/main
topology: per-member-clone
identity: lead
roster:
* 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