skogai-routing
SkogAI routing use when authoring, reading, scaffolding, validating, listing, or explaining SKOGAI.md/CLAUDE.md router files, xml-blocks, route XML tags, or @-link routing.
Files27
View on GitHubSKILL.mddash-skogai/tmp/routing/SKILL.md
GitHub<output>
- list_routers.py: !
${CLAUDE_SKILL_DIR}/scripts/list_routers.py - list_xml_tags.py: !
${CLAUDE_SKILL_DIR}/scripts/list_xml_tags.py
For how these !command``lines actually execute (permission gating viaallowed-tools, why ${CLAUDE_SKILL_DIR}matters, plugin cache gotchas, and
how subagents that preload this skill can answer with zero tool calls without
fabricating), seereferences/dynamic-output-blocks.md.
SkogAI Routing
A router document is YAML frontmatter plus one XML root block. In v1, type: router pairs with <routes>. CLAUDE.md and SKOGAI.md use the same document
shape at different levels of the routing chain.
Load references/router-file-convention.md when the task needs the exact v1
schema, examples, loading model, or boundary between implemented router behavior
and future document types. Load references/claude-md-routing-rules.md when
deciding whether a route should be an @-link or a plain path. Load
references/at-linking.md only for Claude Code @-link mechanics.
Reading Frontmatter
Use ${CLAUDE_SKILL_DIR}/scripts/parse-frontmatter.sh <file> [field] to extract
the YAML frontmatter block (or a single field from it) from a routing file —
adapted from plugin-dev's plugin-settings frontmatter parser.
Validating A Routing File
Use ${CLAUDE_SKILL_DIR}/scripts/validate_router.py <file...> to check one or more files against
schemas/router.schema.json: frontmatter parses as YAML, type equals
router, only the v1 frontmatter fields are present, and the body contains
exactly one attribute-free <routes> XML block whose nonblank lines are list
entries. Explicit targets are fail-closed: missing/malformed frontmatter,
another document type, extra fields, or an invalid body all exit nonzero. It's
a single uv run --script executable (schema path resolved relative to its own
location via Path(__file__)) — there's no separate shell wrapper, since a
wrapper would only exist to loop over args and resolve paths, both of which
Python already does natively.
Self-check, run live every time this skill loads (proof the validator and the bundled example still agree, not just a description of the command):
- Bundled example: !
${CLAUDE_SKILL_DIR}/scripts/validate_router.py ${CLAUDE_SKILL_DIR}/examples/SKOGAI.md.example
When the user asks to validate SKOGAI.md/CLAUDE.md routing files:
- Resolve targets from the user's request: a given file path, or if a
directory (or nothing) is given, use
list_routers.pyunder that directory (default: cwd) to discover router candidates. Complete when every intended target path is explicit. - Pass only those discovered candidates, or the user's explicit target paths, to the validator. Discovery skips non-router and unparseable Markdown; explicit validation fails either case.
- Run
${CLAUDE_SKILL_DIR}/scripts/validate_router.py <file...>. - Report PASS/FAIL per file. For any FAIL, quote the specific schema
error so the user knows exactly what to fix (e.g. missing
<routes>section,typenotrouter, missing frontmatter). Complete when every target has a PASS/FAIL line and every FAIL includes the validator reason. Don't auto-fix failures — report them and let the user or a follow-up edit fix the file.
Finding all router files in a project
Use ${CLAUDE_SKILL_DIR}/scripts/list_routers.py [root_dir] [-o output_file] to recursively scan
a project for router documents: it walks every *.md file under root_dir
(default: cwd; skips .git/node_modules), parses frontmatter, and prints
the relative path of each file where type: router. This is a cheap
frontmatter-only scan (no schema validation) — its job is discovery ("what
router files exist here"), not correctness ("are they valid"); pipe the
result into validate_router.py for that. Files with missing, malformed, or
non-mapping frontmatter are ignored by discovery rather than aborting the scan.
When the user asks to list/find/inventory routing files across a project:
- Resolve
root_dirfrom the user's request, else the current working directory (or${CLAUDE_PROJECT_DIR}if the user means "this whole project" specifically, since that's the substitution that resolves to the project root regardless of current subdirectory — requires Claude Code v2.1.196+). - Run
${CLAUDE_SKILL_DIR}/scripts/list_routers.py <root_dir>. If the user wants the list saved somewhere, pass-o <path>. If they want it saved but haven't named a path, default to a file under/tmp(e.g./tmp/routers-<root-dir-name>.txt) rather than writing into the project — this default is provisional until a real project-relative save location (e.g. a.claude/or.skogai/convention) has actually been used and confirmed, so don't upgrade it to a project path on your own judgment. - Optionally follow up with
${CLAUDE_SKILL_DIR}/scripts/validate_router.py <files...>on the discovered list if the user also wants validation, not just discovery. Complete when the router list has been returned or written to the requested output path.
Printing the XML tags in every router file
Use ${CLAUDE_SKILL_DIR}/scripts/list_xml_tags.py [root_dir] [-o output_file] — it does the same
router discovery as list_routers.py (frontmatter type: router, .git/
node_modules skipped) but prints, per file, the unique XML tag names found
in it: <relative-path>: <tag1> <tag2> ... (or (no xml tags)). This is the
automated form of "find the routers, then show me their tags" as a single
command instead of two manual steps — run this directly rather than chaining
list_routers.py output into something else by hand.
When the user asks what tags exist in the routing files (or wants an
overview of a project's <routes>-and-beyond structure):
- Run
${CLAUDE_SKILL_DIR}/scripts/list_xml_tags.py <root_dir>(root_dir: whatever the user pointed at, else cwd). - Report the per-file tag lines back to the user as-is. Same
/tmpdefault aslist_routers.pyif they want the output saved but haven't named a path — don't invent a project-relative location. Complete when every printed router line is preserved in the report or saved output.
Scaffolding a new routing file
When the user asks to add/set up a routing file in a repo:
- Resolve the target directory from the user's request, else the current
working directory. Confirm it looks like a repo root (has
.gitor the user already told you it is one). Complete when the target directory and repo-root evidence are known. - Check whether
SKOGAI.mdalready exists there. If it does, stop and tell the user — do not overwrite silently. - Read
examples/SKOGAI.md.example(relative to this skill's directory) as the template. Write a newSKOGAI.mdin the target directory with:type: routerin frontmatterpermalinkset from whatever the user specified, otherwise a reasonable slug derived from the repo/directory name (e.g.<repo-name>/claude)- an empty or minimal
<routes>block — do not invent route entries the user hasn't asked for
- Check the target's
CLAUDE.md:- If it doesn't exist, ask the user before creating one — a missing CLAUDE.md may be intentional.
- If it already has a
<routes>block containing an@SKOGAI.mdentry (in any form), leave it alone. - If it already has a
<routes>block without that entry, add- @SKOGAI.mdas a new line inside it. - If it has no
<routes>block at all, ask the user before restructuring an existing CLAUDE.md into router form — don't silently convert it.examples/CLAUDE.md.exampleshows the target shape for a fresh file.
- Run
scripts/validate_router.pyon each routing file created or edited. Report exactly what changed and whether validation passed; do not describe the scaffold as complete if validation fails. Complete when every created or edited routing file has a validation result.