Wenlan
Wenlan is a source-backed AI knowledge base and LLM wiki for AI work: organize documents and decisions into pages you can find, inspect, and review.
Events for your Discord server.
ProductivityRust · CSSGitHub @chaoskOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
the discord scheduler
Translation pending
Loading the full README.
Read the full README ↗Marian keeps a Discord community's events, signups, reminders, and recurring dates. It starts only with a bot token. That same process opens an outbound Discord gateway, posts the events, and takes signup buttons. The cluster does not need a public interactions URL.
Rust 1.99.1 (see rust-toolchain.toml).
docker compose up -d
DATABASE_URL=postgres://marian:[email protected]:5432/marian \
DISCORD_TOKEN=... scripts/dev
docker compose starts Postgres 17 and publishes it on 127.0.0.1:5432 (user marian, password marian, database marian). Set DATABASE_URL to that connection string. Marian listens on 0.0.0.0:8080. An empty database stays empty until the bot joins a Discord server.
The dashboard is a Leptos app: pages render on the server and hydrate in the browser. cargo-leptos builds both sides and serves the wasm and CSS from target/site:
cargo install cargo-leptos --locked
cargo leptos watch
cargo leptos watch rebuilds the pages on save, and listens on 127.0.0.1:8080. scripts/dev runs it, first running cargo clean when target/ has grown past 20 GB (MARIAN_TARGET_LIMIT_GB): cargo keeps what a toolchain or dependency bump left behind. Dev and test builds keep line tables for Marian's own crates and no debug info for dependencies. A release build is cargo leptos build --release --precompress: --precompress writes brotli and gzip copies of the wasm, script, and stylesheet, and the server sends those to browsers that accept them. The binary reads the site from LEPTOS_SITE_ROOT (target/site during development). A release build with LEPTOS_HASH_FILES=true puts each file's content hash in its name, and browsers keep those files for a year; the build writes the names to hash.txt beside the binary, which a deployment keeps next to it and runs with LEPTOS_HASH_FILES=true. CI and the image do both. cargo leptos watch keeps plain names, which browsers check on each load. A musl image sets LEPTOS_BIN_TARGET_TRIPLE=x86_64-unknown-linux-musl and passes --bin-features static-libpq.
Pages ask /api for the resources they need. Server pages hold one live connection at /api/servers/<id>/live. Each message names what changed (someone's signups for an event, an event, or the server), and pages refetch only the reads that change touches. cargo test --workspace --exclude marian-frontend runs the server and page tests. cargo test -p marian-app --features ssr covers the pages as the server renders them.
If cargo cannot find libpq, point pkg-config at it. Homebrew keeps it off the default path:
export PKG_CONFIG_PATH="/opt/homebrew/lib/postgresql@14/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
| Variable | Default | Role |
|---|---|---|
PORT | 8080 | HTTP port |
DATABASE_URL | required | Postgres connection string |
MARIAN_DB_POOL | 10 | How many Postgres connections this process keeps |
DISCORD_TOKEN | required | Bot token. Marian exits if this is empty |
DISCORD_CLIENT_ID | empty | Application id. Used for the invite link and for dashboard sign-in |
DISCORD_CLIENT_SECRET | empty | OAuth client secret. The site stays on the landing page until this is set |
GOOGLE_CLIENT_ID | empty | Google OAuth client id. Empty leaves Google Calendar disconnected |
GOOGLE_CLIENT_SECRET | empty | Google OAuth client secret. The redirect URI is MARIAN_PUBLIC_URL plus /auth/google/callback |
MARIAN_PUBLIC_URL | empty | Dashboard URL. Discord embeds link here, and it is the OAuth redirect base |
MARIAN_STATUS | empty | Custom status under the bot's name, up to 128 characters. Empty leaves it unset |
OTEL_EXPORTER_OTLP_ENDPOINT | empty | Base URL of an OTLP/HTTP collector, such as http://tempo:4318. Empty leaves traces off and keeps logs on stderr. Do not append /v1/traces |
OTEL_SERVICE_NAME | marian | Service name on exported spans. service.version is the image version |
/healthz and /readyz report the process and the database. Readiness does not wait for Discord.
DATABASE_URL=postgres://marian:[email protected]:5432/marian \
DISCORD_TOKEN=... DISCORD_CLIENT_ID=... \
MARIAN_PUBLIC_URL=https://marian.example.com \
MARIAN_STATUS="marian.example.com | /event" \
cargo leptos watch --release
Invite the bot with View Channel, Manage Channels, Send Messages, Manage Messages, Embed Links, Read Message History, Mention Everyone, Add Reactions, Manage Roles, and the public-thread permissions. That set is the permissions integer 326686174288:
https://discord.com/api/oauth2/authorize?client_id=YOUR_ID&permissions=326686174288&scope=bot%20applications.commands
Marian asks for the GUILDS and DIRECT_MESSAGES intents, plus the privileged GUILD_MEMBERS intent so members' roles, joins and departures reach it as they happen. Turn on Server Members Intent under Bot in the Discord Developer Portal. Without it Marian logs a warning and connects without it; members' roles then update only when they use Marian or open its pages. A bad token is logged and retried; the dashboard stays up.
This is the beginning of the README. Read the rest at the original. Read the full README ↗