plugin-authoring
Skill1 starsChanged 8 days agoMITView on GitHub
This repo's plugin doctrine — how a plugin is structured,
6 other projects use a version of this.
Adopted by
Most recently taken up by
- selamy-labs/agent-skillstheir own version, first seen Nov 8, 2026
- iap/hermes-guidetheir own version, first seen Nov 1, 2026
- NazmusSayad/skillstheir own version, first seen Oct 13, 2026
- eehrich/ScarabHivetheir own version, first seen Oct 9, 2026
- nafeeur/MaskShifttheir own version, first seen Sep 12, 2026
- polyant-ai/polyanttheir own version, first seen Sep 11, 2026
Other versions6 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 6
- polyant-ai/polyant★ 10same name
- iap/hermes-guide★ 6same name
- eehrich/ScarabHive★ 2same name
- nafeeur/MaskShift★ 2same name
- NazmusSayad/skills★ 2same name
- selamy-labs/agent-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository7 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- installer/CLAUDE.mdCLAUDE.md
- site/CLAUDE.mdCLAUDE.md
- releaseSkill
- skill-kitSkill
- stackgen-pluginSkill
- vwf-pluginSkill
The file
We split this skill into the rules it gives an agent
4 rules. 0 are common, 2 are distinctive, and 2 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
2
Distinctive
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 40
Never edit either by hand.
- Distinctive: line 52
No gate lints or formats the shell a pack ships.
- Very specific: line 76
A dependency stays inside this marketplace: Add the name to dependencies in plugin.json with "marketplace": "virajp-plugins".
- Very specific: line 119
prose: no citation a pack or /vwf:init lands may be plugin-relative, because the file is copied into a repo where no plugin is installed …
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Plugin Authoring — this repo
Plugin creation is this repo's alone and is deliberately not distributed. There is no shipped plugin-authoring plugin: the one that existed was dissolved on 2026-08-29 because the toolkit has no business teaching plugin creation to anyone else.
The doctrine split in two on the way out, and the halves have different homes:
- How a plugin is structured, packaged and registered — the manifest, directory-convention discovery, versions, the marketplace and its two traps — is here, in structure.md.
- What makes a skill, agent or hook valid — the invocation states and their silent failure, strict-YAML frontmatter, hook verdict shapes, MCP and LSP wiring — is distributed via stackgen, at
plugins/stackgen/assets/artifact-doctrine.md, because stackgen generates those artifacts and its reviewer gates them against it. Read it when writing a skill or a hook anywhere, including here: the rules are the host's and apply to a plugin's artifacts exactly as they apply to a generated one.
plugins/<name>/ is the only authored tree — what you edit is exactly what
a user installs. There is no template layer, no render step, and no per-target
variant.
Two files are generated: .claude-plugin/marketplace.json at the repo root,
a projection of the 2 per-plugin manifests, and
plugins/stackgen/stacks/inventory.md, a projection of the stacks tree.
Never edit either by hand.
The one rule
A change under plugins/ is not done until the gates pass:
mise run p:plugins:check # validates the authored tree
mise run p:plugins:marketplace # regenerate, if you touched a manifest
mise run p:plugins:inventory # regenerate, if you touched stackgen's stacks/ or kinds.mdNo gate lints or formats the shell a pack ships.
--check on the two generators is what CI and pre-commit run. It exists because
each output is generated and committed, so a source edited without a
regenerate is invisible to every other check — this is the one piece of
staleness the retired plugins:render-clean was really guarding, narrowed to
the two files that still have the problem.
Three traps that are ours, not Claude's
- dprint deliberately excludes
plugins/**/*.md. Do not reach for the formatter — match the surrounding fold width by hand. (The exclusion outlived its original reason, which was Eta reflowing folded scalars. It stays because formatting ~2000 authored prose files is a decision, not a side effect.)CLAUDE.md,readme.mdanddocs/are formatted. plugins/*/stacks/*/*/config/is excluded too, and for a different reason. That tier is payload — copied byte-for-byte into a target repo, where the dprint config bootstrap syncs there formats it. A payload file formatted here under a different config comes out different from what that config produces, and a freshly shaped repo fails its own first--all-fileshook run on a file nobody touched. It has happened. The exclusion is on the directory, so a new payload file type cannot silently re-acquire the defect; when a payload file genuinely needs formatting, run bootstrap's config over it, never this repo's overrides.- A dependency stays inside this marketplace. Add the name to
dependenciesinplugin.jsonwith"marketplace": "virajp-plugins"; the marketplace entry is generated from it, andp:plugins:checkasserts it resolves. Nothing here is url-sourced and nothing should be — the two outside dependencies vwf once had are vendored skills now, with provenance underplugins/vwf/vendor/.
Hooks
Hooks are authored directly as a plugin's hooks/hooks.json, in Claude's own
format, with the scripts beside it. Three rules that bite every command hook,
whichever plugin it belongs to:
- Scripts must be portable to macOS BSD
sed— no\s, no\b. - Plugin hooks are never written to
settings.json. They are auto-discovered fromhooks/hooks.json, so verify them with/hooks. - A script's verdict shape is decided by its event, not by convention.
hookSpecificOutput.permissionDecisionisPreToolUse-only;StopandPreCompactdeny with the top-leveldecision/reason, and Claude rejects the whole verdict if ahookSpecificOutputarrives without a matchinghookEventName— which reads exactly like a hook that decided to stay quiet.
A hooks module is the other kind: a Claude Code mod in TypeScript, listed
under modules in the same hooks/hooks.json, beside the hooks block. vwf
ships one, hooks/monitor/register.tsx, the /vwf:execute progress pane. Its
$.state keys sit under the plugin's own name, because a ref's plugin must be
the plugin that loads the module, and they are declared in a types contract
(types/index.d.ts) the manifest's types key names. Its local gates are
claude plugin test <plugin>, which runs only the *.test.ts(x) inside the
plugin folder, and claude plugin validate --strict <plugin>, which
p:plugins:check also runs when claude is on PATH. CI has no claude, so
neither runs there. The three rules above are for command hooks; a module has no
script, verdict or sed.
p:plugins:check's hook rule reads only the command hooks of a plugin's own
hooks/hooks.json, but rule 11 covers a stackgen pack's payload scripts from
the other end — exec bit and shebang, bash or sh only; nothing lints their
bodies. The shebang set is narrower than a task's on purpose: a hook is wired
into settings.json as a bare path, so only a shell the host can find on PATH
will do. What the stackgen-plugin skill still owns is what those scripts are
for. The host rules in full are stackgen's assets/artifact-doctrine.md §4.
The payload's other two halves have rules of their own. Rule 13 covers its
prose: no citation a pack or /vwf:init lands may be
plugin-relative, because the file is copied into a repo where no plugin is
installed and the path resolves to nothing without a word. Rule 4 covers its
frontmatter, parsing every pack skill and pack agent under stacks/*/*/, on
the same strict terms as a plugin's own.
Skill scripts
A skill may ship a node script for the mechanical half of its work —
vwf:plan-management's scripts/plan.mjs plus scripts/lib/, vwf:execute's
scripts/log.mjs — and the judgement stays with the session. Bash or node only,
never python. Rule 16
holds every skills/*/scripts/**/*.mjs: an entry directly under scripts/
starts #!/usr/bin/env node and is executable, and no file calls require( or
imports anything but a node: built-in or a relative module, since the
installed plugin ships no node_modules. No formatter and no shell gate read
.mjs; its gate is a vitest suite under scripts/src/ that spawns the script
in temp repos, as execute-log.test.ts does. Only the owning plugin may cite
the
script's path — rule 6 refuses ${CLAUDE_PLUGIN_ROOT} across plugins.
Rule 17 fails any mise use a plugin ships, dot directories included, unless
the line forbids it (never or bare right before it, is never or — never
right after). A tool is entered into the mise.toml of the conf.d/ folder
that owns it first — zz-repo/ for a repo's own — then installed
with mise install.
Comments in shipped config and task files
Anything under a pack's config/ or hooks/ lands in a repo as its own file,
so its
comments are read by every person who opens it. Keep only the comments something
reads:
#MISEand#USAGElines, and shebangs# shellcheckdirectivesMARKED POSITIONlines, plus whatever a filler needs beside one to find its value- grype ignore-reason comments, one unit with their entry
- commented-out templates a skill fills in and uncomments
- any comment the owning reference names as load-bearing — grep that reference before removing a comment
Beyond those, a comment is at most one line, and only as a warning where a
reader would otherwise break something non-obvious. Every longer explanation
goes: dropped when the owning reference already says it, moved into it when it
does not — the pack's conventions.md for a payload. Boilerplate repeated
across files goes; a
directive it sat above stays. A comment-only payload change still bumps its
pack. stackgen's assets/pack-format.md states the same rule for pack
authors.
References
| Reference | Covers |
| structure.md | the authored tree, plugin.json, versions, the marketplace and its traps |
| checks.md | what p:plugins:check asserts, rule by rule, and the technology-free guard |
Artifact validity — frontmatter, invocation, hooks — is not in this table.
It is stackgen's assets/artifact-doctrine.md, and it applies here too. Nor is
the language-plugin contract that used to sit beside these: it is retired with
the curated language plugins, and a language is a stackgen language-bundle
kind now, per plugins/stackgen/assets/kinds.md.
Documentation
Any change to plugin behaviour must reconcile readme.md, CLAUDE.md and
site/src/content/docs/plugins/<plugin>.md in the same commit — the repo's
hard rule. Delegate the sweep to /vwf:docs-sync (its surveyor agent reads the
docs) rather than reading those files inline; CLAUDE.md and the vwf manual are
large enough that loading them costs the rest of the session.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

