tea and tdl were two repositories, each carrying its own
.claude-plugin/marketplace.json — two marketplaces to register for what
is one collection. Fold them into one.
The repo root is now the marketplace and nothing else: a single
.claude-plugin/marketplace.json whose entries point at ./plugins/tea and
./plugins/tdl. A plugin's root is its own directory under plugins/, so
${CLAUDE_PLUGIN_ROOT} still resolves inside it and every path a plugin
uses stays relative to itself — the hooks and the test roots needed no
adjustment beyond the move.
tea's files move with git mv, so its history and blame follow. tdl
arrives as a plain copy; its history stays in claude-skills/threedotslab.
test_payload_root asserted `tmp/` was ignored by REPO/.gitignore. The
rule is that tmp/ is ignored, not which file says so, and git reads every
.gitignore on the way up — so the test now walks up to the repo root the
same way git does.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
7.8 KiB
name: use
description: Reference docs for the tea CLI — Gitea's command-line client. Load when the user asks about Gitea repos, pulls, releases, milestones, labels, actions, webhooks, or other Gitea entities, to look up the right tea command and flags. Always write the login as the literal placeholder --login "$GITEA_LOGIN" — the tea-guard hook substitutes the operator-pinned login; set it with /tea:auth. Issues are NOT handled here: use /tea:issue to work on them and /tea:sync to move them to and from Gitea.
/tea:use — tea CLI reference
Reference material for the tea CLI (Gitea's official command-line client).
Use these docs to look up commands, flags, filters, and output fields before
running tea via Bash.
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 |
|---|---|
/tea:issue |
issues as units of work — create, read, grep, validate, dependency graph. Offline. |
/tea:sync |
moving issues between the local store and Gitea — pull, push, comment. |
This skill covers everything else Gitea has: pulls, releases, milestones, labels, repos, branches, actions, webhooks, notifications, times.
Login: always write the placeholder, never a name (enforced)
Every tea invocation that touches Gitea MUST carry the login as the literal
placeholder --login "$GITEA_LOGIN" (or -l "$GITEA_LOGIN"). Do not
substitute an actual login name yourself.
The tea-guard PreToolUse hook enforces this and resolves it:
- no
--login→ blocked. --login "$GITEA_LOGIN"→ the hook reads the operator's pinned login from.claude/settings.local.json(env.GITEA_LOGIN) at call time and rewrites the command to use that literal before it runs.--login <some-name>or any other variable → blocked. You may not choose the login; only the operator does (via/tea:auth).- no login pinned → blocked with a pointer to run
/tea:auth.
Why: without an explicit login tea silently falls back to the machine's
default (possibly the user's personal account), and a login you pick may be
the wrong identity. Pinning is the operator's decision; the hook guarantees it.
The pin takes effect immediately — no restart. Only tea logins list and
tea --version/--help are exempt from the guard.
How to use
- Identify the entity in the request: pulls, labels, milestones, releases, times, repos, branches, actions, webhooks, notifications, etc.
- Find the matching command in the index below.
- Run it via Bash with the placeholder login, e.g.
tea pulls list --login "$GITEA_LOGIN" --repo owner/repo --state open. (The hook rewrites"$GITEA_LOGIN"to the operator-pinned login.)
tea auto-detects owner/repo from $PWD inside a git repo; otherwise pass
--repo owner/repo (or -r). Login is not auto-detected — it is pinned
per-project by the operator (see /tea:auth) and injected by the guard.
Config lives in $XDG_CONFIG_HOME/tea.
--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 --login "$GITEA_LOGIN" --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 --login "$GITEA_LOGIN" --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 --login "$GITEA_LOGIN" -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 moved to
../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 $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 /tea:sync rather than
hand-rolling their JSON. The procedure below covers everything else.
Procedure
- Ensure the target dir exists:
mkdir -p tmp/{kind}where{kind}ispull,release, etc. - 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:Newlines inside the body must be encoded asmkdir -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\nin the JSON string. If composing programmatically, pipe throughjq -Rs '{body: .}' < body.md > tmp/release/v0-2-0.json. - POST with
tea api, passing the file with-d @<path>:tea api --login "$GITEA_LOGIN" \ -X POST -d @tmp/release/v0-2-0.json \ repos/{owner}/{repo}/releases - 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" --login "$GITEA_LOGIN")
are still fine via entity commands. Always the placeholder, never a login name.
Tips
- Pass
-o jsonfor structured output when parsing programmatically — on entity commands only. Ontea api,-ois a file name:-o jsonwrites the response body to a file calledjsonand leaves stdout empty. The response is already JSON, so there is nothing to format; use-for stdout, or leave the flag off. - Use
--fields, -fto narrow columns. - Pagination:
--page, -p <n>and--limit, --lm <n>(defaults 1 / 30). - If a
teacommand is blocked bytea-guard: either you forgot--login "$GITEA_LOGIN", you wrote a literal login name instead of the placeholder (not allowed — let the guard substitute), or no login is pinned (run/tea:auth).