Skip to content

Doc-Symbol Linking

Version: 7.3

CKB can automatically detect symbol references in markdown documentation and link them to actual code symbols. This enables powerful queries like "What docs mention this symbol?" and "Which docs have stale references?".

Overview

Documentation often references code symbols in backticks like UserService.Authenticate or Engine.Start. CKB scans your markdown files, detects these references, and links them to SCIP symbol IDs. This creates a bidirectional mapping:

  • Symbol → Docs: "What documentation references this symbol?"
  • Doc → Symbols: "What symbols does this document reference?"
  • Staleness: "Which references are broken because the symbol was renamed/deleted?"

Quick Start

# Index documentation (scans docs/, README.md, ARCHITECTURE.md, etc.)
ckb docs index

# Find docs that reference a symbol
ckb docs symbol Engine.Start

# Check a document for stale references
ckb docs stale README.md

# Check all docs for staleness
ckb docs stale --all

# Get documentation coverage stats
ckb docs coverage

Detection Methods

CKB uses three methods to detect symbol references:

1. Backtick Detection (DetectBacktick)

References in backticks are automatically detected:

Use `UserService.Authenticate` to validate credentials.
See `Session.Create` for session management.

Requirements:

  • Must have at least 2 segments (e.g., Foo.Bar, not just Foo)
  • Supports multiple delimiter styles:
    • Dots: Foo.Bar
    • Double colons: crate::module::Type (Rust)
    • Hash: Class#method (JS/Ruby)
    • Slash + dot: pkg/sub.Func (Go)
    • Arrow: Class->method (PHP)

2. Directive Detection (DetectDirective)

For explicit symbol references, use HTML comments:

<!-- ckb:symbol internal.auth.UserService.Authenticate -->

This is useful when:

  • The symbol name is ambiguous
  • You need to reference a fully qualified name
  • You want to force a specific resolution

3. Fence Detection (DetectFence) — v1.1

CKB can extract symbol references from fenced code blocks using tree-sitter:

func example() {
    result := pkg.DoSomething()
    obj.Method()
}

Supported languages: Go, Python, JavaScript, TypeScript, TSX, Rust, Java, Kotlin

Notes:

  • Only qualified identifiers are extracted (e.g., pkg.Func, not x)
  • Lower confidence (0.7x multiplier) compared to backtick detection
  • Requires CGO for tree-sitter parsing

Resolution Process

When CKB finds a potential symbol reference, it attempts to resolve it:

  1. Exact Match: Try to find a symbol with an exact canonical name match
  2. Suffix Match: Look for symbols ending with the reference text
  3. Classification:
    • exact — Fully qualified match (confidence: 1.0)
    • suffix — Unique suffix match (confidence: 0.95)
    • ambiguous — Multiple candidates match
    • missing — No match found
    • ineligible — Single-segment name (requires directive)

Directives

Module Linking

Link a document to a module explicitly:

<!-- ckb:module internal/auth -->

This enables queries like ckb docs module internal/auth to find all documentation for a module.

Known Symbols (v1.1)

Allow single-segment symbol detection for specific names:

<!-- ckb:known_symbols Engine, Start, UserService -->

This bypasses the 2-segment requirement for the listed symbols. Multiple directives are cumulative within a document.

Staleness Detection

Documentation can become stale when:

  1. Symbol Deleted (missing_symbol) — The referenced symbol no longer exists
  2. Symbol Ambiguous (ambiguous_symbol) — The reference now matches multiple symbols
  3. Index Gap (index_incomplete) — The language isn't indexed at the current tier
  4. Symbol Renamed (symbol_renamed) — v1.1: The symbol was renamed or moved

Rename Detection (v1.1)

When a documented symbol is renamed, CKB can detect this via the alias chain:

$ ckb docs stale README.md
{
  "reports": [{
    "docPath": "README.md",
    "stale": [{
      "rawText": "`OldService.Method`",
      "line": 42,
      "reason": "symbol_renamed",
      "message": "Symbol was renamed",
      "suggestions": ["NewService.Method"],
      "newSymbolId": "ckb:repo:sym:abc123"
    }]
  }]
}

MCP Tools

indexDocs

Scan and index documentation for symbol references.

{
  "force": false  // Re-index all docs even if unchanged
}

getDocsForSymbol

Find all documents that reference a symbol.

{
  "symbol": "Engine.Start",
  "limit": 10
}

getSymbolsInDoc

List all symbol references in a document.

{
  "path": "README.md"
}

getDocsForModule

Find documents linked to a module via directives.

{
  "moduleId": "internal/query"
}

checkDocStaleness

Check a document for stale symbol references.

{
  "path": "README.md"
}

Or check all documents:

{
  "all": true
}

getDocCoverage

Get documentation coverage statistics.

{
  "exportedOnly": false,  // Only count exported symbols
  "topN": 10              // Number of top undocumented symbols
}

CI Integration

Coverage Threshold (v1.1)

Enforce minimum documentation coverage in CI:

# Fail if coverage drops below 80%
ckb docs coverage --fail-under=80

Exit codes:

  • 0 — Coverage meets or exceeds threshold
  • 1 — Coverage below threshold

Staleness Checks

Check for stale documentation in CI:

# Check all docs, fail if any are stale
ckb docs stale --all --format json | jq '.totalStale'

Configuration

Documentation indexing is configured in .ckb/config.json:

{
  "docs": {
    "paths": ["docs", "README.md", "ARCHITECTURE.md", "DESIGN.md", "CONTRIBUTING.md"],
    "include": ["*.md"],
    "exclude": ["node_modules", "vendor", ".git"]
  }
}

Best Practices

Writing Documentation

  1. Use qualified names: Write UserService.Authenticate instead of just Authenticate
  2. Use backticks consistently: Always wrap symbol references in backticks
  3. Add module directives: Link architectural docs to their modules
  4. Use known_symbols sparingly: Only for truly unique single-segment names

Maintaining Documentation

  1. Run staleness checks regularly: Add to CI pipeline
  2. Set coverage thresholds: Prevent documentation from falling behind
  3. Review rename suggestions: Update docs when symbols are renamed
  4. Check ambiguous references: Disambiguate with full paths or directives

Example Workflow

# 1. Index your codebase
ckb index

# 2. Index documentation
ckb docs index

# 3. Check for stale references
ckb docs stale --all

# 4. Find what docs mention a symbol you're changing
ckb docs symbol UserService.Authenticate

# 5. Update docs before merging
# ... fix stale references ...

# 6. Verify in CI
ckb docs coverage --fail-under=80

Limitations

  • Single-segment names: Engine alone won't be detected (use known_symbols directive)
  • Dynamic references: Computed symbol names can't be detected
  • Non-markdown: Only .md and .markdown files are scanned
  • Code blocks without language: Fence detection requires a language hint (go, python, etc.)
  • Complex expressions: Fence detection only extracts simple qualified names, not method chains

Changelog

v1.1 (December 2024)

  • CI Enforcement: --fail-under flag for coverage threshold
  • Rename Detection: Detect when documented symbols are renamed via alias chain
  • known_symbols Directive: Allow single-segment detection for listed symbols
  • Fence Symbol Scanning: Extract identifiers from fenced code blocks (8 languages)

v1.0 (December 2024)

  • Initial release with backtick and directive detection
  • Suffix-based resolution with confidence scoring
  • Staleness detection for missing/ambiguous references
  • MCP tools: indexDocs, getDocsForSymbol, checkDocStaleness, getDocCoverage