Agent communication

Forge uses a two-layer communication stack: Matrix/Element for humans (phone and browser), and a machine bus (NATS JetStream) for agent-to-agent traffic. Chat requests work; Lenses will govern later; workers execute…

Updated

Architecture

Layer Role Technology
Human UX Phone/browser chat, ops rooms Matrix + Element
Channel gateway Chat ↔ intents and status forge-cursor-bridge matrix adapter
Agent bus Commands, events, peer traffic NATS JetStream on Granite
Cursor worker Headless agents on your laptop forge-cursor-bridge + Cursor SDK (composer-2.5)
Contracts Ingress and worker events forge.chat_intent.v1, forge.agent_event.v1

Lane (v1):

  1. You send !agent … in Element (#cursor room).
  2. Matrix adapter emits envelopes (and logs forge.chat_intent.v1).
  3. Cursor worker runs a local headless agent (not IDE Composer tabs).
  4. Status returns to the room via the adapter.

Future agents subscribe to the same NATS subjects; they do not use Matrix as their primary protocol.

Related: OpenClaw integration, Matrix channel notes.

Hostnames

Hostname Service
matrix.forgedc.net Synapse homeserver (sticky — do not rename)
element.forgedc.net Element Web UI
NATS 127.0.0.1:4222 on Granite only (SSH tunnel from laptop)

Registration is disabled. Accounts are created by an operator on Granite.

Repos

Repo Purpose
forge-matrix Synapse, Element, Postgres, NATS compose + Granite deploy scripts
forge-cursor-bridge Matrix bot, Cursor worker, envelopes, transport

1. Matrix + Element on Granite

From your workstation (Code/forge-matrix):

cd forge-matrix
cp .env.example .env
./scripts/generate-secrets.sh
./scripts/bootstrap-synapse.sh
./scripts/install-on-granite.sh

Cloudflare tunnel + DNS (uses CLOUDFLARE_API_TOKEN from forge-knowledge-assistant/.env.local when present):

./scripts/apply-cf-matrix-tunnel.sh
python3 scripts/ensure-matrix-dns.py

Tunnel target is the Precision SSH connector on Granite (CF_TUNNEL_ID in .env).

Create operator accounts

On Granite:

cd ~/forge-matrix
docker compose exec -T synapse register_new_matrix_user \
  -c /data/homeserver.yaml http://localhost:8008 \
  -u forgeadmin -p 'YOUR_PASSWORD' -a --exists-ok

docker compose exec -T synapse register_new_matrix_user \
  -c /data/homeserver.yaml http://localhost:8008 \
  -u cursorbot -p 'BOT_PASSWORD' --no-admin --exists-ok

Create rooms (from laptop, with admin password):

export MATRIX_HOMESERVER=https://matrix.forgedc.net
export MATRIX_ADMIN_USER=forgeadmin
export MATRIX_ADMIN_PASSWORD='YOUR_PASSWORD'
python3 scripts/setup-matrix-rooms.py

Rooms: #cursor, #ops, space #forge-agents. Keep #cursor and #ops unencrypted so the bot can read messages.

Sign in (web or mobile)

  • Element Web: https://element.forgedc.net
  • Homeserver: https://matrix.forgedc.net
  • Username: local part only (e.g. forgeadmin)

Mobile: choose Sign in / I already have an account — not Create account.
If you see Registration has been disabled, the app is on the sign-up path; go back and use Sign in.

Alternatives on phone: open Element Web in the browser, or pair with desktop via Sign in with QR code.


2. Cursor bridge on your laptop

cd forge-cursor-bridge
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env

Edit .env:

Variable Example
MATRIX_HOMESERVER https://matrix.forgedc.net
MATRIX_USER @cursorbot:matrix.forgedc.net
MATRIX_PASSWORD bot password from step 1
MATRIX_ALLOWED_USERS @forgeadmin:matrix.forgedc.net
MATRIX_CURSOR_ROOM #cursor:matrix.forgedc.net
MATRIX_OPS_ROOM #ops:matrix.forgedc.net
CURSOR_API_KEY from Cursor Integrations
CWD_ALLOWLIST /home/YOU/Code/*

CURSOR_API_KEY is required for !agent new even though agents run locally — the SDK authenticates headless runs on your machine.

Run

forge-cursor-bridge matrix-adapter

Or install the user service:

./scripts/install-user-service.sh
systemctl --user enable --now forge-cursor-bridge.service

Commands in #cursor

!agent new /home/you/Code/forgesdlc | Summarize the generator layout
!agent list
!agent send <agent_id> Add a test for the parser
!agent cancel <agent_id>
!agent status <agent_id>
!agent help

3. NATS agent bus (multi-agent)

NATS runs inside the Granite compose stack. It is not on the public internet.

SSH tunnel from laptop:

# forge-matrix/scripts/nats-ssh-tunnel.sh
ssh -N -L 4222:127.0.0.1:4222 granite

In forge-cursor-bridge/.env:

TRANSPORT=nats
NATS_URL=nats://USER:PASS@127.0.0.1:4222

Run adapter and worker (or use matrix-adapter which embeds the worker). Test the bus:

forge-cursor-bridge echo-agent

4. Script reference

Script Repo Purpose
scripts/generate-secrets.sh forge-matrix Fill .env secrets
scripts/bootstrap-synapse.sh forge-matrix Synapse signing key + homeserver.yaml
scripts/install-on-granite.sh forge-matrix rsync + docker compose up on Granite
scripts/apply-cf-matrix-tunnel.sh forge-matrix Cloudflare ingress for matrix/element
scripts/ensure-matrix-dns.py forge-matrix CNAME records
scripts/setup-matrix-rooms.py forge-matrix #cursor, #ops, space
scripts/nats-ssh-tunnel.sh forge-matrix Local NATS forward
scripts/install-user-service.sh forge-cursor-bridge systemd user unit

5. Troubleshooting

Symptom Fix
Registration has been disabled (mobile) Use Sign in, not Create account
Login rate limited (429) Wait a few minutes; Synapse rc_login is relaxed for private use
502 on matrix/element Check Cloudflare tunnel points at Granite Precision SSH connector and DNS CNAME matches
!agent new fails: no API key Set CURSOR_API_KEY in bridge .env
Bot silent in room Confirm #cursor is not E2EE; bot user invited

Security boundaries

  • Matrix federation is closed; registration is off.
  • NATS is localhost on Granite or reached via SSH tunnel — not exposed publicly.
  • Bridge allowlists Matrix user IDs and working-directory paths.
  • Headless Cursor agents do not open IDE chat tabs; they use the same account auth as the SDK/CLI.