Blogs and newsletters, built in.
A blog is a channel: an owner, a slug, a visibility level. Posts are markdown. Any blog can also be a newsletter with double opt-in and a durable sender. It is all in the framework, themed, with feeds, a public read API and the same REST and MCP surface as everything else — so your project starts at the writing.
Two surfaces, one set of rules.
Authors write in their own studio. Operators manage every blog from the admin console. Both call the same service, so there is one idea of "publish", one slug rule, one rendered body.
/my/blogs/. Any signed-in user can own a blog; drafts, scheduling and publishing happen here.
/blog/. Themed, with per-blog pages, permalinks, tags, an archive and feeds — gated by one setting until you are ready.Visibility is a ladder
Private (owner and staff), members (anyone signed in), public (the internet). A post's own lifecycle sits on top: draft, scheduled, published, archived. Both gates apply.
Newsletter when you want it
Turn it on per blog. Subscribers confirm by email (double opt-in), issues are snapshots of what was sent, and the sender resumes if the worker restarts. RFC 8058 one-click unsubscribe included.
Runbook pages publish too
A versioned runbook document can be published into a blog and kept in sync — write operational docs once, publish the ones worth sharing.
Publish from your own code.
Every write goes through the service, which keeps slugs unique, renders the body and stamps the timestamps — from the studio, the console, REST, MCP, or a line in your own app.
from apps.blog import service post = service.create_post( blog, title="October release notes", body_markdown="## What changed\n\n- Calendars…", tags=["release"], actor=request.user, ) service.publish_post(post, actor=request.user) # or at=<datetime> to schedule
Publishing is always an explicit act — nothing goes live because a row was saved.
Reading, for anyone
/blog/,/blog/<blog>/,/blog/<blog>/<post>//blog/<blog>/feed.rss—.atomand.jsontoo/blog/api/blogs/…anonymous JSON read API for your own front end/feed/blog.rssthe site-wide river
Writing, for your apps and agents
/smallstack/api/blog/posts/REST, authenticated and owner-scoped- MCP:
list_posts,create_post,update_post— Claude can draft for you - Webhooks on create and update, for Slack or a static-site rebuild
- Datasets:
smallstack_blog_posts,…_issueswith correct send-rate ratios
A changelog, a company blog, a letter.
All three are the same app with different settings. Ask a coding agent to set one up and it will reach for the built-in rather than new models.