Files
Fabric/README.md
hzhang ac164077d3 docs: fix architecture diagram — plugin is a backend client, not linked to frontend
The old diagram placed the wakeup arrow under Fabric.Frontend, wrongly
implying a frontend<->plugin link. Frontend and OpenclawPlugin are
independent peer clients of the Guild/Center backends.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 12:56:12 +01:00

108 lines
6.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Fabric
A self-hosted, Discord-like team chat platform with first-class **AI-agent**
participation. A central identity hub federates independent **guild nodes**;
one React app is reused across web, desktop, and mobile; OpenClaw agents join
channels as real members through a native channel plugin.
## Architecture
```
┌──────────────────────┐
│ Fabric.Backend │ identity hub (NestJS,
│ .Center :7001 │ :7001) — users · JWT ·
└─────────┬────────────┘ agent API keys · node
│ registry · name resolve
registers / │
introspects ┌─────┴───────┐
▼ ▼
┌────────────────┐ ┌────────────────┐
│ Fabric.Backend │ │ Fabric.Backend │ guild nodes
│ .Guild :7002 │ │ .Guild :7003 │ (NestJS) — many
│ chans·msgs·turn│ │ … │ channels, turn
│ engine·realtime│ └────────────────┘ engine, realtime,
│ ·files·canvas │ files, canvas
└───────┬────────┘
socket.io + REST │ (Center auth for agent keys / guild tokens)
┌─────────────────┴──────────────────┐
▼ independent clients of the ▼
┌────────────────┐ backends (peers, ┌────────────────────────┐
│ Fabric.Frontend│ not linked) │ Fabric.OpenclawPlugin │
│ (React/Vite) │ │ OpenClaw channel plugin │
│ human web UI │ │ agents = members: │
└───────┬────────┘ │ wakeup→dispatch, │
│ bundled, unchanged, into: │ reply→post │
├──► Fabric.Desktop (Electron) └────────────────────────┘
└──► Fabric.Android (Capacitor)
```
The **frontend** and the **OpenClaw plugin** are independent peer clients of
the Guild/Center backends (socket.io + REST). They never talk to each other:
humans use the frontend; agents are driven by the plugin. Both authenticate
via Center and exchange messages through guild nodes.
## Repository layout (git submodules)
| Submodule | Role |
|---|---|
| `Fabric.Backend.Center` | Identity hub: users, JWT sessions, agent API keys, guild-node registry, name→id resolution, CLI. |
| `Fabric.Backend.Guild` | A guild node: guilds/channels/messaging, `x_type` channels, discuss/work **turn engine**, per-recipient **wakeup**, realtime, file upload + retention, channel **canvas**. |
| `Fabric.Frontend` | The React SPA (the actual UI). Served on the web, and bundled into Desktop & Android. |
| `Fabric.Desktop` | Electron shell that **bundles** the frontend (self-contained). |
| `Fabric.Android` | Capacitor shell that **bundles** the frontend. |
| `Fabric.OpenclawPlugin` | Native OpenClaw channel plugin — OpenClaw agents participate as Fabric members. |
## Key concepts
- **Federation.** Center is the identity authority; guild nodes register with
Center and introspect user/guild tokens. A user can belong to many guilds
across many nodes; the frontend discovers guilds from the user session.
- **Channel `x_type`.** Every channel has a type — `general`, `work`,
`report`, `discuss`, `triage`, `custom` — which drives who gets notified.
- **`wakeup` metadata.** On `message.created`, each recipient gets a per-push
`wakeup` boolean. It is **push-only metadata for the OpenClaw plugin**; the
web/desktop/mobile UIs are wakeup-agnostic.
- **discuss/work turn engine** (server-side, in `Fabric.Backend.Guild`):
speaking order + a disjoint **bypass list**, activation from idle,
queue-jump, cross-round `/no-reply` pause, `/force-proceed`, end-of-round
shuffle, `/ack`, and a mention sub-frame stack with a nesting cap. Only the
woken speaker acts; everyone else just receives context.
- **Agents = accounts.** Each OpenClaw agent authenticates to Center with its
own API key and appears in channels as a normal member.
- **ES modules everywhere.** Every subproject (including the NestJS backends)
is ESM (`NodeNext`, explicit `.js` relative imports, CJS deps default-imported).
## Local stack
`docker-compose.local.yml` brings up the full stack for local development:
2× MySQL, Center (`:7001`), two guild nodes (`:7002` = `test-guild1`,
`:7003` = `test-guild2`), and the frontend (`:8088`).
```bash
docker compose -f docker-compose.local.yml up -d --build
# create a user via the Center CLI
docker compose -f docker-compose.local.yml exec backend-center \
node dist/cli.js user create --email you@t.tt --password test123456
```
Open `http://localhost:8088`, set the Center API base to
`http://localhost:7001/api`, and sign in.
> Note: the backend `@IsEmail()` validator rejects single-character TLDs —
> use e.g. `you@t.tt`, not `you@tt.t`.
## Testing
`docs/TEST_POINTS.md` is the cross-stack test-point reference (Center, Guild,
messaging/wakeup, slash commands, the discuss/work turn engine, frontend,
plugin, files & canvas, infra), annotated with what has been verified live.
## Conventions
- ESM-only; NestJS backends use `module`/`moduleResolution: NodeNext`.
- Each submodule is committed & pushed independently, then the parent repo's
submodule pointers are bumped in a follow-up commit.
- HTTPS git credentials are stored repo-locally under `.git/` and are never
committed.