This repository is the generation authority and archive for Iron Software's product API ("object-reference") documentation.
It does two things:
- Hosts the generated documentation as a static site. GitHub Pages serves every committed build at
https://iron-software.github.io/object-reference/<code>/<version>/…. Downstream sites (ironsoftware.com, ironpdf.com) and build pipelines (devops.ironsoftware) fetch from here rather than regenerating. - Generates that documentation from each product's published package (DocFX for .NET, JavaDoc for IronPDF-for-Java) and caches each build under
object-reference/.
Only
object-reference/is published to the web. This README, the tooling, the scaffolds, and the internal docs are excluded from the GitHub Pages build (see_config.yml).
| Path | Purpose |
|---|---|
object-reference/<code>/<version>/ |
The published, committed documentation builds (the archive). |
iron-products.json |
Product catalog — package type, package name / Maven coordinates, domain, and URL path per product. |
scaffolds/ |
DocFX templates, docfx.<code>.json configs, homepages, and the tools/ toolchain (DocFX, JDK — Git LFS). |
docs/ |
Internal operator notes (e.g. the Windows/DocFX limitation) and generated API diffs under docs/api-diffs/. |
apidiff/ |
Modules behind diff-apidocs, in both ports. |
*.py / *.mjs |
The tooling, in two interchangeable ports (see below). |
The tooling exists in two equivalent versions:
- Python — the original management set, utilized on the staging server and in the
devops.ironsoftwareBuild-Chain pipeline - Node.js — ported from Python, built for use in the modern Node.js / Astro website repository (https://github.com/iron-software/astro/)
Both versions read from the same iron-products.json and write to the same object-reference/ cache.
| Task | Python | Node.js |
|---|---|---|
| Inspect a product's version / build status | check-apidocs.py |
check-apidocs.mjs |
| Generate any missing documentation | update-apidocs.py |
update-apidocs.mjs |
| Diff the API surface between two versions | diff-apidocs.py |
diff-apidocs.mjs |
| Shared version/path helpers | apidocs.py |
apidocs.mjs |
| Colorized status output | statuslogger.py |
statuslogger.mjs |
| Build + diff new releases (nightly CI) | — | nightly-apidocs.mjs |
Reports a product's latest (or specified) version and, optionally, whether its docs are built.
# Python
python check-apidocs.py -p ironpdf -V -a
# Node
node check-apidocs.mjs -p ironpdf -V -a| Flag | Meaning |
|---|---|
-p, --product-code |
Product code (e.g. ironpdf, ironpdfjava, ironocr). |
-n, --product-name |
Product display name (alternative to the code). |
-v, --version |
A specific version. |
-V, --latest-version |
Resolve the latest published version. |
-a, --docs-exists |
Also report whether the docs are built and their archive path. |
Version data is sourced live per package type: NuGet/PyPI/Maven/npm registries.
Walks the catalog and builds any version not already in object-reference/.
.NET products are built with DocFX from their NuGet package; IronPDF-for-Java from its published JavaDoc jar. Each .NET build is post-processed (GUID-marker stripping, canonical-link tags, and Archetype-N SEO overview injection — see below) and cached.
# Python
python update-apidocs.py
# Node (run `npm install` once for the adm-zip dependency used to unpack the nupkg)
npm install
node update-apidocs.mjs| Flag | Meaning |
|---|---|
--no-enhancement |
Skip the Archetype-N overview injection that otherwise runs after DocFX. |
--enhance-force |
Regenerate cached overviews (POLISHED_PRESERVED entries are still preserved). |
--provider claude|openai |
Force the LLM provider (default: auto-detect by API key). |
--model <id> |
Override the LLM model. |
--code <code> |
Only build/enhance this product. |
--version <v> |
Only build/enhance this version. |
Important
Generation must run on Linux or WSL (native filesystem), not native Windows. DocFX emits
file names containing <…> GUID markers, which are illegal in Windows file names and abort the
build at write time — see docs/windows-docfx-guid-limitation.md.
Windows operators who want to generate locally can do so via WSL:
docs/running-generation-in-wsl.md.
The version-inspection tooling (check-apidocs) runs fine on any platform.
Reports what changed in a product's public API between two builds already in object-reference/,
classified as breaking, additive, or cosmetic.
# Python — newest vs previous archived version
python diff-apidocs.py -p ironzip
# Node — an explicit pair, written out as JSON + Markdown
node diff-apidocs.mjs -p ironzip --from 2024.1.1 --to 2026.6.2 --json --markdown| Flag | Meaning |
|---|---|
-p, --product-code |
Product code (e.g. ironzip). |
-n, --product-name |
Product display name (alternative to the code). |
--from / --to |
The versions to compare. Omit both for newest-vs-previous; omit one and the newest is used for that end. |
--namespace GLOB |
Only report types matching the glob; repeatable. |
--exclude GLOB |
Skip types matching the glob; repeatable. |
--include-internal |
Include vendored/internal namespaces (.Internal, Interop, grpc, Pdfium, BouncyCastle, GrpcLayer), which are excluded by default. |
--all-visibility |
Include non-public declarations (public/protected only by default). |
--json [PATH] / --markdown [PATH] |
Write an artifact; defaults to docs/api-diffs/<code>/<from>..<to>.{json,md}. |
--quiet / --no-warnings |
Suppress the terminal report / parser warnings. |
--fail-on-breaking |
Exit 2 when breaking changes are found (for release gating). |
--list-versions |
List the product's archived versions and exit. |
Exit codes: 0 success, 1 tool error (unknown product, missing version), 2 breaking changes
found with --fail-on-breaking.
This tool is entirely offline — it reads only the committed archive, never a package registry, so
it needs no network and triggers no build. Two sources are combined per version: xrefmap.yml for
member identity (uid, kind, parameter types) and the DocFX api/*.html pages for the signature
detail xrefmap lacks (modifiers, return types, base types, default parameter values, and property
accessors). Each declaration is located by the data-uid DocFX writes on its heading, which is
byte-identical to the xrefmap uid.
Because a uid encodes parameter types, a parameter-type change or a new overload appears as a
removal plus an addition rather than a modification; the report notes the pairing. Only DocFX (.NET)
products are supported — ironpdfjava is JavaDoc output with no xrefmap and exits with a message.
.github/workflows/nightly-apidocs.yml runs nightly-apidocs.mjs every night at 02:00 ICT. It builds
each release published since a product's newest archived version, diffs it against the release
before it, and commits both to the nightly/apidocs branch with one open PR into main. Nothing is
published until that PR is merged; delete the branch when merging.
It is forward-only: versions older than the newest archived one are never built, so a version
that cannot build is not retried forever. Fill old gaps with update-apidocs by hand.
node nightly-apidocs.mjs --dry-run # what would be built
node nightly-apidocs.mjs --code ironpdf # build one product's new releases (Linux/WSL)The workflow needs the APIDOCS_CLAUDE_API_KEY repository secret (Archetype-N overviews), and the
repository must allow GitHub Actions to create pull requests (Settings > Actions > General).
"Run workflow" has a dry-run option.
.github/workflows/object-reference-sync.yml runs when a push to main changes object-reference/
(normally the merged nightly PR). It checks out iron-websites on develop, runs that repo's
manage:products:sync -- --apply and manage:docs:sync -- --match-site --no-generate against the
commit just merged, and opens one PR into develop from the sync/object-reference branch. Only
new versions are copied: a product already at its recorded version is skipped, so docs rebuilt in
place under that version do not reach the site.
- The branch is rebuilt from
developand force-pushed on every run, so an open PR is refreshed, not duplicated. Do not push fixes tosync/object-reference— the next run discards them. Fix things in a separate PR. - No change means no PR, and an open sync PR is closed as out of date.
- If a product's new site version has no docs here yet, the PR is still opened, its body lists the product, and the run turns red. That product's API reference stays on the old version until the docs arrive.
It needs the IRON_WEBSITES_PR_TOKEN repository secret: a fine-grained token on
iron-software/iron-websites with Contents and Pull requests read/write. The current token is
Darrius Serrant's, so the PRs show him as the author. When it expires the run fails on the
checkout of iron-websites; its expiry date is on the token's page under his GitHub Settings >
Developer settings > Fine-grained tokens. "Run workflow" has a dry-run option that runs both syncs
and prints the diff without pushing.
After DocFX generates a .NET product's …/object-reference/api/ pages, update-apidocs injects a short, task-led SEO overview into each class-reference page (prose + three meta-title/description variants + TechArticle/FAQPage JSON-LD), placed below the class summary and above the member tables, wrapped in <!-- archetype-N:start … --> / <!-- archetype-N:end --> sentinels (idempotent). This is on by default; pass --no-enhancement to skip it.
The capability is self-contained under scaffolds/tools/archetype-n/ — no dependency on Claude Code or the ore-foundry plugin. It exists as two equivalent ports (Python for update-apidocs.py, native JS for update-apidocs.mjs) whose injector/validator output is byte-identical. The LLM prompts are externalized to scaffolds/tools/archetype-n/spec/prompts.md (a single source of truth both ports load), so they are edited in one place.
How a page is enhanced:
- Route the page to a treatment from its DocFX declaration —
full(rich classes/interfaces),mid(thin types), orlite(enums/exceptions/delegates). - Reuse the cached overview at
scaffolds/tools/archetype-n/_generated_/<code>/<FQN>.mdif present (token-free); otherwise author one with an LLM and self-validate it against the injector's HARD gates, retrying with the gate feedback until it passes. - Inject the validated overview into the page.
The per-product cache (committed, with a _manifest.json) makes steady-state rebuilds make zero LLM calls. --enhance-force regenerates entries except human-authored ones marked POLISHED_PRESERVED. Seed the cache from existing authored samples with python scaffolds/tools/archetype-n/seed_cache.py --all. Each tool can also be run standalone (enhance.py/enhance.mjs, seed_cache.py/seed-cache.mjs, inject_archetype_n.py/inject_archetype_n.mjs).
API keys: generation reads CLAUDE_API_KEY (preferred) or OPENAI_API_KEY from the environment or a .env file at the repo root (gitignored; see .env-example). With no key set, the build still injects every cached page and only warns about pages it could not author.
- Python:
requests,colorama(pip install requests colorama).diff-apidocs.pyis stdlib-only apart fromcolorama(viastatuslogger.py) — it does not userequests. - Node.js:
adm-zip(npm install) — only needed byupdate-apidocs.mjsfor nupkg extraction;check-apidocs.mjs,diff-apidocs.mjs, andapidocs.mjsare dependency-free. - Generation only: the DocFX + JDK toolchain under
scaffolds/tools/(Git LFS), plusmonoon Linux to run DocFX. - Archetype-N enhancement: stdlib-only (Python) / native (Node
>=18, globalfetch); no extra packages. An LLM API key is only needed to author pages not already in the cache.