Files
ue-toolchain/docs/architecture/decisions/0002-harness-neutral-skill-bundle.md
T
ue-toolchain dab3f35079 feat(skills): ship ue-design-skills bundle, licensing and delivery gate
Phase 0 of the handoff plan, as a marketplace rather than a flat skills/
directory. Content moved out of the LyraResearch archive and depersonalised:
addresses stay in the archive, recipes ship.

- plugins/ue-design-skills: 17 skills, 232 failure-mode entries, each with the
  six required fields; catalog.json as the harness-neutral source of truth and
  .claude-plugin/ as one adapter over it.
- _gate: 16 rules, one poisoned fixture per rule, plus surface coverage so a
  declared file cannot silently miss the line rules.
- ADR-0002 (harness-neutral bundle behind a marketplace) and ADR-0003 (split
  licensing: CC BY-ND 4.0 prose, Apache-2.0 code and metadata).
- LICENSE files at both levels, CONTRIBUTING.md, docs/licensing-options.md as
  the material the licence decision grew from.

Verified: gate.py 0 violations; test_gate.py 16/16 rules redden on their
fixtures with a clean baseline and 2 root files reaching the line rules.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 23:48:55 +07:00

6.6 KiB

status, date, deciders, consulted, informed
status date deciders consulted informed
accepted 2026-09-02 project owner LyraResearch depersonalization pilot future contributors

Harness-neutral skill bundle behind a marketplace

Context and Problem Statement

The skills/ component of ue-toolchain is not speculative work: it already exists as 18 skill bundles in the LyraResearch archive, grown from a line-by-line audit of a first-party UE 5.6 sample. What is new is turning them into something a stranger can install.

Two forces pull against each other.

Distribution wants a vendor format. Agent runners discover plugins through their own manifest, in their own directory, with their own rules — component directories must sit at the plugin root, and paths outside it are rejected. Writing to one such format is the only way to get a one-command install today.

The product must outlive that vendor. The owner's constraint is explicit: "не привязывайся к клоду... инструмент должен нормально работать с любым харнесом или агентом." A skill that says "run this vendor command" is not portable content, it is a script for one runner.

There is also a physical question. An agent runner copies the entire plugin root into its cache on install. If the plugin root is the repository root, then the UE C++ plugin, the MCP server and examples/ are copied too — for a bundle whose actual payload is Markdown. The precedent is measured: the VibeUE plugin copied into the reference project weighs 161 MB.

Decision Drivers

  • Content portability is a property of the files, not of the installer. It has to be checkable, or it will rot on the first convenient exception.
  • One vendor adapter must not become the interface. Adding a second harness must not require editing a single file under skills/.
  • The install surface should carry only what it delivers. Source trees for the editor plugin and the MCP server are not part of a documentation bundle.
  • Discoverability without a runtime. A harness that has never heard of any plugin format still needs to know what is in here and when to reach for each piece.

Considered Options

  1. Whole repository is one plugin. Vendor manifest at the repo root, skills/ beside Engine/ and mcp-server/.
  2. Separate repository for the skills. Independent versioning and release cadence.
  3. Repository is a marketplace; the bundle is a subdirectory.

Decision Outcome

Chosen: option 3, with a neutral catalog inside the bundle.

ue-toolchain/
├── .claude-plugin/marketplace.json     one adapter, points at the bundle
└── plugins/ue-design-skills/           the bundle, and the whole install surface
    ├── catalog.json                    source of truth: what is here, when to use it
    ├── .claude-plugin/plugin.json      the same adapter, one level down
    ├── skills/<name>/SKILL.md          plain Markdown + YAML frontmatter
    └── _gate/                          rules, poisoned fixtures, self-test

Three commitments follow:

The catalog is the source of truth; the vendor manifest is an adapter. catalog.json lists every skill with id, path, entry, description, use_when and its references. Any harness can read it, or ignore it and load the directory as context. A second adapter is a new file beside the first, never an edit under skills/.

Skill content names no harness. Not the vendor, not its path variables, not its command syntax. The rule holds for everything under skills/; the adapter directories are exempt because being vendor-specific is their entire job.

Both commitments are enforced, not documented. They became gate rules P13 and P14 the same hour the decision was made. A portability promise that lives only in an ADR is a promise nobody checks.

Consequences

  • Good: the install surface holds only Markdown, JSON and the gate. C++ and examples stay out of the plugin cache.
  • Good: skills release on their own cadence, before the editor plugin (phase 1) and the MCP server (phase 2) exist.
  • Good: the neutrality claim is falsifiable — a single grep decides it.
  • Bad: the layout is one level deeper than the component table in the handoff implies (plugins/ue-design-skills/, not skills/). The README is updated to match.
  • Bad: two manifests describe the same bundle. They will drift unless the catalog stays authoritative and adapters are generated or reviewed against it.
  • Neutral: nothing here prevents later extraction into its own repository. The bundle is self-contained by construction — the gate rejects any link that escapes a skill directory, so it moves with a mv. That was verified when it moved out of the archive.

Confirmation

Checked at the time of writing, and required for every later change:

  • claude plugin validate . --strict passes at the marketplace root and at the bundle root. (passing)
  • python _gate/gate.py . reports zero violations on the bundle. (passing, 14 rules)
  • python _gate/test_gate.py reports every rule reddening on its own poisoned fixture with a clean baseline. A rule that never reddens is treated as absent and fails the build. (passing, 14/14)
  • No file under skills/ matches the harness token list — vendor names, vendor path variables, vendor command syntax. (P13)
  • Every skill directory has a catalog entry whose path holds a SKILL.md, and the catalog names no skill that is absent. (P14, both directions)
  • Adding a second harness adapter changes no file under skills/. (structural; re-check when the second adapter is written)

Deferred

  • Which second adapter comes first. Not guessed. It will be written when a real harness needs it, and it will be the test of whether the catalog was actually enough.
  • License. Still open (handoff question 2). Deliberately removed from catalog.json and the vendor manifest rather than filled in with the planned value: a license asserted in shipped metadata before it is chosen is a claim with no author. Resolved by ADR-0003: prose CC BY-ND 4.0, code and metadata Apache-2.0, holder named. The original wording is kept struck through rather than deleted — the reason the field was left empty is part of how it was filled.
  • Whether the addressed audits are ever published. For now the delivery carries detection recipes and stable entry identifiers; the source addresses stay in the research archive, where _tools/resolve_id.py resolves any identifier back to the file and line it came from.