McNeel.Owl
0.16.0
dotnet tool install --global McNeel.Owl --version 0.16.0
dotnet new tool-manifest
dotnet tool install --local McNeel.Owl --version 0.16.0
#tool dotnet:?package=McNeel.Owl&version=0.16.0
nuke :add-package McNeel.Owl --version 0.16.0
<img src="https://media.githubusercontent.com/media/mcneel/Owl/main/art/icon.png" alt="" width="40" align="top"> Owl
Turn your .NET library into a documentation website.
Owl reads your C# or Visual Basic project and builds a searchable site with a page for every type.
Install
You need .NET SDK 8.0+ and Node 18+.
dotnet tool install --global McNeel.Owl
Preview Documentation
owl serve MyLib.csproj
Open http://localhost:8080. Edit your docs and refresh to see the changes.
Publish Documentation
owl build MyLib.csproj --out ./public
Upload the public folder to any web host.
If the site lives under a path, such as https://example.com/api/mylib, say so:
owl build MyLib.csproj --out ./public --base /api/mylib --site-url https://example.com
Document Several Projects Together
owl serve MyLib.csproj MyLib.Extras.csproj --name "MyLib"
Links between the projects just work.
Documentation Categories
Group types into categories with a <category> tag:
/// <summary>Saves files.</summary>
/// <category>Storage</category>
public class FileStore { }
Then put Markdown files in a docs/api folder next to where you run owl:
docs/api/MAIN.md home page
docs/api/logo.svg header icon
docs/api/MyLib/MAIN.md MyLib's page
docs/api/MyLib/Storage.md the Storage category's page
docs/api/MyLib/SORT.txt category order, optional
The sidebar lists your categories, and owl shows a placeholder for any page you haven't written yet.
Categories are listed alphabetically. To choose the order, list them one per line in SORT.txt:
Storage
Shapes
Categories you leave out follow, alphabetically.
Pages somewhere else? Use --docs path/to/pages.
Pages can include diagrams. Install d2 first:
```d2
Code -> Compile -> Run
```
Pages can also include math:
The area of a circle is $\pi r^2$.
Pages can link to your API. Write the name the way you would in <see cref="..."/>:
[FileStore](xref:FileStore) saves files. Call [](xref:FileStore.Read(string)) to read one back.
Leave the text empty and owl fills in the name. Qualify a name that matches more than one thing, as in
xref:MyLib.Storage.FileStore, or give its doc id, as in xref:M:MyLib.FileStore.Read(System.String).
Documentation Version
/// <summary>Saves files.</summary>
/// <since>2.1</since>
public class FileStore { }
owl build MyLib.csproj --api-versions 3,2,1
Readers pick a version from the header and see what existed up to the next version listed: picking 2 shows
what 2.1 added, but not what 3 added. Picking an older version adds it to the address, as ?version=2, so a
link to the page opens on that version; without it, a page opens on the newest.
The header's What's New link lists what the picked version added and made obsolete, up to the next version
listed. To compare any two versions, open whatsnew/8.4...8.12/: it lists what came after 8.4, up to and including 8.12. That works on a plain file host only for
the listed versions; build with --server (below) for any pair.
Link to Your Source Code
owl build MyLib.csproj --source-refs https://github.com/me/mylib/blob/main
Every type and member links to the line it is declared on.
Link to Another Library's Docs
If your library uses types from another library that is also documented with owl:
owl build MyPlugin.csproj --link MyLib=/api/mylib
Those types now link to the other site. .NET types link to Microsoft Learn automatically.
Keep Old Links Working
Moving from Sandcastle or docify? Old page addresses can redirect to the new pages:
owl build MyLib.csproj --sandcastle # html/T_MyLib_Storage.htm
owl build MyLib.csproj --docify # mylib.storage/ and mylib.storage/read
Each old address gets a page that forwards the reader. If your host can send redirects itself, answer from
redirects.json in the output instead. It maps each old address, lower case and without a trailing slash, to its
new one. Add the request's query to the new address's own.
Member Link Previews
A member's address reads type/mylib.storage/?member=read#read, so a pasted link can preview as that member
rather than its type. A plain file host previews it as the type. To preview the member, build with --server:
owl build MyLib.csproj --base /api/mylib --server -o app
The site goes in app/site, with a node server beside it. Push app to any node host, Heroku included, and it
starts with npm start on the port the host gives it. It also redirects the old addresses of --sandcastle and
--docify.
Check Documentation in CI
owl verify MyLib.csproj
Lists undocumented API, and fails on broken <see cref="..."/> links and broken xref: links in your pages.
More Options
| Command | Option | What It Does |
|---|---|---|
| all | --name <text> |
Site name |
| all | --tfm <tfm> |
Framework to document, e.g. net48 |
| all | -c <name> |
Build configuration, e.g. Release |
| serve | --port <n> |
Port to use (default 8080) |
| build | --out <dir> |
Where to write the site |
| serve, build | --docs <dir> |
Folder of your own pages |
| serve, build | --logo <file> |
Header icon |
| serve, build | --favicon <file> |
Browser tab icon |
| serve, build | --skip-undocumented |
Hide anything without a summary |
Run owl --help to see all options.
Development
owl/is the command-line toolowl-gen/reads projects and writes the docs dataowl-site/turns that data into the website
Run it from source:
dotnet run --project owl -- serve MyLib.csproj
Design decisions are explained in NOTES.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.16.0 | 90 | 11/4/2026 |
| 0.15.0 | 111 | 11/2/2026 |
| 0.14.0 | 122 | 10/30/2026 |
| 0.13.0 | 107 | 10/30/2026 |
| 0.12.0 | 111 | 10/29/2026 |
| 0.11.0 | 117 | 10/29/2026 |
| 0.10.0 | 120 | 10/28/2026 |
| 0.9.0 | 108 | 10/28/2026 |
| 0.8.0 | 115 | 10/27/2026 |
| 0.7.0 | 112 | 10/27/2026 |
| 0.6.0 | 118 | 10/26/2026 |
| 0.5.0 | 113 | 10/26/2026 |
| 0.4.0 | 110 | 10/26/2026 |
| 0.3.0 | 119 | 10/22/2026 |
| 0.2.0 | 117 | 10/21/2026 |
| 0.1.0 | 111 | 10/21/2026 |