.agents/skills/api-docs/references/adding.md
Use this when new APIs have shipped and their doc files contain To be added. placeholders (typically
triggered by the daily auto-api-docs-writer workflow after a NuGet/CI update). You edit the mdoc XML
directly.
You run this yourself, end to end — one agent. Accuracy comes from reading the C# source first; prose comes from the .NET conventions in the reference files. You write for developers who copy your examples into real code, so every claim must be true and every example must compile.
patterns.md — .NET XML doc syntax, verb conventions, summary/param/return patterns.skia-patterns.md — SkiaSharp/HarfBuzz domain facts (color layouts, struct
defaults, standard-based enums, caller-owned vs parent-owned).obsolete-api-map.md — members that must never appear in an example, and
replacements.Apply these facts; do not restate them in the docs. If a fact is in a reference file, trust it over your own recollection.
Regenerate stubs (only if new APIs were added). Skip if you are editing existing docs or the automated workflow already ran this as a pre-step.
dotnet tool restore
dotnet cake --target=docs-download-output # latest NuGets from the CI feed
dotnet cake --target=update-docs # mdoc update + format → "To be added." placeholders
List the docs to fill. Right after a stub regen the new placeholders show up as changed files:
git -C docs diff --name-only --diff-filter=ACM
Map each <Type>.xml to its source at binding/<Namespace>/<Type>.cs (if the guess is wrong, grep
for the type). Shard the result into ~25–40-file batches.
Write (per file). A field is in scope to fill when it is empty, self-closing, or still a
placeholder (To be added., or a bracketed remarks scaffold like [Describe …]). Do not rewrite
already-written prose.
binding/ and read it. Build a
fact sheet: constructors, method overloads, property accessors ({ get; } vs { get; set; }),
validation behavior (throws? clamps? pads? truncates?), numeric constants, and defaults. The source
is authoritative — never document from the member name alone..xml and locate each <Docs> block. Each <Member>/type carries a
MemberSignature[@Language='DocId'] you use as the stable id. Fill the in-scope children:
<summary>, <param>, <returns>, <value>, <typeparam>, <exception>, and <remarks>.{ get; set; } → "Gets or sets …",
{ get; } → "Gets …". Many struct properties look read-only but are settable — check the signature.0/null/false; do not copy a "typical" sibling constant.<remarks> (description + disposal note if applicable +
one compiling example). Simple members get self-closing <remarks />. Inside CDATA remarks use
<xref:Bare.Uid> with no T:/M:/P: prefix; <see cref> (with prefix) is for non-CDATA prose.using/Dispose a parent-owned object (e.g. SKSurface.Canvas).<Docs> content.Review the files just written with the review checks (reviewing.md §Checks), then
fix CRITICAL findings by editing the XML directly.
Validate & format (validation.md): run docs-format-docs — it formats and runs
the deterministic checks; fix any build-failing broken-XML errors.
Land: commit on a dev/... branch in the docs submodule and open a PR (the submodule protects
main).
After all files, emit a compact manifest — one line per file:
WROTE | <file> | summaries:<n> params:<n> returns:<n> remarks:<n> | source:<binding path or NONE>
Then list any field you intentionally left as a placeholder (ran out of certainty/time) so the next run re-detects it:
DEFERRED | <file> | <docId> | <field> | <reason>
.xml files, and only <Docs> content — never touch MemberSignature,
TypeSignature, or generated files (index.xml, ns-*.xml, _filter.xml, FrameworksIndex/).DEFERRED) so the next run
re-detects it — the file stays clean and well-formed either way.