--- name: use description: Reference docs for the `tea` CLI — Gitea's command-line client. Load when the user asks about Gitea repos, issues, pulls, releases, actions, 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. --- # /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. ## 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 ` 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 1. Identify the entity in the request: issues, pulls, labels, milestones, releases, times, repos, branches, actions, webhooks, comments, notifications, etc. 2. Find the matching command in the index below. 3. Run it via Bash with the placeholder login, e.g. `tea issues 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`. ## Issues: work on local files, not on live `tea` calls Never run `tea issues -o json` or `tea api .../issues/` to read an issue — the full JSON payload (avatars, nested user objects, every comment body) lands in your context whether you need it or not. Use the scripts in `/scripts/`. They pull issues into a flat, greppable cache under `$PWD/tmp/issues/` and print only a compact index. This is a **cache, not a mirror**: nothing tracks drift, nothing syncs back. Refetch when you need current data; the `fetched:` field tells you the age. | Script | Network | What it does | |---|---|---| | `issue_get.py ` or `issue_get.py --milestone M \| --label L \| -q TEXT` | yes | fetch issue(s) → `tmp/issues/.md` (+ `.comments.md`, `tree-.md`) | | `issue_list.py [--state] [--label] [--milestone] [-q TEXT]` | yes | discovery: one line per issue to stdout, writes nothing | | `issue_push.py \|--all [--keep] [--dry-run]` | yes | validate a draft, create labels, POST the issue, delete the draft | | `issue_index.py` | no | rebuild `tmp/issues/INDEX.md` (auto after get/push) | ``` tmp/issues/INDEX.md table of everything cached — read this first tmp/issues/42.md metadata block + `# Title` + body tmp/issues/42.comments.md comments (only with --comments) tmp/issues/tree-40.md dependency map (only with --deps) tmp/issues/drafts/.md issues not yet created in Gitea ``` Key forms for ``: `42`, `#42`, `owner/repo#42`, or a full issue URL. Repo defaults to the current directory's git remote (add `--repo owner/repo` outside one). No `--login` on any script call: they resolve the operator's pin from `.claude/settings.local.json` themselves — same source as the tea-guard hook. No pin → exit with a pointer to `/tea:auth`. ### Fetching a whole set: milestone, label, search Do not loop `issue_get.py` over numbers to pull a group — pass the filter. The list endpoint carries the issue bodies, so a milestone costs **one request per 50 issues**, not one per issue: ```bash python3 /scripts/issue_get.py --milestone 6 # id or title python3 /scripts/issue_get.py --milestone v0.2 --deps python3 /scripts/issue_get.py --label type/bug --label comp/hooks --state all python3 /scripts/issue_get.py -q sqlc --limit 20 ``` Filters AND together; `--state` defaults to `open`; `--limit` defaults to 100. Keys and filters are mutually exclusive. `--comments` stays single-issue — loop over the numbers when a whole thread set is needed. Two traps this handles for you: - **Gitea silently ignores an unresolvable milestone filter** and returns the whole backlog. The script resolves the milestone first (exits listing the real ones if it does not exist) and re-checks every returned issue locally. Never trust a raw `tea api ...issues?milestones=X` call for this. - **Projects are not fetchable.** The projects API is not exposed (404 on Gitea 1.26 for `repos/…/projects`, `orgs/…/projects`, `projects/{id}`). Use milestones or labels; project columns live in the web UI only. After a filtered fetch, `INDEX.md` carries a `milestone` column, and the cache is greppable by it: `grep -l 'milestone: v0.2' tmp/issues/*.md`. ### Working a feature as one document `--deps` walks the dependency graph **downwards** — the structured `## Depends on` and `## Issues` sections plus Gitea's native dependencies. Prose `#N` mentions are ignored on purpose, or the walk would drag in half the backlog. Comments are not fetched during a walk (loop over the numbers if you need them). ```bash python3 /scripts/issue_get.py 40 --deps # feature + children ``` Read `tree-40.md` once for the shape (a filtered fetch writes one forest, `tree-.md`), then grep the files as one document: ```bash grep -ln 'depends:.*#42' tmp/issues/*.md # who depends on #42 (upwards) grep -l 'labels:.*type/bug' tmp/issues/*.md # all cached bugs grep -A3 '## Acceptance criteria' tmp/issues/4*.md grep -c '^- \[ \]' tmp/issues/42.md # open checkboxes ``` Metadata is written one field per line with inline lists (`labels: [a, b]`) precisely so plain grep works without a parser. ### Creating issues: draft locally, push once During planning write drafts to `tmp/issues/drafts/.md` — no network, no `tea` call. A draft is the metadata block with `labels:` only, plus the canonical body: ```markdown --- labels: [type/task, tech/sql] --- # Wire sqlc into the appclick repo layer ## Summary ... ``` When the plan is agreed, `issue_push.py` validates the format (exactly one `type/*`, English title without a type prefix, `## Summary` / `## Spec` / `## Acceptance criteria` present), creates missing labels with the right colors and exclusivity, POSTs, prints the URL and **deletes the draft** — the issue lives in Gitea now. `--keep` writes `tmp/issues/.md` instead; `--dry-run` validates without touching the network. Guided procedure: `/tea:issue`. ## Index - [tea CLI overview](references/tea/index.md) — global flags, common options, output formats - [ENTITIES](references/tea/entities.md) — issues, pulls, labels, milestones, releases, times, repos, branches, actions, webhooks, comment - [HELPERS](references/tea/helpers.md) — open, notifications, clone, api - [MISC](references/tea/misc.md) — whoami, admin - [SETUP](references/tea/setup.md) — logins, logout, ssh-keys - [ISSUE FORMAT](references/issue-format.md) — canonical issue format: label namespaces (`type/*`, `severity/*` exclusive; `tech/*`, `comp/*` free), types `bug|task|refactor|test|feature|draft`, templates, dependencies, title and language rules. MANDATORY whenever creating or editing an issue; the `/tea:issue` skill is the guided procedure for it. ## Rich payloads — write to `$PWD/tmp/` first, then `tea api` Entity subcommands (`tea comment`, `tea issues create`, `tea pulls 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`. Issue creation is already wrapped: use `issue_push.py` (above) instead of hand-rolling the JSON. The procedure below covers everything else — comments, pulls, releases, and PATCHes to existing issues. ### Procedure 1. Ensure the target dir exists: `mkdir -p tmp/{kind}` where `{kind}` is `comment`, `issue`, `pull`, `release`, etc. 2. Write the **complete request body as JSON** to `$PWD/tmp/{kind}/.json`. One file = one request. Use a quoted heredoc to avoid shell expansion: ```bash mkdir -p tmp/comment cat > tmp/comment/issue-60.json <<'EOF' {"body": "## Heading\n\nMulti-line markdown with `code`, | tables |, and ```fences```."} 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/comment/issue-60.json`. 3. POST with `tea api`, passing the file with `-d @`: ```bash tea api --login "$GITEA_LOGIN" \ -X POST -d @tmp/comment/issue-60.json \ repos/{owner}/{repo}/issues/60/comments ``` 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 | |---|---| | Comment on issue/PR | `POST repos/{owner}/{repo}/issues/{n}/comments` | | Edit comment | `PATCH repos/{owner}/{repo}/issues/comments/{id}` | | Create issue | `POST repos/{owner}/{repo}/issues` | | Edit issue/PR body or title | `PATCH repos/{owner}/{repo}/issues/{n}` | | Create PR | `POST repos/{owner}/{repo}/pulls` | | Create release | `POST repos/{owner}/{repo}/releases` | 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 json` for structured output when parsing programmatically. - Use `--fields, -f` to narrow columns. - Pagination: `--page, -p ` and `--limit, --lm ` (defaults 1 / 30). - If a `tea` command is blocked by `tea-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`).