4674c5a2b75172881d528d1812cb78dcdbc932ed
The socket.io client was sending its own EIO ping frames every
pingInterval (default 25s). That's wrong for engine.io v4: in v4 the
SERVER initiates pings and the CLIENT must respond with pong inside
pingTimeout, else the server closes the connection. Client-initiated
pings get misinterpreted by Fabric's NestJS socket.io backend, which
quietly closes the connection — producing the warn-flap every ~25s:
inbound: socket ended; reconnecting
err="read: failed to get reader: received close frame:
status = StatusNoStatusRcvd and reason = \"\""
Fix:
- delete pingLoop() entirely
- delete the pingPeriod/pingTimeout struct fields + their assignments
in recvOpen (server enforces both anyway; client doesn't need them)
- keep the eioPing case in handlePacket (already correct — responds
with pong)
- drop the now-unused "time" import
End-to-end verified on live Fabric:
- Restarted Plexum at 20:17:35; watched for 90+ seconds
- ZERO "socket ended" events (vs. ~3-4 per 90s before the fix)
- Channel inbound still delivers: alice posted seq=20 → gem agent
(gemini CLI) replied seq=21 "pong"
The plugin no longer flaps. Reconnect backoff machinery (1s→60s)
stays in place as a safety net for genuine network drops.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Plexum-fabric-channel-plugin
Native Plexum channel plugin connecting Plexum agents to Fabric guilds as
real channel members. Port of Fabric.OpenclawPlugin — delivered in phases.
Status
| Phase | Scope | Status |
|---|---|---|
| F-1 | identity + REST + plugin scaffold + send outbound |
✅ |
| F-2 | socket.io inbound + wakeup gate + token refresh + per-channel serial | ✅ |
| F-3 | exponential reconnect backoff | ✅ |
| F-4 | tool surface batch 1 (8 tools) | ✅ |
| F-5 | command-sync (slash autocomplete) | ✅ |
| F-6 | attachments → temp-dir + footer | ✅ |
| F-7 | sub-discussion KV + create-*-channel + discussion-complete | ✅ |
| F-8 | coalesce parity | ⏭ no-op — Plexum doesn't segment deliver |
| F-5b | presence-sync | ⏭ deferred — Plexum state machine ≠ HF semantics |
Agent-facing tools (16)
send— host-driven channel outbound (channel manager → plugin)fabric-send-message,fabric-send-sys-msg— post normal / system msgsfabric-channel-list,fabric-guild-list— discoveryfabric-message-history— paginate by seqfabric-channel,fabric-channel-set-purpose— channel metadatafabric-canvas— get/share/update/remove canvascreate-{chat,work,report,discussion}-channel— create new channelsdiscussion-complete— summary + closecreate-sub-discussion,close-sub-discussion— sub-discussion lifecycle
Install
cd ~/Plexum-fabric-channel-plugin
./scripts/install.sh # build + install plugin + register CLI
Then:
-
Mint a Center API key for each Plexum agent that should speak in Fabric:
docker exec fabric-backend-center node dist/cli.js user apikey --email <agent-email> -
Register the key with Plexum:
plexum-fabric-register --agent-id alice --api-key fak_xxxx # writes ~/.plexum/fabric-identity.json -
Configure plugin-level settings at
~/.plexum/plugins/plexum-fabric-channel/config.json:{ "center_api_base": "http://localhost:7001/api" } -
Bind a Plexum channel name to a Fabric channel at
~/.plexum/channels/<plexum-channel-name>.json:{ "agent_id": "alice", "plugin": "plexum-fabric-channel", "fabric": { "guild_node_id": "test-guild1", "channel_id": "ch_xxxxxxxxx" } } -
Allow the plugin in
~/.plexum/plexum.json:{"plugins": {"allow": ["plexum-fabric-channel"]}} -
Restart the gateway:
systemctl --user restart plexum
What you get in F-1
- Plugin loads at gateway start, validates every bound agent's API key
against Center via
agentLogin, and warms a session per agent. sendMCP tool posts plain text to the bound Fabric channel as the agent user.- No inbound yet — Fabric → Plexum routing arrives in F-2.
Build manually
go build -o bin/plexum-fabric-channel-plugin ./cmd/plexum-fabric-channel-plugin
go build -o bin/plexum-fabric-register ./cmd/plexum-fabric-register
License
Same as Plexum.
Description
Languages
Go
92.9%
Shell
7.1%