Enrich
AI maintainer team for Open Data Discovery — coordinates audit, gap-closing, and sustainable maintenance across ODD repositories using navigation indexes, coverage-tracked scanners, and structured work items.
npx -y skills add opendatadiscovery/odd-team --skill enrichAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Run the file-analyser subagent against one or more substrate nodes to produce per-node semantic enrichment sidecars. Resolves a path / node-id / batch spec to substrate nodes; spawns file-analyser per node; validates the resulting sidecar against the schema; updates the manifest's `enrichment` block.
SKILL.md
10.6 KB, ~2.8k tokens by cl100k_base, as published. Nobody here has run it
Enrich an ontology node (DOC-164 slice 5+)
Drive the agentic-code-ontology pipeline for one or more substrate nodes. Each invocation produces (or refreshes) Markdown sidecars at lineage/{repo}/understanding/{slug}.md, written by the file-analyser subagent with the live-URL-only doc rule and Gate 9 code-anchor mandate.
This skill is the maintainer-facing entry point for the per-node enrichment layer per adrs/drafts/agentic-code-ontology.md revision 2.
Prerequisite
The substrate scaffold (DOC-164 slices 1-4) must have run against the target repo. lineage/{repo}/nodes.jsonl must exist. If it doesn't, run /scan scanners/code-lineage/{axis}.md first or invoke the substrate's lineage-extractor scan {repo} --full.
Argument forms
| Form | Behaviour |
|---|---|
/enrich <path> | Single-file enrichment. Resolves <path> (relative to a repo) to its substrate node(s) and enriches each. If the path matches multiple nodes (e.g. a controller file with multiple methods), enrich the file-level node first, then the maintainer can drill into method nodes via /enrich --node <id>. |
/enrich --node <node-id> | Single-node enrichment by node ID (verbatim from nodes.jsonl's id field). |
/enrich --touched | Per-PR incremental. Reads lineage/{repo}/manifest.yaml's enrichment.last_enriched_commit; computes git diff against repo HEAD; enriches every node whose source file appears in the diff (1-hop fanout NOT YET — slice 5 is single-file granularity). |
/enrich --batch <axis> | Backfill mode. Picks the next N (default 5) unenriched-or-stale nodes from a given axis (ui_shell, ui_routes, controllers, openapi_tags, config_prefixes). Useful for working through the backlog one axis at a time. |
/enrich --max-nodes N | Cap how many enrichments this session runs. Default 5 (fits comfortably in a session's context budget; tune empirically). Caps any of the above forms. |
Protocol
1. Orient
Read these (skip if already loaded this session):
CLAUDE.md— the workspace's quality baradrs/drafts/agentic-code-ontology.md— the layered ADR + the per-node sidecar schema.claude/agents/file-analyser.md— the subagent system prompt you'll invoke (so you know what input shape it expects)
2. Resolve the worklist
Build a list of (node_id, path, kind, axis) tuples for this invocation:
- For
<path>form:jq -c 'select(.path == "<path>" or (.path | startswith("<path>:")))' lineage/{repo}/nodes.jsonl. Pick the file-level match first; if multiple symbol-level nodes also match, list them but don't enrich them this invocation (one node at a time). - For
--node <id>:jq -c 'select(.id == "<id>")' lineage/{repo}/nodes.jsonl. Exactly one match expected; error if 0 or >1. - For
--touched: readlineage/{repo}/manifest.yaml'senrichment.last_enriched_commit(orlast_scan_commitif no enrichment block yet).git -C ../{repo} diff --name-only <commit>..HEAD→ list of touched files. For each touched file,jqfor nodes whosepathstarts with that file. Cap at--max-nodes. - For
--batch <axis>:jq -c 'select(.axis == "<axis>")' lineage/{repo}/nodes.jsonl→ all nodes; filter out those with an existinglineage/{repo}/understanding/{slug}.mdwhoseenriched_at_commitmatches current HEAD; pick the first--max-nodes.
If the worklist is empty, report "Nothing to enrich (all nodes current)" and exit.
3. Resolve the sidecar slug for each node
Slug rule (matches the ADR): node_id.replace(' ', '__').replace('/', '_').replace(':', '__').replace('.', '_'). Filesystem-safe, reversible, greppable.
Sidecar path: lineage/{repo}/understanding/{slug}.md.
4. Resolve scaffold edges per node (1-hop)
For each node in the worklist, read lineage/{repo}/edges.jsonl and collect:
imports: edges where this node issrcand type=importsimported-by: edges where this node isdstand type=importsexposes: src→dst with type=exposesconfigures: src→dst with type=configuresmounts: src→dst with type=mounts
This goes into the file-analyser's prompt as SCAFFOLD_EDGES.
4.5. Cache check (slice 6+)
Before spawning file-analyser for a node, check whether the sidecar is already current:
- If
lineage/{repo}/understanding/{slug}.mddoes NOT exist → CACHE MISS, proceed to spawn. - If the sidecar exists, parse its frontmatter:
enriched_at_commit— substrate commit at which the sidecar was authoredprompt_version— the file-analyser prompt version that authored it- (planned:
extracted_at_commit,model,scaffold_hashfor finer cache keys)
- Compare to the current substrate state (manifest's
last_scan_commit) AND the current file-analyser prompt version (read the frontmatter of.claude/agents/file-analyser.md— typicallyfile-analyser/0.1.0for slice 5/6). - Skip the spawn IF:
enriched_at_commit == last_scan_commit(substrate hasn't moved)prompt_version == current file-analyser version(prompt unchanged)- The node's source file hasn't changed since
enriched_at_commit(usegit -C ../{repo} log --oneline <enriched_at_commit>..HEAD -- <source_path>— empty output = unchanged)
- Force re-enrichment when the maintainer passes
--no-cacheor--force. Default is cache-on; this is the cheap/fast path.
Cache hits are reported as <node-id>: cached (no change since <commit>). Cache misses fall through to the spawn step.
The cache invariant per the ADR: an enrichment is reused iff (node_id, scaffold_hash_of_file, prompt_version, model) matches. MVP slice-6 collapses this to (node_id, source_unchanged_since_enriched_at_commit, prompt_version) — the source-unchanged check is a proxy for scaffold_hash. Future slices may add explicit content-hash keys if false-cache-misses surface.
5. Spawn the file-analyser per cache-missed node
Invoke the file-analyser subagent via the Agent tool, one node at a time (parallel-spawn is fine for independent nodes — they don't share state). Construct the prompt as:
NODE_ID: <id>
NODE_KIND: <kind>
AXIS: <axis>
PATH: <path>
REPO: <repo>
REPO_ROOT_ABS: <absolute, e.g. /home/.../work/odd/{repo}>
SCAFFOLD_EDGES:
imports: [...]
imported-by: [...]
exposes: [...]
configures: [...]
mounts: [...]
NODE_METADATA: <verbatim from nodes.jsonl's metadata block>
SIDECAR_TARGET: <absolute path>
WORKSPACE_ROOT_ABS: <absolute, e.g. /home/.../work/odd/odd-team>
EXISTING_SIDECAR: <if a sidecar exists, the verbatim content; else "(none)">
The subagent's tool surface is fixed by the .claude/agents/file-analyser.md frontmatter (Read, Grep, Glob, WebFetch, Write). It writes the sidecar via Write to SIDECAR_TARGET and replies with Wrote: <path> + Confidence: ....
6. Validate the resulting sidecar
For each sidecar produced:
- Run the validator:
python -m lineage_extractor.cli validate-sidecar <sidecar-path>(Bash). The validator parses YAML frontmatter + named Markdown sections and verifies required fields are present. - If validation fails, log the failure to
lineage/{repo}/enrichment.logand surface to the maintainer. Do NOT auto-retry in slice 5 — single-shot per invocation; the maintainer iterates the prompt if quality is wrong.
7. Update the manifest
After all nodes in the worklist complete (success or failure):
- Read
lineage/{repo}/manifest.yaml. - Add or update the
enrichmentblock:schema_version: 0.1.0subagent_versions.file-analyser: file-analyser/0.1.0last_enriched_commit: <repo's HEAD commit>(only advance if every node in the worklist succeeded)enriched_node_count: <count of unique sidecars under understanding/>total_node_count: <count of unique node IDs in nodes.jsonl>enrichment_coverage: <pct>last_session_id: <Claude Code session id, if available; else timestamp>
- Append to
lineage/{repo}/enrichment.log: one line per node —<timestamp>\t<session_id>\t<node_id>\t<sidecar_path>\t<confidence>\t<doc_urls_fetched>.
8. Report
Concise output:
- Worklist size: N
- Successful enrichments: M
- Failed enrichments: K (list them with the validator's reason)
- Coverage now: X% (Y/Z nodes)
- Suggested next:
/enrich --batch <axis>for the next N unenriched nodes, or/enrich <specific-path>for ad-hoc work.
Rules
- Live-URL-only doc rule is non-negotiable. If a sidecar has a
documents.declared_docsentry withoutlast_verified_status, validation fails. The file-analyser prompt enforces this; the validator double-checks. - One sidecar per node. Don't enrich neighbour nodes in the same invocation — they get their own
/enrichcall when the maintainer chooses. - Don't auto-fix the source code. The file-analyser's tool surface excludes
Edit. If enrichment surfaces a bug, log it as a backlog item viaplaybooks/follow-up-on-disk.md; don't patch the code. - Preserve
## Maintainer notes. If a sidecar already exists, pass its content asEXISTING_SIDECARso the file-analyser preserves the maintainer notes block. - Skip auto-advance if any node failed.
last_enriched_commitonly advances when every node in the worklist passed validation. Partial success leaves the mark where it was. - Cap at
--max-nodes. Token budget per session is the constraint. Default 5; the maintainer can raise if files are small.
Failure modes to surface (not auto-fix)
- Validator rejects sidecar (missing required field, fabricated file:line, banned phrase) → log + report; maintainer iterates the prompt.
- WebFetch fails (404 doc URL) → the sidecar records
last_verified_status: 404; the doc-gap-finder reducer (slice 7) will surface these as DOC-NNN candidates. - Source file hash differs from substrate's
nodes.jsonl(substrate is stale relative to current HEAD) → report; recommendlineage-extractor scan {repo} --fullfirst.
Cross-references
- Subagent:
.claude/agents/file-analyser.md - Validator:
lineage/_extractor/src/lineage_extractor/validators.py - ADR:
adrs/drafts/agentic-code-ontology.mdrevision 2 - Substrate ADR:
adrs/drafts/code-lineage-substrate.mdrevision 2 - Probe set:
lineage/PROBES.md(extended for semantic claims peradrs/drafts/research/agentic-code-ontology/PROBES.md)
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.