--- 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. `/.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. `/.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 other CLI 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. **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 ` 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. --scopes RECORDS WHAT THE TOKEN WAS MINTED WITH, and records is all it does: nothing is checked against it and nothing is refused because of it. It is worth writing down because the instance will not answer the question — Gitea's own token listing needs a password, not a token, so a token cannot be asked what it may do. Gitea spells them :; issues need `write:issue`, and everything `kettle api` reaches outside issues — releases, pull requests, branches, tags, actions — is `repository`. A token minted for issues alone answers 403 there, and the 403 names no scope. | flag | default | what it does | | --- | --- | --- | | `--name` | — | login name (add) | | `--scopes` | — | what the token was minted with, comma separated, e.g. write:issue,write:repository; documentation only (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 add --name noodles --url https://git.example.com --scopes write:issue,write:repository < t.txt # and write down what it can do 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 /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 ```