| name | ref-check |
| description | Extract and validate @ref annotations from source code. Reports broken references (references to LLPs or sections that don't exist), orphaned annotations (references with no matching code construct), and summary statistics. The foundational tool for everything else LLP does with references. |
ref-check
Use this skill to validate the @ref annotations in a codebase. References are the link between code and LLP design documents, and they go stale silently when either side changes. This skill catches the staleness before it turns into incorrect AI-generated code.
Invoke as:
/ref-check: scan the current working directory for all reference annotations and report problems
/ref-check <path>: scan a specific file or directory
/ref-check --fix: attempt to auto-repair broken references where possible (e.g., LLP moved to a new number but title still matches)
What a @ref annotation looks like
Per LLP 0000, the reference syntax is:
@ref LLP NNNN#anchor: gloss
@ref LLP NNNN#anchor [relation]: gloss
@ref LLP NNNN: gloss
@ref path/to/doc.md#anchor: gloss
Where:
NNNN is a zero-padded four-digit LLP number (or just NNNN without padding, e.g. LLP 42)
#anchor is an optional section anchor within the document (maps to a heading in the target file)
[relation] is an optional relation type: implements, constrained-by, tests, explains, or a project-defined type
: gloss is a short human-readable summary (required per LLP 0000 for readability); the colon separates the structured prefix from the gloss
- The whole thing appears in a language-appropriate comment (
//, #, /* */, --, etc.)
References are commonly attached to the construct below them: a function, a struct, a block, a variable declaration. Per LLP 0000's attachment semantics, the reference binds to the next named construct.
Ground rules
- LLP documents live in
llp/ (and any additional directories configured for the project).
- Reference syntax is defined in LLP 0000. If the project has extensions to the syntax, they may be documented in a project-specific LLP; check
llp/ for any that mention reference syntax.
- This skill does not modify source files unless
--fix is provided and the user approves each fix individually.
- All references in all source files are scanned, not just those in files the user mentioned.
Workflow
1. Discover source files
Walk the specified directory (or current directory). By default, include common source file extensions:
.rs, .ts, .tsx, .js, .jsx, .mjs, .cjs
.py, .go, .c, .cpp, .cc, .h, .hpp
.swift, .kt, .java, .scala
.rb, .php, .cs, .lua, .zig
.md, .txt (to catch references in prose too)
Respect .gitignore. Skip node_modules, target, build, dist, .git, and similar noise directories.
If the project has configured explicit paths or exclusions (via a config file or project LLP), honor them.
2. Extract references
For each source file, scan for lines containing @ref followed by either LLP <number> or a markdown path (LLP 0042#anchor, path/to/doc.md#anchor, etc.).
Capture for each:
- Source file path and line number
- Full raw reference text
- Target: LLP number (if LLP reference) or file path (if path reference)
- Anchor: section name, if any
- Relation:
implements, constrained-by, etc., if any
- Gloss: the human-readable summary, if any
3. Build the LLP index
Scan llp/ (and any other configured LLP trees) for all documents. For each, extract:
- LLP number
- Title
- File path
- All heading anchors in the document (generated by slugifying each heading: lowercased, spaces to
-, non-alphanumerics stripped)
Build a map from (LLP number) → (file path, title, {anchor: heading text}).
4. Validate each reference
For each reference:
LLP reference (@ref LLP 0042#anchor):
- Does LLP 0042 exist? If not, report the reference as
BROKEN: LLP 0042 does not exist.
- If an anchor is specified, does the anchor exist in LLP 0042? If not, report as
BROKEN: LLP 0042 has no section "anchor". Include the list of sections that do exist in the error output so the user can pick a replacement.
- Is the LLP tombstoned? If yes, report as
WARNING: references tombstoned LLP 0042. Tombstoned LLPs are not errors, but the user should probably update the reference to a replacement or remove the annotation.
- Is the LLP superseded? If yes, report as
WARNING: references superseded LLP 0042 (superseded by LLP NNNN if the header says so).
- Does the gloss match the LLP's actual content? This is a soft check. If the LLP's section anchor text doesn't resemble the gloss at all, report as
HINT: gloss may be out of date. Don't block on this; just inform.
Path reference (@ref docs/vendor/spec.md#tokens):
- Does the file exist? If not, report as
BROKEN: file docs/vendor/spec.md does not exist.
- If an anchor is specified, does the heading exist? Same check as LLP references.
Relation validation:
- If a relation type is used, verify it's one of the standard types (
implements, constrained-by, tests, explains) or is documented in a project LLP. Otherwise report as HINT: relation type "foo" is not standard.
5. Report findings
Group the output by severity:
ref-check found 47 references in 23 files.
BROKEN (3), these must be fixed:
src/auth/tokens.rs:42 @ref LLP 0099 (nonexistent LLP)
src/ui/modal.ts:15 @ref LLP 0074#focus-trap (no such section; did you mean "focus-trapping"?)
src/net/client.go:88 @ref docs/vendor/spec.md#tokens (file not found)
WARNING (2), references point at deprecated LLPs:
src/legacy/sync.rs:12 @ref LLP 0009 (tombstoned, no replacement indicated)
src/db/migrate.rs:55 @ref LLP 0021 (superseded by LLP 0044)
HINT (5), consider updating:
src/ui/button.ts:33 @ref LLP 0007#layout: gloss "button click handler" does not obviously relate to section "layout"
...
Summary:
Total references: 47
Broken: 3
Warnings: 2
Hints: 5
Clean: 37
6. Optional: fix mode
If invoked with --fix, for each broken reference:
- LLP moved or renumbered. If an LLP with a matching title exists at a different number, propose the fix and ask the user to approve.
- Anchor typo. If the user said
#focus-trap but the actual anchor is #focus-trapping, propose the fix.
- Path typo. If the file doesn't exist but a similarly-named file does, propose the fix.
- Unfixable. For truly orphaned references (referenced content genuinely gone), offer to remove the annotation, leave it with a
BROKEN marker in the comment, or do nothing.
Apply each fix one at a time with the user's approval. Never batch-apply without confirmation.
7. Exit status
For scripting (this skill can be invoked from CI):
- Exit 0 if no broken references
- Exit 1 if any broken references
- Warnings and hints do not cause a non-zero exit code
Output formats
- Plain text (default)
- JSON (
--format=json): an array of finding objects for programmatic consumption
- SARIF (
--format=sarif): for integration with CI systems that consume SARIF reports
Scope limits
- Do not modify source files without explicit approval in
--fix mode.
- Do not modify LLP documents.
- Do not follow references into unrelated repositories or external URLs.
- Do not attempt to resolve references that use unknown relation types or unknown reference syntax; report them as hints instead.
- Do not assume an LLP moved just because a title matches; always confirm with the user.
Integration with other skills
ref-story consumes the output of ref-check to generate rationale-ordered views of source files.
llp-impact uses the reference map to answer "what code depends on LLP NNNN?"
llp-review-pr uses reference validation to check whether a pull request breaks existing references.
ref-check is the foundation. If its output is wrong, everything downstream is wrong. Treat it as the canonical source of "what references exist and which are broken."