fix(gitea): restore the withLines exception and route rename_branch through the orchestrator

gitea-files' always-loaded Gotchas said "content is base64 both ways" without
qualification. The `main` text carried an exception for `withLines: true` and both
halves were dropped. Verified live: `get_file_contents` with `withLines: true`
returns plain JSON text while the same response still reports `"encoding":"base64"`.
An agent that follows the recommendation two sentences later and applies the
unconditional decode gets garbage, with the response's own field confirming the
wrong answer. Exception restored, and the lying field named.

gitea-orchestrate was never updated for `rename_branch`: absent from the operation
enum, so an agent caller got "unknown operation", and absent from the
destructive-confirm list, though branches.md requires a rename with open PRs or a
protection rule to be confirmed exactly as `delete_branch` is. Added to both — the
confirm gate rather than the enum alone, because accepting the operation without it
routes around a rule the skill states while appearing to support it. The
compatibility frontmatter, which the agent reads, still omitted the tool too.

Two more always-loaded Gotchas contradicted their own reference files, and the
Gotcha was wrong both times: issues and PRs are distinguishable on a list item by
the `html_url` path segment (confirmed live — #129 at /pulls/, #128 at /issues/),
and `get_repository_tree` takes `tree_sha`, not `ref`.

`review_comments` was asserted as unconditionally present on the PR get response.
It is absent on a PR with no review comments, so the claim is downgraded to
present-when-non-zero rather than stated as response shape.

The label-exclusivity relocation moved the rule out of label-inference.md and into
labels.md without updating sources.md, leaving the one rule in this branch that
writes differently to live repos citing a file that no longer carries it. The rule
itself is correct as it stands and `main` was wrong — every Kind/* label on this
instance is exclusive:false, every Priority/* and Status/* is true — so only the
provenance record is corrected.

Routing: gitea-workflow lost the human-caller discriminator and widened from status
checks to any request, which sent "close #42" to a branch that resolves the number
and presents detail without ever closing it. gitea-branches and gitea-issues regain
trigger phrasings the retrofit dropped.

Refs: #92
This commit is contained in:
2026-09-01 12:38:53 +00:00
parent 20e5627fd7
commit be9b8d277f
22 changed files with 66 additions and 44 deletions

View File

@@ -23,6 +23,7 @@ You resolve `owner`/`repo` once per session (via `git remote -v` on `origin`) an
These are non-negotiable regardless of `confirm` or any skill-local override:
- Never delete the repository's default branch (typically `main` or `master`) — refused outright, independent of `confirm`.
- `delete_release` takes a numeric `id`; `delete_tag` takes a `tag_name` string. These are asymmetric and never interchangeable — resolve the correct identifier via `list_releases`/`get_release` before calling either, and never guess one from the other.
- `rename-branch` is gated like a delete even though it destroys nothing: what a rename does to open PRs using the branch as head or base, to a matching protection rule, and to every other clone's tracking branch is unconfirmed by `gitea-branches`' sources. Require `confirm: true`, and verify the PR and protection sides afterwards.
- Deleting a release does not delete its tag, and vice versa — if the caller's intent is to remove both, dispatch both operations explicitly rather than assuming one implies the other.
- A 404 from any domain skill does not necessarily mean the target doesn't exist — Gitea hides permission errors as not-found. Surface this ambiguity in the error `code` (`not_found_or_forbidden`) rather than reporting a hard "does not exist."
- Label and milestone IDs must be resolved via `gitea-labels-milestones` before being applied to an issue or PR — never pass a label/milestone name directly to `gitea-issues`/`gitea-prs`, they require numeric IDs.
@@ -43,7 +44,7 @@ Sub-skills carry their own local copies of relevant gotchas for humans who invok
When invoked, you:
1. Parse the incoming workflow request (operation type, parameters, context overrides)
2. Check safety gates: if the operation is destructive (delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr) and the request lacks explicit `confirm: true`, fail immediately with "requires explicit confirmation"; deleting the default branch is refused outright regardless of `confirm`
2. Check safety gates: if the operation is destructive (rename-branch, delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr) and the request lacks explicit `confirm: true`, fail immediately with "requires explicit confirmation"; deleting the default branch is refused outright regardless of `confirm`
3. Route to the appropriate domain skill: `gitea-issues`, `gitea-labels-milestones`, `gitea-prs`, `gitea-branches`, `gitea-files`, `gitea-releases`
4. Manage session context: resolve and carry forward `owner`/`repo` and any cached number-space resolutions, passing them explicitly to each skill
5. Handle error recovery: for recoverable failures (rate limiting, transient 5xx, pagination gaps) retry or complete the operation; for ambiguous 404s, attempt the permission-vs-not-found disambiguation before failing
@@ -55,12 +56,12 @@ When invoked, you:
- issues: list-issues, get-issue, create-issue, update-issue, comment-issue, search-issues
- labels/milestones: list-labels, create-label, update-label, delete-label, list-milestones, create-milestone, update-milestone, close-milestone, delete-milestone, resolve-labels
- prs: list-prs, get-pr, create-pr, update-pr, close-pr, reopen-pr, merge-pr, review-pr
- branches/commits: list-branches, create-branch, delete-branch, list-commits, get-commit
- branches/commits: list-branches, create-branch, rename-branch, delete-branch, list-commits, get-commit
- files: get-file, get-dir, get-tree, write-file, delete-file
- releases/tags: list-releases, get-release, create-release, delete-release, list-tags, create-tag, delete-tag
- **parameters:** object, operation-specific arguments (issue/PR number, title, body, label names, tag name, file path, etc.)
- **context:** object (optional), session state to carry forward (`owner`, `repo`, cached number-space resolutions)
- **confirm:** boolean (optional), explicit confirmation for destructive operations (required if not set for delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr)
- **confirm:** boolean (optional), explicit confirmation for destructive operations (required if not set for rename-branch, delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr)
## Process

View File

@@ -3,11 +3,12 @@ name: gitea-branches
description: >
Use when listing, creating, renaming, or deleting branches in a Gitea repository,
or reading its commit history — even when the user does not say "Gitea". Not a
or reading its commit history — "what commits are on this branch", "what changed
in that commit" — even when the user does not say "Gitea". Not a
local checkout's branches -> `git-branches`. Not local history ->
`git-history`. Not a PR's head or base -> `gitea-prs`.
compatibility: Requires Gitea MCP server configured with a token with write:repository scope; this is confirmed to gate list_branches, create_branch, and delete_branch (Gitea gates reads behind write scope for repo-scoped operations), and is inferred by analogy (not explicitly confirmed by source docs) to also gate list_commits and get_commit. Requires git remote "origin" pointing to the Gitea instance.
compatibility: Requires Gitea MCP server configured with a token with write:repository scope; this is confirmed to gate list_branches, create_branch, and delete_branch (Gitea gates reads behind write scope for repo-scoped operations), and is inferred by analogy (not explicitly confirmed by source docs) to also gate rename_branch, list_commits, and get_commit. Requires git remote "origin" pointing to the Gitea instance.
metadata:
category: integration

View File

@@ -23,8 +23,8 @@ allowed-tools: mcp__gitea__get_file_contents mcp__gitea__get_dir_contents mcp__g
## Gotchas
- **A 404 may mean an under-scoped token, not a missing path.** Every tool here gates on `write:repository`, and Gitea masks insufficient scope as 404. Check scopes first.
- **Reads take `ref`, writes take `branch_name`.** One concept, two parameter names — chaining a read into a write drops the branch if you carry the wrong key.
- **`content` is base64 both ways.** Encode before a write, decode after a read.
- **Reads take `ref` (`tree_sha` on `get_repository_tree`), writes take `branch_name`.** One concept, three names — carry the wrong key and the branch is dropped.
- **`content` is base64 both ways — except under `withLines: true`.** Encode before a write, decode after a read; but with `withLines: true` `content` is already plain JSON text and the reported `"encoding": "base64"` is a lie. Decoding it yields garbage.
## Inputs

View File

@@ -14,9 +14,13 @@ All three read calls select what to read with `ref` — a branch name, tag, or c
`get_file_contents(owner, repo, ref, path)`.
The response carries the file's `sha` at the **top level**, not nested under `content`. That field
is the write-ready SHA, so capture it whenever a write may follow. Content comes back
base64-encoded — decode it. Pass `withLines: true` only when you need numbered lines to quote
specific lines back to the user; omit it for a normal content fetch.
is the write-ready SHA, so capture it whenever a write may follow.
Content comes back base64-encoded — decode it — **unless `withLines: true` was passed**, in which
case `content` is already plain text: a JSON array of `{"line": N, "content": "..."}` objects.
The response reports `"encoding": "base64"` either way, so that field is wrong under `withLines`
and decoding on its word yields garbage. Pass `withLines: true` only when you need numbered lines
to quote specific lines back to the user; omit it for a normal content fetch.
## One directory level

View File

@@ -3,8 +3,8 @@ name: gitea-issues
description: >
Use when reading or writing Gitea issues — "create an issue", "what issues are open",
"close issue #N", "comment on issue #N", "search issues for X" — even when the user does not
say "Gitea". Not pull requests -> `gitea-prs`.
"close issue #N", "comment on issue #N", "label issue #N", "search issues for X" — even when
the user does not say "Gitea". Not pull requests -> `gitea-prs`.
Not label or milestone definitions -> `gitea-labels-milestones`.
compatibility: Requires Gitea MCP server configured with write:issue and write:repository token
@@ -26,7 +26,7 @@ allowed-tools: Bash mcp__gitea__list_issues mcp__gitea__issue_read mcp__gitea__i
## Gotchas
- **`list_issues` mixes in PRs unless you filter.** Issues and PRs share one repo number space; pass `type: "issues"` to exclude PRs (or `"pulls"` for only PRs). Nothing on a list item flags which is which — `is_pull` appears only on `issue_read method: "get"`.
- **`list_issues` mixes in PRs unless you filter.** Issues and PRs share one number space; pass `type: "issues"` to exclude PRs (or `"pulls"`). `is_pull` is returned only by `issue_read method: "get"` — on a list item the only tell is `html_url`'s path segment (`/issues/` vs `/pulls/`).
- **Label IDs and names are not interchangeable.** `issue_write` takes numeric IDs only; `list_issues` and `search_issues` filter by name; `issue_read "get"` returns names but `"get_labels"` returns full objects with IDs. Resolve via `gitea-labels-milestones` unless the caller named exact labels.
- **A merge does not itself close the issue.** Gitea has no close-on-merge event, but a `Fixes #N` in the merged commits can, depending on merge style (`gitea-prs`). Re-read its state after a merge before closing it manually.
- **A 404 may really be a 403.** Gitea hides permission errors as not-found — check the token's `write:issue` scope before concluding the issue does not exist.

View File

@@ -3,6 +3,7 @@ topic: labels
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
- context7-websites-gitea
---
# Label operations

View File

@@ -21,7 +21,7 @@
- **URL:** context7:/websites/gitea
- **Description:** Official Gitea docs mirror on Context7 (docs.gitea.com content) — scoped/exclusive label conventions and milestone/label state-transition semantics
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** SKILL.md, references/label-inference.md
- **Contributing files:** SKILL.md, references/labels.md, references/label-inference.md
- **Status:** `extracted`
## context7-gitea-tea-cli

View File

@@ -36,7 +36,7 @@ List responses trim PRs down to summary fields — `head`/`base` are bare ref st
`"get"`, `"get_diff"`, `"get_files"`, and `"get_status"` are covered here. `"get_reviews"`, `"get_review"`, and `"get_review_comments"` are covered in `references/reviews.md`.
- `"get"` returns the full PR object: state, draft, merged, mergeable flags; `head`/`base` as full objects (`{ref, sha, repo?}`); `milestone` as a bare title string (not `{id, title}`); and `review_comments` as an integer count, not comment objects (see `references/reviews.md`).
- `"get"` returns the full PR object: state, draft, merged, mergeable flags; `head`/`base` as full objects (`{ref, sha, repo?}`); `milestone` as a bare title string (not `{id, title}`); and `review_comments`, *when present*, as an integer count rather than comment objects — it was absent from a live `"get"` on a PR with no inline comments, so verify the key before reading it (see `references/reviews.md`).
- `"get_diff"` returns raw diff text.
- `"get_files"` returns the list of changed file objects.
- `"get_status"` returns the combined commit status for the PR's head commit — CI result only, not review/approval state (see `references/merging.md`).

View File

@@ -49,6 +49,6 @@ Get the `comment_id` from `pull_request_read method: "get_review_comments"`. Cal
- `method: "get_review"` (requires `review_id` — omitting it fails with `review_id is required`) — single review detail.
- `method: "get_review_comments"` (`review_id` **optional** — omit it to list every inline comment on the PR in one call, rather than one review's) — array of inline comments: `id`, `body`, `path`, `position`, `old_position`, `diff_hunk`, `user`, `html_url`, `created_at`, `updated_at`.
**`review_comments` on the `"get"` response is a count, not the comments.** The full PR object returned by `pull_request_read method: "get"` carries `review_comments` as an integer — the number of inline review comments. It is distinct from the `get_review_comments` method above, which returns the actual comment objects; reading the count is no substitute for that call. Older gitea-mcp releases misspelled this key as `review_scomments`; the misspelling was corrected upstream and the deployed v1.7.0 response carries no such key, so treat any instruction that reaches for `review_scomments` as stale.
**`review_comments` on the `"get"` response is a count, not the comments — and it may be absent.** Where the full PR object returned by `pull_request_read method: "get"` carries `review_comments`, it is an integer: the number of inline review comments. Presence is not guaranteed. A live `"get"` against a PR with zero inline comments carried no such key at all — only `comments`, which counts issue-style comments, not review ones. Treat it as present only when non-zero, and check for the key before reading it rather than assuming the response shape. Either way it is distinct from the `get_review_comments` method above, which returns the actual comment objects; reading the count is no substitute for that call. Older gitea-mcp releases misspelled this key as `review_scomments`; the misspelling was corrected upstream and the deployed v1.7.0 response carries no such key, so treat any instruction that reaches for `review_scomments` as stale.
**Inline-comment field names differ between write and read.** The `comments` array on `pull_request_review_write method: "create"` uses `old_line_num`/`new_line_num`. The `get_review_comments` read response uses different field names for the same concept — `position` (new-side line) and `old_position` (old-side line). Do not assume the same key names apply on both sides of the round trip.

View File

@@ -2,11 +2,11 @@
name: gitea-workflow
description: >
Use when a Gitea request is general or ambiguous — a no-args repo check-in, a bare number that
could be an issue or a PR, or a capability whose owning skill is unclear. Resolves which
domain skill applies. Not an unambiguous issue request -> `gitea-issues`. Not an
unambiguous PR request -> `gitea-prs`. Not local git work with no Gitea component ->
`git-workflow`.
Use when a human wants an ambiguous Gitea status check — a no-args check-in, a bare number
asked *about* without saying issue or PR ("status of #42"), or a capability whose owning skill
is unclear. Not an agent caller -> `gitea-orchestrate`. Not a stated action on a number
("close #42") -> `gitea-issues`. Not an unambiguous PR request -> `gitea-prs`. Not local-only
git -> `git-workflow`.
compatibility: Requires Gitea MCP server configured with a token; delegates all calls to the six
domain skills, which in turn require write:issue and write:repository scopes at minimum.
@@ -31,9 +31,11 @@ The invocation's shape selects exactly one branch.
| Invocation shape | Flow | Reference |
|---|---|---|
| No arguments, no specific request | Repo status check-in | `references/status-checkin.md` |
| A bare number, with neither "issue" nor "PR" said | Resolve which domain the number belongs to | `references/number-resolution.md` |
| A bare number the user asks *about*, with neither "issue" nor "PR" said and no action stated | Resolve which domain the number belongs to | `references/number-resolution.md` |
| A named capability whose owning skill is unclear | Route to the domain skill that owns it | `references/skill-index.md` |
A bare number carrying a stated action ("close #42", "merge #42", "label #42") is not row 2: that is a write, and row 2 only presents detail. Resolve the domain per `references/number-resolution.md`, then hand the action to `gitea-issues` or `gitea-prs` to perform.
Read only the reference file matching the selected branch — each is self-contained for its concern.
## Report

View File

@@ -16,4 +16,6 @@ The user has referenced a bare number without saying "issue" or "PR" (e.g. "what
- `false` or absent → it's an issue. Present the issue detail already retrieved.
3. If the resolution call 404s, don't conclude the number doesn't exist. Gitea hides permission errors as not-found (documented in `gitea-issues`' Gotchas), so report the 404 and suggest verifying the token carries `write:issue` rather than reporting "no such issue or PR."
If the user stated an action on the number rather than asking about it, resolution is only step one: hand the action, with the resolved domain, to `gitea-issues` or `gitea-prs` to carry out. Presenting detail is not a substitute for performing the write.
Then report per `SKILL.md`'s Report section, saying which domain the number turned out to be before showing detail ("That's a pull request:" / "That's an issue:") — otherwise the user cannot tell the resolution happened.

View File

@@ -23,6 +23,7 @@ You resolve `owner`/`repo` once per session (via `git remote -v` on `origin`) an
These are non-negotiable regardless of `confirm` or any skill-local override:
- Never delete the repository's default branch (typically `main` or `master`) — refused outright, independent of `confirm`.
- `delete_release` takes a numeric `id`; `delete_tag` takes a `tag_name` string. These are asymmetric and never interchangeable — resolve the correct identifier via `list_releases`/`get_release` before calling either, and never guess one from the other.
- `rename-branch` is gated like a delete even though it destroys nothing: what a rename does to open PRs using the branch as head or base, to a matching protection rule, and to every other clone's tracking branch is unconfirmed by `gitea-branches`' sources. Require `confirm: true`, and verify the PR and protection sides afterwards.
- Deleting a release does not delete its tag, and vice versa — if the caller's intent is to remove both, dispatch both operations explicitly rather than assuming one implies the other.
- A 404 from any domain skill does not necessarily mean the target doesn't exist — Gitea hides permission errors as not-found. Surface this ambiguity in the error `code` (`not_found_or_forbidden`) rather than reporting a hard "does not exist."
- Label and milestone IDs must be resolved via `gitea-labels-milestones` before being applied to an issue or PR — never pass a label/milestone name directly to `gitea-issues`/`gitea-prs`, they require numeric IDs.
@@ -43,7 +44,7 @@ Sub-skills carry their own local copies of relevant gotchas for humans who invok
When invoked, you:
1. Parse the incoming workflow request (operation type, parameters, context overrides)
2. Check safety gates: if the operation is destructive (delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr) and the request lacks explicit `confirm: true`, fail immediately with "requires explicit confirmation"; deleting the default branch is refused outright regardless of `confirm`
2. Check safety gates: if the operation is destructive (rename-branch, delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr) and the request lacks explicit `confirm: true`, fail immediately with "requires explicit confirmation"; deleting the default branch is refused outright regardless of `confirm`
3. Route to the appropriate domain skill: `gitea-issues`, `gitea-labels-milestones`, `gitea-prs`, `gitea-branches`, `gitea-files`, `gitea-releases`
4. Manage session context: resolve and carry forward `owner`/`repo` and any cached number-space resolutions, passing them explicitly to each skill
5. Handle error recovery: for recoverable failures (rate limiting, transient 5xx, pagination gaps) retry or complete the operation; for ambiguous 404s, attempt the permission-vs-not-found disambiguation before failing
@@ -55,12 +56,12 @@ When invoked, you:
- issues: list-issues, get-issue, create-issue, update-issue, comment-issue, search-issues
- labels/milestones: list-labels, create-label, update-label, delete-label, list-milestones, create-milestone, update-milestone, close-milestone, delete-milestone, resolve-labels
- prs: list-prs, get-pr, create-pr, update-pr, close-pr, reopen-pr, merge-pr, review-pr
- branches/commits: list-branches, create-branch, delete-branch, list-commits, get-commit
- branches/commits: list-branches, create-branch, rename-branch, delete-branch, list-commits, get-commit
- files: get-file, get-dir, get-tree, write-file, delete-file
- releases/tags: list-releases, get-release, create-release, delete-release, list-tags, create-tag, delete-tag
- **parameters:** object, operation-specific arguments (issue/PR number, title, body, label names, tag name, file path, etc.)
- **context:** object (optional), session state to carry forward (`owner`, `repo`, cached number-space resolutions)
- **confirm:** boolean (optional), explicit confirmation for destructive operations (required if not set for delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr)
- **confirm:** boolean (optional), explicit confirmation for destructive operations (required if not set for rename-branch, delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr)
## Process

View File

@@ -3,11 +3,12 @@ name: gitea-branches
description: >
Use when listing, creating, renaming, or deleting branches in a Gitea repository,
or reading its commit history — even when the user does not say "Gitea". Not a
or reading its commit history — "what commits are on this branch", "what changed
in that commit" — even when the user does not say "Gitea". Not a
local checkout's branches -> `git-branches`. Not local history ->
`git-history`. Not a PR's head or base -> `gitea-prs`.
compatibility: Requires Gitea MCP server configured with a token with write:repository scope; this is confirmed to gate list_branches, create_branch, and delete_branch (Gitea gates reads behind write scope for repo-scoped operations), and is inferred by analogy (not explicitly confirmed by source docs) to also gate list_commits and get_commit. Requires git remote "origin" pointing to the Gitea instance.
compatibility: Requires Gitea MCP server configured with a token with write:repository scope; this is confirmed to gate list_branches, create_branch, and delete_branch (Gitea gates reads behind write scope for repo-scoped operations), and is inferred by analogy (not explicitly confirmed by source docs) to also gate rename_branch, list_commits, and get_commit. Requires git remote "origin" pointing to the Gitea instance.
metadata:
category: integration

View File

@@ -23,8 +23,8 @@ allowed-tools: mcp__gitea__get_file_contents mcp__gitea__get_dir_contents mcp__g
## Gotchas
- **A 404 may mean an under-scoped token, not a missing path.** Every tool here gates on `write:repository`, and Gitea masks insufficient scope as 404. Check scopes first.
- **Reads take `ref`, writes take `branch_name`.** One concept, two parameter names — chaining a read into a write drops the branch if you carry the wrong key.
- **`content` is base64 both ways.** Encode before a write, decode after a read.
- **Reads take `ref` (`tree_sha` on `get_repository_tree`), writes take `branch_name`.** One concept, three names — carry the wrong key and the branch is dropped.
- **`content` is base64 both ways — except under `withLines: true`.** Encode before a write, decode after a read; but with `withLines: true` `content` is already plain JSON text and the reported `"encoding": "base64"` is a lie. Decoding it yields garbage.
## Inputs

View File

@@ -14,9 +14,13 @@ All three read calls select what to read with `ref` — a branch name, tag, or c
`get_file_contents(owner, repo, ref, path)`.
The response carries the file's `sha` at the **top level**, not nested under `content`. That field
is the write-ready SHA, so capture it whenever a write may follow. Content comes back
base64-encoded — decode it. Pass `withLines: true` only when you need numbered lines to quote
specific lines back to the user; omit it for a normal content fetch.
is the write-ready SHA, so capture it whenever a write may follow.
Content comes back base64-encoded — decode it — **unless `withLines: true` was passed**, in which
case `content` is already plain text: a JSON array of `{"line": N, "content": "..."}` objects.
The response reports `"encoding": "base64"` either way, so that field is wrong under `withLines`
and decoding on its word yields garbage. Pass `withLines: true` only when you need numbered lines
to quote specific lines back to the user; omit it for a normal content fetch.
## One directory level

View File

@@ -3,8 +3,8 @@ name: gitea-issues
description: >
Use when reading or writing Gitea issues — "create an issue", "what issues are open",
"close issue #N", "comment on issue #N", "search issues for X" — even when the user does not
say "Gitea". Not pull requests -> `gitea-prs`.
"close issue #N", "comment on issue #N", "label issue #N", "search issues for X" — even when
the user does not say "Gitea". Not pull requests -> `gitea-prs`.
Not label or milestone definitions -> `gitea-labels-milestones`.
compatibility: Requires Gitea MCP server configured with write:issue and write:repository token
@@ -26,7 +26,7 @@ allowed-tools: Bash mcp__gitea__list_issues mcp__gitea__issue_read mcp__gitea__i
## Gotchas
- **`list_issues` mixes in PRs unless you filter.** Issues and PRs share one repo number space; pass `type: "issues"` to exclude PRs (or `"pulls"` for only PRs). Nothing on a list item flags which is which — `is_pull` appears only on `issue_read method: "get"`.
- **`list_issues` mixes in PRs unless you filter.** Issues and PRs share one number space; pass `type: "issues"` to exclude PRs (or `"pulls"`). `is_pull` is returned only by `issue_read method: "get"` — on a list item the only tell is `html_url`'s path segment (`/issues/` vs `/pulls/`).
- **Label IDs and names are not interchangeable.** `issue_write` takes numeric IDs only; `list_issues` and `search_issues` filter by name; `issue_read "get"` returns names but `"get_labels"` returns full objects with IDs. Resolve via `gitea-labels-milestones` unless the caller named exact labels.
- **A merge does not itself close the issue.** Gitea has no close-on-merge event, but a `Fixes #N` in the merged commits can, depending on merge style (`gitea-prs`). Re-read its state after a merge before closing it manually.
- **A 404 may really be a 403.** Gitea hides permission errors as not-found — check the token's `write:issue` scope before concluding the issue does not exist.

View File

@@ -3,6 +3,7 @@ topic: labels
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
- context7-websites-gitea
---
# Label operations

View File

@@ -21,7 +21,7 @@
- **URL:** context7:/websites/gitea
- **Description:** Official Gitea docs mirror on Context7 (docs.gitea.com content) — scoped/exclusive label conventions and milestone/label state-transition semantics
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** SKILL.md, references/label-inference.md
- **Contributing files:** SKILL.md, references/labels.md, references/label-inference.md
- **Status:** `extracted`
## context7-gitea-tea-cli

View File

@@ -36,7 +36,7 @@ List responses trim PRs down to summary fields — `head`/`base` are bare ref st
`"get"`, `"get_diff"`, `"get_files"`, and `"get_status"` are covered here. `"get_reviews"`, `"get_review"`, and `"get_review_comments"` are covered in `references/reviews.md`.
- `"get"` returns the full PR object: state, draft, merged, mergeable flags; `head`/`base` as full objects (`{ref, sha, repo?}`); `milestone` as a bare title string (not `{id, title}`); and `review_comments` as an integer count, not comment objects (see `references/reviews.md`).
- `"get"` returns the full PR object: state, draft, merged, mergeable flags; `head`/`base` as full objects (`{ref, sha, repo?}`); `milestone` as a bare title string (not `{id, title}`); and `review_comments`, *when present*, as an integer count rather than comment objects — it was absent from a live `"get"` on a PR with no inline comments, so verify the key before reading it (see `references/reviews.md`).
- `"get_diff"` returns raw diff text.
- `"get_files"` returns the list of changed file objects.
- `"get_status"` returns the combined commit status for the PR's head commit — CI result only, not review/approval state (see `references/merging.md`).

View File

@@ -49,6 +49,6 @@ Get the `comment_id` from `pull_request_read method: "get_review_comments"`. Cal
- `method: "get_review"` (requires `review_id` — omitting it fails with `review_id is required`) — single review detail.
- `method: "get_review_comments"` (`review_id` **optional** — omit it to list every inline comment on the PR in one call, rather than one review's) — array of inline comments: `id`, `body`, `path`, `position`, `old_position`, `diff_hunk`, `user`, `html_url`, `created_at`, `updated_at`.
**`review_comments` on the `"get"` response is a count, not the comments.** The full PR object returned by `pull_request_read method: "get"` carries `review_comments` as an integer — the number of inline review comments. It is distinct from the `get_review_comments` method above, which returns the actual comment objects; reading the count is no substitute for that call. Older gitea-mcp releases misspelled this key as `review_scomments`; the misspelling was corrected upstream and the deployed v1.7.0 response carries no such key, so treat any instruction that reaches for `review_scomments` as stale.
**`review_comments` on the `"get"` response is a count, not the comments — and it may be absent.** Where the full PR object returned by `pull_request_read method: "get"` carries `review_comments`, it is an integer: the number of inline review comments. Presence is not guaranteed. A live `"get"` against a PR with zero inline comments carried no such key at all — only `comments`, which counts issue-style comments, not review ones. Treat it as present only when non-zero, and check for the key before reading it rather than assuming the response shape. Either way it is distinct from the `get_review_comments` method above, which returns the actual comment objects; reading the count is no substitute for that call. Older gitea-mcp releases misspelled this key as `review_scomments`; the misspelling was corrected upstream and the deployed v1.7.0 response carries no such key, so treat any instruction that reaches for `review_scomments` as stale.
**Inline-comment field names differ between write and read.** The `comments` array on `pull_request_review_write method: "create"` uses `old_line_num`/`new_line_num`. The `get_review_comments` read response uses different field names for the same concept — `position` (new-side line) and `old_position` (old-side line). Do not assume the same key names apply on both sides of the round trip.

View File

@@ -2,11 +2,11 @@
name: gitea-workflow
description: >
Use when a Gitea request is general or ambiguous — a no-args repo check-in, a bare number that
could be an issue or a PR, or a capability whose owning skill is unclear. Resolves which
domain skill applies. Not an unambiguous issue request -> `gitea-issues`. Not an
unambiguous PR request -> `gitea-prs`. Not local git work with no Gitea component ->
`git-workflow`.
Use when a human wants an ambiguous Gitea status check — a no-args check-in, a bare number
asked *about* without saying issue or PR ("status of #42"), or a capability whose owning skill
is unclear. Not an agent caller -> `gitea-orchestrate`. Not a stated action on a number
("close #42") -> `gitea-issues`. Not an unambiguous PR request -> `gitea-prs`. Not local-only
git -> `git-workflow`.
compatibility: Requires Gitea MCP server configured with a token; delegates all calls to the six
domain skills, which in turn require write:issue and write:repository scopes at minimum.
@@ -31,9 +31,11 @@ The invocation's shape selects exactly one branch.
| Invocation shape | Flow | Reference |
|---|---|---|
| No arguments, no specific request | Repo status check-in | `references/status-checkin.md` |
| A bare number, with neither "issue" nor "PR" said | Resolve which domain the number belongs to | `references/number-resolution.md` |
| A bare number the user asks *about*, with neither "issue" nor "PR" said and no action stated | Resolve which domain the number belongs to | `references/number-resolution.md` |
| A named capability whose owning skill is unclear | Route to the domain skill that owns it | `references/skill-index.md` |
A bare number carrying a stated action ("close #42", "merge #42", "label #42") is not row 2: that is a write, and row 2 only presents detail. Resolve the domain per `references/number-resolution.md`, then hand the action to `gitea-issues` or `gitea-prs` to perform.
Read only the reference file matching the selected branch — each is self-contained for its concern.
## Report

View File

@@ -16,4 +16,6 @@ The user has referenced a bare number without saying "issue" or "PR" (e.g. "what
- `false` or absent → it's an issue. Present the issue detail already retrieved.
3. If the resolution call 404s, don't conclude the number doesn't exist. Gitea hides permission errors as not-found (documented in `gitea-issues`' Gotchas), so report the 404 and suggest verifying the token carries `write:issue` rather than reporting "no such issue or PR."
If the user stated an action on the number rather than asking about it, resolution is only step one: hand the action, with the resolved domain, to `gitea-issues` or `gitea-prs` to carry out. Presenting detail is not a substitute for performing the write.
Then report per `SKILL.md`'s Report section, saying which domain the number turned out to be before showing detail ("That's a pull request:" / "That's an issue:") — otherwise the user cannot tell the resolution happened.