ocaml-docs
Fixing odoc documentation warnings and errors. Use when running dune build @doc, resolving reference syntax issues, cross-package references, ambiguous references, hidden fields, or @raise tags in OCaml documentation.
What this skill does
# OCaml Documentation (odoc) Skill
## When to Use
Use this skill when fixing odoc documentation warnings, typically from `dune build @doc`.
**Prerequisites:** This skill covers odoc v3 syntax which is not yet in released versions of dune or odoc. You need:
- dune pinned to https://github.com/jonludlam/dune/tree/odoc-v3-rules-3.21
- odoc pinned to https://github.com/jonludlam/odoc/tree/staging
## Reference Syntax
Use path-based disambiguation `{!Path.To.kind-Name}` rather than `{!kind:Path.To.Name}`:
```ocaml
(* Correct *)
{!Jsont.exception-Error}
{!Proto.Incoming.t.constructor-Message}
{!module-Foo.module-type-Bar.exception-Baz}
(* Incorrect *)
{!exception:Jsont.Error}
{!constructor:Proto.Incoming.t.Message}
```
This allows disambiguation at any position in the path.
## Reference Kinds
- `module-` for modules
- `type-` for types
- `val-` for values
- `exception-` for exceptions
- `constructor-` for variant constructors
- `field-` for record fields
- `module-type-` for module types
## Cross-Package References
When odoc cannot resolve a reference to another package, add a documentation dependency in `dune-project`:
```lisp
(package
(name mypackage)
...
(documentation (depends other-package)))
```
Do NOT convert doc references `{!Foo}` to code markup `[Foo]` - this loses the hyperlink.
## Cross-Library References (Same Package)
When referencing modules from another library in the same package, use the full path through re-exported modules.
Example: If `claude.mli` has `module Proto = Proto`, reference proto modules as `{!Proto.Incoming}` not `{!Incoming}`.
## Missing Module Exports
If odoc reports "Couldn't find X" where X is the last path component:
1. Check if the module is re-exported in the parent module's `.mli`
2. Add `module X = X` to the parent's `.mli` if missing
## Ambiguous References
When odoc warns about ambiguity (e.g., both an exception and module named `Error`):
```ocaml
{!Jsont.exception-Error} (* for the exception *)
{!Jsont.module-Error} (* for the module *)
```
## @raise Tags
For `@raise` documentation tags, use the exception path with disambiguation:
```ocaml
@raise Jsont.exception-Error
@raise Tomlt.Toml.Error.exception-Error
```
## Escaping @ Symbols
The `@` character is interpreted as a tag marker in odoc. When you need a literal `@` in documentation text (e.g., describing @-mentions), escape it with a backslash:
```ocaml
(* Correct - escaped @ *)
(** User was \@-mentioned *)
(** Mentioned via \@all/\@everyone *)
(* Incorrect - will produce "Stray '@'" or "Unknown tag" warnings *)
(** User was @-mentioned *)
(** Mentioned via @all *)
```
## Hidden Fields Warning
When odoc warns about "Hidden fields in type 'Foo.Bar.t': field_name", it means a record field uses a type that odoc can't resolve in the documentation.
**Diagnosis:**
1. Find the field definition in the `.mli` file
2. Identify what type the field uses (e.g., `uri : Uri.t`)
3. Check if that type's module is re-exported in the wrapper `.mli`
**Fix Option 1:** Re-export the module in the wrapper `.mli`:
```ocaml
(** RFC 3986 URI parsing *)
module Uri = Uri
```
**Fix Option 2:** If you only want to expose the type (not the whole module), use `@canonical`:
1. Add a type alias in the wrapper `.mli`:
```ocaml
type uri = Uri.t
```
2. Add `@canonical` to the original type's documentation:
```ocaml
(* In uri.mli *)
type t
(** A URI. @canonical Requests.uri *)
```
This tells odoc to link `Uri.t` to `Requests.uri` in the generated documentation.
## Interpreting Error Messages
| Error Pattern | Meaning | Fix |
|--------------|---------|-----|
| `unresolvedroot(X)` | X not found as root module | Check library dependencies, add documentation depends |
| `Couldn't find "Y"` after valid path | Y doesn't exist at that location | Verify module structure, check exports |
| `Reference to 'X' is ambiguous` | Multiple items named X | Add kind qualifier (e.g., `exception-X`) |
| `Hidden fields in type ... : field` | Field's type not resolvable | Re-export the type's module in wrapper `.mli` |
## Debugging
1. Run `dune clean` before `dune build @doc` to ensure fresh builds
2. Check the library's `.mli` file to see what modules are exported
3. For cross-library refs, trace the module path through re-exports
Related in Writing & Docs
jax-development
IncludedUse this skill when the user is writing, debugging, profiling, refactoring, reviewing, benchmarking, parallelising, exporting, or explaining JAX code, or when they mention JAX, jax.numpy, jit, grad, value_and_grad, vmap, scan, lax, random keys, pytrees, jax.Array, sharding, Mesh, PartitionSpec, NamedSharding, pmap, shard_map, Pallas, XLA, StableHLO, checkify, profiler, or the JAX repo. It helps turn NumPy or PyTorch-style code into pure functional JAX, fix tracer/control-flow/shape/PRNG bugs, remove recompiles and host-device syncs, choose transforms and sharding strategies, inspect jaxpr/lowering/IR, and benchmark compiled code correctly.
nature-article-writer
IncludedDrafts, rewrites, diagnostically critiques, and style-calibrates primary research manuscripts for Nature and Nature Portfolio journals. Use when the user wants a Nature-style title, summary paragraph or abstract, introduction, results, discussion, methods, figure legends, presubmission enquiry, cover letter, reviewer response, or when a scientific draft sounds generic, jargon-heavy, structurally weak, or AI-ish and needs precise, broad-reader-friendly prose without inventing data, analyses, or references. Best for primary research articles and letters rather than reviews or press releases unless explicitly adapting one.
deckrd
IncludedDocument-driven framework that derives requirements, specifications, implementation plans, and executable tasks from goals through structured AI dialogue. Use when user says "write requirements", "create spec", "plan implementation", "derive tasks", "structure this feature", "break down into tasks", or "document this module". Also use for reverse engineering existing code into docs (/deckrd rev). Do NOT use for direct code writing — use /deckrd-coder after tasks are generated. Do NOT use when the user only wants to run or fix existing code without planning.
clinical-decision-support
IncludedGenerate professional clinical decision support (CDS) documents for pharmaceutical and clinical research settings, including patient cohort analyses (biomarker-stratified with outcomes) and treatment recommendation reports (evidence-based guidelines with decision algorithms). Supports GRADE evidence grading, statistical analysis (hazard ratios, survival curves, waterfall plots), biomarker integration, and regulatory compliance. Outputs publication-ready LaTeX/PDF format optimized for drug development, clinical research, and evidence synthesis.
handling-sf-data
IncludedSalesforce data operations with 130-point scoring. Use this skill to create, update, delete, bulk import/export, generate test data, and clean up org records using sf CLI and anonymous Apex. TRIGGER when: user creates test data, performs bulk import/export, uses sf data CLI commands, needs data factory patterns for Apex tests, or needs to seed/clean records in a Salesforce org. DO NOT TRIGGER when: SOQL query writing only (use querying-soql), Apex test execution (use running-apex-tests), or metadata deployment (use deploying-metadata).
accelint-ac-to-playwright
IncludedConvert and validate acceptance criteria for Playwright test automation. Use when user asks to (1) review/evaluate/check if AC are ready for automation, (2) assess if AC can be converted as-is, (3) validate AC quality for Playwright, (4) turn AC into tests, (5) generate tests from acceptance criteria, (6) convert .md bullets or .feature Gherkin files to Playwright specs, (7) create test automation from requirements. Handles both bullet-style markdown and Gherkin syntax with JSON test plan generation and validation.