feat: publish releases with this repository's own SDK code

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>
This commit is contained in:
naudachu
2026-08-12 01:01:27 +05:00
parent ec0a1893b7
commit 01fb5a2703
27 changed files with 3385 additions and 266 deletions
+24 -4
View File
@@ -31,8 +31,9 @@ go install git.noodles.cam/claude-skills/marketplace/cli/cmd/kettle@latest
```
`cli/go.mod` says **go 1.26** — the Gitea SDK requires it, so that is the minimum
for anybody building this. `vendor/` is committed, so a build from a clone needs
no network.
for anybody building this. There is no `vendor/`: a build resolves its modules from
the module cache or the network, and `go.sum` is what makes that safe. Why that
trade was taken is in [`cli/AGENTS.md`](../../cli/AGENTS.md).
An operator who sees `command not found: kettle` installs it and re-runs; there
is nothing to configure in this plugin either way. `kettle config` is the command
@@ -89,7 +90,7 @@ agents/
kettle-runner.md subagent (Haiku): runs kettle commands, reports a
receipt. Batches only, and no opinions about content
hooks/
hooks.json registers the PreToolUse hooks
hooks.json registers the one hook: PreToolUse(Bash)
agents-sync.sh keeps every directory canonical: AGENTS.md a real
file, CLAUDE.md a symlink to it
skills/
@@ -138,7 +139,12 @@ and it stays hand-written.
| `.claude/settings.local.json``env.GITEA_LOGIN`, the login pin | `<project>/.kettle/config.yaml` (a login **name**) plus `~/.config/kettle/logins.yaml` (the tokens, 0600, outside every working tree) |
| the tea plugin's own store marker | `.kettle/`; `kettle init` migrates an older layout in, and each migration is a move |
`hooks/agents-sync.sh` is unrelated to any of that and stays.
`hooks/agents-sync.sh` is unrelated to any of that and stays. It maintains the
`AGENTS.md` convention by repairing the filesystem layout — a real file, with
`CLAUDE.md` a symlink to it — and the convention itself is documented once,
in [the repository root's AGENTS.md](../../AGENTS.md#the-agentsmd-convention). It
cannot fail a tool call: it exits 0 on every path, including its own bugs —
documentation maintenance is not permitted to break a build.
All of it is in git history. `git log --diff-filter=D` finds it if a decision
needs to be re-read rather than re-derived.
@@ -154,3 +160,17 @@ cd cli && go test ./...
The second line is the plugin's only mechanical invariant: the documentation an
agent reads agrees with the binary it is documenting.
## Keeping this file true
- **Scope:** everything under `plugins/kettle/` — the skills, the runner subagent,
the two hooks, and the group ⇄ skill seam. `skills/` and `agents/` carry no
AGENTS.md of their own on purpose: a SKILL.md already states its own procedure,
and a second document beside it would be the copy that goes stale.
- **Update it when** a skill is added or removed (the layout and the generated-region
table both name every one), a hook is added or its event changes, a rule in *the
rules that must survive* changes, or the binary takes over something this plugin
used to state.
- **Do not** restate the binary's design. [`cli/AGENTS.md`](../../cli/AGENTS.md) and
the eight package files under it own that; if the two ever disagree, the binary is
right and the prose is stale.
+4 -3
View File
@@ -27,7 +27,7 @@ the tool.
- **Claude Code** — CLI, desktop app, or IDE extension.
- **The `kettle` binary, on your `PATH`.** It is not installed for you, and
nothing here works without it — see below.
- **Python 3** — the `agents-sync` hook is a Python script; `python3` must be on
- **Python 3** — the two `agents-*` hooks are Python scripts; `python3` must be on
`$PATH`. Nothing else here needs it.
- **`tea`** (optional) — Gitea's own CLI, only for `/kettle:use`. `brew install
tea`, or from [gitea.com/gitea/tea/releases](https://gitea.com/gitea/tea/releases).
@@ -36,7 +36,8 @@ the tool.
### Installing the binary
Building it needs **Go 1.26** — `cli/go.mod` says so because the Gitea SDK
requires it. `vendor/` is committed, so the build itself needs no network.
requires it. There is no `vendor/` directory: the first build downloads eight
modules, verified against `go.sum`.
```bash
# from a clone of this repository
@@ -159,7 +160,7 @@ dependency come back as a question, not as a guess.
agents/
kettle-runner.md subagent (Haiku) that runs the commands
hooks/
hooks.json registers the PreToolUse hooks
hooks.json registers the one hook
agents-sync.sh keeps AGENTS.md real and CLAUDE.md a symlink to it
skills/
init/ /kettle:init — make a directory a project
+25
View File
@@ -158,4 +158,29 @@ kettle init --login noodles --repo claude-skills/marketplace # and point it at
kettle init --at ~/code/x # initialize somewhere else
kettle init --dry-run # say what it would do, touch nothing
```
## `kettle version`
print the version this binary was built as
A binary that cannot say what it is, is a support problem: an operator with an
old copy on PATH and a skill written against a newer one has no way to see the
mismatch, and neither does anybody reading their transcript.
The version is stamped at link time. A build from source says "dev" and means
it — that is not a placeholder to be edited, it is the answer for a binary that
came out of somebody's working tree rather than off a tag.
The commit is reported when the build recorded one, which `go build` does from
git and a build from an unpacked tarball cannot. A tree with uncommitted
changes in it says so beside the commit.
| flag | default | what it does |
| --- | --- | --- |
| `--short` | `false` | print the version alone, with nothing around it |
```bash
kettle version # the version, the toolchain and the commit
kettle version --short # just the version, for a script
```
<!-- /kettle:gen -->