refactor!: rewire the plugin onto the kettle binary, and rename it

BREAKING: the plugin is `kettle`, not `tea`, and its commands are `/kettle:*`.
It also now needs a binary on PATH that it did not need before; the README and
every skill say how to get one and what a missing one looks like.

The plugin was 3800 lines of Python doing what a compiled binary does better,
and the name pointed at a tool that no longer takes part: `tea` is Gitea's CLI,
and since the transport moved into the binary nothing here shells out to it for
issues at all. A plugin named after it was going to keep suggesting otherwise.

Deleted: 19 scripts, the 14-file unittest suite, and the tea-guard hook. The
guard blocked any `tea` invocation that would run under a login the model picked
instead of the operator; the binary holds its own credentials and reads the
pinned login out of the project's own config, so that failure is no longer
expressible and there is nothing left to police. agents-sync stays — it is about
AGENTS.md symlinks and has nothing to do with any of this.

What the plugin keeps is what only a plugin can carry: the rules an operator
states and a binary cannot enforce. `init` still refuses to run inside a linked
worktree and still may not be model-invoked, because which directory is the
project is a statement a person makes. The issue format reference stays here and
stays the source of truth. The runner subagent is still for batches and still
may not decide what an issue says.

The command reference in the issue, sync and project skills is GENERATED from
the binary's own command registry, between markers, so a flag that changed
cannot ship with a skill that recommends the old one. `kettle gen skills
--check` exits non-zero when they drift. The generator owns the region and
nothing outside it: the frontmatter description, which is what decides whether a
skill loads at all, stays hand-written.

`use` survives and is the one place `tea` is still named — for releases,
webhooks and actions, which kettle does not cover. Its instruction to write
`--login "$GITEA_LOGIN"` and let the hook substitute the pin was true until this
commit and is now rewritten: `tea` keeps its own configuration, kettle keeps
its own, and configuring one configures nothing in the other.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
naudachu
2026-08-12 00:04:44 +05:00
parent 1239fdee70
commit e628ad6fd9
66 changed files with 2091 additions and 12499 deletions
+161
View File
@@ -0,0 +1,161 @@
---
name: project
description: Generated flag reference for the project-level `kettle` commands — `kettle init`, `kettle auth`, `kettle config`, `kettle gen`. Load it to look up the exact flags and defaults of one of those four, or when a command answers "no project" / "no login" and you need `kettle config` to say what this directory resolved to. The rules around initializing are /kettle:init and the credential workflow is /kettle:auth; this file is the flag table both of them point at.
---
# kettle project — the project itself
`kettle` resolves everything from one marker. `<project>/.kettle/` is created by
`kettle init` and never inferred: `.git` is in every clone, so a tool that
guessed a root from one would write issues into whatever tree it happened to be
standing in. With no marker anywhere the command stops and names the directories
it searched — that is an answer, not a fallback.
Two configuration files, and the split is the point. `<project>/.kettle/config.yaml`
holds the tracker repository and the **name** of a login; the name is worth
nothing on its own, which is what makes it safe inside a working tree.
`~/.config/kettle/logins.yaml` (0600, one per machine, `$KETTLE_CONFIG_HOME` or
`$XDG_CONFIG_HOME` move it) holds the tokens. `KETTLE_LOGIN`, `KETTLE_REPO`,
`KETTLE_URL` and `KETTLE_TOKEN` each override the file they shadow.
**No `kettle` on PATH?** `command not found: kettle` is the whole story — no
script and no `tea` invocation substitutes for it. Stop and tell the operator to
install it: `cd cli && go build -o ~/.local/bin/kettle ./cmd/kettle` in the
marketplace repository (go.mod requires **go 1.26**), or
`go install git.noodles.cam/claude-skills/marketplace/cli/cmd/kettle@latest`.
`kettle gen` is a maintainer command: it rewrites the generated region of these
SKILL.md files from the command registry the binary was built from. Run it after
changing the CLI, never to "fix" documentation by hand.
<!-- kettle:gen -->
**Generated from the kettle command registry by `kettle gen skills`.** Everything between the two markers is replaced on the next run — hand-written prose belongs outside them.
## `kettle auth list | add | remove <name>`
manage the tokens this machine holds
Credentials live in one file per machine, outside every working tree, mode
0600. A project pins a login by NAME; the name is worth nothing on its own,
which is what makes it safe to keep in a file inside the repository.
The token is read from standard input unless --token is given, because an
argument is in the shell history the moment it is typed:
kettle auth add --name noodles --url https://git.example.com < token.txt
pass show gitea/token | kettle auth add --name noodles --url https://git.example.com
`list` never prints a token. There is no flag to make it.
| flag | default | what it does |
| --- | --- | --- |
| `--name` | — | login name (add) |
| `--token` | — | token, if you would rather not use stdin (add) |
| `--url` | — | instance URL, e.g. https://git.example.com (add) |
| `--user` | — | account this token belongs to; documentation only (add) |
```bash
kettle auth list # what this machine holds
pass show gitea | kettle auth add --name noodles --url https://git.example.com # add one, token on stdin
kettle auth remove noodles # forget it
```
## `kettle config`
show what this project resolved to
Every path and every setting, with the overrides already applied, so a run that
went somewhere unexpected can be explained without guessing.
The token is never printed — only whether one was found.
This is the command to reach for when the store looks empty, when a push says
401, or when two directories disagree about which project they are in.
```bash
kettle config # resolved paths and settings
```
## `kettle gen skills`
write the plugin's SKILL.md files from the command registry
A SKILL.md tells an agent how to invoke this binary. Hand-written, it drifts: a
flag is renamed here and the documentation goes on recommending the old one,
and the agent that reads it fails in a way nobody traces back to a stale
sentence. Everything those files say about a command — its usage line, its
flags with their defaults, its worked examples — is already in the registry
this binary is built from, so it is written from there and cannot disagree.
THE GENERATOR OWNS A REGION, NOT A FILE. Each SKILL.md carries a pair of HTML
comment markers — `kettle:gen` to open and `/kettle:gen` to close, both written in
the `<!-- … -->` form and visible at the top and bottom of the block below.
Everything between them is replaced on every run; every byte outside them comes
back exactly as it was, which matters most for `description:`, the prose that
decides whether an agent loads the skill at all, and the one thing here that no
generator can write.
A file with no markers is REPORTED AND LEFT ALONE, never overwritten: clobbering
somebody's prose because they forgot a marker is the failure this design exists
to prevent. A file that does not exist yet is created with a frontmatter stub
around a generated block, for a human to fill in.
The output is deterministic to the byte — no timestamps, no map iteration — so
regenerating something that has not changed produces no diff. --check is that
property made useful: it writes nothing and exits 1 when any file on disk
differs from what would be generated, which is what a pre-commit hook or a CI
step calls. It wins over --dry-run when both are given.
| flag | default | what it does |
| --- | --- | --- |
| `--check` | `false` | write nothing, exit 1 if anything is out of date |
| `--dry-run` | `false` | print what would change; write nothing |
| `--out` | — | directory the skills live in; one <group>/SKILL.md under it |
```bash
kettle gen skills --out ../plugins/kettle/skills # write the region in every group's SKILL.md
kettle gen skills --out ../plugins/kettle/skills --dry-run # print what would change; write nothing
kettle gen skills --out ../plugins/kettle/skills --check # exit 1 if the docs are out of date
```
## `kettle init`
make this directory a project that tracks issues
Creates `.kettle/` — the marker every other command resolves the store from,
and `.kettle/config.yaml`, which says which tracker repository these issues
belong to and which login to reach it under.
The marker is deliberately something an operator makes, not something inferred
from the tree: `.git` is in every clone, so anything that inferred a root from
one would write issues into whatever it happened to be installed in.
--login pins a name, never a credential. The tokens live in one file per
machine, outside every working tree, managed with `kettle auth`.
All of it is idempotent: it creates .kettle/issues and .kettle/payload, migrates
an older store in if it finds one (either layout the tea plugin used, oldest
first), writes the config without disturbing settings it was not given, and adds
.kettle/ to .gitignore. Each migration is a move, not a copy — two stores is the
state the marker exists to prevent — and it refuses to pick a winner when both
sides hold a file of the same name.
Do NOT run this inside a linked worktree. A worktree is the same project on
another branch and reaches the store by a hop out to the main checkout; a marker
here would give one project two stores, and the directory holding the second one
disappears with the branch.
| flag | default | what it does |
| --- | --- | --- |
| `--at` | — | directory to initialize (default: the working directory) |
| `--dry-run` | `false` | report what would happen; change nothing |
| `--login` | — | name of a login in the machine-wide file (see `kettle auth`) |
| `--repo` | — | tracker repository, as owner/name |
```bash
kettle init # initialize the current directory
kettle init --login noodles --repo claude-skills/marketplace # and point it at a tracker
kettle init --at ~/code/x # initialize somewhere else
kettle init --dry-run # say what it would do, touch nothing
```
<!-- /kettle:gen -->