name: kxmeta-author
description: Write qdoc annotations for aimeta so the compiler publishes tables and functions correctly. Mandatory @kind/@name markers, the chained @col modifier form, q-language traps that silently drop items, and the recompile loop. Use when adding or editing / @kind ... annotation blocks in a q codebase that loads aimeta, or when annotated items aren't surfacing in meta.json. For the wire model & tag vocabulary see ../../reference/agent-guide.md.
Writing aimeta annotations
When to use
- Adding
/ @kind ...blocks above tables or functions in a q codebase that loadsaimeta. - Editing existing annotations.
- Diagnosing why an annotated item is missing from
meta.json(the compiler ran clean but the item didn't surface).
The wire model — tag vocabulary, meta.json shape, type-string rules, references[] semantics — lives in reference/agent-guide.md. This skill covers the behaviour of getting annotations correct.
The two mandatory markers
Every annotated item needs these. Without them the parser drops the item from meta.json — no error, no warning.
@kind datafor a table,@kind functionfor a callable.@kind tableis a common mistake — it silently drops because qdoc's preprocessor only recognisesfunction/data/readme/file.@name <bindingName>— required on every annotated item. The compiler reads names from@nameonly, never from qdoc's auto-detection (unreliable for multi-line lambdas). Convention: leaf for top-level (@name trade), fully-qualified for namespaced (@name .gw.vwap).
Syntax rules
- Annotation lines start with
/ @tagat column 0. Indented/lines are code context, not annotations. - One tag per line. A blank line, a non-comment line, or a different binding ends the block.
- Free-text fields run to end-of-line (
@desc,@paramdescription,@returnsdescription,@example). Repeatable tags:@param,@col,@example,@uses,@tag,@sampleRow— every other tag appears at most once. - Types use qdoc names inside
{...}(symbol,symbol[],float,timestamp), not q's single-char codes. The compiler maps tos/f/p/… when emittingkdbType. - Annotations sit immediately above the binding. A blank line between the block and the binding breaks the association.
Chained @col modifiers
Column modifiers pile up on a single @col line after the required name {type} description. prefix:
/ @col sym {symbol} Instrument symbol. @semanticType:instrument @foreignRef:instrument.sym @attr:u
Order doesn't matter. Modifiers: @semanticType:X, @foreignRef:T.C, @cardinality:{low,medium,high}, @attr:{s,u,p,g} (may repeat), @label.
Sample rows
@sampleRow attaches example data — one row per tag (repeatable), comma-separated q literals: / @sampleRow 2026.04.29D14:30:00,`AAPL,175.5.
- One cell per
@col, each matching the column's type — an{int}column needs100i, not100. - Literals only, no expressions; strings containing commas must be
"..."-quoted.
q-language silent-drop traps
These are q-tokeniser quirks, not annotation rules. Symptom: compiler runs clean, item is missing from meta.json.
- Bare
/at column 0 can open a block comment that swallows subsequent annotations. Use//for non-annotation comments interleaved between bindings. -in symbols —`:foo-barparses as`:foominusbar. Use_or camelCase:`:foo_bar,`:fooBar.if[c; '"err"]; restinline in a function body silently drops the host function. Use$[c; '"err"; rest]— semantically equivalent, parses cleanly.- Compound type strings in
{...}—dict(a:long;b:long)orfn(long;long)->longmay silently drop the item. Stick to baredict,function,*; put structure into@desc. @descsplit across multiple/lines — only the first line is the description; the rest are dropped silently.- Annotations below the binding — must come immediately above.
Visibility defaults
- Tables are published by default. Opt out with
@private(the binding is omitted frommeta.jsonentirely, including thereferences[]index). - Functions are excluded by default. Opt in with
@public. The block parses cleanly without@publicbut the function won't appear in the published surface.
Required tags on @public functions
@kind, @name, @desc, @returns, one @param per declared argument. Recommended: @example (at least one), @uses (table dependencies — drives the cross-process publish graph). Optional: @tag.
Reference tables (vocabulary resolvers)
A @reference X table is the canonical resolver for vocabulary X. It needs at least one @attr:u column (the key) and may carry @label columns (human-readable names). Other tables link to it via @semanticType:X on the joining column. See the worked example in reference/agent-guide.md for the full pattern.
Validation rules (not yet enforced by the compiler — follow them anyway):
@reference Xrequires the table to have a@attr:ucolumn.- Two tables claiming
@reference Xfor the sameXis an error. @labeloutside an@referencetable is dropped.@reference X↔@semanticType Xis a vocabulary link;@foreignRef T.Cis an edge. Independent — a column can carry both.
Recompile and sanity-check
After substantive edits, restart the host — init[] recompiles on
boot by default:
q host.q
Or run the standalone CLI form (useful in CI, or when iterating without booting):
scripts/kx-meta.sh compile /path/to/your/q/source
Either path writes <srcDir>/.aimeta/meta.json — byte-deterministic; commit it and let CI guard against drift.
The parser doesn't report what it silently dropped. Count what made it through:
m: .aimeta.data[];
expectedFns: `.gw.vwap`.gw.fxConvert; / what you expect
gotFns: key m`functions;
missing: expectedFns except gotFns;
if[count missing;
-1 "MISSING from meta.json: ", "," sv string missing;
-1 " → first check: missing @kind, missing @name, mismatched @name.";
-1 " → then: bare `/` comments, `-` in symbols, if[c;'\"err\"];rest bodies, compound types."];
If items are missing and the compiler reported no errors, the cause is one of the silent-drop traps above.
Pointers
- reference/agent-guide.md — wire model & tag vocabulary (the closed tag table, type-string rules,
meta.jsonshape,references[]semantics). - reference/meta.schema.json — machine-readable wire schema; useful for sanity-checking compiled output shape.