generated from ben/template
107 lines
3.7 KiB
Org Mode
107 lines
3.7 KiB
Org Mode
#+title: 0.1.0 v0 Bridge Contract
|
|
#+created: [2026-04-14 Tue 14:28]
|
|
|
|
* summary
|
|
v0 is a tiny Python relay bridging one XMPP MUC room to one Zulip stream/topic.
|
|
|
|
The bridge is append-only. It relays new human-written messages in both directions. It does not attempt to sync edits, reactions, threads beyond a fixed Zulip topic, presence, history, or rich metadata.
|
|
|
|
The design goal is to make transport behavior obvious. If something breaks, it should be clear whether the problem is Zulip ingress, XMPP ingress, relay logic, or configuration.
|
|
|
|
* first-run assumptions
|
|
- single bridge process
|
|
- single XMPP MUC room
|
|
- single Zulip stream + fixed topic
|
|
- trusted private deployment
|
|
- Python implementation
|
|
- one bridge identity on each side
|
|
- human-readable sender attribution is sufficient for v0
|
|
|
|
* system actors
|
|
** Zulip bot/client
|
|
- connects to one Zulip server
|
|
- subscribes to events for one stream/topic target
|
|
- receives new Zulip messages
|
|
- sends relay messages into the configured stream/topic
|
|
|
|
** XMPP client
|
|
- connects as one XMPP account
|
|
- joins one MUC room with one nick
|
|
- receives new groupchat messages
|
|
- sends relay messages into that room
|
|
|
|
** relay core
|
|
- owns config, logging, message normalization, and loop prevention
|
|
- accepts inbound events from either side
|
|
- converts them into one minimal internal message shape
|
|
- republishes them to the opposite side
|
|
|
|
* message flow
|
|
** Zulip -> XMPP
|
|
1. a new Zulip message arrives in the configured stream/topic
|
|
2. Zulip bot/client emits an inbound event to the relay core
|
|
3. relay core validates scope
|
|
- correct stream
|
|
- correct fixed topic
|
|
- not authored by the bridge itself
|
|
4. relay core normalizes sender name + body
|
|
5. relay core formats a plain relay message
|
|
6. XMPP client posts that message into the configured MUC room
|
|
7. relay core logs success/failure
|
|
|
|
** XMPP -> Zulip
|
|
1. a new XMPP groupchat message arrives in the configured MUC room
|
|
2. XMPP client emits an inbound event to the relay core
|
|
3. relay core validates scope
|
|
- correct room
|
|
- not authored by the bridge nick/account
|
|
- ignore non-message noise
|
|
4. relay core normalizes sender name + body
|
|
5. relay core formats a plain relay message
|
|
6. Zulip bot/client posts that message into the configured stream/topic
|
|
7. relay core logs success/failure
|
|
|
|
* v0 relay format
|
|
Plain text only.
|
|
|
|
Recommended shape:
|
|
- Zulip -> XMPP: "[zulip] <sender>: <body>"
|
|
- XMPP -> Zulip: "[xmpp] <sender>: <body>"
|
|
|
|
This is intentionally crude. The point is attribution and debuggability, not elegance.
|
|
|
|
* non-goals
|
|
- no message edit sync
|
|
- no delete sync
|
|
- no emoji/reaction sync
|
|
- no attachment mirroring in v0
|
|
- no presence mirroring
|
|
- no roster/contact sync
|
|
- no multi-room routing
|
|
- no per-thread/topic mapping beyond one fixed Zulip topic
|
|
- no history backfill
|
|
- no Hermes behavior in the transport process
|
|
- no Retcon writeback in the transport process
|
|
|
|
* operational boundaries
|
|
- the bridge should ignore service noise such as joins, parts, presence, and subscription events
|
|
- the bridge should only handle newly observed messages after startup
|
|
- the bridge should fail loudly in logs and stay simple in behavior
|
|
- the bridge should not try to be clever about replay, dedupe, or recovery yet beyond basic self-loop avoidance
|
|
|
|
* why this scope
|
|
This gives the smallest useful system:
|
|
- phone-friendly Zulip UI
|
|
- XMPP room remains the low-friction bus
|
|
- one boring relay to test whether the transport idea is worth keeping
|
|
|
|
If this small version is unreliable, adding Hermes or Retcon would only hide the real problems.
|
|
|
|
* exit condition for 0.1.0
|
|
Task 0.1.0 is complete when:
|
|
- this note exists
|
|
- the actor model is frozen
|
|
- both message directions are described
|
|
- v0 non-goals are explicit
|
|
- first-run assumptions are frozen
|