"opinion is the medium between knowledge and ignorance."
plato is a forum. Reddit-shaped (subs, threads, votes, mods). Every sub is its own universe — the mod is its owner, the operator is a facilitator who runs the lights, not a referee for sub-level disputes. Every mod action lands in a public log; the community can reverse soft removals via votes; if a mod goes rogue, you fork the sub. People leave the mod, not the platform.
The modern web has trained us to accept that what you see isn't what you get — algorithmic feeds, tracking pixels, shadowbans, "for you" everywhere. plato runs upstream: what you see is what you get. Chronological feed, public modlog, posts as plain markdown on disk. The visible truth is the only truth.
- Plain text. Markdown for posts, hyperlinks for everything else. No image / video / file hosting. The forum loads on any device, on any connection, in any decade.
- Magic-link sign-in, no identity lock. Click an emailed link → you're in. No password, no profile, no captcha, no second factor. The moment the link is sent, the email is forgotten — only a one-way fingerprint, scoped to this site, remains. Same email on two plato sites = two different pseudonyms.
- Mods own their sub, members hold them accountable. Every action — soft removal (fold-behind-a-chip, body still readable), hard removal (stub, reason required), ban, transfer — lands in a public log per sub. The audit trail is the social pressure. Members have symmetric levers: flag a target → 3 distinct flaggers auto-collapse it for review; upvote a soft-removed target → community auto-lifts it once the threshold is met. The mod doesn't have to be convinced; the community overrules.
- Subs that go quiet go read-only, not zombie. If a mod steps down with no co-mods, or if no mod has been active in a sub for 30 days (with a 28-day warning banner before that), the sub becomes read-only — content stays viewable, no new posts. Any current mod can flip it back. The operator does NOT assign new mods or override sub state; communities reactivate themselves or members migrate by creating a successor sub. This is plato's load-bearing defense against authority-coercion: a "lawful order to install a chosen mod" has no admin path in plato to attach to.
- One dashboard for mods, one public log for everyone.
/modlogwith three modes — open (pending flags, expand any row to decide inline), inbox (deduped current state), audit (every event flat). The audit mode is public — instance-wide, no login required, linked from the footer of every page. open / inbox stay mod-only. Per-sub/sub/<name>/modlogis also public. - RSSvp. Three pull-only feed tiers, no email digests, no push, no app: every sub publishes
/sub/<name>/rss(public Atom); each logged-in user gets two token-gated personal feeds at/u/<token>/subs.rss(everything across the subs they follow) and/u/<token>/rss(the above plus replies + mod actions on their own content) — token shown on/memlogwith a regenerate button. Drop the URLs into NetNewsWire, Miniflux, FreshRSS, or any reader. No notification system to fight, no app to install, no algorithm. Plato will never email you about activity — magic-link login is the only outbound mail, deliberately. - Interoperable from day one. Posts are plain markdown files on disk. The database is an index, regenerable. One-command export = full history or a sub's archive, readable in any text editor.
- You pick the feed. Home page top-nav: Posts / Comments tabs, sort by new / old / top / hot, filter by 24h / week / all.
/subslists every sub at a glance. Each sub keeps its own color in the feed so you can scan-and-skim. No algorithm decides what you see. - Runs on a $5 VPS. One process, one SQLite file, one HTTP port. Backups = two
cpcommands. No build step, no frontend framework. Apache 2.0, fork without asking.
Decisions, not roadmap items:
- Ads, analytics, tracking pixels, third-party JavaScript.
- Algorithmic feeds.
- Karma, follower counts, post counts, leaderboards, "online now" badges.
- Real names, phone numbers, photos, locations.
- Image / video / file uploads.
- Tags, hashtags.
- Private subs, DMs, hidden side-channels.
- Password auth, OAuth, SSO, federation.
Lemmy is the open-source Reddit clone most often suggested. Same shape, different bet:
| Lemmy | plato | |
|---|---|---|
| To run it | 5 services + database server, container setup | One program, one file, two commands on a cheap VPS |
| Sign in | Username + password (recovery, 2FA, CAPTCHA) | Click an emailed link, address forgotten |
| Privacy of your email | Kept on file, same identity across sites | One-way fingerprint, different pseudonym per site |
| Federation + image hosting | Yes (cross-server protocol, server caches strangers' images) | No — one site, links only |
| If the operator goes bad | Move to another federated instance | Fork the code + your archive, run your own |
Other forum software (NodeBB, Discourse, phpBB, Discuz!, vBulletin) is bbforum-shaped (categories and topics), runs heavier stacks, and inherits a 25-year-old auth pattern (account row + password + email-on-record). plato keeps the self-host ethics of that era and the interaction model of Reddit's small-subs era. None of the bloat either accumulated.
- Stack: Node.js ≥ 22.5, SQLite (single file), no build step, ~5 runtime deps.
- Install:
git clone && npm install && npm run migrate && npm start— one HTTP port, default 8080. - Backup:
cpthe SQLite file + theposts/directory. - Mail: dev → Mailpit on port 1025; prod → see the knowless OPS guide.
- Spam knobs: tighten via
config.json(rate limits, link cap, regex patterns, URLhaus). Floors are PRD-locked — operators tighten, never loosen. - Per-sub settings: owner sets auto-uncollapse thresholds at
/sub/create. Spam knobs are forum-wide on purpose. - Cron jobs: hourly URLhaus refresh, daily full-state backup (7-day retention), daily stats snapshot, weekly stats digest by email, quarterly disposable-domains refresh — all autoconfig from
config.jsonoperator.{email,service}. See cron-jobs.md. - Privacy-led discoverability: declarative head tags (description, canonical, OpenGraph, Twitter card),
/robots.txt,/sitemap.xml. No analytics, no tracking pixels, no third-party JS, no cookie banner. The audit checklist for keeping it that way is in privacy-seo.md.
git clone https://github.com/hamr0/plato
cd plato
npm install
cp .env.example .env
# generate a one-time secret for this instance
SECRET=$(node -e "process.stdout.write(require('crypto').randomBytes(32).toString('hex'))") \
&& sed -i '/^KNOWLESS_SECRET=$/d' .env \
&& echo "KNOWLESS_SECRET=$SECRET" >> .env
npm run migrate
npm startOpen http://localhost:8080 and post.
- Operator Guide — running and customizing your instance.
- Cron jobs — URLhaus + disposable-domains refresh, autoconfig from
config.json. - Integration Guide — wiring plato into a project.
- PRD — spec + rationale for every locked-in choice.
- Build plan — milestone roadmap.
- Changelog — what has shipped.
Apache 2.0. Fork without asking.