Scope: Monorepo root (applies to orchestration, shared tooling, and cross-app concerns).
Unified chat infrastructure for All Things Linux: IRC, XMPP, web, and protocol bridges.
- Layout: Monorepo with
apps/*(UnrealIRCd, Atheme, Prosody, WebPanel, Web, Docs, Bridge, The Lounge, ObsidianIRC, Gamja) - Orchestration: Docker Compose (root
compose.yamlincludesinfra/compose/*.yaml) - Task Runner: just (root + per-app via
mod) - Key Commands:
just init,just dev,just prod,just test,just test-all
apps/
├── unrealircd/ # UnrealIRCd 6.x IRC server (config, Lua, scripts)
├── atheme/ # IRC services (NickServ, ChanServ, OperServ, MemoServ)
├── webpanel/ # UnrealIRCd web admin (nginx)
├── prosody/ # XMPP server (Lua config)
├── web/ # Next.js web application
├── bridge/ # Discord↔IRC↔XMPP bridge (Python, in-repo)
├── thelounge/ # Web IRC client (private mode, WebIRC, janitor/giphy plugins)
├── obsidianirc/ # Modern IRC web client (custom build)
├── gamja/ # IRC web client (planned)
├── docs/ # Fumadocs documentation site (Next.js)
└── fluux-messenger/ # Fluux XMPP messenger (nginx, Docker)
infra/
├── compose/ # Compose fragments: irc, xmpp, bridge, thelounge, obsidianirc, fluux-messenger, cert-manager, networks
├── nginx/ # Nginx config for Prosody HTTPS
└── turn-standalone/
scripts/ # init.sh, prepare-config.sh, gencloak-update-env.sh
tests/ # Root pytest suite (IRC, integration, e2e, protocol)
docs/ # Static assets (examples/unrealircd/tls/)
| Command | Purpose |
|---|---|
just init |
Create data/ dirs, generate config, dev certs |
just dev |
Start stack with dev profile (.env.dev overlay) |
just prod |
Start production stack |
just down |
Stop dev stack |
just down-prod |
Stop production stack |
just logs [service] |
Follow logs |
just status |
Container status |
just test |
Run root pytest (tests/) |
just test-all |
Root tests + just bridge test |
just lint |
pre-commit run --all-files |
just scan |
Security scans (Gitleaks, Trivy) — placeholder |
just build |
docker compose build |
just clean |
Prune unused Docker resources and volumes |
just prosody-token |
Generate a non-expiring Prosody admin API Bearer token |
.env— Copy from.env.example; customize domains, passwords, tokens. Required forjust initand compose..env.dev— Overlay forjust dev; overrideIRC_DOMAIN,PROSODY_DOMAIN, etc. for localhost. Required forjust dev; copy from.env.dev.example.
| Mod | Loads | Example |
|---|---|---|
just irc |
apps/unrealircd | just irc shell, just irc reload, just irc test, just irc sra-bootstrap <nick> |
just xmpp |
apps/prosody | just xmpp shell, just xmpp reload, just xmpp adduser, just xmpp check |
just web |
apps/web | just web dev, just web build, just web lint |
just bridge |
apps/bridge | just bridge test, just bridge check, just bridge lint |
just lounge |
apps/thelounge | just lounge add <name>, just lounge list, just lounge reset <name> |
just obsidianirc |
apps/obsidianirc | just obsidianirc shell, just obsidianirc rebuild, just obsidianirc rebuild-clean |
- apps/atheme/AGENTS.md
- apps/bridge/AGENTS.md
- apps/gamja/AGENTS.md
- apps/obsidianirc/AGENTS.md
- apps/prosody/AGENTS.md
- apps/thelounge/AGENTS.md
- apps/unrealircd/AGENTS.md
- apps/web/AGENTS.md
- apps/webpanel/AGENTS.md
- apps/docs/AGENTS.md
- apps/fluux-messenger/AGENTS.md
- infra/AGENTS.md
- scripts/AGENTS.md
- tests/AGENTS.md
- README.md
Docker, just, uv, pnpm, Node.js 22, Python 3.11+3.12, envsubst (gettext-base).
Docker daemon must be started manually: sudo dockerd &>/tmp/dockerd.log &. For non-root Docker access add your user to the docker group (sudo usermod -aG docker $USER then re-login), or prefix Docker commands with sudo. Avoid chmod 666 /var/run/docker.sock — it grants root-equivalent access to all local users.
- Env files:
cp .env.example .env && cp .env.dev.example .env.dev(idempotent; skip if files exist). - Init + Docker stack:
just dev— runsscripts/init.sh(createsdata/dirs, generates self-signed certs, substitutes config templates) then starts all Docker Compose services with the dev profile. - Next.js web app:
cd apps/web && NEXT_PUBLIC_IRC_WS_URL="ws://localhost:8000" NEXT_PUBLIC_XMPP_BOSH_URL="http://localhost:5280/http-bind" pnpm dev(port 3000). This runs outside Docker as a local Node process.
| Service | Port | Notes |
|---|---|---|
| IRC (TLS) | 6697 | UnrealIRCd; self-signed cert for irc.localhost |
| IRC WebSocket | 8000 | UnrealIRCd WS |
| IRC RPC | 8600 | UnrealIRCd JSON-RPC |
| Atheme HTTP | 8081 | IRC services JSON-RPC |
| WebPanel | 8080 | UnrealIRCd admin panel |
| XMPP C2S | 5222 | Prosody client-to-server |
| XMPP HTTP | 5280 | Prosody BOSH/WebSocket |
| XMPP HTTPS | 5281 | Prosody (via nginx) |
| XMPP HTTPS (default URL) | 443 | Same nginx; 127.0.0.1:443 only — https://xmpp.localhost/… without :5281 (Fluux) |
| The Lounge | 9000 | Web IRC client (private mode; needs user created via just lounge add) |
| Fluux messenger | 8091 / 8443 | XMPP web client (HTTP / HTTPS host ports → nginx in container) |
| Dozzle | 8082 | Docker log viewer (dev profile only) |
| Next.js | 3000 | Web app (runs locally, not Docker) |
- Unit tests (fast, no Docker needed):
uv run pytest tests/unit/ - Bridge tests (fast, no Docker needed):
uv run pytest apps/bridge/tests/ - Full root suite (
just test): includes integration tests that build Docker images — these may time out in constrained environments. Prefer runningtests/unit/andapps/bridge/tests/for quick validation. - All tests:
just test-all(root tests + bridge tests).
uv run pre-commit run --all-files (equivalent to just lint). Requires Python 3.11 on PATH (installed by snapshot as /usr/local/bin/python3.11). Pre-existing lint warnings: luacheck warning in apps/prosody/config/prosody.cfg.lua.
- ObsidianIRC + Firefox (dev): The WebSocket at
wss://127.0.0.1:8000uses a self-signed cert. Firefox blocks it without prompting. Visithttps://127.0.0.1:8000/first, accept the cert exception, then reload ObsidianIRC. CLOUDFLARE_DNS_API_TOKENwarning: Docker Compose emits a warning about this unset variable — safe to ignore in dev (cert-manager is not needed locally).pnpm installbuild scripts warning: esbuild/sharp/workerd build scripts are blocked by default. They have fallback binaries and the warning is non-blocking.apps/weblint (ultracite check): Currently fails due to biome config expecting a.gitignoreinapps/web/. This is a pre-existing issue.pnpm run build(Next.js build) works fine.pre-commit install: Ifcore.hooksPathis set by the environment, rungit config --unset-all core.hooksPathfirst.- Integration tests:
tests/integration/andtests/e2e/tests attempt to build fresh Docker images and may time out. Usetests/unit/for quick validation.