Every key of the two config schemas, end to end: .docuriser-site and .docuriser-project.
Everything Docuriser builds is described by a small family of JSON files: a .docuriser-site at a website's root, a .docuriser-project in each project directory the site registers, and a .docuriser manifest at the root of each project's source repository. Builds also write one derived file, the .docuriser-built provenance beside each built version. The GUI's configurators edit the first three; this page documents every key end-to-end, including the ones the panels don't surface (the configurators' Text view covers those).
The format tag. Every Docuriser-owned file carries "format": 1 as its first key. Readers accept files at or below their own format (a file with no format reads as pre-1.0 legacy) and refuse newer files with a message naming the Docuriser upgrade as the remedy, so an old install can never silently misread configs written by a newer one. Save paths stamp the tag automatically, including onto legacy files on their first edit.
Path rules. Relative paths in a site config resolve against the directory containing .docuriser-site; a leading / also reads from that directory (and, for values that end up as links in the emitted pages, from the built site's root). Build-shaped paths (README, topic sources, include directories) live in the manifest and resolve against the repository root that contains it: your checkout for working-tree reads, the tag's snapshot at build time. Keys documented as URL are addresses in the built site (e.g. /images/logo.svg, which is the file images/logo.svg beside the config), not source-tree paths.
.docuriser-site| Key | Type | Meaning |
|---|---|---|
title |
string | Site title; the home page <title> unless pages.home_title overrides it. |
description |
string | Baseline meta description for every page (also og:description). |
url |
string | Canonical site URL, available to templates. |
copyright |
string | Footer copyright line. |
output |
string | Required to build. Where the site emits, resolved against the site directory (e.g. "./build/site"). |
vortex.default_theme |
string | Default theme display id for the emitted pages' theme picker. Defaults to "Dark (huntrsoftwarellc)". |
branding| Key | Type | Meaning |
|---|---|---|
logo_path |
URL | Brand tab logo image. When empty, the tab shows tab_text instead. |
tab_text |
string | Text label for the brand tab (used when there is no logo). |
logo_height |
string | Brand logo height in pixels ("25px" and "25" both parse). Default 25. |
logo_height_mobile |
string | Edited and previewed by the GUI's tab preview; the emitted site currently consumes only logo_height. |
favicon_from_logo |
bool | Generate the favicon set from logo_path, re-derived whenever the logo changes (the panel's Generate from logo). |
favicon_source |
URL | Explicitly picked favicon source image (recorded by the panel's Browse; absent in from-logo mode). |
favicon_background |
string | #rrggbb fill behind the home-screen icon sizes (apple-touch and Android). Unset: the default theme's primary surface color. |
The generated set lives in the site's favicon/ directory and overlays the built site's root (/favicon.ico, /favicon-16x16.png, /favicon-32x32.png, /apple-touch-icon.png, /android-chrome-192x192.png, /android-chrome-512x512.png); a hand-made set dropped there under the same names ships just as well, and a site with no favicon/ ships Docuriser's defaults. site.webmanifest is derived at build time (name and short name from title and branding.tab_text, colors from the default theme's primary), and a favicon/site.webmanifest overrides the derived one.
projects[]Each entry registers one project:
{ "config": "./projects/layers/.docuriser-project" }
The path resolves against the site directory. Any extra keys on the entry override the referenced project config's keys for this site, a per-site inline override. Ordering matters: family members are conventionally listed contiguously after their family root (the GUI keeps them that way). See the projects guide.
socials[]Rendered as cards on the socials page, and a non-empty array adds the Socials entry to the site's navigation.
| Key | Type | Meaning |
|---|---|---|
label |
string | Card title. |
username |
string | Handle shown on the card (optional). |
url |
string | Link target. |
icon |
URL | Card icon (optional). |
external |
bool | Marks the link external (adds the external-link glyph). |
policies[]Each policy renders to /<slug>.html from a Markdown source and gets a titlebar tab on its page.
| Key | Type | Meaning |
|---|---|---|
slug |
string | Required: the output page name. |
file |
string | Required: Markdown source path under the site directory. |
title |
string | Page <title> (falls back to the slug). |
name |
string | Tab label (falls back to title). |
icon |
URL | Tab icon (defaults to the policies glyph). |
A policy is usually paired with a footer_links entry pointing at /<slug>.html; the GUI's Add/Remove Policy flows keep the two in sync.
footer_links[]{ "label": ..., "href": ... } pairs rendered in every page's footer.
homeThe home page is composed from an ordered list of sections (home.sections), rendered top to bottom in the order given. The GUI's Website → Home Page editor manages this list (add, remove, reorder, edit), and you can also author it directly.
"home": {
"sections": [
{ "type": "description" },
{ "type": "projects" },
{ "type": "socials" },
{
"type": "custom",
"id": "sponsor",
"label": "Sponsor",
"subtext": "Sponsor CTA with animated hearts",
"icon": "/images/heart.svg",
"body": "/content-fragments/sponsor_home.html",
"head": "/content-fragments/sponsor_home_head.html"
}
]
}
Each entry has a type:
type |
Renders |
|---|---|
description |
The site description value as the home's lead paragraph. This is the same field that drives the meta description, so the visible tagline and the SEO snippet share one source. |
projects |
The project cards (shown only when projects[] is non-empty). |
socials |
The social cards (shown only when socials[] is non-empty). |
custom |
An author-supplied HTML fragment. |
The three preset types carry only type and appear at most once. A custom section adds:
| Key | Type | Meaning |
|---|---|---|
id |
string | Stable identifier (also names the fragment the GUI seeds). |
body |
path | Required. The section's HTML fragment (a full <section>…</section>) under the site directory. This is the rendered section. |
head |
path | Optional. A <head> fragment (scripts or styles the section needs), folded into the page <head>. |
label / subtext / icon |
string / string / URL | GUI-only: the section's card title, subtitle, and avatar in the Home Page editor. They have no effect on the built site. |
The home layout and the navigation bar are independent: removing the projects or socials section from home.sections does not remove its nav dropdown. Navigation is derived from projects[]/socials[] presence (see nav_menus below).
slotsA map of slot name to HTML fragment path under the site directory. Fragments are pre-rendered and spliced into the built-in pages. The home page's body is composed from the home block (above), not slots. Slots feed the sponsor page (sponsor_body, sponsor_sidebar, sponsor_head) plus the optional shared home_head (extra home-page <head> content, though a custom section's own head is the usual way to add scripts a section needs). Custom names are allowed and become available to page templates.
content_pages[]Free-form extra pages, each emitted at /<slug>.html.
| Key | Type | Meaning |
|---|---|---|
slug |
string | Required: the output page name. |
title |
string | Page <title>. |
body |
path | HTML body fragment under the site directory. |
extra_head |
path | Extra <head> fragment. |
description |
string | Per-page meta description (overrides the site's). |
tab |
object | {name, icon, close_href?}: the page's titlebar tab; close_href defaults to /. |
images/A site's images/ directory is first-class: everything in it is copied to the built site's /images, with nothing to declare. Drop logo.svg in images/ and any config URL can address it as /images/logo.svg (the web path and the path on disk are the same). The GUI's image pickers (site logo, project logo, social/dependency icons) all copy the file you choose into this directory and write the matching URL.
Docuriser's own interface images (the sidebar and nav glyphs) share the /images namespace, so a site can replace one by name: an images/socials.svg overrides the built-in.
static_files[] and static_dirs[]For verbatim content that isn't images. static_files lists individual files (paths under the site directory) copied into the output preserving their relative path. static_dirs lists whole-tree overlays, { "src": "framework/api", "dest": "api" } (dest defaults to src): this is how downloadable artifacts, a backend, or any other tree reaches the built site. Overlays may target /images too; they merge with the site's images/ rather than replacing it.
sponsor and pagessponsor ({url, label}) switches on the sponsor affordance in the site chrome. pages holds per-page <title> overrides: home_title, sponsor_title.
nav_menus: derived, don't author itThe site's navigation is derived at build time from what the config declares (a Projects menu when projects[] is non-empty, a Socials menu when socials[] is non-empty). Anything written under nav_menus is replaced.
.docuriser-project| Key | Type | Meaning |
|---|---|---|
slug |
string | Required. The project's id and URL segment: lowercase letters and digits in dash-separated runs. |
name |
string | Display name. |
tagline |
string | Short descriptor; the project page's meta description, and the subtext on family cards and the member switcher. |
logo |
URL | Project logo. |
parent_slug |
string | Names the family root this project belongs to. Absent means standalone. See families. |
family_label |
string | This member's label in the family switcher and grid (falls back to name). |
family_index |
bool | On a root that has members: false opts out of the umbrella index page, making the root an ordinary switchable member again. Default true. |
Which version fronts the project is not part of its identity: it is derived at site build from versions[] and the built output on disk (see the note under versions[] below). The retired latest_version and default_version keys are ignored, with a line in the advanced log.
buildOne key. Everything else build-shaped lives in the source repository's own manifest (next section), because it describes the source tree and should be versioned with it.
| Key | Type | Meaning |
|---|---|---|
source_path |
string | Root of the project's local source checkout, relative to the config's directory (absolute paths work too). This is where tags are read and where the manifest is found. Machine-local, so it stays on the site side. |
facts[]The fact rows in the project page's sidebar.
| Key | Type | Meaning |
|---|---|---|
label |
string | Row label. |
value |
string | Row value. |
href |
string | Optional: makes the value a link. |
note |
string | Optional: rendered in parentheses after the value. |
preset |
string | Optional: makes the row derived instead of authored (below). |
The License fact is special by convention: when you include a version in the Versions table, its value seeds the new entry's license_display, so the version records the license name it shipped under. (The license text needs no seeding: the version build bundles it from the manifest's build.license; see versions.)
Preset facts. A fact carrying "preset": "stable_release" renders the project's derived latest version (the versions guide): its value is the built tag (e.g. 2.1.3), its note is that version's release date, and it never links. Any authored value/href/note on such a row is overridden, and the row is skipped entirely when the project has no included versions yet. The entry itself is the opt-in, so a typical row is just:
{ "label": "Latest", "preset": "stable_release" }
repoThe repository card in the sidebar: platform (e.g. "Codeberg"), path (e.g. "HuntrSoftware/docuriser"), and url. The card's icon is Docuriser's stock repository glyph, nothing to configure.
requires[]Dependency cards: name, url (site-relative like /vortex.html for internal projects, absolute for external ones), optional icon (URL), and external (bool, adds the external-link glyph).
downloads[]Download rows for the project page sidebar. The config only references URLs; the artifacts themselves are staged via a static_dirs overlay (e.g. a site-level downloads/ directory).
| Key | Type | Meaning |
|---|---|---|
url |
string | Site-relative path to the artifact (e.g. /downloads/nodeyou/nodeyou-2.0-linux-x86_64.tar.gz). |
platform_label |
string | Platform name shown on the button (e.g. "Linux"). |
platform_icon |
URL | Optional platform glyph. |
platform_key |
string | Optional os-arch key (e.g. linux-x86_64, windows-x86_64). A row that carries one becomes a per-platform entry of the desktop update manifest (below). |
size |
string | Optional hand-typed display size. Whenever the artifact is staged, the generator replaces this with the file's real size, so the button never drifts from the binary and you rarely need to set it. |
The desktop update manifest. A project that has a derivable latest version (at least one included versions[] entry) and at least one platform_key download also emits /downloads/<dir>/latest.json, in the folder its platform binaries were staged into. Installed desktop apps (Vortex's update channel) poll that file to learn a newer build exists. Its schema:
{
"version": "2.0.1",
"pub_date": "2026-07-20T00:00:00Z",
"notes_url": "https://huntrsoftware.com/nodeyou/docs/2.0/changelog.html",
"download_page": "https://huntrsoftware.com/nodeyou.html",
"platforms": {
"linux-x86_64": { "url": "https://huntrsoftware.com/downloads/nodeyou/nodeyou-2.0-linux-x86_64.tar.gz", "size": 31457280, "sha256": "..." },
"windows-x86_64": { "url": "https://huntrsoftware.com/downloads/nodeyou/nodeyou-2.0-windows-x86_64-setup.exe", "size": 29360128, "sha256": "..." }
}
}
The manifest is derived, never hand-authored: each platform entry's url is absolutized against the site url, and its size (bytes) and sha256 are computed from the staged file. version is the derived latest version's full built tag (from its .docuriser-built provenance), so patch releases reach the update channel too. The remaining top-level fields come from these project keys:
| Key | Type | Meaning |
|---|---|---|
download_page |
URL | Optional. Defaults to the project's own landing page. |
notes_url |
URL | Optional release-notes/changelog link (site-relative is made absolute). |
pub_date |
string | Optional RFC 3339 timestamp, passed through verbatim. |
Because the sidebar buttons and the manifest both derive from the same latest version, building a release updates the site page and every installed app's update check together, and the two can never disagree.
versions[]The included versions: the minors the site publishes. Entries are created by the Include checkbox in the Versions table (hand-authoring works too) and listed newest-first.
| Key | Type | Meaning |
|---|---|---|
label |
string | Required: the version's id (major.minor, matching its tags) and its versions/<label>/ directory name. |
release_date |
string | Display date. Auto-refreshed by every tag build to the built tag's date, so it tracks what is actually published. |
license_display |
string | The license name shown on the version's license page (e.g. "MIT"), seeded from the License fact at include time. The page itself is gated by the version bundle's LICENSE.md, captured at build from the manifest's build.license. |
The latest version is derived. At site build, the newest included entry (semver order on labels) whose versions/<label>/ output exists on disk fronts the project: its README renders on the landing page, its label names the download button, the docs tab defaults to it, the update manifest advertises its built tag, and the stable_release preset fact shows it. When nothing is built yet, the newest included entry stands in. Building a newer version is all it takes to front it; there is nothing to author.
versions_excluded[]An array of minor labels (["1.0", "0.17", "0.16"]) recording the versions you unchecked: tags that exist but should not publish. Without the record, every old tag would resurface as New forever. The Versions table maintains it; you rarely touch it by hand.
A version's status (New, Excluded, Pending, Complete, No Tag) is never stored anywhere: it is derived from the repository's tags, these two arrays, and what versions/<label>/ on disk was built from. See the versions guide.
tabs[] and author fragmentstabs[] adds extra sidebar tabs ({slug, label, href, icon?, subtext?}); a docs tab is always regenerated from the built versions, so don't author one. A project may also name HTML fragments (paths relative to its config directory): body (replaces the default README-rendering body), extra_head, sidebar_top, sidebar_bottom, plus its own static_files[]/static_dirs[], copied under the project's output path.
.docuriser (the in-repo manifest)The build recipe lives in the project's repository, at its root, versioned with the code. That is what lets every tag describe itself: when Docuriser builds version 2.1 from tag 2.1.3, it reads the manifest as it was at that tag, so renamed guides, moved READMEs, and changed include directories never break old versions. A tag whose snapshot has no manifest cannot build (see the versions guide).
{
"format": 1,
"build": {
"includes": ["include/Layers/"],
"external": ["include/"],
"defines": ["LAYERS_EXPORT="],
"readme": "README.md",
"license": "LICENSE",
"topics": [
{ "slug": "build", "label": "Build", "title": "Build Layers",
"intro": "Follow these steps to build this version.",
"source": "guides/build.md" }
]
}
}
All paths are relative to the repository root. The GUI edits the manifest through the README, License, and Topics panels (resolving it through the project's build.source_path), and creates it on the first such edit if the repository doesn't have one yet.
| Key | Type | Meaning |
|---|---|---|
build.includes[] |
string[] | Include directories whose headers are parsed (libclang) into the API reference: a page per class and struct, and a page per header for its functions, aliases, and enums. See the API reference guide. |
build.external[] |
string[] | Additional include directories passed to the parser but not documented. |
build.defines[] |
string[] | Preprocessor macros (NAME=value) for the parse. |
build.readme |
string | The project README's path; it renders on the project landing page. |
build.license |
string | The project's license file (usually just LICENSE; it need not be Markdown). Each version build copies it into the bundle as versions/<label>/LICENSE.md, which is what gives the version a license page — so every version keeps the license it shipped under. |
build.topics[] |
object[] | The project's Markdown guide pages. See the topics guide. |
There is no output setting: a version build always emits to versions/<label>/ beside the project config.
Topic entries:
| Key | Type | Meaning |
|---|---|---|
slug |
string | Required: the topic's page name and sidebar href. Entries without one are skipped. |
source |
string | Required: the Markdown source path (relative to the repository root). |
label |
string | Sidebar label. |
title |
string | Page <title> lead (falls back to label). |
intro |
string | Optional paragraph rendered above the topic. |
.docuriser-built (provenance, derived)Written into versions/<label>/ by every tag build; never hand-authored and never published to the site.
{ "format": 1, "tag": "2.1.3", "commit": "<sha>", "built": "2026-07-15" }
It records which tag the directory was built from, which is how the Versions table knows a version is Complete (the recorded tag matches the minor's latest patch tag) or Pending again (a newer patch tag has landed). Output that predates provenance, or was built with --working-tree, reads Pending until a tag build replaces it.
The site Docuriser emits belongs to its author: your content, your license; Docuriser claims nothing over generated sites. The only Docuriser-owned bytes in a build are the runtime assets it copies in (the stamped uv_* CSS/JS and framework images), which remain MIT-licensed wherever they land.