diff --git a/CMakeLists.txt b/CMakeLists.txt
index a06b59f..22ff741 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -188,16 +188,30 @@ if(DOXYGEN_FOUND)
set(DOXYGEN_GENERATE_LATEX NO)
endif()
- # The reference is generated from the source and its documentation
- # comments. The markdown in docs/ is written and read on its own and
- # stays out of the input.
+ # The prose documents, each rendered as its own page in the generated
+ # reference. Named one per line so the set of documents reaching the
+ # output is stated here instead of implied by a directory.
+ set(DPM_DOC_PAGES
+ ${CMAKE_CURRENT_SOURCE_DIR}/docs/OVERVIEW.md
+ ${CMAKE_CURRENT_SOURCE_DIR}/docs/DESIGN.md
+ ${CMAKE_CURRENT_SOURCE_DIR}/docs/CONSUMERS.md
+ ${CMAKE_CURRENT_SOURCE_DIR}/docs/MODULES.md
+ ${CMAKE_CURRENT_SOURCE_DIR}/docs/BUILD.md
+ ${CMAKE_CURRENT_SOURCE_DIR}/docs/DOCUMENTATION.md
+ )
+
+ # Two kinds of input: include/ and src/ supply the API and internals
+ # reference extracted from the source, DPM_DOC_PAGES supplies the
+ # prose pages.
+ #
# One target, so `cmake --build
--target docs` is the whole
# procedure and the IDE lists a single entry for it. The commands
# below run after Doxygen and place the finished documents.
doxygen_add_docs(docs
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
- COMMENT "Generating the code reference with Doxygen"
+ ${DPM_DOC_PAGES}
+ COMMENT "Generating the reference with Doxygen"
)
if(DPM_DOCS_PDF)
@@ -205,6 +219,8 @@ if(DOXYGEN_FOUND)
if(PDFLATEX_EXECUTABLE)
add_custom_command(TARGET docs POST_BUILD
COMMAND make -C ${CMAKE_BINARY_DIR}/docs/tmp/latex
+ COMMAND ${CMAKE_COMMAND} -E rm -rf
+ ${CMAKE_BINARY_DIR}/docs/pdf
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_BINARY_DIR}/docs/tmp/latex/refman.pdf
${CMAKE_BINARY_DIR}/docs/pdf/dpm-core-${PROJECT_VERSION}.pdf
@@ -217,12 +233,23 @@ if(DOXYGEN_FOUND)
if(DPM_DOCS_HTML)
add_custom_command(TARGET docs POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E rm -rf
+ ${CMAKE_BINARY_DIR}/docs/html
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_BINARY_DIR}/docs/tmp/html
${CMAKE_BINARY_DIR}/docs/html
COMMENT "Placing the HTML reference"
)
endif()
+
+ # Doxygen keeps output files it judges unchanged, so a run over a
+ # populated scratch directory can carry pages forward from an earlier
+ # one. Removing it here means the next run regenerates everything,
+ # and leaves docs/ holding the finished documents alone.
+ add_custom_command(TARGET docs POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E rm -rf ${CMAKE_BINARY_DIR}/docs/tmp
+ COMMENT "Clearing the generators' scratch directory"
+ )
endif()
# ---------------------------------------------------------------------
diff --git a/docs/BUILD.md b/docs/BUILD.md
index f5073ee..81cc1f6 100644
--- a/docs/BUILD.md
+++ b/docs/BUILD.md
@@ -1,4 +1,4 @@
-# Building libdpm-core.so and the dpm Binary
+# Building libdpm-core.so and the dpm Binary {#build}
## Prerequisites
diff --git a/docs/CONSUMERS.md b/docs/CONSUMERS.md
index c2dc912..2a4e2b6 100644
--- a/docs/CONSUMERS.md
+++ b/docs/CONSUMERS.md
@@ -1,4 +1,4 @@
-# Consuming libdpm-core.so
+# Consuming libdpm-core.so {#consumers}
Programs link libdpm-core.so as an ordinary shared library dependency — the same way they link any other library — to reach the package manager in-process: build systems, installers, image builders, system tooling, and foreign-language bindings all use the library the `dpm` binary is built on. A program holding a default context is working against system configuration, the system module path, the system tree, and system locking, the same environment the installed `dpm` binary sees.
diff --git a/docs/DESIGN.md b/docs/DESIGN.md
index ab9fc5e..66105b8 100644
--- a/docs/DESIGN.md
+++ b/docs/DESIGN.md
@@ -1,4 +1,4 @@
-# DPM — Dark Horse Package Manager: Design
+# DPM — Dark Horse Package Manager: Design {#design}
## Constraints
diff --git a/docs/DOCUMENTATION.md b/docs/DOCUMENTATION.md
index 2884b01..21406aa 100644
--- a/docs/DOCUMENTATION.md
+++ b/docs/DOCUMENTATION.md
@@ -1,4 +1,4 @@
-# Generating the Code Reference
+# Generating the Code Reference {#documentation}
When Doxygen is present, the build offers a `docs` target that generates the API and source reference from the documentation comments carried in the headers and sources. It opens on a front page declared in `include/dpm/core.h`, followed by the module contract, then the namespace, class, and file reference.
diff --git a/docs/MODULES.md b/docs/MODULES.md
index 0a8735a..ead4d5a 100644
--- a/docs/MODULES.md
+++ b/docs/MODULES.md
@@ -1,4 +1,4 @@
-# Developing DPM Modules
+# Developing DPM Modules {#modules}
A DPM module is one shared object in the module directory. libdpm-core.so loads it, validates it completely, and dispatches commands to it on behalf of whatever asked — the `dpm` binary, a build system, or another module. This document covers writing, building, testing, and installing a module.
diff --git a/docs/OVERVIEW.md b/docs/OVERVIEW.md
index 1b8d996..83b5f5c 100644
--- a/docs/OVERVIEW.md
+++ b/docs/OVERVIEW.md
@@ -1,4 +1,4 @@
-# DPM — An Overview
+# DPM — An Overview {#overview}
## What DPM Is
@@ -178,11 +178,3 @@ Every other module is developed against libdpm-core.so and lives outside this re
4. Writes flow down, never sideways: a layer mutates the system only through the layer beneath it, in-process through mediated calls.
5. A module is either fully valid or not loaded — no partial states, no consumer-side defense.
6. Anything a linked program can redirect, a shell user can redirect too.
-
-## Further Reading
-
-- **DESIGN.md** — the full design specification
-- **CONSUMERS.md** — linking libdpm-core.so and driving it from a program
-- **MODULES.md** — writing, building, testing, and installing a module
-- **BUILD.md** — building, testing, and installing libdpm-core.so and the `dpm` binary
-- **DOCUMENTATION.md** — generating the code reference
diff --git a/include/dpm/core.h b/include/dpm/core.h
index e121427..bf0ac53 100644
--- a/include/dpm/core.h
+++ b/include/dpm/core.h
@@ -320,66 +320,17 @@ DPM_API const char* dpm_last_error(dpm_ctx* ctx);
/* Module contract (implemented by modules, called by libdpm-core) */
/* ------------------------------------------------------------------ */
-/**
- * @mainpage libdpm-core.so — API Reference
+/*
+ * Every module exports, as extern "C":
*
- * This is the generated reference for libdpm-core.so, extracted from
- * the source. It covers the public C API in , the library's
- * internals, and the module contract.
- *
- * Start at core.h for the API a consumer or a module calls, and at
- * @ref module_contract for what a module implements.
- *
- * The project's prose documentation — overview, design, build, module
- * authoring, and consumer guide — lives in the docs/ directory of the
- * repository and is read there.
- */
-
-/**
- * @page module_contract The Module Contract
- *
- * A module is one .so in the module directory. It includes
- * , links -ldpm-core, and exports three reserved symbols as
- * extern "C":
- *
- * @code
- * int dpm_module_execute(dpm_ctx* ctx, const char* command,
- * int argc, char** argv);
- * const char* dpm_module_version(void);
- * const char* dpm_module_description(void);
- * @endcode
- *
- * @section module_contract_surface The Functional Surface
+ * int dpm_module_execute(dpm_ctx* ctx, const char* command,
+ * int argc, char** argv);
+ * const char* dpm_module_version(void);
+ * const char* dpm_module_description(void);
*
* dpm_module_execute is the only entry through which a module performs
- * work; its capabilities are addressed by command string, so a module
- * publishes no headers, struct layouts, or symbols to anything that
- * calls it. NULL or an empty command behaves as the module's help
- * command.
- *
- * dpm_module_version and dpm_module_description are what a module
- * reports about itself. The library reads both at load and serves them
- * to consumers through dpm_module_info_of, where the version is what a
- * calling module judges before deciding to issue a command.
- *
- * @section module_contract_version Version Compatibility
- *
- * A module determines for itself whether it can work with the library
- * it is running against: dpm_core_version() reports the running
- * version, and the module proceeds or fails on its own judgement. A
- * module is built against the system-installed libdpm-core.so and is
- * responsible for being correct against it.
- *
- * The same holds toward a peer. A module requires the peer by name,
- * reads the version the library reports, and decides whether that
- * version suits the commands it intends to issue.
- *
- * @section module_contract_validation Validation
- *
- * The library refuses to load any module that does not validate
- * completely: every reserved symbol resolves, and the version and
- * description probes return well-formed values. A module that loads is
- * fully valid.
+ * work. The other two are what it reports about itself; the library
+ * reads both at load and serves them through dpm_module_info_of.
*/
#ifdef __cplusplus
diff --git a/src/documentation.cpp b/src/documentation.cpp
new file mode 100644
index 0000000..b912b59
--- /dev/null
+++ b/src/documentation.cpp
@@ -0,0 +1,53 @@
+/**
+ * @file documentation.cpp
+ * @brief Documentation loading source: declares the reference's pages
+ *
+ * This file carries no code. It declares what the generated reference
+ * contains and in what order, so the structure of the documentation
+ * lives in a source file of its own rather than in the build
+ * configuration.
+ *
+ * Each entry in the main page names a document by its page label,
+ * declared on the first heading of the corresponding markdown file in
+ * docs/.
+ *
+ * @copyright Copyright (c) 2026 SILO GROUP LLC
+ * @author Chris Punches
+ *
+ * Part of the Dark Horse Linux Package Manager (DPM)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * @mainpage DPM
+ *
+ * Dark Horse Linux Package Manager: libdpm-core.so, the dpm binary, and
+ * the modules that implement package functionality.
+ *
+ * The documents below carry the project's prose. The API and internals
+ * reference extracted from the source follows them.
+ *
+ * @subpage overview
+ *
+ * @subpage design
+ *
+ * @subpage consumers
+ *
+ * @subpage modules
+ *
+ * @subpage build
+ *
+ * @subpage documentation
+ */