Written for AI agents — mandatory when an agent adds or changes docblocks. Human contributors may treat this as a helpful guide.
This project uses Vala’s comment markup for API documentation. Valadoc turns these comments into generated docs (e.g. for valadoc or IDE tooltips).
Use a single block per symbol: brief line, optional long description, then taglets.
/**
* Brief description (one line).
*
* Optional longer description: paragraphs separated by a blank comment line.
* Line breaks within a paragraph are allowed; two spaces after newline for
* line break in output.
*
* @param name description of parameter
* @return description of return value
* @throws TypeName when this error is thrown
*/- Brief: First line(s) before a blank line; keep short (one sentence).
- Long description: Follow the Class and namespace overviews rules below. Taglets at the end.
- Taglets: At the end; use block taglets for parameters, return value, and errors.
Match libollmchat/namespace.vala and major classes such as
libollmchat/Client.vala, libollmchat/Message.vala,
libollmchat/Tool/BaseTool.vala. Anything thinner is usually not good
enough for a public namespace or entry-point class.
Namespace / major class structure:
- Brief — one title sentence.
- Overview paragraph — what the type/namespace is for, and which related types the reader will need (orientation, not method-by-method narration).
- Optional bullets (
== Architecture ==/ benefits) when they help. == Usage Examples ==(or== Example ==) with=== … ===subsections and real{{{ … }}}samples people can copy.- Optional
== Best Practices ==numbered list.
After every == … == / === … === headline, put a blank documentation
line before the next paragraph (valadoc requirement).
Bad (implementation essay, no examples):
/**
* GObject types that read/write on a Stream session. Override bin_write_prop
* / bin_read_prop to omit or customize props; call bin_default_write_prop /
* bin_default_read_prop for stock scalar encoding. Override for Gee.ArrayList
* list properties and uint8[] …
*/Also bad (too thin for a major API):
/**
* Binary wire serialization for RPC payloads.
*
* See docs/bin-rpc-protocol.md for the wire specification.
*/Good (OLLMchat-shaped — overview + titled examples):
/**
* Binary wire codec for {@link OLLMrpc} payloads.
*
* {@link Stream} writes and parses {@link Serializable} GObjects on a
* connection. {@link Json} bridges JSON trees for tests and HTTP. Register
* every wire alias with {@link register} before connect or listen.
*
* == Usage Examples ==
*
* === Round-trip ===
*
* {{{
* OLLMrpc.Bin.register("Pair", typeof(Pair));
* write_bin.write(new Pair() { name = "alpha", count = 42 });
* var parsed = read_bin.parse() as Pair;
* }}}
*/Wire-protocol details belong in docs/bin-rpc-protocol.md or on the
methods that implement them — not as a substitute for examples in the class
header.
- One blank comment line
*= new paragraph in output. - Same paragraph: no blank line between lines.
- For a visible line break inside a paragraph use
<<BR>>.
/**
* First paragraph,
* still the first paragraph
*
* Second paragraph, first line,<<BR>>
* second paragraph, second line
*/| In comment | In output |
|---|---|
''bold'' |
bold |
//italic// |
italic |
__underlined__ |
underlined |
`block quote` |
block quote |
Combined: ''//__bold italic underlined__//'' → bold italic underlined
Use a leading space and list marker; two spaces required after newlines for list layout.
As with long @param text, CODING_STANDARDS line-length guidance is not a reason to wrap a list item so that only a word or two sits alone on the next line—keep a bullet on one line when that reads better, or break at a natural phrase boundary.
- Numbered:
1.or#.ori./I.ora./A. - Bullet:
*
/**
* 1. First item
* 1. Second item
*
* * Bullet one
* * Bullet two
*/Multi-line bullet (same item): Valadoc list rules require two spaces after newlines; continuation lines use the same extra indent as nested list lines in that page’s example ( * then four spaces before the rest of the line: * …). Use as many continuation lines as needed so no single line is an unreadable run-on (do not start another * * line, or it becomes a new bullet):
/**
* * First line of the bullet, break after a phrase or punctuation:
* second line of the same bullet.
* third line still the same bullet.
*/Valadoc markup is defined at valadoc.org/markup.htm.
Supported inline taglets are only {@link Symbol} and {@inheritDoc}.
Text highlighting uses ''bold'', //italic//, __underlined__, and
`block quote` (backticks are not for code).
Valadoc does not support Javadoc {@code …} (CI fails with
Invalid taglet in this context: code).
Official Valadoc documents {{{ … }}} for block code samples — content on
lines between the opening and closing braces:
/**
* Example:
*
* {{{
* var list = new List(runner);
* yield list.run_all_tasks();
* }}}
*/Each {{{ … }}} span becomes a <pre><code> block in HTML. Do not embed
{{{token}}} inside running prose — even a short inline literal becomes its
own block and breaks the sentence across multiple lines (e.g. “Override for” /
Gee.ArrayList / “list properties” rendering as three stacked blocks).
For names, wire keys, flags, and paths inside a sentence, use one of:
| Need | Valadoc markup | Example |
|---|---|---|
| Vala symbol with link | {@link Namespace.Class} |
{@link Gee.ArrayList} |
| Emphasis / literal name | ''bold'' |
''*type'', ''uint8[]'', ''--debug'' |
| Plain identifier | no markup | ollmfilesd, call_* signal prefix |
/**
* Override for {@link Gee.ArrayList} list properties and ''uint8[]'' byte
* arrays (wire as blob or typed array — see docs/bin-rpc-protocol.md).
*
* Wire meta key ''*type'' on every object; see {@link Mode.EXPLICIT}.
*/When a multi-line code block needs literal {, }, or //, avoid valadoc
mis-parsing by using ALL_CAPS placeholders in the surrounding prose instead
of inline triple-brace URL/path fragments. Keep real syntax inside block samples
where valadoc treats the whole block as code.
| Markup | Valadoc | Use |
|---|---|---|
{{{ … }}} on multiple lines |
✅ | Block code samples only |
{{{ token }}} inline in prose |
❌ | Renders as block <pre> — use ''…'' or {@link} |
{@link Symbol} |
✅ | Link to a Vala symbol |
{@inheritDoc} |
✅ | Copy parent docblock |
{@code …} |
❌ | Not valid |
`backticks` |
block quote | Not for code — use ''bold'' inline |
[[http://example.com|label]]→ link with text “label”[[http://example.com]]→ bare URL{@link SymbolName}→ link to a Vala symbol (class, method, property){@inheritDoc}→ inherit description from parent (e.g. overridden method)
Package overview wiki (docs/valadoc-wiki/index.valadoc): Use
full URLs to the published GitHub Pages docs in [[url|label]] links, e.g.
[[https://roojs.github.io/OLLMchat/ollmchat/OLLMchat.html|OLLMchat]]. Valadoc
renders those as external links (target="_blank"). After ninja docs/valadoc,
docs/fix-valadoc-index-links.sh rewrites internal links in index.htm only
to same-directory relative hrefs (no new tab). Keep links aligned with symbols
that exist in docs/meson.build (remove stale pages when classes are deleted).
Sidebar navigation is generated separately and still uses relative paths.
/**
* || ''Header A'' || ''Header B'' ||
* || cell one || cell two ||
* || cell three || cell four ||
*/= headline 1 === headline 2 ===== headline 3 ======= headline 4 ====
valadoc (HTML doc generation): After a headline line (== … == or === … ===), put a
blank documentation line (* only) before the next paragraph. If the first word of a
section body immediately follows a === line on the very next line, valadoc can fail with
errors such as unexpected token on that word. Do not put ''…'' markup inside the
same line as the === … === delimiters (put parameters in the body lines below). In
{{{ … }}} blocks, avoid a line that contains only a closing brace } after * (e.g. the
closing line of a braced if); prefer a one-line if without braces or equivalent so the
sample still compiles. For long bullets, use the Multi-line bullet indentation under
Lists (same idea as nested lines in Valadoc’s list example);
arbitrary or inconsistent continuation indents can still confuse valadoc.
| Taglet | Synopsis | Use for |
|---|---|---|
@param name description |
Parameter | Each parameter of methods/signals |
@return description |
Return value | Non-void methods |
@throws TypeName description |
Thrown error | async/throws methods |
@since version |
Version | When the API was added |
@deprecated version |
Deprecation | When and why deprecated |
@see SymbolName |
See also | Related symbol |
Prefer several readable lines over one very long line. After the first line ( * @param name …), put each continuation on a new comment line that starts with * and two spaces before the rest of the text, so the description stays one taglet:
/**
* @param start_or_count Head mode: line count from the top; ''-1'' or ''0'' = entire file.
* Range mode: first line number, **1-based inclusive** (unchanged).
*/This matches common gtk-doc / Valadoc usage and works with ninja docs/valadoc (unlike some wiki list continuations in the long description above). CODING_STANDARDS suggests keeping docblock lines reasonably short (often cited as ~72 characters); that is not a reason to split in the middle of a short phrase or leave a lone word on the next line—prefer natural phrase breaks or leave a slightly longer line.
{@link SymbolName}— link to another symbol.{@inheritDoc}— copy description from parent (e.g. overridden method).
Not supported: {@code …} and other Javadoc taglets. Use {{{ … }}} for literals
(see Code in comments above).
Generated HTML docs are built with:
ninja -C build docs/valadocThat runs docs/run-valadoc.sh (valadoc, then docs/fix-valadoc-index-links.sh
on build/valadoc/ollmchat/index.htm only).
CI runs the same target. Keep these in sync when you change the tree:
| When you… | Also update… |
|---|---|
Add/remove/rename a .vala in any documented library |
docs/meson.build — add the same path to the valadoc_docs input: list |
| Add a new library subdirectory | Root meson.build subdir() and a new block in docs/meson.build (dependency order) |
| Introduce types used by later files | Put defining files before users in the valadoc list (same rule as each library's meson.build) |
How valadoc is wired
- Internal libraries are listed as source files, not
--pkg— using VAPIs duplicates definitions and breaks the build (see header comment indocs/meson.build). - External deps stay as
--pkg=…(gtk4, seccomp, tree-sitter, etc.). - Linux-only sources (e.g.
libocbwrap/Bubble.vala, notlibocbwrap/windows/*) go in the list; Windows stub trees are build-only. - Many library
meson.buildfiles repeat: updatedocs/meson.buildwhen sources change — follow that.
Common ordering traps (define before use):
ollmapp/ChatUserInterface.vala,AgentDropdown.valabeforeWindow.valalibocbwrap/*beforelibocmcp/*(Stdio usesOLLMbwrap.*)namespace.vala/ interface files before implementations in each library
After docblock or valadoc-list edits, run ninja -C build docs/valadoc locally —
errors are stricter than the Vala compiler (invalid taglets, headline layout, etc.).
Post-build grep checks (after ninja -C build docs/valadoc):
# Inline triple-brace in prose → fragmented <pre> blocks inside <p> (bad layout)
rg '<p>[^<]*<pre class="main_source">' build/valadoc/ollmchat --glob '*.html' \
| rg -v '<br/>'
# Curly braces inside inline triple-brace literals in source (truncation risk)
rg '\{\{\{[^}]*\{' --glob '*.vala'
# index.htm: internal overview links must be relative (no roojs.github.io + _blank)
rg 'target="_blank".*roojs\.github\.io' build/valadoc/ollmchat/index.htmThe first grep should return no matches for pages you changed. The second should return no matches project-wide. The third should return no matches after a successful docs build.
- Every public class has a class-level
/** ... */with at least a brief description; add “Purpose” / “What it does” / “How it fits” where it helps. - Every public method/signal has a brief description and, where relevant:
@paramfor each parameter@returnfor non-void methods@throwswhen the method can throw
- Properties that are part of the public API are documented (brief + optional long).
- Private members may have a short comment when the role is not obvious; full Valadoc is optional.
- Keep copyright/license in the file header as a separate block; do not put Valadoc in the same block as the license.