COMMENT conventions
Kozou reads the COMMENT you attach to tables, columns, views, and
foreign keys and turns it into three surfaces: an Admin UI, a REST
API, and MCP context for AI agents. Most of a COMMENT is plain prose
meant for humans, and Kozou carries that prose through untouched. But
a small, opt-in set of @-prefixed tags lets you add structure —
widget hints, AI guidance, business policy, and example queries —
without leaving SQL.
This page documents that tag vocabulary exactly as @kozou/core
parses it. For how the parsed result lands in each surface, see
Emitted surfaces. For why the database
is the single source for all of this, see
Postgres as source of truth.
The model: prose first, tags as opt-in structure
Section titled “The model: prose first, tags as opt-in structure”A COMMENT is plain text. You write it for a human reader, and the
first line should be short — Kozou uses it as a fallback label. Below
that prose, you may add tag lines. A tag line is recognized when it
starts (after optional leading whitespace) with @, a tag name, and
a colon:
@<name>: <value>Four tag names are known to v0.1.1: @ai, @widget, @policy, and
@example. Each is parsed differently, and the choices below are
deliberate — some tags stay in the displayed body, some are removed,
and one is lifted out entirely. The sections that follow cover each
tag and what happens to a tag Kozou does not recognize.
The parser returns a single structured result per COMMENT:
type ParsedComment = { body: string; // human-facing text, with some tags removed ai: string[]; // every @ai value, in order widget: WidgetType | null; // the last valid @widget value policy: string[]; // every @policy value, in order examples: ExampleQuery[]; // each @example block, lifted out of body};@ai — free-text guidance for AI agents
Section titled “@ai — free-text guidance for AI agents”@ai carries instructions or context aimed at an AI agent rather than
at a UI. You can write more than one @ai line; each value is
collected, in order, into ai[].
COMMENT ON TABLE orders IS 'Customer orders. One row per placed order.
@ai: For revenue figures, prefer the view vw_orders_paid. @ai: Rows where deleted_at is not null are soft-deleted; exclude them.';@ai is the one tag that is both kept in the displayed body and
extracted. The reasoning is that an @ai note usually reads as a
sensible sentence to a human as well, so removing it would lose
context for anyone reading the raw description. The same text
therefore appears in body and in ai[].
@widget — a column-only UI widget hint
Section titled “@widget — a column-only UI widget hint”@widget tells the Admin UI which input control to render for a
column. It is meaningful only on a column COMMENT; on a table or
view COMMENT it has no column to bind to.
COMMENT ON COLUMN products.description IS 'Long-form product copy shown on the storefront. @widget: textarea';Three behaviors are specific to @widget:
- It is removed from the displayed body. Unlike
@ai, a@widgetline is structural noise to a human reader, so it does not appear inbody. - Last one wins. If a COMMENT contains more than one
@widgetline, the final valid value is the one that takes effect. - The value must be a known widget type. If the value is not one of the types below, Kozou logs a warning and records no widget for that column (so it falls back to the heuristic default).
The full set of widget types, exactly as defined in @kozou/core, is
these 12:
texttextareanumberbooleandatedatetimeenum-selectrelation-selectjsonimage-urluuidcurrency@widget is a hint, not the only input. When you omit it, Kozou
infers a widget from the column’s type and constraints (for example, a
column with a CHECK list of allowed values infers enum-select, and a
foreign-key column infers relation-select). A YAML UI Hints file, if
present, takes precedence over both the @widget tag and the
heuristic. image-url renders the image’s URL for display in v0.1.1;
it is not an upload control.
@policy — business-policy text (not enforced in v0.1)
Section titled “@policy — business-policy text (not enforced in v0.1)”@policy records a business rule in prose. Every @policy line is
collected into policy[], and — like @ai — the line is kept in
the displayed body.
COMMENT ON COLUMN orders.status IS 'Order lifecycle state. @policy: An order may only move to ''shipped'' after payment is captured. @widget: enum-select';In v0.1.1, @policy is parsed but not enforced. Kozou extracts
the text and makes it available as context; it does not generate
constraints, triggers, or API-layer checks from it. Treat it as
documentation that travels with the schema and reaches AI agents,
not as a guarantee the runtime upholds.
@example — example queries for views and concepts
Section titled “@example — example queries for views and concepts”@example attaches a runnable example query to a view (surfaced as a
“concept” in MCP). It is the only multi-line tag in v0.1.1, and it
has the most distinctive parsing:
- The text on the
@example:line itself is the description (it may be empty). - The indented continuation lines below it are the SQL.
- The block ends at the first non-indented line, the next
@-tag, or the end of the COMMENT. - The shared leading indentation is stripped, so the stored SQL reads as written rather than indented by the COMMENT block. Blank lines inside the block are preserved, so a multi-statement example keeps its separators.
COMMENT ON VIEW vw_orders_paid IS 'Orders that have been paid for.
@example: Total revenue in the last 30 days select sum(total_amount) from vw_orders_paid where paid_at >= now() - interval ''30 days'';';Unlike every other tag, an @example block is lifted out of the
displayed body entirely. The SQL is surfaced separately — as a list
of { description, sql } entries — because it is presented as
example queries, not as prose. From the COMMENT above, the body keeps
only Orders that have been paid for., and the example becomes one
entry whose description is Total revenue in the last 30 days and
whose sql is the dedented two-line query.
Unknown tags — kept in the body, logged as a warning
Section titled “Unknown tags — kept in the body, logged as a warning”If a COMMENT contains a tag Kozou does not recognize — say a future
@foo: — the parser does not fail. It keeps the line in the
displayed body and logs a warning. This is deliberate forward
compatibility: a COMMENT written for a newer Kozou still renders
sensibly under v0.1.1, and the unknown text is never silently
dropped.
COMMENT ON COLUMN products.sku IS 'Stock-keeping unit. @foo: reserved for a future convention';The @foo: line stays in body, and you will see a warning from
@kozou/core noting that an unknown tag was kept in the body.
A worked example
Section titled “A worked example”Put the rules together on a single generic column. Suppose you have a
products table with a status column constrained to
draft, published, or archived:
COMMENT ON COLUMN products.status IS 'Publication state of the product. draft: not yet visible published: live on the storefront archived: hidden but retained
@ai: Only ''published'' rows should appear in public listings. @widget: enum-select';Kozou parses that one COMMENT into the following pieces:
| Part of the COMMENT | Where it goes |
|---|---|
Publication state of the product. and the three draft/published/archived lines | body — the displayed description |
@ai: Only 'published' rows should appear in public listings. | kept in body and added to ai[] |
@widget: enum-select | removed from body; sets widget to enum-select |
So the displayed body reads as plain prose (the type description plus
the @ai sentence), the column renders with an enum select control in
the Admin UI, and the @ai guidance is available to AI agents through
MCP. One COMMENT, three surfaces.
If you had written @widget: dropdown instead, dropdown is not one
of the 12 known widget types, so Kozou would log a warning, leave
widget unset for that column, and fall back to the inferred default
(here, enum-select, because the column has a CHECK list).
How tags flow into each surface
Section titled “How tags flow into each surface”The same parsed result feeds all three of Kozou’s outputs:
- Admin UI (
@kozou/svelte-ui) —@widgetchooses the input control for a column; thebodytext becomes the field’s description. - REST API — in v0.1.1 the REST layer is provided by
PostgREST running alongside Kozou.
COMMENT prose is what describes your tables and columns. The v0.2
line adds an experimental in-house REST layer,
@kozou/api, behindkozou dev --adapter api; treat it as experimental. - MCP context (
@kozou/mcp) —@ainotes,@policytext, and@examplequeries become structured context an AI agent can read, so the agent learns not just your table shapes but the guidance and example query paths you wrote alongside them.
For a surface-by-surface walkthrough of exactly what each output contains, continue to Emitted surfaces.