There is no CI: the instance has no act_runner and none is planned, so releases are cut by hand. That makes `make check` the only thing standing between a mistake and the tracker, and it is one command: gofmt, vet, the suite with the cache defeated, `go mod verify`, a vendored build, and `kettle gen skills --check`. The last one is the invariant worth having — the plugin's SKILL.md command reference is generated from the binary's registry, so a flag that changed cannot ship with documentation that recommends the old one. `cli/cmd/release` publishes to Gitea using the same SDK the binary already vendors, which is a pleasing thing to be able to say: nothing third-party handles the artifacts. It is a second binary rather than a `kettle` subcommand on purpose — `kettle`'s command tree is what generates the plugin's skills, so a verb there ships to every operator, and publishing a release is build infrastructure. It is idempotent end to end: an existing release for the tag is reused, an asset of the same name is replaced rather than doubled, and a retried run converges instead of duplicating. `make release` refuses three things, each with its own message: a dirty working tree, a TAG that is not what `git describe` reports, and a tag the remote does not have. A release built from uncommitted code is unreproducible and nobody finds out until they need to reproduce it. `kettle version` reports the stamp, the toolchain and the VCS revision. The default is `dev`, and a hand build says so and means it — a binary out of somebody's working tree is not a release and must not claim to be one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2.8 KiB
AGENTS.md — plugins/
One directory per plugin, and each is self-contained: a plugin's root is its
directory here, so ${CLAUDE_PLUGIN_ROOT} resolves inside it and every path a
plugin uses stays relative to itself.
| plugin | what it is |
|---|---|
kettle/ |
issues as local markdown, driven by the kettle binary in cli/. Skills, a runner subagent, two hooks |
tdl/ |
Three Dots Labs Go conventions as an enforceable rule set. One skill, no binary, no state |
Adding one
Two edits, and nothing else in the repository needs to know:
- a directory here holding
.claude-plugin/plugin.json, plus whatever ofskills/,agents/,hooks/,commands/it needs; - one entry in
.claude-plugin/marketplace.jsonwhosesourceis the path into this directory.
The catalog entry's name and the directory name must match, and both must match
plugin.json. They are three spellings of one identity: the catalog resolves a
source path, the manifest names the plugin, and the directory is what
${CLAUDE_PLUGIN_ROOT} becomes. A rename that misses one of the three installs a
plugin that cannot find its own files — which is exactly what happened when tea
became kettle.
The catalog's description is what somebody reads in /plugin; the manifest's is
what the installed plugin reports. Keep them saying the same thing.
What a plugin may and may not do
- A skill is prose an agent loads on demand. Its frontmatter
description:is the only thing that decides whether it gets loaded at all, which makes it the one line worth tuning against real failures — and the one line no generator may write. - Heavy reference material goes in
references/, not in the SKILL.md. The skill says when to read it. - A hook must fail open. Both of
kettle's exit 0 on every path, including their own bugs: a plugin that breaks a user's Bash call because its documentation helper crashed is worse than no plugin. - State belongs to the project, never to the plugin directory. A plugin lives in
a versioned cache that changes path on every update; anything written inside it is
lost or invisible from the next project. This is not hypothetical — it is the bug
that motivated rewriting
kettle's Python scripts as a binary, and the whole reason a project carries a.kettle/marker.
Keeping this file true
- Scope: what a plugin directory is, how the catalog points at it, and the rules common to all of them. The table names every plugin here.
- Update it when a plugin is added or removed or renamed, or when the catalog gains a field a plugin author has to fill in.
- Do not describe an individual plugin's skills or design; each has its own file.