Files
marketplace/plugins/kettle/skills/use/SKILL.md
T
naudachu e628ad6fd9 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>
2026-08-12 00:04:44 +05:00

8.3 KiB


name: use description: Reference docs for the tea CLI — Gitea's own command-line client, and the way to reach every Gitea entity the kettle binary does not cover. Load when the user asks about pull requests, releases, milestones, labels, repos, branches, actions, webhooks, notifications or times, to look up the right tea command and flags. tea keeps its own configuration and its own logins, entirely separate from kettle's. Issues are NOT handled here: /kettle:issue works on them offline and /kettle:sync moves them to and from the tracker.

/kettle:use — tea CLI reference

Reference material for tea, Gitea's official command-line client. Use these docs to look up commands, flags, filters and output fields before running tea via Bash.

kettle covers issues and nothing else. Everything else Gitea has — pulls, releases, milestones, labels, repos, branches, actions, webhooks, notifications, times — is reached through tea, and this skill is how.

Issues are somewhere else

Do not reach for tea issues or tea api …/issues/… to read or create an issue. Two skills own that, and they keep the payload out of your context:

Skill Scope
/kettle:issue issues as units of work — create, read, grep, validate, tick, dependency graph. Offline.
/kettle:sync moving issues between the local store and the tracker — pull, push, comment, close, evict.

Login: tea has its own configuration, and it is not kettle's

Two tools, two credential stores, no connection between them:

tool where its logins live how they are managed
tea $XDG_CONFIG_HOME/tea tea logins list, tea logins add (interactive), tea logins default
kettle ~/.config/kettle/logins.yaml + <project>/.kettle/config.yaml kettle auth, kettle init --login (/kettle:auth)

Configuring one configures nothing in the other. /kettle:auth does not give tea a credential, and tea logins add does not give kettle one. A project whose kettle commands work fine can still have no tea login at all, and the error you get will be about the login tea chose for itself.

There is no $GITEA_LOGIN placeholder and no hook that substitutes one. The PreToolUse guard that used to rewrite it was deleted along with the Python scripts; writing --login "$GITEA_LOGIN" now passes an empty variable to tea and fails in a way that reads like a tea bug. If you find that spelling anywhere, it is stale.

How to name a login honestly:

  • Inside a checkout, tea auto-detects owner, repo and login from the git remote. That is usually right and usually enough — run the command without --login.
  • When the machine holds more than one login, or you are outside a checkout, pass --login <name> with a name out of tea logins list. Which one is the operator's call: ask with AskUserQuestion rather than picking the one that looks likely. A wrong identity writes to a real tracker under somebody else's account.
  • no gitea login detected, falling back to login '…' is a hard failure, not a warning. Stop, do not act on the result, surface the line.
  • Never mutate login state: no tea logins add/edit/delete/default, no tea logout. tea logins list is the only login command that is yours to run, and adding a login is interactive — the operator does it in their own terminal.

How to use

  1. Identify the entity in the request: pulls, labels, milestones, releases, times, repos, branches, actions, webhooks, notifications, etc.
  2. Find the matching command in the index below.
  3. Run it via Bash, e.g. tea pulls list --repo owner/repo --state open.

tea auto-detects owner/repo from $PWD inside a git repo; otherwise pass --repo owner/repo (or -r).

--repo takes a slug — except where a checkout is required

A few commands touch local git, not just the API, and for those --repo must be a path to a checkout; a slug is rejected:

Error: local repository required: execute from a repo dir, or specify a path with --repo

The message reads like the flag is missing even when it was passed. Confirmed for pulls create, pulls checkout and pulls clean (tea 0.14.x). Everything that is only an API call — pulls list, milestones, releases, times, labels, issues — takes the slug from any directory.

Three working forms for pulls create:

# 1. cwd inside the checkout, no --repo at all
tea pulls create --head feat/x --base main --title "…" --description "…"

# 2. from anywhere, --repo as a PATH (this is also the git-worktree answer:
#    point it at the main checkout)
tea pulls create --repo /path/to/checkout \
  --head feat/x --base main --title "…" --description "…"

# 3. no checkout in reach — POST it, where owner/repo is a slug again
tea api -X POST -d @tmp/pull/x.json repos/{owner}/{repo}/pulls

Index

  • tea CLI overview — global flags, common options, output formats
  • ENTITIES — issues, pulls, labels, milestones, releases, times, repos, branches, actions, webhooks, comment
  • HELPERS — open, notifications, clone, api
  • MISC — whoami, admin
  • SETUP — logins, logout, ssh-keys

The canonical issue format lives in ../issue/references/format.md — it describes local files, not tea commands.

Rich payloads — write to $PWD/tmp/ first, then tea api

Entity subcommands (tea comment, tea pulls create, tea releases create, …) are built for humans at a TTY. With a large or formatted body they can hang silently — an empty-looking positional arg triggers the $EDITOR fallback, or a scope/confirm prompt waits on a TTY that doesn't exist. The harness eventually kills the process (e.g. exit 144 = 128 + SIGURG on macOS).

Rule: for any non-trivial body (multi-line, or containing markdown / code fences / backticks / pipes / tables), bypass entity commands. Save the full request payload to $PWD/tmp/ first, then POST via tea api.

Issues and issue comments are already wrapped — use /kettle:sync rather than hand-rolling their JSON. .kettle/payload/ is kettle's own scratchpad and is written by kettle only; do not put hand-made bodies there. The procedure below covers everything else.

Procedure

  1. Ensure the target dir exists: mkdir -p tmp/{kind} where {kind} is pull, release, etc.
  2. Write the complete request body as JSON to $PWD/tmp/{kind}/<slug>.json. One file = one request. Use a quoted heredoc to avoid shell expansion:
    mkdir -p tmp/release
    cat > tmp/release/v0-2-0.json <<'EOF'
    {"tag_name": "v0.2.0", "name": "v0.2.0", "body": "## Changes\n\nMulti-line markdown with `code`."}
    EOF
    
    Newlines inside the body must be encoded as \n in the JSON string. If composing programmatically, pipe through jq -Rs '{body: .}' < body.md > tmp/release/v0-2-0.json.
  3. POST with tea api, passing the file with -d @<path>:
    tea api -X POST -d @tmp/release/v0-2-0.json repos/{owner}/{repo}/releases
    
  4. Keep the file. tmp/ should be gitignored; the saved payload is useful for retries, edits (PATCH), and debugging failed posts.

Common endpoints

Action Method + endpoint
Create PR POST repos/{owner}/{repo}/pulls
Edit PR body or title PATCH repos/{owner}/{repo}/issues/{n}
Comment on a PR POST repos/{owner}/{repo}/issues/{n}/comments
Edit comment PATCH repos/{owner}/{repo}/issues/comments/{id}
Create release POST repos/{owner}/{repo}/releases
Create milestone POST repos/{owner}/{repo}/milestones

Short single-line bodies (e.g. tea comment 42 "lgtm") are still fine via entity commands.

Tips

  • Pass -o json for structured output when parsing programmatically — on entity commands only. On tea api, -o is a file name: -o json writes the response body to a file called json and leaves stdout empty. The response is already JSON, so there is nothing to format; use - for stdout, or leave the flag off.
  • Use --fields, -f to narrow columns.
  • Pagination: --page, -p <n> and --limit, --lm <n> (defaults 1 / 30).
  • A tea command that fails on identity is a login problem in tea's own config, never in kettle's — tea logins list, and the operator decides.