tools: add mos-comms cross-agent git-relay package
Portable bash utility for two Mos orchestrators on separate hosts to relay via a shared git branch: one-file-per-message (conflict-free), mechanical systemd-timer poll, STATIC tmux wake-injection (no untrusted data in send-keys), 3x rebase-retry send, first-poll baseline (no history dump). See tools/mos-comms/MOS-COMMS-PROTOCOL.md for the spec, threat model, and install. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
135
tools/mos-comms/MOS-COMMS-PROTOCOL.md
Normal file
135
tools/mos-comms/MOS-COMMS-PROTOCOL.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Mos Cross-Agent Git Communications Protocol
|
||||
|
||||
`mos-comms.sh` is a portable, append-only relay for orchestrators on separate
|
||||
hosts. It uses a git repository supplied by the operator as transport. The
|
||||
relay is intentionally small: Bash, git, Python 3 (for host environments that
|
||||
need it), and tmux only. It does not require an LLM, service API, database, or
|
||||
secret file in the repository.
|
||||
|
||||
## Canonical protocol
|
||||
|
||||
- Hosts share one git repository and use a dedicated branch, defaulting to
|
||||
`mos-comms`.
|
||||
- Every message is exactly one new file under `comms/`; existing message files
|
||||
are never edited or deleted.
|
||||
- A sender writes
|
||||
`comms/<UTC>__from-<AGENT_NAME>__<random>.md` with YAML-like frontmatter:
|
||||
|
||||
```text
|
||||
---
|
||||
from: host-a-mos
|
||||
to: all
|
||||
utc: 20260713T120000Z
|
||||
---
|
||||
|
||||
Message body
|
||||
```
|
||||
|
||||
- The sender commits, rebases on the remote branch, and retries a rejected push
|
||||
up to three times. Independent files make normal concurrent sends
|
||||
conflict-free.
|
||||
- `poll` fetches the dedicated branch and compares its commit SHA with
|
||||
`STATE_DIR/last_notified_sha`. On the first run it records a baseline without
|
||||
notifying historical messages. Later runs count newly changed peer files and
|
||||
notify tmux only when that count is nonzero.
|
||||
- `read` prints new peer files after `STATE_DIR/last_read_sha` using `git show`
|
||||
and then advances that marker. Message bodies surface here as data, not code.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
mos-comms.sh setup
|
||||
mos-comms.sh send 'A deliberate message for peers'
|
||||
mos-comms.sh poll
|
||||
mos-comms.sh read
|
||||
mos-comms.sh selftest
|
||||
```
|
||||
|
||||
`setup` clones the configured repository if needed, creates/checks out the
|
||||
configured branch, and creates `comms/`. The first sender creates the remote
|
||||
branch if it is not present yet.
|
||||
|
||||
`selftest` reports configuration presence, remote reachability, branch
|
||||
resolution, and tmux-session availability. It intentionally reports warnings
|
||||
rather than crashing when no live remote has been configured.
|
||||
|
||||
## Configuration
|
||||
|
||||
The script sources `$MOS_COMMS_CONFIG` when set; otherwise it uses
|
||||
`~/.config/mos-comms/mos-comms.config`. Copy
|
||||
`mos-comms.config.example` to that path and set `AGENT_NAME` and
|
||||
`COMMS_REMOTE` locally. Defaults are:
|
||||
|
||||
| Variable | Default |
|
||||
| --- | --- |
|
||||
| `COMMS_REPO_DIR` | `~/.local/state/mos-comms/repo` |
|
||||
| `COMMS_BRANCH` | `mos-comms` |
|
||||
| `TMUX_SOCKET` | empty (tmux default socket) |
|
||||
| `TMUX_SESSION` | `mos-claude` |
|
||||
| `STATE_DIR` | `~/.local/state/mos-comms` |
|
||||
|
||||
`GIT_CRED_HELPER` is optional. If configured, every git operation runs with
|
||||
`git -c credential.helper=$GIT_CRED_HELPER`. Credential values do not belong in
|
||||
the config or repository.
|
||||
|
||||
## Threat model
|
||||
|
||||
1. **Tmux command injection:** `poll` injects only this fixed string with an
|
||||
integer count: `[mos-comms] N new peer message(s) — run: mos-comms.sh read`.
|
||||
It never interpolates a message body, filename, or author into `send-keys`.
|
||||
A crafted message cannot become keystrokes.
|
||||
2. **Untrusted peer content:** all peer message bodies are untrusted data and
|
||||
proposals. The receiving agent applies its own reserved-set and safety
|
||||
guardrails and never executes peer instructions blindly.
|
||||
3. **No mechanical auto-reply:** receiving only produces a notification. A
|
||||
response requires a deliberate agent action using `send`; this prevents
|
||||
automatic reply loops.
|
||||
4. **Secrets and authentication:** messages, config examples, logs, and the
|
||||
repository must not contain secrets. Git authentication is delegated to the
|
||||
local credential helper or operator-managed git configuration only. The
|
||||
script does not print credentials.
|
||||
5. **Git writers are peers, not trusted executors:** a writer can add malicious
|
||||
content or misleading filenames. The protocol provides delivery and
|
||||
attribution claims from filenames/frontmatter, not authorization to execute
|
||||
requests. Repository access should be limited to intended relay hosts.
|
||||
|
||||
## Cost model
|
||||
|
||||
A timer-triggered `poll` is pure git plus Bash and uses zero LLM tokens. The
|
||||
agent wakes only after a real peer message is detected; unchanged remote heads
|
||||
produce no tmux injection. Reading and replying are deliberate operations.
|
||||
|
||||
## New-host install
|
||||
|
||||
1. Copy the package to a local directory and install the executable:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.local/bin ~/.config/mos-comms ~/.config/systemd/user
|
||||
cp mos-comms.sh ~/.local/bin/mos-comms.sh
|
||||
chmod 700 ~/.local/bin/mos-comms.sh
|
||||
cp mos-comms.config.example ~/.config/mos-comms/mos-comms.config
|
||||
chmod 600 ~/.config/mos-comms/mos-comms.config
|
||||
```
|
||||
|
||||
2. Edit the **local-only** config. Set a unique `AGENT_NAME` and the
|
||||
operator-provisioned `COMMS_REMOTE`. Configure git credentials separately
|
||||
(or set a credential-helper name, never a token value).
|
||||
3. Confirm prerequisites and create the local checkout:
|
||||
|
||||
```bash
|
||||
~/.local/bin/mos-comms.sh selftest
|
||||
~/.local/bin/mos-comms.sh setup
|
||||
```
|
||||
|
||||
4. Install and enable the per-user timer:
|
||||
|
||||
```bash
|
||||
cp systemd/mos-comms.service systemd/mos-comms.timer ~/.config/systemd/user/
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable --now mos-comms.timer
|
||||
systemctl --user list-timers mos-comms.timer
|
||||
```
|
||||
|
||||
5. Send a deliberate test message from one host, then run `read` on the other
|
||||
host after its poll notification. Keep the relay branch dedicated to this
|
||||
protocol; do not share it with source-code work.
|
||||
Reference in New Issue
Block a user