agentleFS
jyjeannejyjeanne/dita-skills/generate-keyrefs/SKILL.md

generate-keyrefs

Skill2 starsChanged 6 months agoMITView on GitHub

Scans one or more DITA 1.3 topics and automatically generates keydef entries and keyref suggestions. Use this skill when you want to enforce reuse-first authoring, detect repeated inline text or repeated hrefs that should be centralised in the map, or migrate a set of topics to use keyrefs instead of hard-coded values. Returns ready-to-paste keydef XML plus a change list showing exactly which elements to update.

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    When --apply is used, the response also includes:

    line 90

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Overview

generate-keyrefs analyses a set of DITA topics and produces:

  1. keydefs — suggested <keydef> entries to add to your root ditamap
  2. changes — a per-file list of elements to replace with keyref= attributes
  3. keydef_block — a ready-to-paste XML snippet for your map
  4. --apply mode — rewrites files in place, adding keyref= attrs and removing hard-coded values

Candidate detection rules

CategoryElements scannedCondition
Text keys<ph>, <term>, <keyword>, <prodname>, <varname>, <wintitle>, <cmdname>, <option>, <parmname>, <apiname>, <filepath>, <userinput>, <systemoutput>Same text appears ≥ N times across all files
External URL keys<xref href="http…">, <link href="http…">Same URL appears ≥ N times
Image keys<image href="…">Same image path appears ≥ N times
Code ref keys<coderef href="…">Same path appears ≥ N times

Elements that already carry a keyref= attribute are skipped.


Usage

# Scan a directory, show suggestions (dry run)
python generate-keyrefs/scripts/generate_keyrefs.py topics/

# Raise the threshold — only suggest if text appears 3+ times
python generate-keyrefs/scripts/generate_keyrefs.py topics/ --min-occurrences 3

# Scan specific files
python generate-keyrefs/scripts/generate_keyrefs.py overview.dita install.dita reference.dita

# Save keydef XML to a file for pasting into your map
python generate-keyrefs/scripts/generate_keyrefs.py topics/ --keydef-output keydefs.xml

# Rewrite topics in place (adds keyref= attrs, removes old values)
python generate-keyrefs/scripts/generate_keyrefs.py topics/ --apply

Output schema

{
  "summary": {
    "files_scanned":      3,
    "keydefs_suggested":  4,
    "changes_suggested":  9
  },
  "keydefs": [
    {
      "key":         "acme-product",
      "type":        "text",
      "value":       "ACME Product",
      "occurrences": 6,
      "files":       ["topics/overview.dita", "topics/install.dita"]
    },
    {
      "key":         "ext-docs-acme-com-api",
      "type":        "href",
      "href":        "https://docs.acme.com/api",
      "scope":       "external",
      "occurrences": 3,
      "files":       ["topics/overview.dita"]
    }
  ],
  "changes": [
    {
      "file":        "topics/overview.dita",
      "element":     "ph",
      "change":      "add_keyref",
      "old_text":    "ACME Product",
      "new_keyref":  "acme-product",
      "description": "<ph>ACME Product</ph> → <ph keyref=\"acme-product\"/>"
    }
  ],
  "keydef_block": "<keydef key=\"acme-product\">\n  <topicmeta>…</topicmeta>\n</keydef>\n\n<keydef key=\"ext-docs-acme-com-api\" href=\"https://docs.acme.com/api\" scope=\"external\" format=\"html\"/>"
}

When --apply is used, the response also includes:

{
  "applied": {
    "topics/overview.dita": 3,
    "topics/install.dita": 2
  },
  "summary": {
    "files_rewritten": 2
  }
}

Keydef XML produced

Text key

<keydef key="acme-product">
  <topicmeta>
    <keywords>
      <keyword>ACME Product</keyword>
    </keywords>
  </topicmeta>
</keydef>

Usage in topic after --apply:

<!-- Before -->
<ph>ACME Product</ph>

<!-- After -->
<ph keyref="acme-product"/>

External URL key

<keydef key="ext-docs-acme-com-api"
        href="https://docs.acme.com/api"
        scope="external"
        format="html"/>

Usage in topic:

<!-- Before -->
<xref href="https://docs.acme.com/api">API docs</xref>

<!-- After -->
<xref keyref="ext-docs-acme-com-api">API docs</xref>

Image key

<keydef key="img-header-logo" href="images/header-logo.png" format="png"/>

Usage in topic:

<!-- Before -->
<image href="images/header-logo.png" alt="Logo"/>

<!-- After -->
<image keyref="img-header-logo" alt="Logo"/>

Integration into a map

Paste the keydef_block output (or the file written by --keydef-output) before your first <topicref>:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE map PUBLIC "-//OASIS//DTD DITA Map//EN" "map.dtd">
<map>
  <title>Product Guide</title>

  <!-- ── Key definitions ─────────────────────────────────── -->
  <keydef key="acme-product">
    <topicmeta>
      <keywords><keyword>ACME Product</keyword></keywords>
    </topicmeta>
  </keydef>
  <keydef key="ext-docs-acme-com-api"
          href="https://docs.acme.com/api"
          scope="external" format="html"/>

  <!-- ── Topics ──────────────────────────────────────────── -->
  <topicref href="topics/overview.dita"/>
  <topicref href="topics/install.dita"/>
</map>

Common pitfalls

PitfallCauseFix
Key name collisionTwo different values slug to the same keyScript auto-appends -2, -3 suffixes; review and rename if needed
--apply breaks round-tripET serialisation drops CDATA / processing instructionsBack up topics before running --apply; check git diff
Short text over-matchedSingle letters or numbers meet the thresholdRaise --min-occurrences or post-filter the change list
Scope wrong for local imagesImage path treated as externalScript detects http:// prefix; local paths always get format=<ext>
keyref resolution at build timeKeys must be defined before first reference in map orderPlace all <keydef> elements at the top of the map

See also

  • validate-ditamap — validates that all keyrefs in a map resolve to defined keys
  • validate-dita-topic — catches malformed keyref attributes in topics
  • dita-best-practices — flags topics that have hard-coded values instead of keyrefs
  • refactor-dita-content — broader refactoring including conref extraction

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.