Documentation

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

OptionHTML surfacelist_* MCP toolUse when
*(default)*GET /{prefix} (list) + GET /{prefix}/{slug} (item)includedStandard content — posts, docs, essays
smeldr.SingleInstance()GET /{prefix} only, serves first published itemsuppressedTypes with exactly one meaningful live item
smeldr.Standalone()GET /{slug} (top-level, no prefix)includedClean URLs — marketing pages, landing pages
smeldr.APIOnly()None — HTML requests return 404includedAdmin-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}s MCP 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} with Accept: text/html returns 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.