# MessageWeave **[中文文档 / Chinese documentation → README.zh-CN.md](README.zh-CN.md)** > One Telegram bot per mailbox. New mail arrives as metadata; the original is always > fetched read-only from your own JMAP server. ## 1. What it is MessageWeave sits between a JMAP mail server (for example Stalwart) and a Telegram bot. - **Inbound.** A JMAP push subscription tells the service that a message changed. Nothing is polled at rest. - **Outbound.** Each event becomes a short, **metadata-only** Telegram notification: sender, subject, timestamp. Mail bodies are never sent to Telegram. - **On demand.** When you ask, the service reads the original through a fresh JMAP read call. Nothing is cached in between. - **Optionally summarised.** If you explicitly opt in, an OpenAI-compatible LLM returns a short summary. Requests, responses and attachment bytes are never persisted. State is an architectural boundary here, not a preference. - **Redis is the only state store.** No database, no embedded store, no second store. - **The process writes nothing to disk.** No log files, no data files, no local volume. - **No long-lived connections.** No SSE, no WebSocket, no long polling. - **Logs go to stdout only.** The platform's collector owns log storage and retention. - **What it is not.** It is not a mail client, not a proxy, and not a relay. It forwards metadata to one bot; it does not read arbitrary URLs, open tunnels, or broker traffic. ## 2. 5-minute setup Requires a reachable Redis 7 instance and a JMAP session plus a Telegram bot token. ```sh cp .env.example .env # fill REDIS_URL and CONFIG_ENCRYPTION_KEY docker build -t messageweave:latest . docker run --env-file .env -p 8080:8080 messageweave:latest ``` Then open `http://localhost:8080` in a browser. The first-boot SPA calls `POST /api/bootstrap`, stores the business secrets in Redis, and creates the admin session. From that point the browser configures the service through Redis — no environment variable is read or written again for business configuration. For local builds without Docker: `cargo build --locked` produces the `message-weave` binary. If the service answers requests but does nothing useful, check the logs for a startup warning: a missing required variable does **not** crash the process. It serves a read-only setup router over in-memory state instead. See §3. ## 3. Configuration entry points Three layers. They are not interchangeable. **Boot-time environment — 2 required, 2 optional.** | Variable | Required | Default | |---|---|---| | `REDIS_URL` | yes | — | | `CONFIG_ENCRYPTION_KEY` | yes | — | | `PORT` | no | `8080` | | `RUN_MODE` | no | `webhook` | `RUN_MODE` accepts `webhook` or `reconcile`. `.env.example` ships only the two required variables; the rest are documented defaults. **Business configuration — Redis, written by the browser.** `POST /api/bootstrap` is the one-shot trust bootstrap; `PUT /api/business-config` hot- reloads individual settings within about one second. The process never reads business secrets from the environment in normal operation. **Health.** `GET /healthz` returns 200 unconditionally — it is liveness, not readiness. `GET /ready` returns 503 until configuration, Redis, and both upstreams (a JMAP session `GET` and Telegram `getMe`, 3s each) are reachable. Probe `/ready`, not `/healthz`, when deciding whether to route traffic — but `/ready` is the heavier probe (~3s worst case), so a monitor that must stay cheap should watch the gateway's aggregated `/healthz`. ## 4. Security boundary, in one sentence > All state lives in Redis; the process reads only two environment variables and writes > nothing to disk. One corollary matters for setup: the bootstrap one-shot token is the **password component of `REDIS_URL`**. The Redis ACL credential is therefore both the application connection credential and the trust root for bootstrap — keep it private and rotate it as one value. ## 5. Where to read more | Document | What it answers | |---|---| | [`docs/design.md`](docs/design.md) | Why the system is shaped this way: data flow, JMAP semantics, Redis streams, AI consent rules | | [`docs/deployment.md`](docs/deployment.md) | How to deploy: Dockerfile, secrets, Redis hosting, webhook/push/reconcile routing, multi-instance load balancing | | [`docs/reference.md`](docs/reference.md) | **Single source of truth for verifiable facts** — Redis keys and TTLs, error codes, routes, environment layers, budgets | | [`docs/roadmap.md`](docs/roadmap.md) | Gaps, blockers and the next phase | | [`docs/retired.md`](docs/retired.md) | What was tried and dropped — abandoned routes, unreleased designs, and names that never existed | | [`AGENTS.md`](AGENTS.md) | Contribution rules, hard boundaries, the stable-ID index for cross-document references | Facts that matter are traceable. If two documents disagree, `docs/reference.md` wins.