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.
Installation
Details
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
npx agent-skills-cli listSkill Instructions
name: ocaml-docs description: "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." license: ISC
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}:
(* 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 modulestype-for typesval-for valuesexception-for exceptionsconstructor-for variant constructorsfield-for record fieldsmodule-type-for module types
Cross-Package References
When odoc cannot resolve a reference to another package, add a documentation dependency in dune-project:
(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:
- Check if the module is re-exported in the parent module's
.mli - Add
module X = Xto the parent's.mliif missing
Ambiguous References
When odoc warns about ambiguity (e.g., both an exception and module named Error):
{!Jsont.exception-Error} (* for the exception *)
{!Jsont.module-Error} (* for the module *)
@raise Tags
For @raise documentation tags, use the exception path with disambiguation:
@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:
(* 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:
- Find the field definition in the
.mlifile - Identify what type the field uses (e.g.,
uri : Uri.t) - Check if that type's module is re-exported in the wrapper
.mli
Fix Option 1: Re-export the module in the wrapper .mli:
(** RFC 3986 URI parsing *)
module Uri = Uri
Fix Option 2: If you only want to expose the type (not the whole module), use @canonical:
-
Add a type alias in the wrapper
.mli:type uri = Uri.t -
Add
@canonicalto the original type's documentation:(* 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
- Run
dune cleanbeforedune build @docto ensure fresh builds - Check the library's
.mlifile to see what modules are exported - For cross-library refs, trace the module path through re-exports
More by aresbit
View allUse the ClawdHub CLI to search, install, update, and publish agent skills from clawdhub.com. Use when you need to fetch new skills on the fly, sync installed skills to latest or a specific version, or publish new/updated skill folders with the npm-installed clawdhub CLI.
Search GIF providers with CLI/TUI, download results, and extract stills/sheets.
Use CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON.
Use when you need to control Slack from OpenClaw via the slack tool, including reacting to messages or pinning/unpinning items in Slack channels or DMs.
