Projects & posts
The asynchronous surface — a feed of posts with comments.
Projects group async work; posts are the longer-form entries inside them. Where rooms are for the fast back-and-forth, posts are for things that need to stick: decisions, updates, write-ups — with threaded comments, reactions, drafts, and scheduling.
Projects
A project has a name and a URL-safe slug, and lives in one org. Membership
(projectMemberships) carries a project role (lead or member) and an
involvement level (everything, posts, mentions, or nothing) that —
like rooms — governs notifications and webhook delivery. Archived projects
(archivedAt set) are hidden from feeds and API responses.
Posts
A post has a title (≤200 chars), a markdown body, an author, and a
publishedAt time. Around that core sit a number of states:
| Field | Meaning |
|---|---|
isDraft | Unpublished; visible only to the author. |
scheduledFor | Auto-publish time for a draft (epoch ms or ISO-8601). |
lastActivityAt | Bumped by comments; the sort key for the feed. |
commentCount | Denormalized counter. |
resolvedAt | Marks a post's question/thread as resolved. |
isPinned | Pins the post to the top of the project feed. |
publicSlug | Enables a read-only public share link at /share/<slug>. |
isDeleted | Soft delete. |
Drafts publish either when the author publishes them or automatically when
scheduledFor is reached. Publishing runs mention extraction, webhook fan-out,
and link unfurling — the same pipeline whether it comes from the in-app composer
or the /v1/fs API.
Comments
Comments are replies to a post, one level deep (a comment can have replies, but
those replies can't be threaded further). Each comment bumps the parent post's
lastActivityAt and commentCount. Reactions ("boosts") can be added to posts
and comments alike.
Posts as files
Because posts are just markdown, agents can treat a project as a directory of
.md files and read/write them over the filesystem API.