Module routing options
Every Smeldr module has a routing mode. The default registers a full HTML surface with a list page and individual item pages. Three options change that behaviour for types where the default does not fit.
Comparison table
| Option | HTML surface | list_* MCP tool | Use when |
|---|---|---|---|
| *(default)* | GET /{prefix} (list) + GET /{prefix}/{slug} (item) | included | Standard content — posts, docs, essays |
smeldr.SingleInstance() | GET /{prefix} only, serves first published item | suppressed | Types with exactly one meaningful live item |
smeldr.Standalone() | GET /{slug} (top-level, no prefix) | included | Clean URLs — marketing pages, landing pages |
smeldr.APIOnly() | None — HTML requests return 404 | included | Admin-only types; no public web surface needed |
JSON GET, mutation routes (POST / PUT / DELETE), and CLI are unchanged across all four variants.
Default
No option needed. The module registers:
app.Content(&BlogPost{},
smeldr.At("/posts"),
smeldr.Repo(postRepo),
smeldr.MCP(smeldr.MCPWrite),
)
// → GET /posts (list)
// → GET /posts/hello (item)
smeldr.SingleInstance()
For content types where exactly one published item is meaningful — a site configuration, a home page, an about page.
app.Content(&SiteConfig{},
smeldr.At("/site-config"),
smeldr.Repo(configRepo),
smeldr.MCP(smeldr.MCPWrite),
smeldr.SingleInstance(),
)
// → GET /site-config → serves first published SiteConfig directly
// → 404 when no published item exists
GET /{prefix}serves the first published item directly; there is no list page.- The
list_{type}sMCP tool is suppressed.
smeldr.Standalone()
For content types where clean, prefix-free URLs are required.
app.Content(&MarketingPage{},
smeldr.At("/pages"),
smeldr.Repo(pageRepo),
smeldr.MCP(smeldr.MCPWrite),
smeldr.Standalone(),
)
// → GET /about (item with slug "about")
// → GET /pages (list, unchanged)
Individual items are served at GET /{slug} (top-level). The list endpoint and all mutation routes are unchanged.
smeldr.APIOnly()
For content types with no public web surface — admin objects managed entirely via MCP or CLI.
_ = smeldr.NewModule((*PlatformConfig)(nil),
smeldr.At("/platform-configs"),
smeldr.Repo(configRepo),
smeldr.MCP(smeldr.MCPWrite),
smeldr.APIOnly(),
)
// GET /platform-configs Accept: text/html → 404
// GET /platform-configs Accept: application/json → 200 JSON
// All MCP tools present
GET /{prefix}withAccept: text/htmlreturns 404. This hides existence
from browsers and crawlers — the same posture as Draft content.
- JSON GET, MCP tools, and CLI are fully functional.
- Preview token bypass still works for agents.
Common use cases: HomePage managed via MCP, PlatformConfig, NavTree.
Constraint: APIOnly and SingleInstance cannot be combined
NewModule panics at startup if both options are supplied. SingleInstance serves HTML at GET /{prefix}; APIOnly forbids any HTML surface. The two are mutually exclusive.