Files
marketplace/plugins/kettle/skills/project/SKILL.md
T
naudachu 01fb5a2703 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>
2026-08-12 01:01:27 +05:00

187 lines
8.8 KiB
Markdown

---
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 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 -->