# infrastructure/skills
## Purpose
Enumerate `SKILL.md` agent descriptors under configurable repository roots, parse YAML frontmatter, and sync a JSON manifest for Cursor and other tools.
## Module layout
```mermaid
flowchart TB
SK[infrastructure/skills/]
SK --> INIT[__init__.py
Public re-exports]
SK --> MAIN[__main__.py
python -m infrastructure.skills]
SK --> CLI[cli.py
write · check · check-contracts · list-json]
SK --> DISC[discovery.py
discover_skills · manifest helpers]
SK --> CONTRACTS[contracts.py
docs/prompts metadata contracts]
SK --> CHK[check_all_exports.py
AST audit: re-exporting modules must declare __all__]
SK --> DOCS[SKILL.md · README.md · AGENTS.md]
classDef d fill:#0f172a,stroke:#0f172a,color:#fff
classDef code fill:#1e3a8a,stroke:#0f172a,color:#fff
classDef doc fill:#0f766e,stroke:#0f172a,color:#fff
class SK d
class INIT,MAIN,CLI,DISC,CONTRACTS,CHK code
class DOCS doc
```
## Public API (`discovery.py`)
- `DEFAULT_SKILL_SEARCH_ROOTS` — `("infrastructure", "scripts", "projects/templates", "fonds/templates", "rules/templates", "tools/templates", "docs/prompts", ".agents/skills", ".cursor/skills")` relative to repo root; repository-scoped and public-exemplar `.agents/skills/*/SKILL.md` descriptors are intentionally included
- `SkillDescriptor` — `absolute_path`, `relative_path`, `name`, `description`, `frontmatter`; properties `path_posix`, `cursor_at`
- `split_yaml_frontmatter(source: str) -> tuple[dict | None, str]`
- `load_skill_descriptor(skill_path: Path, repo_root: Path) -> SkillDescriptor`
- `iter_skill_paths(repo_root: Path, roots: Sequence[str]) -> Iterator[Path]` — paths under `projects/templates/` are limited to `PUBLIC_PROJECT_NAMES`, so ignored local templates cannot affect public manifests or duplicate-name checks
- `discover_skills(repo_root, *, search_roots=None) -> list[SkillDescriptor]` — sorted by path; raises `ValueError` on duplicate `name`
- `build_manifest_payload(skills) -> dict`
- `write_skill_manifest(repo_root, output_path=None, *, search_roots=None) -> Path` — default `.cursor/skill_manifest.json`
- `load_manifest(manifest_path) -> dict`
- `manifest_matches_discovery(repo_root, manifest_path, *, search_roots=None) -> tuple[bool, str]`
- `manifest_skill_dicts_for_prompt(skills) -> list[dict]`
- `skill_descriptors_as_json_serializable(skills) -> list[dict]`
## Public API (`contracts.py`)
- `iter_contract_skill_paths(repo_root) -> Iterable[Path]` — yields `docs/prompts/**/SKILL.md`
- `validate_skill_contract_file(skill_path) -> list[str]` — validates one workflow skill metadata contract
- `check_skill_contracts(repo_root) -> list[str]` — validates all workflow skill contracts
## Public API (`operation_registry.py`)
Static (AST-only; never imports the target modules) catalog of agent-invocable `python -m` CLIs under `infrastructure/`, mirroring the `discovery.py` contract for *operations*.
- `OperationDescriptor` — one invocable CLI: `module`, `invocation`, `source_path`, `purpose`, `subcommands`, `exports`, `effect`
- `SubcommandInfo` — one statically-parsed `add_parser(name, help=...)` subcommand
- `MUTATING_OPERATIONS` — allowlist of dotted modules whose CLIs mutate external state / incur cost (everything else is `read_only`)
- `discover_operations(repo_root, *, search_roots=None) -> list[OperationDescriptor]`
- `build_operations_payload(ops) -> dict` / `operation_descriptors_as_json_serializable(ops) -> list[dict]`
- `write_operations_manifest(repo_root, output_path=None, *, search_roots=None) -> Path` — default `.cursor/operations_manifest.json`
- `load_operations_manifest(manifest_path) -> dict`
- `operations_manifest_matches_discovery(repo_root, manifest_path, *, search_roots=None) -> tuple[bool, str]`
## Cross-runtime sync (`runtime_sync.py`)
- `validate_vendored_source(repo_root)` — verifies the pinned lock, exact tree
digest, inventory, and skill frontmatter without touching user state.
- `runtime_status(repo_root, home)` — audits the revisioned shared store and
Codex (`~/.agents/skills`), Claude Code, and Hermes links.
- `install_runtime_skills(repo_root, home)` — stages the reviewed tree under
`~/.local/share`, backs up same-name runtime paths under `~/.local/state`,
then creates managed links and a receipt. It never executes skill scripts.
- CLI: `python -m infrastructure.skills runtime-status|runtime-install`; the
lower-level `python -m infrastructure.skills.runtime_sync status|install`
form also supports `--json`. The operation registry classifies
`infrastructure.skills` as `mutating` because its install/write subcommands
update repository or user-level state.
## CLI (`cli.py`)
- `main(argv=None) -> int`
- Subcommands: `list-json`, `write` (`--output`), `write-index` (`--output`), `check` (`--manifest`), `check-contracts`, `check-all-exports`
- Shared flags on each subcommand (after the verb): `--repo-root`, `--roots DIR [DIR ...]`
- Example: `uv run python -m infrastructure.skills write --roots infrastructure docs/prompts .cursor/skills`
## Tests
`tests/infra_tests/skills/test_skill_discovery.py`