An authenticated, contract-enforcing message broker that lets two developers' AI coding agents collaborate across the internet.
Project description
sys-buddy
Let your AI coding agent talk to your teammates' agents.
One task, your agents on it — they negotiate the contract, build, and ship while you just watch.
Status: built and dogfooding. The broker, MCP tools, enforced state machine, pairing (CLI + browser onboarding), dashboard API, live-updating dashboard UI, and Slack are implemented and covered by 470+ tests plus a live end-to-end. See the Quickstart to run it. Design/spec live in
SPEC.md,KICKOFF.md, andDECISIONS.md.
The problem
You're the backend engineer. Your teammate is the frontend engineer. You both use Claude Code.
Every API contract, every field rename, every "ok it's deployed now" gets manually relayed by you, copy-pasting between two agent sessions. You're a message bus made of meat, sitting between two systems that could coordinate at machine speed.
Existing tools all assume one developer, one machine, one trust domain. sys-buddy is for agents belonging to different humans, coordinating over the internet, with authenticated identity, an enforced workflow, and an audit trail both people can watch.
The principle
The broker enforces. Agents request.
Rules that live in prompts get ignored, injected, and forgotten. Rules that live in database constraints don't. So the broker owns the workflow: it validates contracts, rejects out-of-order actions, counts test failures, and stamps every message with a cryptographically-verified identity the agent cannot forge.
How it works
┌──────────────────────────────────┐
│ sys-buddy (FastMCP) │
your agent ─MCP─▶ │ /mcp MCP tools │
buddy's agent ─MCP─▶ │ /pair pairing REST │ ─▶ Slack
browser ─HTTP─▶ │ /ui + /api dashboard │
│ SQLite (WAL) │
└──────────────────────────────────┘
One Python process. One port. One tunnel.
- You create a task and mint a single-use invite for your buddy's role
- They run
sys-buddy join <url> <code>— their agent gets a scoped token, they get a read-only dashboard link - Both agents propose and lock a structured API contract — Slack pings both humans
- Backend builds, deploys, reports live. Only then can the frontend agent run its tests — the broker refuses earlier
- Tests fail? Frontend reports it, backend fixes, retry. The broker counts. Three strikes → task marked stuck, humans pinged
- Tests pass →
VERIFIED→ both agents stop → Slack says so
Nobody relayed a message.
Quickstart
Install
git clone https://github.com/tooney92/sys-buddy && cd sys-buddy
uv sync # creates .venv with everything
That tracks main — the latest, still-moving code. For a stable, frozen version,
check out a release tag instead:
git clone https://github.com/tooney92/sys-buddy && cd sys-buddy
git checkout v1.1.1 # a released version — see the Releases page for the latest
uv sync
Coming with the next release:
pip install sys-buddyand a prebuilt container (docker pull ghcr.io/tooney92/sys-buddy). These activate automatically the first time a release is cut through the new publish pipeline — until then, use the clone methods above.
The CLI runs as uv run sys-buddy .... The examples below drop that prefix — so
alias it once (or activate the venv) and the commands work as written:
alias sys-buddy="uv run sys-buddy" # add to ~/.zshrc / ~/.bashrc to keep it
Local — 60 seconds, no auth (solo dev, many repos on one machine)
# 1. start the broker (loopback, zero auth)
sys-buddy local # → http://127.0.0.1:8787
# 2. register it with Claude Code in each repo
# (re-pairing later? run `claude mcp remove sys-buddy` first — a name can't be overwritten)
claude mcp add --transport http sys-buddy http://127.0.0.1:8787/mcp
# 3. watch it happen (optional)
sys-buddy host-viewer # prints a dashboard link → /ui?v=...
That's it. Your agents call send_message / check_messages / propose_contract
/ report_status with a task and agent name — the broker auto-creates the task
on first use. Drop the CLAUDE.md snippet from SPEC.md §13 into each repo to make
coordination automatic.
Remote — two humans, two machines (the real thing)
# ── HOST ─────────────────────────────────────────────
ngrok http 8787 # or Tailscale / real infra
# tell every command the tunnel origin — serve AND invite/host-viewer read this,
# so the links they print point at the tunnel, not loopback:
export SYS_BUDDY_PUBLIC_URL=https://abc123.ngrok.app
sys-buddy serve # binds 0.0.0.0, auth enforced
sys-buddy task create signin --roles backend,frontend
sys-buddy invite --task signin --role frontend # → prints the buddy's https://…/join link + code
# send your buddy that /join link over Slack/Signal (or the sb1_ blob for CLI/desktop)
# ── BUDDY ────────────────────────────────────────────
sys-buddy join https://abc123.ngrok.app signin-J7fK2mQx --name dave-frontend
# → prints the agent token + the exact `claude mcp add ... --header "Authorization: Bearer sbk_..."`
# command to run, plus a read-only dashboard link
--name is your agent's alias — the label that stamps every message and Slack
ping (e.g. dave-frontend). Pick something recognizable; it's how the other humans
tell whose agent said what.
No CLI required for the buddy. The invite doubles as a browser link — the host can
send it straight over Slack/Signal. Opening it lands on /join, which walks the buddy
through the Claude setup command, the briefing prompt, and their dashboard link. Cloning
the repo is optional (only needed if they want to run their own broker).
Slack pings (optional): set SLACK_WEBHOOK_URL before sys-buddy serve and both
humans get a message on contract-lock, verified, and stuck.
Revoke anytime: sys-buddy revoke-agent dave-frontend, sys-buddy revoke-viewer dave, or sys-buddy close signin (kills everything for that task).
Two modes
sys-buddy local |
sys-buddy serve |
|---|---|
| loopback, no auth, zero friction | invite-pairing, scoped tokens, enforced state machine |
| your repos, your machine | two humans, two machines, two orgs |
Same tools, same schema, same dashboard. One flag.
Security, honestly
The full model is in SPEC.md §9. The short version:
- An ngrok URL is not a secret. They get scanned within minutes, leak via link previews, and appear in certificate transparency logs. All security lives in authentication, never in obscurity.
- You cannot filter prompt injection to zero. So the model doesn't try. Assume injection sometimes succeeds and make success worthless: agents can't request file reads or shell commands, staging URLs come only from signed contracts (never from chat), tokens are role-scoped to one task, irreversible steps need a human tap in Slack, and an injected loop still dies at three strikes.
- Agent access and dashboard access are separate credentials. A leaked viewer link reads one task's transcript until you revoke it. It can't send anything.
Repo layout
SPEC.md ← the complete specification. Start here.
KICKOFF.md ← build instructions for a coding agent
DECISIONS.md ← design decisions and spec deviations, with reasoning
CHANGELOG.md ← released changes (Keep a Changelog + SemVer)
CONTRIBUTING.md ← how to contribute: fork, branch, test, PR
v2.md ← the backlog, with a build-difficulty score per entry
design/ ← Claude Design handoff: the dashboard prototype (visual source of truth)
reference/ ← agent_bus.py: working local-only predecessor + its ops guide
releases/ ← the fuller note per tagged release
Development
uv sync # install deps into .venv
uv run pytest -q # the full spec suite (470+ tests)
uv run sys-buddy --help # the CLI surface
Source lives in src/sys_buddy/: db (schema/WAL) · identity + middleware
(auth) · service (messaging) · state + contracts (the enforced workflow) ·
pairing + admin (invites/tokens) · api (dashboard JSON) · server (assembly)
· ui.html (single-file dashboard). Implementation decisions and spec deviations
are logged in DECISIONS.md.
Versioning and releases
sys-buddy follows Semantic Versioning, and every notable
change is recorded in CHANGELOG.md in
Keep a Changelog format. Because this is a broker
that agents talk to, the version boundaries are defined in terms of what an agent
can see:
- MAJOR — incompatible changes to the tool/wire contract or agent-visible behaviour.
- MINOR — new, backwards-compatible capability.
- PATCH — backwards-compatible fixes.
Releases are automated: contributors don't touch the version or the changelog. Merged
PR titles follow Conventional Commits (feat: →
minor, fix: → patch, feat!: → major), a release bot computes the next version and
drafts the notes, and merging its release PR tags vX.Y.Z and publishes. See
CONTRIBUTING.md for the commit conventions. Each release is git-tagged
with a fuller note in releases/vX.Y.Z.md.
Contributing
Contributions are welcome — see CONTRIBUTING.md for the full
walkthrough: forking, environment setup with uv, branch and commit conventions,
what to run before review, and how to open the PR.
The short version:
# fork on GitHub, then:
git clone https://github.com/YOUR_USERNAME/sys-buddy.git && cd sys-buddy
git remote add upstream https://github.com/tooney92/sys-buddy.git
uv sync && git checkout -b feat/my-change
# ...change...
uv run pytest -q # must be green
git push -u origin feat/my-change && gh pr create --base main --fill
Three things worth knowing before you start:
mainis branch-protected. Every change lands through a reviewed PR — the maintainer's included — so there is no faster path to take.- UI/dashboard changes need more than a green suite: prove them against a running
local broker and attach screenshots. See
CLAUDE.md. - Add a line to
CHANGELOG.mdunder[Unreleased], and flag it in the PR if your change is agent-visible — that forces a MAJOR bump.
License
MIT.
Credits
Grew out of agent-bus, a ~130-line FastMCP message bus for coordinating Claude Code agents across repos on one machine (see reference/). sys-buddy is that idea taken across the internet, between people.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sys_buddy-1.2.0.tar.gz.
File metadata
- Download URL: sys_buddy-1.2.0.tar.gz
- Upload date:
- Size: 1.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
841a73cc7c6976537de6382dc096356130605078dfa0d5761e37060a20b87e29
|
|
| MD5 |
6fe11416414a7357565c0bdb0e3bbefa
|
|
| BLAKE2b-256 |
935c2ccefe00411a2f6cf3c905b4f174511c5bb0fdd4520fdffb406908d7657a
|
Provenance
The following attestation bundles were made for sys_buddy-1.2.0.tar.gz:
Publisher:
release-please.yml on tooney92/sys-buddy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sys_buddy-1.2.0.tar.gz -
Subject digest:
841a73cc7c6976537de6382dc096356130605078dfa0d5761e37060a20b87e29 - Sigstore transparency entry: 2254043284
- Sigstore integration time:
-
Permalink:
tooney92/sys-buddy@d8ba6f8d83219ed73f7482b6df87cecf2569fc4d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/tooney92
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-please.yml@d8ba6f8d83219ed73f7482b6df87cecf2569fc4d -
Trigger Event:
push
-
Statement type:
File details
Details for the file sys_buddy-1.2.0-py3-none-any.whl.
File metadata
- Download URL: sys_buddy-1.2.0-py3-none-any.whl
- Upload date:
- Size: 174.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e1aa943e44bcbda824028113389eb1cabf90306c7b2e5d8febffde1bf4e711b
|
|
| MD5 |
39fd4f2463ab5dfe340418351394be12
|
|
| BLAKE2b-256 |
3dd7847a775d8ce009f29e31da0a3fecd40f6e3e964de5b7216d0f2a19503446
|
Provenance
The following attestation bundles were made for sys_buddy-1.2.0-py3-none-any.whl:
Publisher:
release-please.yml on tooney92/sys-buddy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sys_buddy-1.2.0-py3-none-any.whl -
Subject digest:
6e1aa943e44bcbda824028113389eb1cabf90306c7b2e5d8febffde1bf4e711b - Sigstore transparency entry: 2254043335
- Sigstore integration time:
-
Permalink:
tooney92/sys-buddy@d8ba6f8d83219ed73f7482b6df87cecf2569fc4d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/tooney92
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-please.yml@d8ba6f8d83219ed73f7482b6df87cecf2569fc4d -
Trigger Event:
push
-
Statement type: