Skip to content

feat(peer): link bots across two daemons - #19

Merged
ahilles107 merged 2 commits into
ahilles107:mainfrom
mrinaldi2:codex/peer-bots
Oct 2, 2026
Merged

ahilles107 merged 2 commits into
ahilles107:mainfrom
mrinaldi2:codex/peer-bots

Conversation

@mrinaldi2

Copy link
Copy Markdown
Contributor

Stacked on #18. This branch is built on codex/bot-runtime-choice, so the diff against main also shows #18's 12 commits. This PR's own changes are the last 2 commits (205e4a4, b9da294). Merge #18 first.

What

Lets one Gravity team span two of the owner's machines. For example, a lead and a Mac developer run on a Mac, and a Windows developer runs on a Windows PC. Design: docs/peer-bots.md.

  • Peers: two daemons pair over Tailscale with a one-time invite. The token is bound to the first daemon that presents it. The dialing daemon keeps one WebSocket open to the other's /peer route, and traffic flows both ways over it.
  • Linked bots: a bot that runs on the peer stands in locally as an ordinary bot row with peer_id set. Addressing, list_bots (now with machine and online), task budgets and history all work unchanged. The supervisor never starts a linked bot.
  • Forwarding: the delivery worker forwards deliveries for a linked bot over the link. The receiving daemon stores each message as if the sender were local:
    • a task is mirrored with the sender's deadline and hop count;
    • a result or a cancel closes the mirrored task;
    • the sender gets a linked bot of its own on first contact, so replies route back.
    • An offline peer leaves deliveries waiting without spending retries.
  • Artifacts: files listed in a result travel with it and land in the recipient project's artifacts/peers/<peer>/. Only files from the bot's own directory or its project's artifacts are sent, capped at 16 MB per file and 48 MB per result.
  • Owner messages: a message from the owner to a linked bot arrives on the peer as owner chat.
  • Control plane: new requests list_peers, create_peer_invite, add_peer, revoke_peer, list_peer_bots and link_peer_bot.
  • CLI: gravityd peer invite|add|list|bots|link|revoke drives pairing and linking until there is UI for it.

Why

A cross-platform app needs bots on each platform, and the owner should not have to switch the desktop app between daemons to relay tasks and carry files.

How tested

  • tests/peer_bots.rs runs two in-process daemons on the runtime double. It covers:
    • a task crossing the link, with its result and artifact coming back (including a refused out-of-scope path);
    • a cancel propagating to the other side;
    • the owner messaging a linked bot;
    • a reply on an open task, and the loop check across machines;
    • revocation cutting the link, with deliveries then waiting.
  • cargo fmt, cargo clippy -D warnings, the full workspace tests and the file-length check pass.
  • Live: a Mac and a Windows PC were paired over Tailscale. A Windows bot sent a task to a Mac bot, which completed it, and all deliveries were delivered.

Rollout

  • Schema: migration 14 adds the peer, peer_link, peer_message and peer_task tables, plus bot.peer_id and bot.remote_bot_id.
  • Configuration: the listening daemon must bind its Tailscale address in gravityd.toml.
  • Notices: base64 is now a direct dependency of gravityd; it was already in the lockfile, so only the inventory hashes changed.

Limitations

  • Not live-tested: the Mac→Windows task direction and artifact transfer were exercised only in tests.
  • No UI: pairing and linking are CLI-only. Linked bots appear in the bot list, but there is no pairing UI.
  • One hop: messages travel one link only; there is no relaying between peers.
  • Issue: there is no GitHub issue for this yet.

🤖 Generated with Claude Code

mrinaldi2 and others added 2 commits October 2, 2026 20:55
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pair two of the owner's daemons over Tailscale and stand a bot from one
in as a linked bot in a project on the other. A linked bot is an ordinary
bot row with peer_id set, so addressing, task budgets and history work
unchanged; the delivery worker forwards deliveries for it over the /peer
link instead of writing to a local session.

The receiving daemon stores each forwarded message as if the sender were
local: a task is mirrored with the sender's deadline and hop count, a
result or cancel closes the mirrored task, and the sender gets a linked
bot of its own on first contact so replies route back. Files listed in a
result travel with it (from the bot's own directory or the project
artifacts only, size-capped) and land in the recipient project's
artifacts directory.

Pairing is a one-time invite holding a link token bound to the first
daemon that presents it. Peers can only list bots, link one, and deliver
to bots linked to them; revoking drops the link. `gravityd peer ...`
drives pairing and linking until the desktop UI lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ahilles107
ahilles107 merged commit b77332f into ahilles107:main Oct 2, 2026
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants