Appearance
Target Configurations Reference
To compile documentation for a specific product, UDE reads a small stack of layered JSON config files: a global config, an optional SDK/product config, and a target/doc config. This page walks through the real schema of each, using the engine's own mock example project as the reference (ude_projects/mock/mock_api_py/).
📋 The three config layers
| Layer | Example file | CLI flag |
|---|---|---|
| Global | ude_projects/ude_global_config.json | --global-config / -g |
| SDK / product | ude_projects/mock/ude_sdk_config.json | --sdk-config / -s |
| Target / doc | ude_projects/mock/mock_api_py/ude_doc_config.json | --doc-config / -d (or the legacy --config / -c alias) |
IMPORTANT
Path resolution rule: Paths inside a doc-config file (like src_dir) are resolved relative to the directory containing that doc-config file itself — not relative to your current working directory or the global config.
⚙️ The doc-config file (ude_doc_config.json)
This is the real file from ude_projects/mock/mock_api_py/ude_doc_config.json:
json
{
"project_name": "Mock Python API Reference",
"short_project_name": "Mock",
"src_dir": ["../../../engine/tests/assets/main/_swig/python/mock"],
"static_pages_dir": "./",
"copyright_start_year": 2026,
"incremental": true,
"max_workers": 8,
"collector": {"type": "PyDoxygenCollector", "file_patterns": ["**/*.py"], "include_private": false},
"parser": {"type": "PyDoxygenParser"},
"renderer": {"type": "PyHtmlDefaultRenderer"},
"output_subdir": "mock_api_py",
"validator": {"type": "PyCommentValidator"}
}Field notes
src_dir— must be a JSON array of paths, never a bare string. Passing a string raises:textUdeException: 'src_dir' must be a list of paths. String values are not accepted — wrap single paths in a JSON array.(
engine/ude/orchestrator.py:465-468). Paths are resolved relative to this doc-config file's own directory.collector.type— names a concrete collector class per language (PyDoxygenCollector,CsDoxygenCollector,JavaDoxygenCollector, ...). All of these shell out to the realdoxygenbinary; there is currently no pure-Python C++ collector variant in use.parser.type— names the matching concrete parser class (PyDoxygenParser, etc.), dispatched internally byengine/ude/parsers/doxygen_router.py.renderer.type— this is where the example file and the engine's actual dispatch logic disagree, see the callout below.output_subdir— combined with the global config'soutput_base_dirto build the final output path (output_base_dir / output_subdir).incremental,max_workers,validator.type,copyright_start_year,static_pages_dir,short_project_name— all accepted, real-world keys read by other parts of the pipeline. Their exact runtime effects weren't in scope for this pass, so treat them as "real and used" without over-specifying behavior here.
WARNING
Known discrepancy: renderer.type as a concrete class name The orchestrator's actual runtime dispatch (engine/ude/orchestrator.py:610-618, 671-690) matches renderer.type against generic lowercase tokens by exact string match:
"html"/"static_html""hugo_markdown"/"markdown"/"hugo""legacy_html""legacy_hugo_markdown"/"legacy_markdown"/"legacy_hugo"
A concrete class name like "PyHtmlDefaultRenderer" — as seen in this repo's own ude_projects/* example files — does not match any of those tokens once lowercased ("pyhtmldefaultrenderer"), and would raise UdeException: Unsupported format '...' in target config if it were actually used for dispatch unmodified.
In practice this doesn't bite the mock example, because its generate_docs.bat always passes --format html on the CLI. That CLI flag overrides renderer.type in memory before dispatch happens (_run_single(), engine/ude/orchestrator.py:749-751), so the JSON's "PyHtmlDefaultRenderer" value is replaced with "html" at runtime and never actually reaches the dispatch check. If you write a doc-config that's meant to be run without an explicit --format override, use one of the generic tokens above — that's what engine/tests/test_orchestrator.py (the real test suite) exercises. The concrete-class-name style in ude_projects/* should be treated as stale/legacy and not copied into new configs.
🌍 The global config (ude_global_config.json)
This is the real file from ude_projects/ude_global_config.json:
json
{
"error_policy": "continue-on-error",
"logging": {"level": "INFO", "file": "../ude_system.log"},
"doxygen_binary": "doxygen",
"stylesheet_dir": "../engine/ude/templates/css/default",
"output_base_dir": "../ude_output",
"api_version": "27.6"
}WARNING
Only two of these six keys are part of the actual GlobalConfig schema.GlobalConfig (engine/ude/config.py:116-126) is a Pydantic model with extra="ignore", meaning unknown keys are silently dropped rather than raising an error. Its real fields are:
| Real field | Type / default | Notes |
|---|---|---|
doxygen_path | Optional[str] = None | A directory containing the Doxygen executable, not a binary name. If set, it's prepended to PATH at runtime. |
log_level | str = "WARNING" | Flat string, not a nested object. |
log_file | Optional[str] = None | Flat string, not a nested object. |
cache_root_dir | Optional[str] = None | Root of the on-disk L1/L2 build cache. |
global_templates_dir | Optional[str] = None | Root for shared global templates. |
error_policy | str = "fail-fast" | Real, and used. |
translation_service | Optional[str] = None | |
coverage_mode | "allow-undocumented" | "reject-undocumented", default "allow-undocumented" | Governs the post-compile coverage gate. |
coverage_threshold | float, default 1.0 (100%) | Minimum documented fraction required to pass the gate. |
Of the six keys in the example file above, only error_policy and output_base_dir map onto real behavior. logging, doxygen_binary, and api_version are not GlobalConfig fields at all, so they're silently dropped when the file is loaded as a GlobalConfig and have zero effect at that level. That said, stylesheet_dir and api_version aren't dead weight — they're read directly off the merged config dict elsewhere in the orchestrator, just not through the typed GlobalConfig object.
A global config that actually matches GlobalConfig's real schema looks like this:
json
{
"doxygen_path": null,
"log_level": "INFO",
"log_file": "../ude_system.log",
"cache_root_dir": "../.ude_cache",
"error_policy": "fail-fast",
"coverage_mode": "allow-undocumented",
"coverage_threshold": 1.0
}🚀 Running the Orchestrator
Once you have a doc-config (and, typically, matching global/SDK configs), compile with:
bash
python -m ude.cli --global-config ../../ude_global_config.json --sdk-config ../ude_sdk_config.json --doc-config ude_doc_config.json --format htmlThe --format flag (hugo_markdown or html) is optional but, when present, overrides whatever renderer.type says in the doc-config — see the discrepancy callout above.
For each target, the orchestrator runs the same sequence:
- Collect: resolves and validates
src_dir, then runs Doxygen over it via the configured*DoxygenCollector. - Parse: the matching
*DoxygenParser(dispatched bydoxygen_router.py) turns Doxygen's XML into aProjectCatalogIR. - Render: one of the 16 concrete
<Lang><Output><ID>Rendererclasses writes static HTML or Hugo Markdown tooutput_base_dir / output_subdir. - Audit: every successful compile ends by printing a documentation coverage table (see Getting Started) — this isn't a separate opt-in step, it always runs after a successful compile sweep.
