/index — Knowledge Index Builder
Scan all promoted knowledge files, normalize tags, detect issues, and regenerate {knowledge_folder}/index.md.
Step 0: Resolve Config
Read ~/.claude/aria-knowledge.local.md and extract:
knowledge_folder— base path for all operationsfreeform_promotion_threshold— minimum file count before suggesting promotion (default: 3)staleness_threshold_months— months before a file is flagged stale (default: 6)projects_enabled— defaultfalse; controls whether project tier is scanned and indexedprojects_list— default empty; comma-separatedtag:pathpairs; only relevant ifprojects_enabled: trueprojects_promotion_threshold— default2; minimum projects sharing a similar pattern to surface as a cross-project promotion candidateprojects_shared_knowledge— default empty; comma-separated list of project tags enabled for shared knowledge. When non-empty, scan each listed project's_project-knowledge/folder for team-shared knowledge. Tags not in this list are skipped (their_project-knowledge/folders, if any exist on disk, are NOT indexed).
If the config file doesn't exist, stop: "aria-knowledge is not configured. Run /setup to get started."
Step 1: Scan Promoted Folders
Scan these directories for .md files (excluding directory README stubs that only contain a few lines of boilerplate):
{knowledge_folder}/approaches/{knowledge_folder}/decisions/{knowledge_folder}/guides/(recursive — includes subdirectories){knowledge_folder}/references/(recursive — includessources/and other subdirectories)
Do NOT scan: archive/, intake/, rules/, top-level logs/*.md (audit-log files like config-audit-log.md, knowledge-audit-log.md, hook-debug.log), or root-level files (README.md, LOCAL.md, OVERVIEW.md, index.md).
Carve-out for review reports: the two subfolders logs/prospect/ and logs/retrospect/ ARE scanned as a separate "reviews tier" — see the dedicated sub-step below. Review reports use the same frontmatter scanning convention as cross-project files (tags, Last updated, first heading).
For each .md file found:
- Read the file
- Extract YAML frontmatter (content between
---markers at the top of the file) - From frontmatter, extract:
tags:— array of tags (e.g.,tags: [api, pagination, django]). If missing, record as untagged.Last updated:— date string (YYYY-MM-DD). If missing, record as unknown.semantic-hints:— array of free-form phrases (e.g.,semantic-hints: [cursor pagination, keyset pagination]). Optional; if missing, treat as empty list. Added 2.16.0.- Extract the first
#heading as the file's description - Store:
{path, tags[], hints[], description, last_updated, source: "cross-project"}
Report: "Scanned N files in approaches/, decisions/, guides/, references/."
Reviews tier scan (always run if either review subfolder exists)
After the cross-project scan, scan logs/prospect/ and logs/retrospect/ for review reports written by the /prospect and /retrospect skills.
For each .md file found in either subfolder:
- Read the file
- Extract YAML frontmatter — review reports have a richer schema than cross-project files. Pull:
tags:— array of tags. Always includesprospectorretrospectplus the scope keyword. If missing (legacy reports written before the structured-frontmatter format), record as untagged and emit a soft warning (one-line) suggesting the file be re-run or hand-tagged.Last updated:— fall back todate:ifLast updated:is absent (review reports usedate:for the report-creation date).type:—prospectorretrospect. Used to bucket the file under "Retrospects" or "Prospects" in the## Review Indexsection ofindex.md(see Step 9).scope:— the scope keyword (e.g.,release,deployment,commit,plan).tickets:— for cross-reference enrichment (consumed by/context).- Extract the first
#heading as the file's description (typically "/prospect — <goal>" or "/retrospect — <goal>"). - Store:
{path, tags[], description, last_updated, source: "review", review_type: <prospect|retrospect>, scope: <keyword>, tickets: [...]}
Report: "Scanned R review reports across logs/prospect/ and logs/retrospect/ (P prospect, Q retrospect)."
If neither subfolder exists yet on disk, skip this sub-step silently (first run before any /prospect or /retrospect has been invoked).
Project tier scan (only if projects_enabled: true and projects_list is non-empty)
After the cross-project scan, scan the project tier:
For each tag:path pair in projects_list:
- Glob
{knowledge_folder}/projects/{tag}/**/*.mdrecursively - Exclude
projects/{tag}/README.md(per-project navigation, not knowledge content) - Exclude
projects/README.md(the projects/ tier README, plugin-managed) - For each file found, perform the same frontmatter extraction as above.
- Path-derived tag union (Decision #9): automatically add
{tag}to the file's tag set even if not in YAML frontmatter. The union of YAML tags + path tag is what gets indexed. This means project files don't have to manually include the project tag in their frontmatter. - Store:
{path, tags[], description, last_updated, source: "project-specific", project: tag}
Report: "Scanned M files across N project subdirectories: [project tags]."
If projects_enabled: false or projects_list is empty, skip this sub-step entirely. Project tier files (if any exist on disk) won't be indexed.
Team-shared scan (only if projects_shared_knowledge list is non-empty)
After the project tier scan, scan each enabled project's _project-knowledge/ folder. Only projects whose tags appear in projects_shared_knowledge are scanned — non-listed projects are skipped, even if their _project-knowledge/ folders exist on disk.
For each tag in projects_shared_knowledge (parsed as comma-separated list):
- Resolve the project root: look up the tag in
projects_listto get its path, then resolve to~/Projects/<path>. If the tag is not present inprojects_list, log a warning and skip (config inconsistency —/setupvalidation should catch this, but defensive). - Determine scan locations based on whether the tag has a
projects_groupsentry (multi-repo project): - Single-repo project (no
projects_groups[tag]): scan<project-root>/_project-knowledge/directly. - Multi-repo project (
projects_groups[tag]is set): the project-root is a container, not a repo. Iterate the role:sub-repo pairs inprojects_groups[tag](preserving declaration order), and for EACH sub-repo, scan<project-root>/<sub-repo>/_project-knowledge/. Skip sub-repos whose path doesn't exist on disk (sub-repo not yet cloned). - For each scan location determined in step 2, probe for
_project-knowledge/. If the folder doesn't exist, skip that location (no team-shared knowledge yet there). Continue to next location (don't bail on the whole tag — sibling sub-repos may have content). - Glob
<scan-location>/_project-knowledge/**/*.mdrecursively. - Exclude
<scan-location>/_project-knowledge/README.md(auto-generated convention explainer, not knowledge content). - For each file found, perform frontmatter extraction as in the cross-project scan above.
- Path-derived metadata:
- If the file path is at
<scan-location>/_project-knowledge/*.md(top level), categorize asteam-sharedwithproject: <tag>(always the parent project tag fromprojects_shared_knowledge, NOT the sub-repo name — sub-repo identity is captured in the absolute path stored in step 9). - If the file path is under
<scan-location>/_project-knowledge/cross/*.md, categorize asteam-shared-crosswithproject: cross. - The path-derived project tag is added to the file's tag set even if not in YAML frontmatter (same Decision #9 pattern as project tier).
- **IDEAS