Skip to content

Docs ↔ Implementation Tagging

What this solves

When implementation and the docs that describe it live in different files, they drift silently. A reader editing sync/mod.rs has no way to know that two architecture docs are quoting its heartbeat interval — so the docs go stale without anyone noticing. This skill defines a minimal, greppable convention to make that link visible from both directions.

Two tags, no tooling required:

  1. Last updated by header at the top of every doc that mirrors implementation behaviour.
  2. @docs: block at the top of every source file that implements anything those docs claim.

Together they support two everyday workflows:

  • "I'm editing this code — which docs might need updating?" → read the source file's @docs: block.
  • "I'm editing this doc — which source files implement it?" → grep the repo for the doc filename.

Convention 1 — Last updated by header on docs

Add a single-line header above the existing doc body (after the title, version, and date if those exist):

**Last updated by:** <Full Name> <email@domain> · YYYY-MM-DD

Rules:

  • Update whenever the doc's content changes to reflect a code change, not just typo fixes. The point of the header is to tell a reader when the doc was last reconciled against reality.
  • Use absolute dates (2026-05-12), never relative ("yesterday", "last week").
  • One name + email + date per header line. Keep it short — this is a freshness signal, not a changelog.
  • Leave existing Document Version / Date lines alone; the new header sits alongside them.
  • Do not guess the email. Use the author's organisation email (e.g. <name>@fonterra.com). git config user.email is not a reliable source — it frequently carries a personal or stale domain (this repo's history shows the same person under @fonterra.com, a personal domain, and @gmail.com). If the identity an agent has on hand is a personal domain, ambiguous, or otherwise doesn't look like the org address, stop and ask the author to confirm their actual email rather than writing a guess into the header.

Convention 2 — @docs: block on source files

A short comment block near the top of each implementation file, listing the docs (and ideally the doc sections) that describe its behaviour.

Format — comment-style languages (Rust, Go, C/C++, shell)

// ==============================================
// Module Name
// ==============================================
//
// <existing module description>
//
// @docs:
//   - docs/COMMUNICATION-FLOWS.md            §3 Heartbeat, §4 Sync loops
//   - docs/platform-architecture-overview.md §2 LA↔Backend
//

use ...;

Format — JSDoc-style languages (TypeScript, JavaScript, Java)

// ==============================================
// Module Name
// ==============================================
// <existing module description>
//
// @docs:
//   - docs/COMMUNICATION-FLOWS.md            §1 On-Device flow
//   - docs/platform-architecture-overview.md §1 IPC channels

import { ... } from '...';

Format — Python

"""Module description.

@docs:
  - docs/COMMUNICATION-FLOWS.md §3 Heartbeat
  - docs/platform-architecture-overview.md §2 LA↔Backend
"""

Rules

  • The literal string @docs: is the marker. grep -rn "@docs:" must return every tagged file — do not abbreviate, capitalise, or reflow it.
  • Paths are repo-relative (e.g. docs/COMMUNICATION-FLOWS.md) so the entry reads identically from any file.
  • Cite the doc section (e.g. §3 Heartbeat) when the file maps to a specific section. If the whole doc is relevant, omit the anchor.
  • List one doc per line as a bullet. Two- or three-doc blocks are normal; four or more usually means the file is doing too much.
  • Place the block inside the existing top-of-file comment, not as a separate banner. Visual noise matters; the block is supplementary metadata, not the file's main introduction.

Choosing which source files to tag

Tag a file when both are true:

  1. The file implements behaviour that at least one doc explicitly describes (intervals, schemas, endpoints, port numbers, channel names, ID formats).
  2. Changing the file without updating the doc would mislead a future reader.

Files that deserve the tag:

  • Sync / heartbeat loops, scheduler intervals, retry policies.
  • Wire schemas (request/response structs, protobufs, JSON shapes).
  • Registration / identity / fingerprinting logic.
  • IPC handler registries (channel names, command tables).
  • Network listeners (port numbers, bind paths, socket paths).
  • Config defaults that downstream systems depend on.

Files that don't need it:

  • Pure utilities (string helpers, math, formatting).
  • UI components with no documented behaviour contract.
  • Tests, fixtures, generated code.
  • Build / tooling scripts unless they encode a documented workflow.

Aim for 10–20 tagged files per service, not every file. A bloated tag-set is as bad as none — it trains readers to ignore the marker.

Good vs bad examples

These come from the original VortexNav rollout — verbatim.

Good — anchored, scoped, integrated

// ==============================================
// Sync Module
// ==============================================
//
// Handles synchronization with Horizon:
// - Periodic heartbeats
// - Entitlement refresh
// - Usage reporting
//
// @docs:
//   - docs/COMMUNICATION-FLOWS.md            §2 Device-to-Cloud, §3 Heartbeat, §4 Sync loops, §6 Usage
//   - docs/platform-architecture-overview.md §2 LA↔Backend (transport, auth, token lifecycle)
//

Why it works: lives inside the file's existing top-of-file comment; cites multiple sections so the reader knows which paragraphs to check; two-deep aligned columns make it readable at a glance.

Good — single-doc, single-section

// @docs:
//   - docs/COMMUNICATION-FLOWS.md §3 Heartbeat System — DeviceTelemetry schema

Why it works: precise. A DeviceTelemetry struct change forces a doc update at exactly one location.

Bad — vague, unscoped

// See architecture docs for details.

Problem: not greppable (no @docs: marker), no path, no section anchor. The reader has to know which docs to read and where to look.

Bad — section count exceeds the file's responsibility

// @docs:
//   - docs/COMMUNICATION-FLOWS.md §1, §2, §3, §4, §5, §6, §7
//   - docs/platform-architecture-overview.md §1, §2, §3, §4, §5, §6, §7, §8

Problem: this file claims to back the entire platform. Either the file is a god-object that should be split, or (more often) the author copied the same block into every file. Both cases mean the marker has stopped carrying signal.

Bad — path drift not caught

// @docs:
//   - ../../../docs/COMMUNICATION-FLOWS.md §1

Problem: relative paths break when the file moves. Always repo-root relative.

Bad — separate banner box

// ===============================================================
// @docs
// ===============================================================
// docs/COMMUNICATION-FLOWS.md
// docs/platform-architecture-overview.md
// ===============================================================

Problem: visual heavyweight. The block is metadata, not a section heading. Integrate it into the existing comment.

The maintenance contract

The tags only have value if they are kept honest. Two rules:

  1. When editing a tagged source file, scan its @docs: block. If your change touches anything those docs describe — intervals, schemas, endpoint paths, channel names, port numbers — update the doc in the same PR and bump its Last updated by header.
  2. When editing a tagged doc, grep for its filename across the source tree. If the file you just changed contradicts one of the source files' @docs: entries, the source needs updating too.

If a tagged doc is renamed or deleted: grep and update every source file that referenced it. Treat broken @docs: paths the same as broken imports.

Discovery commands

# Every tagged source file in the repo
grep -rln "@docs:" --include='*.rs' --include='*.ts' --include='*.py'

# Files associated with a specific doc
grep -rln "COMMUNICATION-FLOWS.md" --include='*.rs' --include='*.ts'

# Last-updated dates across all docs (sanity check for staleness)
grep -rn "Last updated by" docs/

A CI check that fails when a tagged path references a missing file is optional but high-value. Keep it as a separate skill if you build it — the tagging convention itself must stay tooling-free.

Roll-out steps for a new project

  1. Pick the docs that will carry Last updated by headers. Usually the small set that mirrors current implementation (communication flows, API surface, architecture overview).
  2. Add the headers with today's date and the human who reconciled the doc against code. From this moment forward, anyone touching the doc updates the header.
  3. Pick the source files to tag (10–20 per service, see "Choosing which source files to tag").
  4. Add @docs: blocks to each. Cite section anchors where the file maps to a specific section.
  5. Add one paragraph to the project's AGENTS.md / CLAUDE.md / contributor docs naming the convention so reviewers know to enforce it.
  6. First PR review under the convention: scan for @docs: hits in the diff and check that any listed doc was updated alongside the code.

Troubleshooting

Error: grep "@docs:" returns nothing in a project that should be tagged. Cause: Tags haven't been rolled out yet, or someone abbreviated the marker (@doc:, // docs:). Solution: Run the roll-out steps above. Fix abbreviated markers — the literal @docs: is non-negotiable.

Error: A @docs: block references a path that no longer exists. Cause: The doc was renamed or deleted without updating callers. Solution: grep -rln "<old-doc-name>" across the source tree, then update every referrer. Same workflow as fixing a broken import.

Error: Every file in a directory has an identical four-doc @docs: block. Cause: Copy-paste during roll-out without scoping per file. Solution: For each file, ask "which doc section would a reader actually need if they were changing this file?". Trim to the specific entries. A block longer than 3 lines is a smell.

Error: Docs have Last updated by headers but the dates are months behind recent code changes. Cause: The maintenance contract isn't being enforced in review. Solution: Treat a code change that touches documented behaviour without a doc-header bump as a review block. Add an example to the team's PR checklist.

Error: A doc's Last updated by shows last month's date but the content was edited yesterday for a typo. Cause: Confusion about when to bump the header. Solution: Bump only when the doc's content is reconciled against implementation, not for cosmetic edits. Typo fixes can leave the header alone.