Skip to content

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

LayerExample fileCLI flag
Globalude_projects/ude_global_config.json--global-config / -g
SDK / productude_projects/mock/ude_sdk_config.json--sdk-config / -s
Target / docude_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:

    text
    UdeException: '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 real doxygen binary; there is currently no pure-Python C++ collector variant in use.

  • parser.type — names the matching concrete parser class (PyDoxygenParser, etc.), dispatched internally by engine/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's output_base_dir to 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 fieldType / defaultNotes
doxygen_pathOptional[str] = NoneA directory containing the Doxygen executable, not a binary name. If set, it's prepended to PATH at runtime.
log_levelstr = "WARNING"Flat string, not a nested object.
log_fileOptional[str] = NoneFlat string, not a nested object.
cache_root_dirOptional[str] = NoneRoot of the on-disk L1/L2 build cache.
global_templates_dirOptional[str] = NoneRoot for shared global templates.
error_policystr = "fail-fast"Real, and used.
translation_serviceOptional[str] = None
coverage_mode"allow-undocumented" | "reject-undocumented", default "allow-undocumented"Governs the post-compile coverage gate.
coverage_thresholdfloat, 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 html

The --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:

  1. Collect: resolves and validates src_dir, then runs Doxygen over it via the configured *DoxygenCollector.
  2. Parse: the matching *DoxygenParser (dispatched by doxygen_router.py) turns Doxygen's XML into a ProjectCatalog IR.
  3. Render: one of the 16 concrete <Lang><Output><ID>Renderer classes writes static HTML or Hugo Markdown to output_base_dir / output_subdir.
  4. 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.