sharpdocs.json schema

Formal shape of the structural sharpdocs.json + the content site.json (base + locale overlays).


A SharpDocs project is described by two required JSON files at its root, plus optional per-locale overlays:

File Purpose Required
sharpdocs.json Structural — locales, defaultLocale, paths yes
site.json Base content — title, description, sidebar yes
site.{locale}.json Sparse content overlay for that locale optional

Path resolution rule: every relative path inside a JSON file is resolved relative to the directory of that file. The root sharpdocs.json's projects[].path is relative to the root docs folder; a per-project sharpdocs.json's artifacts is relative to its own project folder. Paths in appsettings.json follow a different rule (see Configuration options).

sharpdocs.json — single-project / per-project schema

The structural file. Same shape whether it's the root of a single-project site or one project inside a multi-project tree.

{
  "github":        "string | null",            // optional repo URL, rendered in header
  "artifacts":     "string | null",            // optional path; default "./artifacts" (per-project)
                                               //                or appsettings (single-project root)
  "defaultLocale": "string",                   // required; must appear in `locales`
  "locales":       ["string", "string", ...]   // required; non-empty
}

In a single-project root file, optional title / description are accepted for compatibility but unused — the per-locale site.json supplies them.

sharpdocs.json — multi-project root schema

A root file with a non-empty projects array switches the site to multi-project mode. The structural fields above move into each project's own sharpdocs.json; the root file is a thin pointer.

{
  "title":       "string | null",   // optional — picker page branding only, untranslated
  "description": "string | null",   // optional — picker page branding only, untranslated

  "projects": [
    {
      "id":   "string",   // url segment, sanitized to [a-z0-9-]
      "path": "string"    // relative to the root docs folder
    }
  ]
}

There is no root defaultLocale or locales in multi-project mode — each project owns its own.

site.json — base content schema

The default-locale labels and sidebar structure. Required for every project.

{
  "title":       "string",          // shown in header + <title>
  "description": "string",          // meta description

  "sidebar": [
    {
      "label": "string",            // group heading
      "items": [
        {
          "label": "string",        // link text
          "slug":  "string"         // must match a page slug
        }
      ]
    }
  ]
}

site.

Same shape as site.json, but every field is optional. The merge is structural-by-position: each group/item overrides the entry at the same index in the base; missing or empty fields inherit. See Localization for the full overlay model.

{
  "title":       "string | null",
  "description": "string | null",
  "sidebar": [                        // optional; can have fewer groups than base
    {
      "label": "string | null",       // optional — null/missing → inherit from base[i]
      "items": [                      // optional; can have fewer items than base[i].items
        { "label": "string | null", "slug": "string | null" }
      ]
    }
  ]
}

Matching rules

  • JSON property names are case-insensitive.
  • slug is matched case-insensitively against the in-memory page lookup.
  • Leading and trailing slashes on slug are trimmed before lookup.
  • Project id is sanitized: lowercased, anything outside [a-z0-9-] stripped, runs of - collapsed, leading/trailing - trimmed.
  • Reserved ids (post-sanitization), applied to both project ids and locale codes: search, packages, v3, api, docs. A reserved id is degraded with an error.
  • Duplicate project ids or locale codes (post-sanitization) silently drop the second occurrence.
  • Locale-suffix detection on filenames (foo.{locale}.md) only fires when {locale} appears in locales — otherwise the dot is part of the slug.

Validation at startup

  • sharpdocs.json must exist at the docs root — FileNotFoundException otherwise.
  • It must deserialize to a non-null object — InvalidOperationException otherwise.
  • defaultLocale must be present in locales.
  • site.json must exist for each project — fatal for that project if missing.
  • Every sidebar slug must resolve to a markdown file (base or locale override). Missing slugs degrade that locale. If the default locale fails, the whole project degrades.
  • A missing or malformed per-project sharpdocs.json degrades the project, not the site.
  • Per-locale overlay files (site.{locale}.json) are optional — silent when absent, logged-and-skipped when malformed.

Complete examples

Single-project, two locales

sharpdocs.json:

{
  "github": "https://github.com/you/my-library",
  "defaultLocale": "en",
  "locales": ["en", "vi"]
}

site.json:

{
  "title": "My library",
  "description": "A small .NET library.",
  "sidebar": [
    { "label": "Overview", "items": [{ "label": "Introduction", "slug": "index" }] }
  ]
}

site.vi.json (sparse — only the title is translated; sidebar inherits):

{ "title": "My library (Tiếng Việt)" }

Multi-project root

{
  "title": "Codezerg Libraries",
  "description": "Shared utilities.",
  "projects": [
    { "id": "alpha", "path": "../codezerg-alpha" },
    { "id": "beta",  "path": "../codezerg-beta" }
  ]
}

Multi-project per-project sharpdocs.json

{
  "github": "https://github.com/codezerg/alpha",
  "artifacts": "./artifacts",
  "defaultLocale": "en",
  "locales": ["en", "ja"]
}

(plus its own site.json, optional site.ja.json, and *.md / *.ja.md files at that project's root.)