- TypeScript 99.4%
- Dockerfile 0.6%
Replaces the buffer/interval flushing system with per-chunk immediate delivery. Windmill now controls semantic chunking; the appservice controls delivery animation via a new `mode` field on the stream payload. - 'flush' mode: one Matrix edit per chunk (default, no buffering) - 'typewriter' mode: animates each chunk char-by-char at configurable charDelayMs (default 35ms, ~28 chars/sec) Removes STREAM_BUFFER_CHARS and STREAM_FLUSH_INTERVAL_MS env vars and the StreamManagerConfig type entirely — delivery style is now a per-stream runtime decision passed from Windmill in the chunk payload. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .cctx/tasks | ||
| docs | ||
| src | ||
| .env.example | ||
| .gitignore | ||
| bun.lock | ||
| CLAUDE.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| package.json | ||
| README.md | ||
| registration.yaml | ||
| TODO.md | ||
| tsconfig.json | ||
| tuwunel.toml | ||
Matrix AI Appservice
A Matrix Application Service that bridges Matrix rooms to Windmill AI workflows. Each Matrix room is a conversation session — messages from users flow to Windmill flows, and results come back as virtual @ai_* bot messages.
Overview
This appservice sits between a Tuwunel Matrix homeserver and a Windmill workflow engine. Virtual bot users (@ai_claude, @ai_summarizer, etc.) appear as real Matrix users in any room they join. E2E encryption is supported transparently via the Rust crypto SDK.
When a user sends a message in a room that contains an @ai_* bot, the appservice receives the event, triggers a Windmill flow with the message content and session context, and waits for Windmill to POST the result back. The result is then sent into the room by the appropriate virtual bot user.
Prerequisites
- Tuwunel homeserver (running and accessible)
- Windmill instance (local or same Docker network)
- Docker (for deployment) or Bun >= 1.0 (for local dev)
Quick Start (Local Dev)
# 1. Clone and install
bun install
# 2. Copy env template and fill in values
cp .env.example .env
# 3. Start full local stack
docker compose up -d
# 4. Register the appservice with Tuwunel
bun run register-appservice
Environment Variables
All env vars with descriptions. Copy .env.example and fill in values before running.
Dokploy Deployment
Step-by-step guide for deploying on Dokploy alongside Tuwunel and Windmill.
-
Deploy the appservice — Create a new Application in Dokploy pointing at this repo. Dokploy will use the
Dockerfileto build automatically. -
Set environment variables — Configure all required env vars in Dokploy's env panel. Use
APPSERVICE_URL=http://<your-service-name>:8080where the service name matches your Dokploy application name. -
Add persistent volumes — Mount a volume at
/datato persist E2E crypto keys, appservice state, and the session database. SetCRYPTO_STORE_PATH=/data/crypto,FS_STORE_PATH=/data/state.json, andDB_PATH=/data/sessions.db. Losing this volume breaks all existing E2E sessions and requires re-establishing device trust with all room members. -
Configure networking — In Dokploy, ensure the appservice is on the same Docker network as Tuwunel and Windmill so they can reach each other by service name.
-
Register with Tuwunel — After the first deploy, run the registration command (see below).
Registering with Tuwunel
Tuwunel registers appservices via an in-Matrix admin command, not a config file. The registration.yaml in this repo is a template — the generated output from env vars is what gets submitted.
# Option A: Automatic (requires TUWUNEL_ADMIN_ROOM_ID env var)
bun run register-appservice
# Option B: Manual — generate YAML and paste into Tuwunel #admins room
bun run generate-registration
# Then in the #admins Matrix room:
# !admin appservices register
# [paste yaml here]
The #admins room is automatically created when the first admin user registers on the homeserver. Join it as an admin user to run the registration command.
Architecture
See docs/ARCHITECTURE.md for full architecture documentation including data flow diagrams, security model, and storage layout.