Listen to messages from Matrix (bot) accounts and send them to your webhook(s)
  • TypeScript 99.4%
  • Dockerfile 0.6%
Find a file
Claude 13354ae5d9 feat: add typewriter streaming mode with per-chunk immediate delivery
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>
2026-04-19 17:43:44 +02:00
.cctx/tasks task-027: Implement thread reply branching with response_id tracking 2026-04-15 22:37:15 +02:00
docs feat: add typewriter streaming mode with per-chunk immediate delivery 2026-04-19 17:43:44 +02:00
src feat: add typewriter streaming mode with per-chunk immediate delivery 2026-04-19 17:43:44 +02:00
.env.example Update docs, config, and appservice registration cleanup 2026-04-15 22:18:49 +02:00
.gitignore Implement Mautrix re-invite pattern to fix M_FORBIDDEN on virtual user join 2026-04-15 00:49:42 +02:00
bun.lock fix: integrity pass — routing, dedup, encryption, and type hygiene 2026-04-09 21:32:20 +02:00
CLAUDE.md Update docs, config, and appservice registration cleanup 2026-04-15 22:18:49 +02:00
docker-compose.yml windmill internal url 2026-04-13 14:04:46 +02:00
Dockerfile Add wget to Dockerfile for inter-service reachability testing 2026-04-10 21:34:08 +02:00
package.json fix: integrity pass — routing, dedup, encryption, and type hygiene 2026-04-09 21:32:20 +02:00
README.md Focus on only the appservice and update the Env variables 2026-04-08 17:32:03 +02:00
registration.yaml non-exclusive wildcard user to appservice settings for tuwunel compatibilty and to allow sending invites using existing user accounts 2026-04-15 14:02:37 +02:00
TODO.md Update docs, config, and appservice registration cleanup 2026-04-15 22:18:49 +02:00
tsconfig.json chore: simplify tsconfig — remove baseUrl and redundant Bundler-implied options 2026-03-27 21:23:06 +01:00
tuwunel.toml chore: track existing project files (tsconfig, logger, docs, registration) 2026-03-26 12:48:18 +01:00

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.

  1. Deploy the appservice — Create a new Application in Dokploy pointing at this repo. Dokploy will use the Dockerfile to build automatically.

  2. Set environment variables — Configure all required env vars in Dokploy's env panel. Use APPSERVICE_URL=http://<your-service-name>:8080 where the service name matches your Dokploy application name.

  3. Add persistent volumes — Mount a volume at /data to persist E2E crypto keys, appservice state, and the session database. Set CRYPTO_STORE_PATH=/data/crypto, FS_STORE_PATH=/data/state.json, and DB_PATH=/data/sessions.db. Losing this volume breaks all existing E2E sessions and requires re-establishing device trust with all room members.

  4. 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.

  5. 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.