Changelog
Changelog #1
The first of these. Four things shipped to the alpha: Collections (structured data next to your issues), real-time chat with agents in the channel, a mobile app in testing, and built-in product analytics. The throughline is that they all ride the same realtime substrate, so each one was less work than it looks.
7 min
We've been heads-down. This is the first changelog, so it covers more ground than the ones after it will. Four features landed in the alpha since we started, and they're the kind that change what the platform is, not just what it does.
There's a throughline worth saying up front. Plain runs on one realtime substrate: reads stream to the client over Electric shapes, the client holds them in TanStack DB, writes go through server functions that return a Postgres txid so optimistic edits reconcile against a single source of truth, and collaborative bodies + presence ride Yjs over a Hocuspocus socket. We built that for issues. The payoff is that everything below was mostly a matter of putting new data on rails that already existed, which is why four things shipped in one window instead of one.
Collections

Structured data, in your repo, next to Issues and Docs. Collections are the Notion/Airtable-shaped primitive Plain was missing: a collection has fields (columns), records (rows), and views. Spin one up from a template or blank, define your fields (text, select, multi_select, date, number, person, email, url, checkbox, and more) and you've got a CRM, a content calendar, a bug-triage board, whatever shape your team keeps rebuilding in a spreadsheet that lives somewhere your code doesn't.
The reason it landed quickly is the reason it feels good to use: a collection rides the exact rails issues already do. Records stream to your browser over the same Electric shape proxy, filtering and sorting and grouping happen client-side over the streamed rows (no per-view query), and a cell edit is one server function that returns a txid, so it's optimistic locally and live for everyone else watching the table. Editing a cell in a Collection and dragging a card on the issues board are, underneath, the same operation.
What ships today is the Table view and the core field set, enough for a working CRM end-to-end. Board (group by a select field, drag between columns) and Calendar (place records by a date field, drag to reschedule) are next, and they're cheap to add precisely because grouping is already a client-side operation over the same rows.
And because Collections are real platform data, they're in the MCP surface from day one. An agent can collections_list, read rows, and collection_rows_create the same way it files an issue, so "keep this table updated" is something you can hand to an agent, not a thing you do by hand.
Real-time chat

Plain now has its own chat, an integrated Slack alternative that lives where your work does. Public and private channels, DMs, and the nice trick: every issue and PR has a discussion channel that is a real chat channel. Comment threads and team chat are the same primitive, not two inboxes you reconcile.
Messages sync over Electric like everything else, so sends are optimistic and instant and the sidebar's unread counts and last-message previews are denormalized on write (no joins to render your channel list). On top of the baseline, a few things we're happy with:
- Online status and typing, done right. Presence rides Yjs awareness over the collab socket: no heartbeat table, no sweeper job, nothing written to the database. You're "online" when your tab's focused, "away" when it's hidden, and gone the instant you disconnect. The same channel carries who's typing and who's currently viewing an issue or doc.
- Agents in the channel. Agents are first-class members of your org. They show up in the mention picker.
@-mention one and it spins up a scoped session and replies in the timeline like anyone else. Do it inside an issue or PR's discussion channel and the agent is automatically scoped to that repo and told which issue it's in, so "@agent can you look at this" just works, with the context already loaded. - Reactions. A tight, fixed set (š ā¤ļø ā š and a few more) rather than the full emoji firehose: idempotent, one row per person per reaction, streamed in the same shape as the messages they're on.
- Voice transcription. Hold to talk, and the clip is transcribed (via
gpt-4o-mini-transcribe) straight into the composer as text you can edit before sending. The composer re-transcribes the growing clip every couple of seconds, so it feels like live dictation even though each pass is a clean batch transcription.
Mobile app
Plain is on your phone. iOS and Android builds are in testing now (TestFlight and Play internal), with messaging, issues, and docs in this first cut: read, write, and collaboratively edit, on the move.
The interesting part is how little new backend it needed. Reads use the same authenticated Electric shape proxy as the web app, unchanged: a bearer token instead of a cookie, same collections, same row types. Writes go through a typed oRPC contract that wraps the same server-side cores the web's server functions already call, so validation is single-sourced across web, mobile, and CLI (and it emits OpenAPI for free). And the rich-text editor (Plate + Yjs, which has no React Native port) runs as the real web editor inside an Expo DOM component, connected live to the same Hocuspocus collab service. So editing a doc from your phone is genuine co-editing, not a degraded mobile fork.
A longer post is coming, "building for an entire day without a laptop", on what it's actually like to run a project from the app. Short version: more than we expected.
Product analytics
You can now see who's using what without leaving Plain. Analytics is privacy-first product and web analytics built into the platform: a small SDK you drop into your own site, a public ingest endpoint, and a per-repo dashboard.
Install is a one-liner. The SDK is on npm as @plainalpha/analytics. Drop it near your root and you're done:
import { PlainAnalytics } from "@plainalpha/analytics/react";
function RootLayout({ children }: { children: React.ReactNode }) {
return (
<>
<PlainAnalytics publicKey="pa_pub_01Jā¦" />
{children}
</>
);
}It's cookieless by default: no banner to click through. Visitors are identified by a daily-rotating hash (sha256(daySalt ā„ siteId ā„ ip ā„ ua)) computed at ingest; the raw IP and full user-agent are read only to derive country, browser, and OS, then dropped. Nothing identifying is ever written, and the salt rotates at UTC midnight so visitors can't be correlated across days. Do-Not-Track is honored, query strings are stripped from paths, and bots are filtered server-side before they can inflate a count.

The dashboard lives in the repo, alongside the code it's measuring: visitors and pageviews over time, top pages, sources, countries, and devices, plus a live current-visitors count. Aggregation is plain SQL over an indexed events table (the right tool when you want count and group by, not a million rows streamed to the browser), so the dashboard answers in one round trip.
The whole point is the absence of a context switch. The thing you ship, the issues against it, the chat about it, and the numbers on it are now one tab.
That's the window. All four are live in the alpha and still moving. We're looking for a handful of teams to build alongside. If that's you, join the alpha.