feat: drop the kettle plugin; the binary writes its own skills
The plugin and the binary shipped on two release cadences and nothing on an operator's machine ever checked that the one they installed described the other. The generated flag block existed precisely so a renamed flag could not ship with documentation recommending the old one — and then shipped one version behind the registry it came from, which is the same bug one hop downstream. So the prose moved into the binary. `internal/scaffold` embeds every document; `kettle init` and `kettle gen scaffold` write them into a project's own `.claude/`. The two cannot disagree because there is one artefact. The namespace survived the move. A project's skills are flat, so the prefix is spelled into the directory name (`kettle-issue`); a project's *commands* take their namespace from a subdirectory, so `commands/kettle/init.md` is still `/kettle:init`. Four of the six command files are thin pointers at a skill, and that is what kept ~1,600 lines of `/kettle:…` cross-references true without a rewrite. `init` and `auth` lost `disable-model-invocation: true` — being a command is that property — and `auth` now restricts `allowed-tools` so a model cannot reach `kettle auth add` at all. `gen scaffold` writes files whole rather than splicing a region. The old refusal protected somebody's hand-written prose around the block; that prose is embedded now, so there is none to protect, and preserving local edits would freeze a project's documentation at whatever version first initialized it. `--check` warns before an upgrade discards one. The plugin's `agents-sync.sh` — 141 lines of Python behind a filename that said `.sh` — became `internal/mirror` and `kettle mirror`. Same seven branches, same refusal to merge two real files that differ, now with a table test per branch and a check that a repair converges in one pass. `--hook` is the PreToolUse form and exits 0 on every path including a panic. It is opt-in per project, which is strictly narrower than the plugin hook that was on for everybody who installed it. `kettle init --interactive` walks a person through the login, the token (read with the echo off, so it lands in no history and no file), the repository, the `.claude/` tree and the mirror hook. It refuses a stdin that is not a terminal and names the flags instead: every question it asks has one, and it performs nothing itself, so an interactive run and a flag run are one code path. Two rules that used to be prose are now the binary's: init refuses a linked worktree and names the main checkout, and writing into an existing `.claude/settings.json` is refused with the snippet printed rather than reformatting a file the operator commits. The scaffold version stamp went to its own `.kettle/scaffold.yaml` rather than into `config.yaml`, because unknown keys there are a hard error and that file may be committed and read by whatever build each machine has. golang.org/x/term becomes a direct dependency; it was already in the tree indirectly, so no module was added. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,51 +1,63 @@
|
||||
# claude-skills — a Claude Code plugin marketplace
|
||||
# claude-skills — the `kettle` binary, and a plugin marketplace
|
||||
|
||||
One repository, one marketplace, two plugins, and the `kettle` binary the issue
|
||||
plugin is built on. Register the marketplace once and install whichever pieces you
|
||||
want; each plugin is independent and carries its own manifest and docs.
|
||||
One repository holding two things: **`kettle`**, a Go binary that keeps a
|
||||
project's issues as local markdown and syncs them with Gitea, and a small Claude
|
||||
Code **plugin marketplace** with one plugin in it.
|
||||
|
||||
## Installation
|
||||
## Installing kettle
|
||||
|
||||
`kettle` is one binary and it installs itself into your project. There is no
|
||||
plugin to add — `cli/go.mod` requires **Go 1.26**, and the first build downloads
|
||||
eight modules, verified against `go.sum`:
|
||||
|
||||
```bash
|
||||
go install git.noodles.cam/claude-skills/marketplace/cli/cmd/kettle@latest
|
||||
|
||||
# or from a clone of this repository, version stamped:
|
||||
cd cli && make install # ~/.local/bin/kettle
|
||||
cd cli && make install BINDIR=$(go env GOPATH)/bin
|
||||
```
|
||||
|
||||
Put the target directory on your `PATH` and check with `kettle version`. Then, in
|
||||
a project you want to track issues in:
|
||||
|
||||
```bash
|
||||
kettle init --interactive
|
||||
```
|
||||
|
||||
That walks you through the login, the token (typed with the echo off, so it lands
|
||||
in no history and no file), the tracker repository, and the `.claude/` tree —
|
||||
which is where the slash commands and skills come from:
|
||||
|
||||
```
|
||||
.claude/commands/kettle/*.md /kettle:init /kettle:auth /kettle:issue
|
||||
/kettle:sync /kettle:api /kettle:project
|
||||
.claude/skills/kettle-*/ loaded by description, never by name
|
||||
.claude/agents/kettle-runner.md the batch runner, on a cheap model
|
||||
```
|
||||
|
||||
Every flag table in those documents is rendered from the binary's own command
|
||||
registry, and the prose around it is embedded in the same binary. **They cannot
|
||||
describe a version of `kettle` other than the one that wrote them** — which is
|
||||
the whole reason this stopped being a plugin. `kettle config` tells you when the
|
||||
tree on disk was written by an older build; `kettle gen scaffold` refreshes it.
|
||||
|
||||
Prefer flags to prompts? Everything `--interactive` asks has one:
|
||||
|
||||
```bash
|
||||
kettle init --login noodles --repo owner/name --mirror-hook
|
||||
kettle init --no-scaffold # marker and config only
|
||||
```
|
||||
|
||||
## The marketplace
|
||||
|
||||
```
|
||||
/plugin marketplace add https://git.noodles.cam/claude-skills/marketplace.git
|
||||
```
|
||||
|
||||
Working from a local clone? Point at the directory instead:
|
||||
|
||||
```
|
||||
/plugin marketplace add /path/to/marketplace
|
||||
```
|
||||
|
||||
Then install what you need:
|
||||
|
||||
```
|
||||
/plugin install kettle@claude-skills
|
||||
/plugin install tdl@claude-skills
|
||||
```
|
||||
|
||||
Use `/plugin` to enable, disable, or update them later.
|
||||
|
||||
**`kettle` also needs its binary**, which no plugin can install for you. Build it
|
||||
from this repository — `cli/go.mod` requires **Go 1.26**, and the first build
|
||||
downloads eight modules, verified against `go.sum`:
|
||||
|
||||
```bash
|
||||
cd cli && make install # ~/.local/bin/kettle, version stamped
|
||||
cd cli && make install BINDIR=$(go env GOPATH)/bin
|
||||
|
||||
# or plain go, without the version stamp:
|
||||
cd cli && go build -o ~/.local/bin/kettle ./cmd/kettle
|
||||
go install git.noodles.cam/claude-skills/marketplace/cli/cmd/kettle@latest
|
||||
```
|
||||
|
||||
Put the target directory on your `PATH` and check with `kettle version`. A skill
|
||||
that answers `command not found: kettle` is telling you exactly this.
|
||||
|
||||
## What ships here
|
||||
|
||||
| Plugin | Commands | What it does |
|
||||
|---|---|---|
|
||||
| [`kettle`](plugins/kettle) | `/kettle:init` `/kettle:auth` `/kettle:issue` `/kettle:sync` `/kettle:api` `/kettle:project` | Issues as local markdown, cleanly layered. Issues are units of work offline first and tracker rows second; the `kettle` binary does the work, and each skill's command reference is generated from the binary's own command registry so it cannot drift |
|
||||
| [`tdl`](plugins/tdl) | `/tdl:audit` | Three Dots Labs Go conventions as an enforceable rule set — audits a Go project against nine categories of CQRS/DDD/Clean-Architecture rules by severity, or scaffolds services, handlers, entities, repositories and Watermill adapters from templates that already follow them |
|
||||
|
||||
---
|
||||
@@ -68,7 +80,8 @@ internal packages with one direction of imports — see
|
||||
| `kettle init` | makes this directory a project: creates the `.kettle/` marker every other command resolves the store from, migrates an older store in, gitignores it |
|
||||
| `kettle auth` | manages the tokens this machine holds — one file, mode 0600, outside every working tree |
|
||||
| `kettle config` | prints every path and setting a run resolved to, with overrides applied. Never prints a token |
|
||||
| `kettle gen skills` | rewrites the plugin's SKILL.md command reference from the binary's own command registry |
|
||||
| `kettle gen scaffold` | writes the `.claude/` commands, skills and subagent, prose and flag tables both, from inside this binary |
|
||||
| `kettle mirror` | keeps `CLAUDE.md` a symlink to `AGENTS.md` in every directory below here. `--hook` is the `PreToolUse` form and never fails a call |
|
||||
| `kettle version` | what this binary was built as — `dev` from a working tree, the tag when a release build stamped it in |
|
||||
|
||||
**issue** — units of work, offline, no tracker involved
|
||||
@@ -239,22 +252,25 @@ Five steps in one command, non-zero the moment any of them fails:
|
||||
| `go vet ./...` | the compiler's own second opinion |
|
||||
| `go test -count=1 ./...` | the whole suite, with the test cache defeated: a gate that can pass because it passed an hour ago on different code is not a gate |
|
||||
| `go mod verify` + `go build -mod=vendor ./...` | every module matches its hash in `go.sum`, and the committed `vendor/` is complete and is what compiles. A `vendor/` that has drifted from `go.mod` breaks nobody until somebody builds with a cold module cache |
|
||||
| `kettle gen skills --check` | the plugin's SKILL.md command reference still agrees with the binary it documents. Exit 1 the moment it does not, and `gen skills` without `--check` is the fix |
|
||||
| `kettle gen scaffold --check` | the documents embedded in the binary still agree with the registry it is built from. Exit 1 the moment they do not, and `dist/kettle gen scaffold --out internal/scaffold/assets` is the fix |
|
||||
|
||||
That last one is the invariant that keeps the plugin honest: everything a
|
||||
SKILL.md says about a `kettle` command — its usage line, its flags, its
|
||||
examples — is generated from the registry the binary is built from, between
|
||||
`<!-- kettle:gen -->` markers. Prose outside the markers is never touched.
|
||||
That last one is circular on purpose. What a project gets is embedded in the
|
||||
binary with the registry's flag tables **already spliced in**, so the embedded
|
||||
copy has to hold what the current registry would produce. Change a flag and it
|
||||
goes stale; regenerate, then rebuild, because the binary has to pick the new
|
||||
bytes up.
|
||||
|
||||
### Where the design notes are
|
||||
|
||||
**Every directory with a story carries its own `AGENTS.md`**, starting at [the
|
||||
repository root](AGENTS.md) and recursing into [`cli/`](cli/AGENTS.md), each of its
|
||||
packages, and each plugin. A `CLAUDE.md` beside one is a generated symlink to it, and
|
||||
two hooks in the `kettle` plugin keep the arrangement honest: one repairs the layout
|
||||
before every Bash call, the other asks for the nearest `AGENTS.md` to be corrected
|
||||
after a file is written. Read the one next to the code you are changing rather than
|
||||
the whole tree.
|
||||
packages, and each plugin. A `CLAUDE.md` beside one is a generated symlink to it,
|
||||
and `kettle mirror` keeps that arrangement honest — six of the seven states it can
|
||||
find are repaired losslessly, and the seventh (two real files whose contents
|
||||
differ) is reported and left alone, because one of them is somebody's writing.
|
||||
Register it with `kettle init --mirror-hook` if you want it run before every Bash
|
||||
call. Read the file next to the code you are changing rather than the whole
|
||||
tree.
|
||||
|
||||
`make help` lists the rest — `build`, `install [BINDIR=…]`, `dist`, `clean`.
|
||||
`make install` puts a version-stamped binary in `~/.local/bin` (override with
|
||||
@@ -275,7 +291,8 @@ repository's own code. `cli/cmd/release` is a second binary in the same module
|
||||
that talks to Gitea's API through the same SDK `kettle` uses: no third-party
|
||||
action, and nothing between a tag and what people download that is not in this
|
||||
tree. It is deliberately not a `kettle` subcommand — `kettle` is a tool for
|
||||
issues, and its command tree is what generates the plugin's documentation.
|
||||
issues, and its command tree is what generates the documents it writes into a
|
||||
project.
|
||||
|
||||
```bash
|
||||
cd cli
|
||||
|
||||
Reference in New Issue
Block a user