Authoring and publishing documentation
Updated 2026-07-07
How this docs site works
Each page you read on docs.usable.dev (or /usable/... locally) is a published memory fragment in a Usable workspace. The Next.js app does not store copy in Git — it renders live content from the Usable API, caches it for performance, and refreshes when fragments change.
At a high level:
- Authors edit markdown + YAML frontmatter in Usable.
- Media lives in Usable Assets and is referenced with
asset://URIs in markdown. - The docs app fetches fragments, resolves assets to CDN URLs, and renders MDX + Shiki for HTML pages.
- On-demand revalidation busts the cache when content is published or updated.
The diagram below is stored in Usable Assets under the Usable Docs → Testing folder (same tenant as this workspace):

Tip for authors: If the image does not appear, confirm
USABLE_ASSETS_API_KEYis configured on the docs server and that the asset ID inasset://usable-assets/<uuid>matches the image in Assets.
Frontmatter contract
Every doc fragment should include frontmatter like this:
---
slug: authoring-and-publishing
section: Getting Started
order: 2
status: published # draft fragments are hidden from the public site
description: >
One or two sentences for SEO, llms.txt, and search snippets.
---| Field | Required | Purpose |
|---|---|---|
slug | Recommended | URL path under the tenant (/usable/<slug>) |
status | Yes | published or draft |
order | Recommended | Sort order inside a section or collection |
description | Recommended | Shown in metadata and LLM manifests |
Referencing images from Usable Assets
Use the asset:// scheme in markdown. The renderer replaces it with a signed CDN URL at request time:
The same resolved URL appears in the .md variant of the page for LLM consumers.
Example: trigger cache refresh after publish
When a fragment changes, call the docs webhook (or /api/revalidate) with your secret:
curl -sS -X POST "http://localhost:3000/api/webhooks/usable" \
-H "Authorization: Bearer $REVALIDATE_SECRET" \
-H "Content-Type: application/json" \
-d '{
"workspaceId": "ef680c43-c6a2-4897-9470-4cf6d3bb204e",
"tenant": "usable",
"slug": ["authoring-and-publishing"]
}'On the server, revalidation is implemented roughly like this:
import { revalidateTag, revalidatePath } from "next/cache";
export async function refreshTenantPage(tenant: string, slug: string[]) {
revalidateTag(`docs:tenant:${tenant}`, "max");
revalidatePath(`/${tenant}/${slug.join("/")}`);
}Code samples in docs
Syntax highlighting uses Shiki (VS Code themes). Fenced blocks need a language tag:
type DocFrontmatter = {
slug: string;
status: "published" | "draft";
order: number;
};
export function isPublic(doc: DocFrontmatter): boolean {
return doc.status === "published";
}{
"ok": true,
"revalidated": {
"tenantTag": "docs:tenant:usable",
"paths": { "tenantPage": "/usable/authoring-and-publishing" }
}
}What to try next
- View this page as raw markdown:
/usable/authoring-and-publishing.md - Check the tenant manifest:
/usable/llms.txt - Edit this fragment in Usable, revalidate, and refresh to see ISR in action