// your code is already documented

Code annotations from the comments you already wrote

Every codebase is full of invisible documentation. TODOs, deprecation warnings, explanations buried in comment blocks are useful the moment you read them and forgotten the moment you scroll past. The documentation already exists. It just isn't visible outside that one line. Add @gitian to a comment you already wrote and it renders as a structured, browsable card beside the code.

// the migration

One word. That's the entire migration.

There is no wiki to port and no new format to learn. The comments are already written and already correct. They're just invisible to everyone who isn't reading that exact line of that exact file.

before: comments you have definitely written
// TODO: fix N+1 in syncInventory — batch the lookups

// WARNING: retry logic assumes the call is idempotent

/** @deprecated use fetchOrders — this path skips tax */
after: one tag, rendered as cards
@gitian:todofix N+1 in syncInventory — batch the lookupssrc/services/sync.ts:142 · marker
@gitian:warningretry logic assumes the call is idempotentsrc/lib/retry.ts:57 · block, captures the code below
@deprecateduse fetchOrders — this path skips taxsrc/api/orders.ts:88 · doc tier, muted

The annotation travels with the code: rename it, move it, refactor it, and the annotation stays attached. Same file, same commit, same thought. When code changes, the docs beside it change too. When a module is deleted, nothing outlives its source.

// three tiers

Three detection tiers, so adoption can be gradual

Only the first tier is on by default, and it only ever matches a tag you deliberately wrote. The other two exist so a repository can opt into surfacing what's already there without editing a single comment. They render deliberately muted, because a keyword someone typed in 2019 does not carry the same weight as a tag someone wrote on purpose.

priority order: first match wins
@gitian:tagExplicit, always on, and the only full-featured tier: code capture, urgency, groups, pinning, and every metadata key. source: "gitian".
@param · @deprecatedDoc-comment tags inside /** */ and /// blocks. Opt-in via detect_docs. Lightweight: no code capture, muted UI. source: "doc".
TODO · FIXMEBare keywords, anywhere in a comment. Opt-in via detect_keywords. Lightweight: no code capture. source: "keyword".

Detection is settable per file as well as per project: a doc file's YAML front matter can override detect_docs and detect_keywords, and the specificity runs file doc > project config > defaults. So one noisy legacy directory can stay quiet while the rest of the repo surfaces everything.

// four kinds

Four kinds, because not every note wants to be a card

A tag's kind decides how much room it takes. A hundred TODOs should be a list you can scan; one API contract should be a panel you can read. Kinds are configured per tag, so the same annotation vocabulary can be quiet in one repo and loud in another.

markerA collapsible list. The right shape for high-volume tags where the count matters more than any single entry.
inlineA card without captured code. The note itself is the whole payload.
blockA card that captures the code beneath it, so the annotation carries its subject. The captured block renders collapsed by default.
apiA ReadMe-style API card: a title plus Request and Response payload panels, paired by --request= and --response=.

Capture knows the language's shape

A block annotation has to figure out where the thing it describes ends. There is no single rule that works across languages, so there are four: brace depth for C-family syntax, bracket depth for Nix, JSX element tracking for component trees, and indentation for Python.

Seven metadata keys

// @gitian:warning --urgency=critical --group="payments" \
//   --title="Idempotency is assumed, not enforced" --module=billing
export async function retryCharge(id: string) {
--id=A stable identifier for the annotation, so it can be referenced and paired.
--title="…"Overrides the display heading. Quote-aware, so titles can contain spaces and punctuation.
--group=Collects related annotations under one heading across files.
--urgency=One of subtle, normal, loud, or critical. It drives emphasis in the UI.
--module=Assigns the annotation to a module for workspace-level grouping.
--request=On an api tag, names the request payload to render.
--response=On an api tag, names the response payload to render.

// compose

Directives pull live annotations into markdown

Annotations live in your code. Docs give them structure. Directives compose them into pages that update as your code changes. There's no copy-pasting and no drift. Write the directive once and it resolves against the codebase every time the page renders.

{{annotation:@todo}}

↓ resolves at render time to every live @gitian:todo

src/services/sync.ts:142   fix N+1 in syncInventory — batch the lookups
src/lib/retry.ts:57        retry assumes idempotency; verify before enabling
src/api/orders.ts:203      drop legacy pagination after v2 ships

Close the TODO in the source and it leaves the page. The page was never a copy, only a view.

// pull requests

Annotations become a review signal

Once the notes in your code are structured, a pull request can be analyzed against them. gitian posts a comment summarizing what the change did to your annotations: which ones appeared and disappeared, which alert-level tags it touched, which groups it affected, whether the TODO count is trending up, and which docs were left orphaned by a deleted source file.

Six stats run by default and each one is a plugin, enabled or disabled through a pr_analysis section in .gitian/config.yaml.

// config

One optional file

Tags, their kinds, their colors, detection settings, and PR analysis all come from a single .gitian/config.yaml. Having no config file at all is a supported state rather than a degraded one: absent the file, gitian falls back to safe defaults with the built-in tags already defined.

// questions

Questions people actually ask

Do I have to tag anything to get value?

No. Opt into the keyword tier and your existing TODO and FIXME comments surface as-is, with no edits at all. Tagging with @gitian unlocks the full-featured tier: code capture, urgency, groups, and pinning.

Will this clutter my code with markup?

The whole syntax is one token inside a comment you were already writing. Metadata is optional flags on the same line, and a tag with no flags is a complete, valid annotation.

How does it know which code an annotation is about?

Block-kind tags capture the code beneath them using a strategy matched to the language: brace depth for C-family syntax, bracket depth for Nix, JSX element tracking, or indentation for Python.

What happens when I delete the annotated code?

The annotation goes with it. It lived in the same file and the same commit, so nothing outlives its source — unlike a wiki page, which keeps describing a function that no longer exists.

Can I turn detection off for one directory?

Yes. A doc file's front matter can override detect_docs and detect_keywords, and file-level settings take precedence over the project config, which takes precedence over the defaults.

Does it work in a language you haven't listed?

Annotations are comment-based, so any language with comments is detected. What varies is code capture for block-kind tags, which needs a strategy that understands the language's block structure.

// how this page is found

This route's own index plan

This is the reference-grade page in the cluster, and it earns its ranking on depth rather than on phrasing. The tier table, the kind table, and the seven metadata keys are the substance a searcher looking for "how do I annotate code" actually wants. It is also the page most likely to be linked from a README, which is why it's a TechArticle rather than a marketing WebPage.

Title and description

Code Annotations From Comments You Already Wrote | Gitian
Add @gitian to a comment and it renders as a structured card beside your code — three detection tiers, four tag kinds, code capture, and live directives.

The phrases this page is built to own

code annotation tool, surface TODO comments across a codebase, track @deprecated across a repo, document code in comments, TODO tracker for a git repo. The keyword tier is the hook here: it is the only honest way to promise value with zero edits, and "see every TODO in my repo" is a real thing people search for.

Structured data and links

TechArticle plus BreadcrumbList and the FAQ as FAQPage, all referencing the site-wide Organization and SoftwareApplication by id. This page is the natural inbound target for the guide's reference section, so the two should link each other rather than compete. The guide teaches the syntax step by step; this page states the whole surface at once.

A duplication risk worth naming

This page and /guide/reference describe the same syntax, which is exactly how cannibalization starts. The split that keeps both useful: the guide is procedural and signed-in-user-facing, this page is declarative and search-facing, and each canonicalizes to itself while linking the other in its first screen.