Worked example

August 8, 2026 · View on GitHub

A real three-legged system, built August 2026. Everything below is live and inspectable.

LegRepo / pathVisibility
Pluginspec-led-certification-pluginPublic
TemplateSpec-Led-CertificationPublic, marked as a GitHub template
WorkspaceOne private repo per search, instantiated from the templatePrivate
Vault~/.claude-plugins/spec-led-certification/Local

What it does

Chooses a professional certification specification-first: it interviews you, derives a weighted scorecard from your answers alone, freezes it before any credential is looked up, then surveys the market and scores candidates against it.

That freeze is why the workspace has to be a repo. The claim "the scorecard was fixed before the research ran" is only worth anything if it can be checked, and a commit timestamp checks it. A folder cannot.

How the legs divide

Plugin — 14 skills, 3 subagents, one command. Twelve of the skills and all three agents are vendored from the template; two are plugin-owned:

  • create-workspace — instantiates the template as a private repo and clones it
  • scaffold-workspace — copies the structure into a local directory when there is no gh, or when the search belongs inside an existing repo

Both are plugin-owned for the reason in sync.md: inside an existing workspace there is nothing left for them to do.

Template — the working structure (profile/, scorecard/, research/, report/), the twelve stage skills, the three agents, AGENTS.md, and a Typst report template. Because the skills ship in the template, an instantiated workspace is runnable with the plugin uninstalled, by a different assistant, on a different machine. That is the agent-agnostic claim delivered rather than asserted.

Workspace — one private repo per search, named for the subject and the month, since a second search on the same subject two years later is a different repo rather than an overwrite. Holds the profile, the frozen scorecard, the research with its sources, the reports, and archived previous runs.

Vaultowner, visibility, workspace_parent, naming, and the template override. Without it create-workspace asks four questions; with it, one confirmation.

Points where the pattern earned itself

The freeze is evidenced by git. Three mechanisms enforce it, and the one that actually settles arguments is the commit ordering. Nothing in a folder-based design could have provided it.

The workspace outlives the plugin. The template carries the skills, so the private repo is not a data directory for a tool — it is a self-contained record of a decision, readable by whatever comes next.

The vault kept personal defaults out of two public repos. A GitHub username and a preference for private repos are unremarkable, and neither belongs in a repository strangers clone. Without the third leg they would have ended up in the template as "defaults", and every fork would have inherited them.

Instantiation is not a fork. gh repo create --template produces a squashed Initial commit with no upstream link, so a workspace cannot receive template changes later. That sounds like a limitation and is the correct behaviour here: changing the skills underneath a frozen scorecard is exactly the drift the method exists to prevent.

Things learned building it

gh repo create --template --clone handles the instantiation race itself. Template population is asynchronous and an immediate clone can in principle come back empty. It does not — gh retries internally. Verified against a throwaway repo: seven seconds, 46 files, complete. No wait loop is needed, which is worth knowing because writing a speculative one is the obvious defensive move.

Hardcoding one plugin-owned skill name cost a false drift report. The sync script originally excluded scaffold-workspace by name in two places. Adding a second plugin-owned skill made --check report drift on every run until both were replaced with a list. Use a list from the start.

A vendored copy is not a place to make small adjustments. The byte-identical rule is what makes --check mean anything; one legitimate difference and the check reports drift forever and everyone stops reading it.

Reading it

The clearest single file is the plugin's scripts/sync-from-template.sh — it states the canonical direction, the ownership split and the empty-data guard in about a hundred lines. A generalised copy is in reference/sync-from-template.sh.