Skip to content

Sidebar & Groups: The Complete sidebar.toml Reference

Audience: anyone authoring or maintaining a document directory (a folder with its own ude_doc_config.json) — the person who decides what a project's sidebar looks like and how its classes are grouped.

This page is the single consolidated reference for sidebar.toml. Target Settings and Migration Guide (v1.0 → v2.0) each cover a slice of this material in passing; this page is the full picture, and the one to trust if the others ever drift.


Why this file exists

sidebar.toml carries two independent tables for a single document directory:

  • [[sidebar]] — the navigation entries (an array of tables).
  • [groups] — the folder taxonomy used to group classes/structs/enums/etc. inside that navigation.

Both are read by resolve_config() (engine/ude/orchestrator.py:330, via load_sidebar_toml()), and both are mandatory, with no cascade and no default at any tier. That is the one fact worth memorizing about this file: nothing here is optional, and nothing here falls back to a shared or engine-provided default.


An array of tables, each describing one sidebar entry. A minimal, real example (ude_projects/Kernel/kernel_api_cpp/sidebar.toml):

toml
[[sidebar]]
type = "api_reference"
label = "API Reference (C++)"
url = "index.html"

[[sidebar]]
type = "static"
label = "License and Copyright"
url = "license_copyright.html"
source_file = "../../../workspace/dev_guides/Kernel/tkernel_license_copyright.html"

A type = "static" entry's source_file is resolved by the orchestrator into an absolute path and, at render time, read via BaseRenderer._load_static_file_from_path() (engine/ude/interfaces.py) — see Target Settings for the static_source_path search-path mechanics.

If [[sidebar]] is missing, empty, or sidebar = [], the build fails:

text
sidebar.toml in <dir> declares no [[sidebar]] entries. There is no default
navigation to fall back on — every document directory must define its own
[[sidebar]] table.

(engine/ude/orchestrator.py:339-344)


[groups] — folder taxonomy

[groups] controls which virtual folders classes, structs, enums, and similar entities are grouped into on the generated site. A real example, again from Kernel:

toml
[groups]
namespace_level = [
    "Classes",
    "Fields,_Structures_and_Enums",
    "Functions",
    "Types",
]

GroupsConfig (engine/ude/config.py:56-68, model_config = ConfigDict(extra="forbid")) declares exactly one field:

python
namespace_level: List[str] = Field(default_factory=list)

There is no class_level key. Older material in this documentation set (and one now-fixed example in the v1.0 → v2.0 migration guide) described a class_level key alongside namespace_level. That was never valid — the schema only ever declared namespace_level, and extra="forbid" rejects anything else, class_level included, exactly as hard as a genuine typo like namespac_level.

If [groups] is missing, or namespace_level is empty, the build fails — exactly the same treatment as [[sidebar]], no asymmetry:

text
sidebar.toml in <dir> declares no [groups] namespace_level entries. There is no
default taxonomy to fall back on — every document directory must define its
own [groups] table.

(engine/ude/orchestrator.py:346-357)

A known-wrong error message

If you put an unrecognized key in [groups] (a typo, or a stray class_level), Pydantic validation fails and the engine raises:

text
UdeException: Invalid [groups] configuration: only 'namespace_level' and 'class_level' are permitted keys. Details: ...

WARNING

This message is quoted verbatim from engine/ude/config.py:89 and is itself wrong: it names class_level as a permitted key, but the schema one line above (config.py:56-68) only ever declares namespace_level, and rejects class_level exactly as hard as it rejects the message's own claim would suggest it shouldn't. This is a tracked engine defect, not a documentation ambiguity — see ToDo/v3.0/EngineDefects_ToDo.md. Trust the schema, not the exception text: only namespace_level is valid.


No cascade, anywhere, for either table

Unlike almost every other configuration key in this system, [[sidebar]] and [groups] are not part of the global → SDK → doc-config deep-merge cascade described in Target Settings. There used to be a per-Lang×Output engine-tier default taxonomy; it was removed outright ([IMP-32.10]) along with its template fixtures — searching engine/ude/templates/ today turns up only Doxyfile, class_layout.html, csharp/, java/, python/, and css/, no sidebar-taxonomy directory of any kind.

The document's own sidebar.toml is the only source for both tables, at every tier. As a direct consequence, groups and sidebar are forbidden keys in all three JSON config layers:

  • _reject_forbidden_sidebar_keys() (engine/ude/orchestrator.py:164-186) rejects either key found in the global config (:263), the SDK config (:297), or the doc config (:310).
  • GlobalConfig._reject_sidebar_keys() (engine/ude/config.py:125-162) rejects them again at the GlobalConfig level — alongside the removed sidebar_structures_dir key (see Global Settings).

Putting "groups": {...} or "sidebar": [...] in ude_global_config.json, ude_sdk_config.json, or ude_doc_config.json is a hard configuration error, not a legitimate override — there is nothing here for deep_merge() to combine.


Checklist for a new document directory

  1. Create sidebar.toml next to that document's ude_doc_config.json.
  2. Add at least one [[sidebar]] entry.
  3. Add a [groups] table with a non-empty namespace_level list.
  4. Do not add a class_level key, and do not add groups or sidebar to any of the three JSON config files.
  5. Re-run ude compile (or ude audit, if you just want to check the config resolves) — a missing, empty, or malformed sidebar.toml fails immediately, before any parsing happens.

(Paths below are repository-root-relative.)

  • user-docs/docs/target-settings.md — where [groups] fits among the other doc-config keys
  • user-docs/docs/migration-v2.md — why sidebar.toml became mandatory in v2.0
  • user-docs/docs/adding-a-new-sdk.mdsidebar.toml as part of adding a whole new document