Skills

Skill hierarchy, storage roots, sync and audit

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:

  • name must equal the directory name. Loaders resolve a skill by its directory (Zed) or by its declared name (Cursor). A skill at inqua/pipeline/upload/ declaring name: inqua-upload is 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-level SKILL.md is a gap — its skills are invisible to every agent. ae-platform skills validate lists 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 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 copy

sync-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 section

The 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, exit

Catalog

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/skills and 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())
"

Authoring a skill

  1. Create platform/registry/skills/<name>/SKILL.md (directory name == name).
  2. Frontmatter: name plus a description that states scope and routing triggers (USE FOR: / DO NOT USE FOR:), matching the style of the existing skills.
  3. Run ae-platform index so the catalog, hub and MCP see it.
  4. Run ae-platform sync-cursor --commit and ae-platform sync-agents --commit to publish it to the agent surfaces.
  5. Run ae-platform skills validate to confirm it is clean.

For a skill owned by another project, keep the file in that project’s root and add a Cursor symlink instead — do not fork it into the registry.

Use the _cursor/create-skill skill for the authoring workflow itself.