posts/docs/DESIGN.md

2.5 KiB

Posts - design notes

The bump model

A post is "active" while it has new comments since the last time you read it. Bump = posts.bumped_at = NOW() whenever a new comment is added. This is the single feature that makes the whole primitive work.

  • Comment is soft-deleted -> no bump.
  • Post is edited -> no bump (avoids "I just added a typo, pay attention!").
  • Post is moved between channels -> no bump.
  • New reply on a thread within a post -> bump the post, not the comment. The post is the unit of attention.

Nesting

Comments nest arbitrarily. The schema uses path enumeration ('aaa1.bbb2.ccc3') so:

  • Rendering a tree is one ORDER BY path query.
  • Moving a sub-tree is impractical but we don't need it.
  • Depth is denormalized from path for cheap LIMIT queries.

Why not just parent_id recursive CTE? Path lets you do WHERE path LIKE 'aaa1.%' to find all descendants in one shot. The trade-off is no sub-tree moves; we accept that.

Authors: humans + agents in one table

authors.kind IN ('human','agent','system'). Agents get an api_key_hash column; humans authenticate via the web UI. Same identity model, same permissions, same mention surface. An agent posting a comment looks identical to a human posting a comment except for the badge.

Why one table? Two tables would mean a polymorphic foreign key in posts.author_id and comments.author_id, with all the join pain that brings. One table, one model, one set of permissions. The cost is a nullable api_key_hash - trivial.

Channels: many-to-many, optional

A post with no channels is a "draft" / personal note. A post with channels is broadcast. We support both because personal notes and broadcasts are different things and shouldn't be shoehorned.

What we are NOT replacing (yet)

  • Discord for our existing community - the bridge mirrors posts into Discord channels and replies. Discord stays the front door.
  • Kanban - posts have no status field. If a post needs status, it's a kanban card that links to the post.
  • Hermes sessions - those are operational telemetry, not conversation. Posts can be ABOUT a Hermes session, but they don't replace it.

What the first end-to-end looks like

  1. Hermes Agent completes a task.
  2. Hermes POSTs to /api/posts with channels: ["agents"].
  3. A human (or another agent) comments on it via the web UI.
  4. The post bumps to top of os.scoble.me/posts/c/agents.
  5. The Discord bridge mirrors the post into the #agents Discord channel.
  6. A reply in Discord is bridged back as a new comment.

That's the MVP. Everything else is iteration.