Skills
Skills are declarative Markdown files (SKILL.md) that give AI agents (Cursor, Zed) actionable, up-to-date knowledge about tools, workflows, and conventions. platform/registry/skills/ is the single source of truth for platform skills; every mirror is either a symlink into it or a materialised copy of it. Skills owned by another project (PDAI, LWgrammar, Lektorat) stay in that project’s root and are reached with symlinks — they are never forked into the registry.
Hierarchy
platform/registry/skills/
├── ai-platform-registry/ # Platform registry (ports, URLs, catalog)
├── ai-scholar-process/ # PDAI OCR pipeline
├── server-port-registry/ # Port assignment rules
├── inqua/ # INQUA pipeline (group with router SKILL.md)
│ ├── SKILL.md
│ ├── learning/ # Lernzyklus, Lernbericht, Komparatistik, ...
│ ├── pipeline/ # Upload, health-check, orchestrator
│ ├── reporting/ # Typst, improvement-report, ...
│ └── platform/ # AI Studio, data-store, subagents
├── pipeline/ # PDAI pipeline group (no top-level SKILL.md)
│ └── source-harvest/
├── _azure/ # Vendored Azure skills (no top-level SKILL.md)
│ └── microsoft-foundry/
└── _cursor/ # Cursor IDE skills (create-skill, create-rule, ...)
Two conventions matter:
namemust equal the directory name. Loaders resolve a skill by its directory (Zed) or by its declaredname(Cursor). A skill atinqua/pipeline/upload/declaringname: inqua-uploadis ambiguous and is reported by the audit._-prefixed groups are vendored (imported third-party or parked) and are deliberately not mirrored:_azure/,_cursor/. A group without the prefix and without a top-levelSKILL.mdis a gap — its skills are invisible to every agent.ae-platform skills validatelists both cases separately.
Skills that moved into a nested group keep a thin redirect stub at the old flat location (inqua-upload → inqua/pipeline/upload). The stub carries the authoritative description so request matching still works, plus a pointer to the canonical file — see inqua-upload/SKILL.md as the reference shape.
Storage roots
| Root | Owner | Mechanism |
|---|---|---|
platform/registry/skills/ |
humans | source of truth for platform skills |
~/.cursor/skills/ |
ae-platform sync-cursor |
symlinks into the registry |
~/.agents/skills/ (Zed global) |
ae-platform sync-agents |
copies, or a relative symlink into the umbrella on umbrella machines (see below) |
<umbrella>/.agents/skills/ (Zed project) |
ae-platform sync-agents |
copies |
pdai/skills/, LWgrammar/skills/, publication/ai-lektorat/skills/ |
those projects | owner roots; Cursor symlinks point into them |
privat/*/.cursor/skills/ |
those projects | independent lifecycle |
Owner-root skills appear in ~/.cursor/skills/ as symlinks to the owning tree (for example ai-query-monitor → pdai/skills/query/monitor, lektorat → publication/ai-lektorat/skills, lwgrammar-consult → LWgrammar/skills/lwgrammar-consult). The audit reports these as linked/external, not as drift.
Both .agents roots are Syncthing sendreceive folders, and ae-platform doctor flags stray symlinks under the umbrella. Copies — not symlinks — are therefore used for the Zed roots on machines that do not carry the umbrella: an absolute symlink would carry a machine-specific path (/Users/friedrichstr/ai-mac-studio/...) and dangle on any satellite that does not mount the registry at that path. Machines that do carry the umbrella use a single shared tree instead (next section).
Project skills: privatkanzlei
privat/privatkanzlei/.cursor/skills/ holds the skills that only make sense inside the Kanzlei workspace (mail, correspondence, agendas, Firma). They are loaded by Cursor when that folder is the workspace and are not mirrored into the registry. Cross-case skills that the Kanzlei also uses stay in the registry and are not duplicated here: mail-search and genius-scan-agenda-rente live only in platform/registry/skills/ (a stale project copy of mail-search was removed on 23.09.2026).
| Area | Skills |
|---|---|
mail-service (IMAP drafts, send), open-reply-mail, smail-processing |
|
| Korrespondenz | korrespondenz-standup, korrespondenz-sofortsync, korrespondenz-ablage, korrespondenz-ocr |
| Agenda | agenda-abgleich, agenda-kommunikation, schreiben-anlagenkonvolut, etiketten-druck |
| Firma / Finanzen | firma-*, rechnungen, reisekosten-erstattung |
Tools behind these skills come from the korrespondenz MCP server (venv/bin/python3 -m korrespondenz --stdio, cwd = privatkanzlei root), registered in ~/.cursor/mcp.json, VS Code Insiders and code-server User/mcp.json, the workspace .vscode/mcp.json and Zed context_servers. Editors without Cursor skills (Claude Code, Copilot, Zed) reach the same instructions through the pointer files CLAUDE.md and .github/copilot-instructions.md in the privatkanzlei root.
PDAI skill: pdai-collection-intake
pdai/skills/pipeline/pdai-collection-intake/ introduces a new PDAI collection from an import folder (PDFs, images, metadata files, databases) and makes it a famulus reference. It is an owner-root skill of pdai/skills/ and is executable as Partitur pdai-collection-intake (goal path pipeline/intake/collection, one Setting per collection, id intake-<collection>; reference Setting intake-hartmann).
| # | Stage | Tool | Gate |
|---|---|---|---|
| 1 | inventory | famulus-reference inventory |
every file listed with sha256 |
| 2 | profile | document-profile, ai-scholar classify |
document type, scripts, languages named with evidence |
| 3 | dtd-draft | schema-derive, page.dtd v4.0 |
wrapper DTD compiles (xmllint) |
| 4 | segment-plan | ai-scholar segment |
every DTD object element mapped to a seg_type and fr: address |
| 5 | review | docs/dtd_review.md, 5-page pilot, pdai-audit |
owner approval recorded |
| 6 | build | ai-scholar init/fastapple, bib-generate, pdai-complete |
pdai-audit validity fail = 0 |
| 7 | famulus-db | famulus-reference build |
no duplicate fr_id, no orphan page |
| 8 | lake-export | famulus-reference export (mac-studio) |
snapshot id; fr_describe_collection answers |
| Mirror | Location |
|---|---|
| Registry | platform/registry/skills/pdai-collection-intake/SKILL.md |
| Zed project copy | .agents/skills/ |
| Claude Code | symlink ~/.claude/skills/pdai-collection-intake → the skill folder (on openscience; on mac-studio created by pdai/famulus-reference/deploy/install_studio.sh) |
Instructions: agents/infrastructure/ai-instructions/pdai/intake/*.j2. Related skills: pdai-cure (repair an existing collection), pdai-collection-update (re-scan one document).
Sync
ae-platform sync-cursor # dry-run: symlinks + ~/.cursor/mcp.json
ae-platform sync-cursor --commit # apply
ae-platform sync-cursor --commit --force # also replace real dirs (archived first)
ae-platform sync-agents # dry-run: refresh skills already present
ae-platform sync-agents --all --commit # all registry skills
ae-platform sync-agents --skill ai-scholar-process --commit
ae-platform sync-agents --mode link --commit # symlink instead of copysync-agents never deletes local-only files: a hand-edited skill is reported, not overwritten. Divergent entries are copied to platform/archive/skills-sync-<date>/ before being replaced by --force.
Audit
ae-platform skills validate # full report (exit 1 on broken/divergent)
ae-platform skills validate --json # machine-readable
ae-platform skills validate --root cursor
ae-platform doctor # includes a Skill Tree sectionThe audit checks every SKILL.md in the registry and in the owner roots for parsable frontmatter, name, description, and name-vs-directory agreement, then classifies each entry of every consumer root as linked, broken, duplicate, divergent or unregistered. Exit code 1 is reserved for structural problems (broken or divergent links, unparsable frontmatter); advisory items (unregistered dirs, unmirrored groups, owner-root backlogs) are warnings.
Scheduled run
com.ai-platform.skills-audit rebuilds the catalog and runs the audit nightly at 04:20, logging to platform/logs/skills-audit.{out,err}.log. Source of truth: platform/launchd/com.ai-platform.skills-audit.plist + platform/scripts/skills-audit.sh.
launchctl kickstart -k gui/$(id -u)/com.ai-platform.skills-audit # run now
launchctl print gui/$(id -u)/com.ai-platform.skills-audit # state, runs, exitCatalog
ae-platform index rebuilds platform/catalog.duckdb; the skills table holds name, path, description, skill_file, tags (routing keywords taken from frontmatter when/keywords, else the description’s USE FOR: or Use when clause).
Consumers of that table:
- Hub at the hub —
/api/skillsand the catalog page - MCP server
ai-platform-mcp—list_skills(query),get_skill(name) - These docs —
platform/docs/skills.qmd
python3.14 -c "
import duckdb
con = duckdb.connect('platform/catalog.duckdb', read_only=True)
print(con.execute('SELECT name, description FROM skills ORDER BY name').df())
"