-
released this
2026-08-12 11:17:59 +00:00 | 0 commits to main since this releasekettleis no longer a plugin. It installs itself into a project.go install git.noodles.cam/claude-skills/marketplace/cli/cmd/kettle@latest kettle init --interactiveThe 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.The prose lives inside the binary now.
kettle initandkettle gen scaffold
write it into a project's own.claude/, and the two cannot disagree because
there is one artefact.kettle configsays when the tree on disk was written by
an older build.Breaking
kettle gen skillsis nowkettle gen scaffold. It writes commands,
skills and the runner subagent, into<project>/.claudeby default.- Files are written whole. The old generator owned a region between
<!-- kettle:gen -->markers and left the prose around it alone, because that
prose was somebody's hand-written file. It 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.--checkwarns before an upgrade
discards one. - Uninstall the plugin.
/plugin uninstall kettle@claude-skills, then
kettle initin each project you tracked issues in. The marketplace still
carriestdl, which has no binary and never needed one.
Your
.kettle/store, your logins and your config are untouched.The slash commands survive
A project's skills are flat, so the prefix is spelled into the directory name —
kettle-issue, notissue. A project's commands take their namespace from a
subdirectory, so/kettle:init,/kettle:auth,/kettle:issue,/kettle:sync,
/kettle:apiand/kettle:projectare all still what you type.initandauthstopped being skills carryingdisable-model-invocation: true
and became commands, because a command is operator-invoked.authnow
restrictsallowed-toolsso a model cannot reachkettle auth addat all.kettle init --interactiveWalks you through the login, the token, the tracker repository, the
.claude/
tree and the mirror hook. The token is read with the terminal's echo off, so it
lands in no shell history, no temp file and no scrollback — which is the one
thing this can do that no flag can.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 the same code path:kettle init --login noodles --repo owner/name --mirror-hook kettle init --no-scaffold # marker and config onlykettle mirrorKeeps
CLAUDE.mda symlink toAGENTS.mdin every directory below where it is
run — two harnesses reading two filenames for one document otherwise keep two
documents, and they drift.This was 141 lines of Python behind a filename that said
.sh, shipped as a
plugin hook. Same seven branches, same refusal to merge two real files whose
contents differ, now with a table test per branch and a check that a repair
converges in one pass.kettle mirror # repair, and say what changed kettle mirror --check # exit 1 if anything is out of place; write nothing kettle mirror --hook # the PreToolUse form; exits 0 on every path--hookis opt-in per project —kettle init --mirror-hook, or one question
in--interactive. That is strictly narrower than the plugin hook it replaces,
which was on for everybody who installed the plugin in every repository they
touched.Two rules that stopped being prose
initrefuses a linked worktree and names the main checkout. A worktree
reaches the main store on its own; a marker there gives one project two stores,
and the second disappears with the branch.- An existing
.claude/settings.jsonis never reformatted. Go cannot preserve
JSON key order, so a merge would rewrite a file you commit and share.
--mirror-hookprints the snippet to paste instead, and--force-settingsis
the way past it.
Also
.kettle/scaffold.yamlrecords which build wrote a project's tree. Nothing
resolves from it; deleting it costs the warning inkettle configand nothing
else. It is a separate file because an unknown key inconfig.yamlis a hard
error, and that file may be committed and read by whatever build each machine
happens to have.- Two new packages,
internal/mirrorandinternal/scaffold, both importing
nothing but the standard library —mirrorbansos/execandscaffoldbans
os, each held by a layering test. golang.org/x/termbecomes a direct dependency. It was already in the tree
indirectly, so no module was added.
Downloads