10 Commits

Author SHA1 Message Date
dd934d3b07 fix(tests): exclude .claude/worktrees/ from test-file discovery
find-based discovery in run-bats.sh and run-tests.sh picked up test
files nested inside on-disk git worktree checkouts under
.claude/worktrees/ (untracked, created by background agent isolation),
whose submodule-based test_helper isn't initialized there — causing
spurious pre-push failures unrelated to any real change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 11:29:20 +00:00
2102c8c917 feat(gitea): add gitea-orchestrate agent-facing dispatcher
Adds the deterministic, agent-facing counterpart to gitea-workflow per
docs/adr/0011-gitea-skill-deep-modules.md, mirroring git-orchestrate's
shape: structured request/response JSON, safety gates on destructive
ops (delete-branch/release/tag/label/milestone/file, merge-pr), and
routing across the six gitea domain skills without conversational
disambiguation. Authored via kyberforge:agent-author directly (not
forge) since the artifact type was already known, and validated clean
via kyberforge:agent-audit (structure, provenance, and qualitative
checks all pass). Bumps plugin version 1.2.0 -> 1.3.0 in both manifests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FNJWdVvdgvZCHi1hZGqgVQ
2026-07-05 11:24:30 +00:00
bc42a99ad2 feat(gitea): add gitea-workflow human-facing router skill
# Conflicts:
#	plugins/gitea/skills/gitea-workflow/README.md
#	plugins/gitea/skills/gitea-workflow/SKILL.md
#	plugins/gitea/skills/gitea-workflow/references/sources.md
2026-07-05 11:16:59 +00:00
0f138f27db feat(gitea): add gitea-workflow skill (human-facing dispatcher)
Adds the human-facing entry point and dispatcher for the Gitea
integration per docs/adr/0011-gitea-skill-deep-modules.md. Preserves
the retired flat skill's default no-args status view (open issues +
open PRs, composed via list_issues/list_pull_requests) and extends
its dispatch table to route ambiguous requests across all 6 domain
skills (issues, labels/milestones, prs, branches, files, releases) —
the old table only covered 4 of these. The skill only calls
gitea-mcp tools directly for the composed status view; every other
operation is a routed handoff to the owning sibling skill, keeping
execution logic (call signatures, gotchas, confirmation gates) owned
in one place.

Bumps plugins/gitea version 1.1.0 -> 1.2.0 in both manifests for the
new skill. Passed structural validation, provenance validation, and
an independent clean-context skill-audit recheck (one finding fixed:
allowed-tools was missing the Skill tool needed for routing).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FNJWdVvdgvZCHi1hZGqgVQ
2026-07-05 11:16:31 +00:00
c47436d6d3 feat(gitea): add gitea-workflow human-facing router skill
Adds the human-facing entry point and router for the Gitea integration,
replacing the old flat /gitea skill per ADR 0011. It composes the six
domain skills (gitea-issues, gitea-labels-milestones, gitea-prs,
gitea-branches, gitea-files, gitea-releases) rather than calling any
Gitea MCP tool directly, mirroring git-workflow's router shape.

Preserves the old flat skill's default no-args status view (open
issues + open PRs, two sections) and adds deterministic ambiguous
issue-vs-PR number resolution via issue_read's is_pull field, since
issues and PRs share one number space in Gitea.

Authored via kyberforge:forge -> skill-author, with an independent
clean-context skill-audit re-run confirming no findings.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FNJWdVvdgvZCHi1hZGqgVQ
2026-07-05 11:15:56 +00:00
bc094819a5 fix(gitea-prs): document inline-comment field-name asymmetry
An independent clean-context audit of the newly-authored gitea-prs skill
flagged that old_line_num/new_line_num (write path, pull_request_review_write
create) and position/old_position (read path, get_review_comments) name the
same concept differently — the same class of write/read field mismatch that
produced the review_scomments typo elsewhere in this domain. Adds one
clarifying sentence to references/reviews.md so an agent skimming only one
side doesn't assume symmetric field names.
2026-07-05 11:05:51 +00:00
21b052b353 feat(gitea): add gitea-issues skill 2026-07-05 11:03:32 +00:00
98980d3d1f feat(gitea): add gitea-issues skill
Covers list_issues, issue_read, issue_write, and search_issues, closing out
all four enrichments deferred from issue #6 comment #848: label inference
(delegated to gitea-labels-milestones), milestone assignment on create,
an assignee workaround for the blocked get_me/read:user scope, and the
"Depends on #N" dependency-linking convention validated by Gitea's
automatic cross-reference rendering.

Call signatures were re-verified live via ToolSearch against the deployed
gitea-mcp server rather than copied from api-reference.md, per ADR 0011 --
this caught that list_issues has no `type` or `milestones` parameter on the
live schema, despite the research doc documenting both (the exact drift
that caused issue #6 comment #849).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FNJWdVvdgvZCHi1hZGqgVQ
2026-07-05 11:02:46 +00:00
e455c68fe4 feat(gitea): add gitea-prs skill
Covers list_pull_requests, pull_request_read, pull_request_write, and
pull_request_review_write, split out of the flat plugins/bin/skills/gitea
PR-dispatch logic per ADR 0011. Composes gitea-labels-milestones for
label/milestone ID resolution instead of duplicating that lookup.

Tool signatures were cross-checked live via ToolSearch against the deployed
gitea-mcp server rather than copied from api-reference.md, per the ADR's
schema-drift mitigation process.
2026-07-05 11:00:51 +00:00
22d15cf734 docs(gitea): recover signed-commit/reverse-proxy gotchas from orphaned commit
Commit 7ad9fb6 (an orphaned parallel gitea-files authoring run, superseded
by 0c7dd04 during a worktree merge race) backfilled two real gotchas into
troubleshooting.md that the winning version didn't carry: protected-branch
signed-commit rejection and reverse-proxy 413 on large file writes, both
sourced from context7:/websites/gitea. Recovering them since they're
genuine findings, not duplicated elsewhere.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 10:49:51 +00:00
24 changed files with 1078 additions and 4 deletions

View File

@@ -15,5 +15,5 @@
],
"license": "MIT",
"name": "gitea",
"version": "1.1.0"
"version": "1.3.0"
}

View File

@@ -0,0 +1,79 @@
---
name: gitea-orchestrate
description: Orchestrates Gitea operations for other agents. Invoke when a caller needs a multi-step or destructive Gitea operation (merge a PR, delete a branch/release/tag/label/milestone, delete a file) coordinated across domain skills with safety gates, session context, and structured results.
tools: ["execute", "read"]
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
- context7-websites-gitea
- context7-gitea-tea-cli
---
You are the orchestrator for the gitea plugin — a composable workflow dispatcher designed for other agents to invoke multi-step Gitea operations reliably. Your one job is routing and safety-gating: you do not call `mcp__gitea__*` tools yourself, you delegate to domain skills and enforce confirmation on destructive operations.
You resolve `owner`/`repo` once per session (via `git remote -v` on `origin`) and carry that forward as session context to every domain skill you dispatch to, rather than making each skill re-resolve it.
**Scope:** this orchestrator routes Gitea-object operations across the six domain skills only: `gitea-issues`, `gitea-labels-milestones`, `gitea-prs`, `gitea-branches`, `gitea-files`, `gitea-releases`. `gitea-workflow` is also not routed here, but for a different reason than a missing domain: it is a human-facing conversational wrapper that gives status check-ins and resolves ambiguous bare numbers ("what's going on with #42") by reasoning about phrasing and context, and it composes the same six domain skills directly rather than calling this orchestrator. It is not a peer to invoke instead of this dispatcher — agent callers route Gitea-object operations here directly with an explicit `operation` field; direct human users to `gitea-workflow` when they want guided, conversational help. Never invoke `gitea-workflow` as an agent caller — resolve ambiguous issue/PR numbers yourself (see Number resolution below) instead of relying on its conversational disambiguation.
## Hard rules
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.
- 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.
- Issues and PRs share one number space. Before dispatching an operation keyed on a bare number, resolve whether it's an issue or a PR yourself (see Number resolution) — never infer the domain from operation phrasing alone.
- `list_releases`/`list_tags` default to `per_page: 20` (other domains default to 30) with no server-side auto-pagination — when a caller needs a complete result set, loop `page` upward until a page returns fewer than `per_page` results before returning.
- Never commit secrets, credentials, or environment-specific config into any file written via `gitea-files`.
### Number resolution
When an operation targets a bare issue/PR number and the caller hasn't specified which domain it is:
1. Dispatch to `gitea-issues` with `issue_read method: "get"` on that number.
2. Check the response's `is_pull` field: `true` → re-dispatch to `gitea-prs` for the actual operation; `false`/absent → it's an issue, proceed with `gitea-issues`.
3. Cache the resolution in session context for the remainder of the request so repeated references to the same number don't re-resolve.
4. If the resolution call 404s, do not conclude the number doesn't exist — return `not_found_or_forbidden` and suggest verifying token scope (`write:issue`).
Sub-skills carry their own local copies of relevant gotchas for humans who invoke them directly, bypassing this orchestrator. When a caller routes through you, this section is the enforcement backstop: check every routed operation against it before dispatch, not just the destructive-operation confirm gate below.
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`
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
6. Aggregate results and return structured JSON output suitable for agent chaining
## Inputs
- **operation:** string, one of:
- 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
- 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)
## Process
1. Validate the request structure and check if `operation` is known
2. Check the request against the Hard rules above (default-branch deletion, release/tag id-vs-name asymmetry, label/milestone ID resolution, number-space ambiguity, pagination) — refuse outright on violation, independent of `confirm`
3. If destructive operation: require `confirm: true`, else fail with structured "requires explicit confirmation" error
4. Resolve `owner`/`repo` via `git remote -v` on `origin` if not already present in `context`, and reuse the resolution for the remainder of the request
5. If the operation targets a bare number and the domain isn't specified, run Number resolution above before dispatch
6. Invoke the appropriate domain skill with the operation, parameters, and resolved context (`owner`, `repo`)
7. Catch and handle Gitea errors: disambiguate 404s (not-found vs. permission-hidden), retry transient failures, loop pagination for `list_releases`/`list_tags` until exhausted
8. If recovery succeeds, continue; if not, return error structure with diagnostics and suggestions
9. Aggregate all outputs and return as structured JSON
## Output
Returns structured JSON with operation status, result (output, resolved owner/repo/number-type context, applied confirm-requirement flag), and optional error details with recovery suggestions.

View File

@@ -0,0 +1,95 @@
---
name: gitea-orchestrate
description: Orchestrates Gitea operations for other agents. Invoke when a caller needs a multi-step or destructive Gitea operation (merge a PR, delete a branch/release/tag/label/milestone, delete a file) coordinated across domain skills with safety gates, session context, and structured results.
tools: Bash, Read
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
- context7-websites-gitea
- context7-gitea-tea-cli
---
You are the orchestrator for the gitea plugin — a composable workflow dispatcher designed for other agents to invoke multi-step Gitea operations reliably. Your one job is routing and safety-gating: you do not call `mcp__gitea__*` tools yourself, you delegate to domain skills and enforce confirmation on destructive operations.
You resolve `owner`/`repo` once per session (via `git remote -v` on `origin`) and carry that forward as session context to every domain skill you dispatch to, rather than making each skill re-resolve it.
**Scope:** this orchestrator routes Gitea-object operations across the six domain skills only: `gitea-issues`, `gitea-labels-milestones`, `gitea-prs`, `gitea-branches`, `gitea-files`, `gitea-releases`. `gitea-workflow` is also not routed here, but for a different reason than a missing domain: it is a human-facing conversational wrapper that gives status check-ins and resolves ambiguous bare numbers ("what's going on with #42") by reasoning about phrasing and context, and it composes the same six domain skills directly rather than calling this orchestrator. It is not a peer to invoke instead of this dispatcher — agent callers route Gitea-object operations here directly with an explicit `operation` field; direct human users to `gitea-workflow` when they want guided, conversational help. Never invoke `gitea-workflow` as an agent caller — resolve ambiguous issue/PR numbers yourself (see Number resolution below) instead of relying on its conversational disambiguation.
## Hard rules
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.
- 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.
- Issues and PRs share one number space. Before dispatching an operation keyed on a bare number, resolve whether it's an issue or a PR yourself (see Number resolution) — never infer the domain from operation phrasing alone.
- `list_releases`/`list_tags` default to `per_page: 20` (other domains default to 30) with no server-side auto-pagination — when a caller needs a complete result set, loop `page` upward until a page returns fewer than `per_page` results before returning.
- Never commit secrets, credentials, or environment-specific config into any file written via `gitea-files`.
### Number resolution
When an operation targets a bare issue/PR number and the caller hasn't specified which domain it is:
1. Dispatch to `gitea-issues` with `issue_read method: "get"` on that number.
2. Check the response's `is_pull` field: `true` → re-dispatch to `gitea-prs` for the actual operation; `false`/absent → it's an issue, proceed with `gitea-issues`.
3. Cache the resolution in session context for the remainder of the request so repeated references to the same number don't re-resolve.
4. If the resolution call 404s, do not conclude the number doesn't exist — return `not_found_or_forbidden` and suggest verifying token scope (`write:issue`).
Sub-skills carry their own local copies of relevant gotchas for humans who invoke them directly, bypassing this orchestrator. When a caller routes through you, this section is the enforcement backstop: check every routed operation against it before dispatch, not just the destructive-operation confirm gate below.
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`
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
6. Aggregate results and return structured JSON output suitable for agent chaining
## Inputs
- **operation:** string, one of:
- 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
- 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)
## Process
1. Validate the request structure and check if `operation` is known
2. Check the request against the Hard rules above (default-branch deletion, release/tag id-vs-name asymmetry, label/milestone ID resolution, number-space ambiguity, pagination) — refuse outright on violation, independent of `confirm`
3. If destructive operation: require `confirm: true`, else fail with structured "requires explicit confirmation" error
4. Resolve `owner`/`repo` via `git remote -v` on `origin` if not already present in `context`, and reuse the resolution for the remainder of the request
5. If the operation targets a bare number and the domain isn't specified, run Number resolution above before dispatch
6. Invoke the appropriate domain skill via `Skill` with the operation, parameters, and resolved context (`owner`, `repo`)
7. Catch and handle Gitea errors: disambiguate 404s (not-found vs. permission-hidden), retry transient failures, loop pagination for `list_releases`/`list_tags` until exhausted
8. If recovery succeeds, continue; if not, return error structure with diagnostics and suggestions
9. Aggregate all outputs and return as structured JSON
## Output
```json
{
"status": "success" | "error",
"operation": "<operation_name>",
"result": {
"output": "<domain skill output or result>",
"context": { "owner": "...", "repo": "...", "resolved_number_type": "issue" | "pull" | null },
"applied_config": { "confirm_required": true | false }
},
"error": {
"message": "<human-readable error>",
"code": "<error type: not_found_or_forbidden | conflict | auth_failure | invalid_state | pagination_incomplete>",
"recovery_attempted": true | false,
"suggestions": ["<suggestion1>", "<suggestion2>"]
}
}
```

View File

@@ -24,8 +24,8 @@
## context7-websites-gitea
- **URL:** context7:/websites/gitea
- **Description:** Official Gitea docs mirror on Context7 (docs.gitea.com content) — scoped/exclusive label conventions, branch protection and PR review/merge rules, release and webhook semantics, issue/PR automatic cross-reference linking. Backfills the external/best-practice gap left by the original docs.gitea.com fetch timeout.
- **Contributing files:** workflow-conventions.md
- **Description:** Official Gitea docs mirror on Context7 (docs.gitea.com content) — scoped/exclusive label conventions, branch protection and PR review/merge rules, release and webhook semantics, issue/PR automatic cross-reference linking, protected-branch signed-commit safeguards, reverse-proxy request size limits, and repository upload limits. Backfills the external/best-practice gap left by the original docs.gitea.com fetch timeout.
- **Contributing files:** workflow-conventions.md, troubleshooting.md
- **Status:** `extracted`
## context7-gitea-tea-cli

View File

@@ -3,6 +3,7 @@ topic: troubleshooting
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
- context7-websites-gitea
---
# Gitea MCP — Troubleshooting
@@ -86,6 +87,14 @@ The MCP server surfaces HTTP error codes from the Gitea REST API:
The `milestones` parameter on `list_issues` accepts milestone names or IDs as an array. Using IDs is more reliable — milestone names are mutable. Always prefer filtering by milestone ID when programmatically filtering.
## Signed-commit branch protection can silently block file writes
A protected branch can require signed commits as a safeguard (`docs.gitea.com/usage/access-control/protected-branches`). `create_or_update_file` and `delete_file` both create commits server-side via a bare API token call with no 2FA/PGP context — if the target branch's protection rule requires signed commits, Gitea rejects the push outright. The MCP tool surfaces this as a generic write failure (typically 403 or 422), not a message naming "signed commit required" — `get_file_contents` (read) keeps succeeding right up until the write. When a file write fails without a 409 (missing/stale SHA) or 404 (bad path) explanation, check whether the target branch's protection rule requires signed commits before assuming the SHA is wrong.
## Large file content can hit a reverse-proxy 413, not a Gitea limit
`create_or_update_file` sends `content` base64-encoded, which inflates the payload ~33% over the raw file size. A `413 Request Entity Too Large` response is commonly a reverse-proxy body-size limit in front of the Gitea instance (e.g. nginx `client_max_body_size`), not a Gitea-side rejection (`docs.gitea.com/administration/reverse-proxies`, `docs.gitea.com/help/faq`) — Gitea's own configured upload limit is a separate, unrelated setting (50MB per file by default, for the web upload feature). A 413 on a file-write call is an infrastructure-layer symptom that cannot be fixed by changing the request (a different SHA, path, or branch won't help) — it requires the reverse-proxy config to be raised, which is outside the skill's or the calling agent's control. Surface this distinction to the user rather than retrying the same call.
## `per_page` defaults vary
Not all endpoints share the same default `per_page`:

View File

@@ -20,5 +20,5 @@
"skills": [
"skills/"
],
"version": "1.1.0"
"version": "1.3.0"
}

View File

@@ -0,0 +1,42 @@
# gitea-issues
Read and write Gitea issues — list, get, create, comment, close, and search — via the Gitea MCP server.
## What it does
This skill handles the issue lifecycle (`list_issues`, `issue_read`, `issue_write`, `search_issues`):
listing repo issues, reading a single issue's details/comments/labels, creating an issue, updating
its state, adding/editing comments, applying labels, and searching issues/PRs across repositories.
The create flow closes out four enrichments deferred from issue #6 comment #848: label inference
and milestone assignment (both by composing `gitea-labels-milestones`), an assignee workaround for
the blocked `get_me` scope, and the "Depends on #N" dependency-linking convention. It supersedes the
`issue`/`issue <N>`/`issue close <N>`/`issue comment <N>` dispatch in the old flat
`plugins/bin/skills/gitea/SKILL.md`, which remains in place untouched as a fallback per
`docs/adr/0011-gitea-skill-deep-modules.md`.
## Before you start
Requires a Gitea MCP server configured with a token holding `write:issue` + `write:repository`.
Requires a git remote named `origin` pointing at the Gitea instance, unless an orchestrating caller
(e.g. `gitea-workflow`) already resolved `owner`/`repo` for you. Label and milestone management
(creating/editing a label, creating/closing a milestone) is out of scope here — that's
`gitea-labels-milestones`, which this skill composes rather than duplicates.
## Usage
```
/gitea-issues
```
Describe your task: list issues, create one, get/comment/close a specific issue number, or search
across repos. See `SKILL.md`'s dispatch table for the full set of recognized invocations.
## Files
| File | Purpose |
|------|---------|
| `SKILL.md` | Skill instructions for agents — dispatch table, Gotchas |
| `references/issues.md` | Verified call signatures and mechanics for `list_issues`/`issue_read`/`issue_write` |
| `references/search.md` | Verified call signature and mechanics for `search_issues` |
| `references/enrichments.md` | Create-flow enrichments — label inference, milestone assignment, assignee workaround, dependency-linking convention |
| `references/sources.md` | Research sources backing the issue guidance |

View File

@@ -0,0 +1,105 @@
---
name: gitea-issues
description: >
Use when reading or writing Gitea issues: listing repo issues, getting a single issue's details/
comments/labels, creating an issue, updating its state, adding or editing comments, applying
labels via issue_write, or searching issues/PRs across repositories. Triggers on "create an
issue", "what issues are open", "get issue #N", "close issue #N", "comment on issue #N", "search
issues for X" — even when the user doesn't say "Gitea" explicitly. Composes gitea-labels-
milestones for all label inference/resolution and milestone lookup — do not use this skill to
manage label or milestone definitions themselves (create/edit/delete a label, create/close a
milestone), that's gitea-labels-milestones directly. Do not use for pull requests (use gitea-prs)
or for local git branch/commit work (use gitea-branches or git-branches).
compatibility: Requires Gitea MCP server configured with write:issue and write:repository token
scopes. Requires git remote "origin" pointing to the Gitea instance for owner/repo resolution
when invoked directly by a human; an orchestrating caller (e.g. gitea-workflow) may pass
owner/repo already resolved.
metadata:
category: integration
version: "0.1.0"
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
- context7-websites-gitea
- context7-gitea-tea-cli
allowed-tools: Bash mcp__gitea__list_issues mcp__gitea__issue_read mcp__gitea__issue_write mcp__gitea__search_issues
---
## Gotchas
- **`list_issues` has no `type` or `milestones` parameter — despite `api-reference.md` documenting both.** The live MCP schema (re-verified via `ToolSearch` at authoring time — see `references/sources.md`) only accepts `owner`, `repo` (required), `state` (default `"all"`), `labels` (array of label *names*), `since`, `before` (ISO 8601), `page`, `per_page` (default 30). There is no way to filter issues-vs-PRs or by milestone through this tool. Since issues and PRs share one number space, `list_issues` results can include PR entries with no client-side filter to exclude them. If you need to know whether a specific number is a PR, call `issue_read method: "get"` and check `is_pull` — that field only appears on the single-item response, never in a list item. This exact drift (a prior skill trusted the research doc's `type` param and broke) is why this skill's reference files were re-verified live rather than copied from `api-reference.md`.
- **`search_issues` does have a working `type` filter** (`"issues"` | `"pulls"`) — unlike `list_issues`. Its `labels` parameter is also shaped differently: a comma-separated string, not an array of names.
- **Labels are numeric IDs on write, name strings on read.** `issue_write`'s `labels` parameter (used by `add_labels`/`replace_labels`) takes IDs. `list_issues`/`issue_read` return names. Never resolve this yourself — compose `gitea-labels-milestones` (see `references/enrichments.md`) to get IDs.
- **Milestone on `issue_read` is `{id, title}`** — an object, not a bare string. This skill only ever needs the `id`. (The bare-title-string case only happens on the PR side, which is `gitea-prs`' problem, not this skill's.)
- **A closing keyword in a commit message can auto-close an issue without any `issue_write` call.** Gitea has no GitHub-style "merge closes issue" event, but it does parse `Fixes #N`/`Closes #N` in commit messages landing on the default branch. After a PR merges (a `gitea-prs` operation), re-check the issue's state here via `issue_read method: "get"` before deciding whether to close it manually — closing an already-closed issue is a harmless no-op, but don't assume a manual close is always needed.
- **Pagination is manual.** `list_issues` and `search_issues` return one page at a time. Iterate `page: 1, 2, ...` until the returned count is less than `per_page`.
- **HTTP 404 may actually mean 403.** Gitea hides permission errors as not-found. If a call 404s unexpectedly, verify the token holds `write:issue` scope (see `references/issues.md`'s Token scope note) before concluding the issue doesn't exist.
## Step 1 — Resolve owner and repo
Before any tool call, extract `owner` and `repo` from the git remote (skip this if an orchestrating caller already passed them in):
```bash
git remote get-url origin
```
If origin is not set or the URL is not a Gitea URL, stop and report: "No Gitea remote found — set origin to your Gitea instance URL."
## Step 2 — Dispatch
| Invocation | Action |
|---|---|
| `/gitea-issues` or `/gitea-issues list` | List issues (optional state filter) |
| `/gitea-issues create` | Create an issue from conversation context — infers labels, checks milestone fit, applies a configured default assignee if set |
| `/gitea-issues <N>` | Get issue details (flag it as a PR if `is_pull: true`) |
| `/gitea-issues <N> comments` | Get an issue's comments |
| `/gitea-issues close <N>` | Close an issue |
| `/gitea-issues comment <N>` | Add a comment from conversation context |
| `/gitea-issues search <query>` | Cross-repo search via `search_issues` |
For full parameter detail on `list_issues`/`issue_read`/`issue_write`, read `references/issues.md`. For `search_issues`, read `references/search.md`. For the create-flow enrichments (label inference, milestone assignment, assignee workaround, dependency-linking), read `references/enrichments.md`.
## Step 3 — Execute
### list (default)
Call `list_issues owner: <owner> repo: <repo> state: <"open"|"closed"|"all", default "all">`. Remember: results may include PR entries (see Gotchas) — if the caller needs issues only, this tool cannot filter that server-side; note the limitation rather than silently mislabeling PR entries as issues.
### create
1. Extract `title` and `body` from conversation context (the most recent task, bug description, or explicit statement). Fall back to an empty body if nothing is available.
2. Run the enrichment sequence in `references/enrichments.md`: infer labels (composing `gitea-labels-milestones`), check for a clearly-fitting open milestone (composing the same skill), and check for a configured default assignee.
3. Call `issue_write method: "create" owner: <owner> repo: <repo> title: <title> body: <body> labels: [<resolved IDs, or omit>] milestone: <resolved ID, or omit> assignees: [<default login, or omit>]`.
4. Fire immediately — no confirmation step for the create itself.
### `<N>` (get)
Call `issue_read method: "get" owner: <owner> repo: <repo> issue_number: <N>`. If `is_pull: true`, report that this number is actually a PR and suggest `gitea-prs` for full detail.
### `<N> comments`
Call `issue_read method: "get_comments" owner: <owner> repo: <repo> issue_number: <N>`.
### close `<N>`
Call `issue_write method: "update" owner: <owner> repo: <repo> issue_number: <N> state: "closed"`. There is no `method: "close"`.
### comment `<N>`
Extract the comment body from conversation context (same sourcing as create). Call `issue_write method: "add_comment" owner: <owner> repo: <repo> issue_number: <N> body: <body>`.
### search `<query>`
Call `search_issues query: <query>`, adding `owner`, `state`, `type`, or `labels` filters if the request narrows scope (e.g. "search open PRs for X" → `type: "pulls" state: "open"`).
## Step 4 — Report
For reads: a compact table or numbered list — number, title, state, labels, milestone.
For writes: confirm what was created/updated with the issue number and URL if returned.
For errors: surface the HTTP code and message; check token scope per the Gotchas if a 404 looks wrong.

View File

@@ -0,0 +1,92 @@
---
topic: enrichments
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
- context7-websites-gitea
---
# Create-flow enrichments
Closes out the four enrichments deferred from issue #6 comment #848. Run in this order before the
`issue_write method: "create"` call in SKILL.md's create dispatch: **labels → milestone →
assignee → dependency link**. Each step is independent and skippable on its own — a missing
milestone fit doesn't block label inference, and so on — but this is the order that lets later
steps use context established earlier (e.g. the inferred `Kind/*` label can inform which milestone
plausibly fits).
**Cross-skill composition note:** none of the steps below read `gitea-labels-milestones`'s
reference files directly by path. A plugin install copies each skill's directory into an isolated
cache — any file path that leaves this skill's own directory breaks post-install. Instead, compose
`gitea-labels-milestones` as a skill: describe the task to it (its own `SKILL.md` and description
trigger it) and consume the resolved IDs it returns. This mirrors how `gitea-labels-milestones`'s
own description already frames the relationship ("`gitea-issues` and `gitea-prs` both compose it").
## 1. Label inference
Delegate the entire signal-to-label mapping to `gitea-labels-milestones` — this skill does not
duplicate the `Kind/*`/`Priority/*`/`Status/*` taxonomy table.
1. Compose `gitea-labels-milestones` to resolve labels for the issue being created: give it the
draft title/body and ask it to infer and resolve applicable labels (it calls
`label_read method: "list_repo_labels"` internally and runs its own inference procedure).
2. Take back the resolved label IDs (and which scope groups, if any, need replacing — not relevant
yet on a brand-new issue, since there's nothing to replace).
3. If `gitea-labels-milestones` reports low confidence and omits a `Kind/*` label, pass no `Kind/*`
ID rather than guessing one yourself. `Priority/Medium` is the one label its own inference
procedure defaults to when no urgency signal is present — that's expected, not a gap.
4. Pass the resulting label IDs to `issue_write`'s `labels` parameter (omit the parameter entirely
if the resolved list is empty).
## 2. Milestone assignment on create
1. Compose `gitea-labels-milestones` to list open milestones (it calls
`milestone_read method: "list" state: "open"` internally).
2. Compare the issue's inferred scope (title, body, and any `Kind/*` label from step 1) against
each open milestone's title/description. Assign a milestone only when the fit is clear — a
milestone literally named for the feature area, or one whose description explicitly covers this
kind of work. A milestone that's merely "the current one" without a clear scope match is not a
confident fit.
3. If a milestone clearly fits, pass its **numeric ID** (never the title) as `issue_write`'s
`milestone` parameter. `issue_write`'s `milestone` field only accepts the ID — see
`references/issues.md`.
4. If no milestone clearly fits, omit `milestone` entirely. Guessing a milestone assignment is worse
than leaving it unset — an issue can always be milestoned later, but a wrong milestone
assignment pollutes that milestone's issue count and scope.
## 3. Assignee on create — the `get_me` workaround
`issue_write` accepts `assignees: [<login>]`, but there is no way to discover the *current user's*
own login to self-assign: `get_me` requires the `read:user` scope, and this repo's Gitea MCP token is
scoped to `write:issue` + `write:repository` only, with no `read:user` grant. This is a hard
capability gap, not something to work around with a guess.
**Workaround:** support an optional user-configured default assignee login, supplied one of two
ways:
- A config value the caller or orchestrator (e.g. `gitea-workflow`) already resolved and passes in
when invoking this skill.
- A login explicitly stated in the conversation ("assign this to alice") — use that login directly,
no lookup needed, since Gitea accepts a login string without requiring you to resolve an ID first.
**If neither is available, omit `assignees` entirely.** Do not guess a login, do not fail the create
over a missing assignee, and do not attempt `get_me`/`search_users` as a fallback — both are blocked
by the same scope gap and will only produce a confusing secondary error.
## 4. Dependency-linking convention
gitea-mcp has no native issue-dependency field (no "blocks"/"blocked by" relationship in the API
surface this skill has access to). The convention is to write **"Depends on #N"** as a line in the
issue body.
This is not just a text convention with no effect — Gitea auto-renders `#N` (and `!N` for PRs) as a
real clickable cross-reference with no separate API call, a documented platform behavior (see
`references/sources.md` for the backing research). This works because issues and PRs share one
repo-scoped number space. Use the bare `#N` form for same-repo dependencies; use `owner/repo#N` for
a dependency in a different repo.
When creating an issue that depends on another, append a line like:
```
Depends on #42
```
to the body before calling `issue_write method: "create"`. There is no separate field or follow-up
call — the rendering happens automatically once the body is saved.

View File

@@ -0,0 +1,123 @@
---
topic: issues
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
---
# Issue operations
Call signatures below were verified live against the deployed `gitea-mcp` server via `ToolSearch`
at authoring time, not copied from `api-reference.md` — this is deliberate: research docs are
generated from source at a point in time and can drift from the server actually deployed (see the
`list_issues` gotcha below, which is the exact drift this policy exists to catch). Re-verify against
the live schema if these tools appear to behave differently than documented here.
## `list_issues`
**Parameters (live schema):**
- `owner` (string, required)
- `repo` (string, required)
- `state` (string, optional, default `"all"`) — conventional values `"open"`/`"closed"`/`"all"`, not
schema-enforced as an enum
- `labels` (array of strings, optional) — filter by label *name* (not ID)
- `since` (string, optional) — ISO 8601, issues updated after this time
- `before` (string, optional) — ISO 8601, issues updated before this time
- `page` (number, optional, default `1`)
- `per_page` (number, optional, default `30`)
**There is no `type` parameter and no `milestones` parameter**, despite both appearing in
`api-reference.md`. This tool cannot filter issues-vs-PRs or by milestone — see the Gotchas section
of SKILL.md for the consequence (PR entries can appear in results with no way to exclude them here).
**Call:**
```
list_issues owner: <owner> repo: <repo> state: "open"
```
**Response (list item):** `number`, `title`, `state`, `html_url`, `user`, `comments`, `created_at`,
`updated_at`, and optionally `labels` (`[]string`), `milestone` (`{id, title}`), `ref`, `deadline`.
Body and `closed_at` are omitted from list responses — call `issue_read method: "get"` for those.
Paginate with `page`/`per_page` until the returned count is less than `per_page`.
## `issue_read`
**Parameters (live schema, matches `api-reference.md`):**
- `method` (string, required, enum) — `"get"` | `"get_comments"` | `"get_labels"`
- `owner` (string, required)
- `repo` (string, required)
- `issue_number` (number, required)
**`get`** — full issue: `number`, `title`, `body`, `state`, `html_url`, `user`, `labels`
(`[]string`), `comments`, `created_at`, `updated_at`, `closed_at`, and optionally `assignees`
(`[]string`), `milestone` (`{id, title}`), `ref`, `deadline`, `is_pull` (present only when this
number is backed by a pull request — absent, not `false`, on true issues).
**`get_comments`** — array of `{id, body, user, html_url, created_at, updated_at}`.
**`get_labels`** — array of full label objects (`id`, `name`, `color`, `description` — not slimmed
to name strings, unlike the labels array on `get`).
**Call:**
```
issue_read method: "get" owner: <owner> repo: <repo> issue_number: <N>
```
Always check `is_pull` before treating a number as a plain issue — see the shared number-space
gotcha in SKILL.md.
## `issue_write`
**Parameters (live schema, matches `api-reference.md`):**
- `method` (string, required, enum) — `"create"` | `"update"` | `"add_comment"` | `"edit_comment"` |
`"add_labels"` | `"remove_label"` | `"replace_labels"` | `"clear_labels"`
- `owner` (string, required)
- `repo` (string, required)
- `issue_number` (number, required for every method except `"create"`)
- `title` (string, required for `"create"`)
- `body` (string, required for `"create"`, `"add_comment"`, `"edit_comment"`)
- `assignees` (array of strings, optional) — login names (see `references/enrichments.md` for why
this is usually omitted)
- `milestone` (number, optional) — milestone ID, never a title
- `state` (string, enum `"open"`/`"closed"`/`"all"`, optional) — for `"update"`
- `commentID` (number, optional, required for `"edit_comment"`)
- `labels` (array of numbers, optional) — label IDs, never names — for `add_labels`/`replace_labels`
- `label_id` (number, optional, required for `"remove_label"`) — singular, not the array form
- `ref` (string, optional) — branch association, informational only
- `deadline` (string, optional) — ISO 8601
- `remove_deadline` (boolean, optional)
**Create:**
```
issue_write method: "create"
owner: <owner> repo: <repo>
title: <title> body: <body>
labels: [<resolved IDs>] ← omit if none confidently inferred
milestone: <resolved ID> ← omit if none clearly fits
assignees: ["<login>"] ← omit if no default configured
```
**Close:**
```
issue_write method: "update" owner: <owner> repo: <repo> issue_number: <N> state: "closed"
```
There is no `method: "close"` — using one will error.
**Comment:**
```
issue_write method: "add_comment" owner: <owner> repo: <repo> issue_number: <N> body: <text>
```
**Apply resolved label IDs directly** (bypassing `references/enrichments.md`'s inference step, e.g.
when the caller already named exact labels):
```
issue_write method: "add_labels" owner: <owner> repo: <repo> issue_number: <N> labels: [<IDs>]
```
To replace all labels atomically instead of adding: `method: "replace_labels"`.
To remove one: `method: "remove_label" label_id: <single ID>`.
## Token scope
All of `list_issues`, `issue_read`, and `issue_write` are verified working under a token holding
`write:issue` + `write:repository`.

View File

@@ -0,0 +1,39 @@
---
topic: search
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
---
# `search_issues`
Call signature verified live against the deployed `gitea-mcp` server via `ToolSearch` at authoring
time (see `references/sources.md`) — confirmed to match `api-reference.md`.
**Parameters:**
- `query` (string, required) — the only hard-required parameter
- `state` (string, enum `"open"` | `"closed"` | `"all"`, optional)
- `type` (string, enum `"issues"` | `"pulls"`, optional) — **this tool has a working type filter**,
unlike `list_issues` (see `references/issues.md`)
- `labels` (string, optional) — comma-separated label **names** — a plain string, not the array form
`list_issues` uses
- `owner` (string, optional) — restrict results to one owner
- `page` (number, optional, default `1`)
- `per_page` (number, optional, default `30`)
**Call:**
```
search_issues query: <text>
```
**Narrowing the search:**
```
search_issues query: <text> owner: <owner> state: "open" type: "pulls" labels: "bug,urgent"
```
This is a cross-repository search (unlike `list_issues`, which is scoped to one `owner`/`repo`) —
useful when the caller doesn't know which repo an issue lives in, or wants results across an
organization. Pass `owner` to narrow scope if the caller does know it.
Paginate the same way as `list_issues`: iterate `page` until the returned count is less than
`per_page`.

View File

@@ -0,0 +1,41 @@
# Sources
**Note on call signatures:** per `docs/adr/0011-gitea-skill-deep-modules.md`, the tool parameter
signatures in `references/issues.md` and `references/search.md` were re-verified live via
`ToolSearch` against the deployed `gitea-mcp` server at authoring time — they are not copied
verbatim from `api-reference.md`. This resolves issue #6 comment #849's root-cause finding that a
prior skill was authored from API docs that had drifted from the actual MCP tool schema; the live
check caught exactly this drift on `list_issues` (see SKILL.md Gotchas — the research doc documents
a `type` and a `milestones` parameter that do not exist on the deployed server).
## gitea-mcp-repo
- **URL:** https://gitea.com/gitea/gitea-mcp
- **Description:** Official gitea-mcp repository (v1.3.0); operation/*.go source files documenting all 55 MCP tools, their parameters, and CLI flags.
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** SKILL.md, references/issues.md, references/search.md, references/enrichments.md
- **Status:** `extracted`
## gitea-mcp-slim-go
- **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/issue/slim.go
- **Description:** Slim response shape structs from gitea-mcp source; defines exactly which fields the MCP server returns for issues (label name-vs-ID slimming, milestone object-vs-string shape, `is_pull` presence on single-item reads only).
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** SKILL.md, references/issues.md
- **Status:** `extracted`
## context7-websites-gitea
- **URL:** context7:/websites/gitea
- **Description:** Official Gitea docs mirror on Context7 (docs.gitea.com content) — backs the automatic cross-reference rendering (`#N`/`!N`) that validates the "Depends on #N" dependency-linking convention.
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** references/enrichments.md
- **Status:** `extracted`
## context7-gitea-tea-cli
- **URL:** context7:/git_gitea_com/gitea_tea
- **Description:** Official `tea` CLI (reference Gitea client) docs on Context7 — practitioner command patterns for issues, PRs, and releases. Consulted alongside context7-websites-gitea while researching `workflow-conventions.md`'s cross-reference-linking section (both sources contribute to that research doc); its issue-specific command patterns did not end up informing any gitea-issues content beyond what context7-websites-gitea already backs.
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** (none)
- **Status:** `extracted`

View File

@@ -0,0 +1,25 @@
# gitea-prs
List, read, create, update, merge, and review Gitea pull requests.
## What it does
This skill handles the pull request lifecycle within the Gitea integration suite — listing and reading PRs (details, diff, changed files, CI status, reviews), creating and updating them (title, body, reviewers, labels, milestone), closing/reopening, merging with a chosen strategy and post-merge branch cleanup, and the full code-review flow (create a review with inline comments, submit it, dismiss or delete it). It composes `gitea-labels-milestones` for label/milestone ID resolution rather than duplicating that logic, and defers to `gitea-issues` for anything that turns out to be an issue rather than a PR (they share one number space) and to `gitea-branches`/`gitea-files` for the underlying branch/file operations behind a PR.
## Usage
```
/gitea-prs
```
Describe the PR or review task: list PRs, get a PR's status/diff/reviews, create or update a PR, merge one, or create/submit/dismiss a code review. The skill will determine owner/repo from context and resolve any label or milestone names via `gitea-labels-milestones` before writing them.
## Files
| File | Purpose |
|------|---------|
| `SKILL.md` | Skill instructions for agents — Gotchas, composition with `gitea-labels-milestones`, and the dispatch table |
| `references/pull-requests.md` | Execution detail for `list_pull_requests`, `pull_request_read` (get/get_diff/get_files/get_status), and `pull_request_write` (create/update/close/reopen/update_branch/add_reviewers/remove_reviewers) |
| `references/reviews.md` | Execution detail for `pull_request_review_write` (create/submit/delete/dismiss) and the review-related `pull_request_read` methods |
| `references/merging.md` | The merge workflow — CI vs. review/branch-protection gates, merge styles, branch cleanup, and the post-merge issue-close check |
| `references/sources.md` | Research sources backing the PR/review guidance |

View File

@@ -0,0 +1,68 @@
---
name: gitea-prs
description: >
Use when listing, reading, creating, updating, merging, or reviewing Gitea pull requests —
getting PR status/diff/changed files/CI status, opening a PR, updating title/body/reviewers,
closing/reopening, merging with a chosen strategy, or submitting/dismissing a code review with
inline comments. Composes `gitea-labels-milestones` to resolve label names or milestone titles
to the numeric IDs `pull_request_write` requires, rather than duplicating that resolution logic.
Do not use for issues (`gitea-issues`) or branch/commit operations (`gitea-branches`) — a number
the user mentions may refer to either an issue or a PR since they share one number space, so
confirm which domain applies before dispatching.
compatibility: Requires Gitea MCP server configured with write:issue and write:repository token scopes.
metadata:
category: integration
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
- context7-websites-gitea
- context7-gitea-tea-cli
version: "0.1.0"
allowed-tools: mcp__gitea__list_pull_requests mcp__gitea__pull_request_read mcp__gitea__pull_request_write mcp__gitea__pull_request_review_write
---
## Gotchas
- **Issues and PRs share one number space.** A number the user mentions (`#42`) might be an issue, not a PR — there is only one counter per repo. If you're not certain, call `pull_request_read method: "get"` and treat a 404 as "this number is an issue, not a PR" (or check `is_pull` on an `issue_read` response first if you already have one).
- **`pull_request_read method: "get"` returns `review_scomments`, not `review_comments`.** Source-level typo in gitea-mcp v1.3.0. Never reference `review_comments` — it will always be undefined.
- **`draft: true` on create prepends `"WIP:"` to the title.** There is no first-class draft field — Gitea implements draft PRs via title prefix. To un-draft, call `update` and pass the title without the `WIP:` prefix.
- **Cross-repo fork PRs require `head` as `"fork-owner:branch-name"`.** A bare branch name causes Gitea to search the base repo for it and return 422. Same-repo PRs use a bare branch name.
- **PR `milestone` is a bare title string, not `{id, title}`.** Unlike issues, you cannot recover a milestone's ID from a PR response. If you need the ID (e.g. to filter or to pass to another write), call into `gitea-labels-milestones` and match by title via `milestone_read method: "list"`.
- **CI status and review/approval state are independent merge gates.** `get_status` only reports CI. Branch-protection rules (required approvals, requested-reviewer coverage, stale-approval handling) are enforced server-side by the merge call itself and will error if unmet — passing CI does not mean the merge will succeed.
- **Reviews move through a state machine, not a single write.** `create` opens a review in `PENDING` state with inline comments attached; `submit` finalizes it with a terminal `state` (`APPROVED`/`REQUEST_CHANGES`/`COMMENT`). A submitted review can be `dismiss`ed afterward, but never deleted — `delete` only removes a review that was never submitted.
- **Merging a PR does not auto-close linked issues.** Unlike GitHub, Gitea has no merge-triggers-close event. It does parse closing keywords (`Fixes #N`, `Closes #N`) in commit messages landing on the default branch, so a non-squash merge that preserves those commit messages may auto-close the issue — but a squash merge rewrites history into one commit, so survival of the keyword depends on the squash commit's message. Always call `issue_read method: "get"` on any referenced issue after merging to check whether it already closed before deciding to close it explicitly.
## Composing `gitea-labels-milestones`
Before any `pull_request_write` call that includes a `labels` or `milestone` parameter, resolve names/titles to numeric IDs via `gitea-labels-milestones` — `label_read method: "list_repo_labels"` for label name → ID, `milestone_read method: "list"` for milestone title → ID. Never pass a label name string or milestone title string directly to `pull_request_write`; both parameters take numeric IDs only. This skill does not duplicate that lookup logic — it composes the shared skill.
## Dispatch
| Task | Tool | method |
|---|---|---|
| List PRs | `list_pull_requests` | — |
| Get PR details | `pull_request_read` | `"get"` |
| Get PR diff | `pull_request_read` | `"get_diff"` |
| Get PR changed files | `pull_request_read` | `"get_files"` |
| Get PR CI status | `pull_request_read` | `"get_status"` |
| Get PR reviews | `pull_request_read` | `"get_reviews"` |
| Get one review | `pull_request_read` | `"get_review"` |
| Get review inline comments | `pull_request_read` | `"get_review_comments"` |
| Create a PR | `pull_request_write` | `"create"` |
| Update a PR | `pull_request_write` | `"update"` |
| Close a PR | `pull_request_write` | `"close"` |
| Reopen a PR | `pull_request_write` | `"reopen"` |
| Merge a PR | `pull_request_write` | `"merge"` |
| Update branch from base | `pull_request_write` | `"update_branch"` |
| Add reviewers | `pull_request_write` | `"add_reviewers"` |
| Remove reviewers | `pull_request_write` | `"remove_reviewers"` |
| Create a review | `pull_request_review_write` | `"create"` |
| Submit a review | `pull_request_review_write` | `"submit"` |
| Delete a review | `pull_request_review_write` | `"delete"` |
| Dismiss a review | `pull_request_review_write` | `"dismiss"` |
For full parameter detail on listing/reading/creating/updating/closing PRs, read `references/pull-requests.md`. For review-specific detail (create/submit/delete/dismiss, inline comment shape), read `references/reviews.md`. For the merge workflow specifically (CI gate, merge styles, branch cleanup, post-merge issue check), read `references/merging.md`.

View File

@@ -0,0 +1,41 @@
---
topic: merging
source_keys:
- gitea-mcp-repo
- context7-websites-gitea
- context7-gitea-tea-cli
---
# Merge workflow
## Two independent gates
Before merging, two things can each independently block the merge, and only one of them is visible from `get_status`:
1. **CI status** — `pull_request_read method: "get_status"` returns the combined commit status for the PR's head commit. This reflects CI/build checks only.
2. **Review and branch-protection state** — required approval counts, an allowlist of required approvers/teams, whether requested reviewers have reviewed, and stale-approval handling (an approval given before new commits were pushed may be auto-dismissed or ignored, depending on repo settings). None of this is exposed via `get_status` — it is enforced server-side by the merge call itself, and repository admins are not exempt from it by default (an explicit "administrators must follow branch protection" setting is what removes that bypass).
A green `get_status` does not mean the merge will succeed. Treat both gates as independently checkable, and expect `pull_request_write method: "merge"` to return an error if branch-protection requirements aren't met even when CI is passing.
## `pull_request_write method: "merge"`
**Parameters** (in addition to `owner`, `repo`, `pull_number` — see `references/pull-requests.md` for the full parameter list):
- `merge_style` (string, optional, default `"merge"`) — `"merge"` | `"rebase"` | `"rebase-merge"` | `"squash"` | `"fast-forward-only"`
- `title` (string, optional) — override the merge/squash commit's title
- `message` (string, optional) — merge commit message (for squash, this becomes the squash commit's message — see the auto-close gotcha below)
- `delete_branch` (boolean, optional) — delete the head branch after a successful merge
- `force_merge` (boolean, optional) — merge even if checks are failing; use only when the user explicitly asks to override a failing CI status
- `merge_when_checks_succeed` (boolean, optional) — queue the merge to happen automatically once checks pass, instead of merging immediately
- `head_commit_id` (string, optional) — expected head SHA; supplying it lets the server detect if the branch moved since you last read it (conflict detection) rather than merging a stale diff
## Recommended sequence
1. Call `pull_request_read method: "get_status"` first. Report CI status to the user. Do not block the merge attempt solely because CI is failing unless the user asks you to stop — but do surface it before proceeding.
2. Call `pull_request_write method: "merge"` with the chosen `merge_style` (ask the user if unspecified; do not default to squash silently, since squash has the closing-keyword implication below) and `delete_branch: true` unless told otherwise.
3. If branch-protection requirements block the merge, the call itself will return the error — report it verbatim rather than retrying with `force_merge` unless the user explicitly asks to override.
## Merging does not auto-close linked issues
Gitea has no GitHub-style "merge triggers close" event. It does parse closing keywords (`Fixes #N`, `Closes #N`) in commit messages that land on the default branch — so a regular (non-squash) merge, which preserves each original commit message, can auto-close an issue this way if one of those commits used a closing keyword. A squash merge rewrites history into a single commit, so whether the keyword survives depends entirely on what `message` (or the default squash message) ends up being.
After any merge, call `issue_read method: "get"` (in `gitea-issues`) on any issue the PR references before deciding whether to close it explicitly. Closing an already-closed issue is a harmless no-op, but don't assume a manual close is always needed, and don't assume it never is.

View File

@@ -0,0 +1,75 @@
---
topic: pull-requests
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
---
# Pull request read/write execution detail
Parameter signatures below are cross-checked live against the deployed gitea-mcp server tool schemas at authoring time — not copied verbatim from the plugin's research doc for this domain, which has a known history of drifting from the deployed server (e.g. a prior `type` parameter that no longer exists on `list_issues`, and the `review_scomments` typo covered in `references/reviews.md`). Re-verify via `ToolSearch` before trusting this file if the gitea-mcp version changes.
## `list_pull_requests`
**Parameters:**
- `owner` (string, required)
- `repo` (string, required)
- `state` (string, optional, default `"all"`) — `"open"` | `"closed"` | `"all"`
- `sort` (string, optional, default `"recentupdate"`) — `"oldest"` | `"recentupdate"` | `"leastupdate"` | `"mostcomment"` | `"leastcomment"` | `"priority"`
- `milestone` (number, optional) — milestone ID filter, not a title
- `page` (number, optional, default 1)
- `per_page` (number, optional, default 30)
List responses trim PRs down to summary fields — `head`/`base` are bare ref strings and `milestone` does not appear as an object. Don't rely on this call to resolve a milestone's ID; see the Gotcha below.
## `pull_request_read`
**Parameters:**
- `method` (string, required) — `"get"` | `"get_diff"` | `"get_files"` | `"get_status"` | `"get_reviews"` | `"get_review"` | `"get_review_comments"`
- `owner` (string, required)
- `repo` (string, required)
- `pull_number` (number, required)
- `review_id` (number, optional) — required for `"get_review"` and `"get_review_comments"`; see `references/reviews.md`
- `binary` (boolean, optional) — include binary diff content for `"get_diff"`
- `page` (number, optional, default 1)
- `per_page` (number, optional, default 30)
`"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}`); `review_scomments` (typo, 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`).
**Milestone gotcha:** because `pull_request_read` only ever returns a milestone title, never an ID, resolving "which milestone ID does this PR belong to" requires calling into `gitea-labels-milestones`' `milestone_read method: "list"` and matching by title. Do not attempt to infer or guess the ID.
## `pull_request_write`
**Parameters:**
- `method` (string, required) — `"create"` | `"update"` | `"close"` | `"reopen"` | `"merge"` | `"update_branch"` | `"add_reviewers"` | `"remove_reviewers"`
- `owner` (string, required)
- `repo` (string, required)
- `pull_number` (number, required for every method except `"create"` — this is enforced by convention, not by the tool's schema, so passing it incorrectly produces a runtime error rather than a client-side validation error)
- `title` (string, required for `"create"`; optional for `"update"`)
- `body` (string, required for `"create"`; optional for `"update"`)
- `head` (string, required for `"create"`) — source branch; same-repo PRs use a bare branch name, cross-repo fork PRs use `"fork-owner:branch-name"` (see Gotcha)
- `base` (string, required for `"create"`) — target branch
- `assignee` (string, optional) — single login
- `assignees` (array of strings, optional) — login names
- `milestone` (number, optional, for `"update"`) — milestone ID, never a title
- `state` (string, optional, for `"update"`) — `"open"` | `"closed"` (no `"all"` — unlike issue state filters)
- `allow_maintainer_edit` (boolean, optional, for `"update"`)
- `labels` (array of numbers, optional) — label IDs, never names — resolve via `gitea-labels-milestones` first
- `deadline` (string, optional) — ISO 8601
- `remove_deadline` (boolean, optional)
- `reviewers` (array of strings, optional, for `"add_reviewers"`/`"remove_reviewers"`) — login names
- `team_reviewers` (array of strings, optional, for `"add_reviewers"`/`"remove_reviewers"`)
- `draft` (boolean, optional, for `"create"`) — prepends `"WIP:"` to the title (see Gotcha)
Merge-specific parameters (`merge_style`, `delete_branch`, `force_merge`, `merge_when_checks_succeed`, `head_commit_id`, `message` as merge commit message) are covered in `references/merging.md`.
**Cross-repo head format:** `head` must be `"fork-owner:branch-name"` for a PR originating from a fork of the base repo. Passing a bare branch name causes Gitea to search for that branch in the base repo instead, and returns 422 when it isn't found there.
**Draft/WIP behavior:** `draft: true` on `"create"` is implemented by prepending `"WIP:"` to the title — there is no first-class draft boolean stored separately from the title. The title returned by subsequent reads will include the prefix. To un-draft, call `"update"` with `title` set to the same text minus the `"WIP:"` prefix; there is no dedicated undraft method.
**`update_branch`:** takes only `owner`, `repo`, `pull_number` — no other parameters. It merges the current base branch into the PR's head branch server-side, resolving a PR that Gitea reports as behind its base (analogous to GitHub's "Update branch" button). Use it when a PR shows `mergeable: false` or an out-of-date status due to base-branch drift rather than an actual conflict; if the head and base have truly diverged with conflicting changes, this call fails and the conflict must be resolved by pushing a merge/rebase to the head branch directly, outside this skill's scope.

View File

@@ -0,0 +1,43 @@
---
topic: reviews
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
---
# PR review execution detail
Parameter signatures below are cross-checked live against the deployed gitea-mcp server tool schema, not copied from the plugin's research doc verbatim — same sourcing discipline as `references/pull-requests.md`.
## Review state machine
A review is not a single write. It moves through states:
1. **`create`** — opens a review in `"PENDING"` state, optionally attaching inline comments. Nothing is visible to other users yet.
2. **`submit`** — finalizes the pending review with a terminal `state`: `"APPROVED"`, `"REQUEST_CHANGES"`, or `"COMMENT"`. This is the point at which the review becomes visible and counts toward merge-gate requirements (see `references/merging.md`).
3. **`dismiss`** — invalidates an already-submitted review (e.g. an approval that's no longer valid after force-push), with an optional `message` giving the reason. Dismissal does not delete the review record — it stays visible but marked dismissed.
4. **`delete`** — removes a review outright. Use only for a review that was never submitted (e.g. abandoning a `PENDING` draft); do not use `delete` to retract a submitted review — use `dismiss` instead.
## `pull_request_review_write`
**Parameters:**
- `method` (string, required) — `"create"` | `"submit"` | `"delete"` | `"dismiss"`
- `owner` (string, required)
- `repo` (string, required)
- `pull_number` (number, required)
- `review_id` (number, required for every method except `"create"`, which returns the ID to use for the follow-up `submit`/`delete`/`dismiss` call)
- `state` (string, optional) — `"APPROVED"` | `"REQUEST_CHANGES"` | `"COMMENT"` | `"PENDING"` — set on `"create"` (typically `"PENDING"`, or a terminal state to create-and-submit in one call if the server supports it) or `"submit"` (terminal state)
- `body` (string, optional) — overall review comment text
- `commit_id` (string, optional, for `"create"`) — anchors inline comments to a specific commit SHA (typically the PR's current head SHA from `pull_request_read method: "get"`)
- `message` (string, optional, for `"dismiss"`) — dismissal reason
- `comments` (array of objects, optional, for `"create"`) — inline comments, each: `{path, body, old_line_num, new_line_num}` — `path` is the file path, `body` is the comment text, `new_line_num` anchors to a line in the new (added) side of the diff, `old_line_num` anchors to a line in the old (removed) side; use whichever side the comment applies to, not both
## Reading reviews (`pull_request_read`)
- `method: "get_reviews"` — array of review summaries: `id`, `state`, `body`, `user` (login), `comments_count`, `submitted_at`, `html_url`, `stale` (bool — the PR was pushed to after this review was submitted, meaning it may be outdated), `official` (bool), `dismissed` (bool).
- `method: "get_review"` (requires `review_id`) — single review detail.
- `method: "get_review_comments"` (requires `review_id`) — array of inline comments: `id`, `body`, `path`, `position`, `old_position`, `diff_hunk`, `user`, `html_url`, `created_at`, `updated_at`.
**`review_scomments` typo:** the full PR object returned by `pull_request_read method: "get"` includes a field named `review_scomments` (a count), not `review_comments` — a source-level misspelling in gitea-mcp v1.3.0's `slim.go`. Do not write code or instructions that reference `review_comments` on that response; it will always be `undefined`. This is distinct from the `get_review_comments` method above, which is spelled correctly and returns the actual comment objects.
**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

@@ -0,0 +1,33 @@
# Sources
## gitea-mcp-repo
- **URL:** https://gitea.com/gitea/gitea-mcp
- **Description:** Official gitea-mcp repository (v1.3.0) — `operation/*.go` source files documenting all 55 MCP tools, their parameters, and CLI flags. Live tool schemas (`list_pull_requests`, `pull_request_read`, `pull_request_write`, `pull_request_review_write`) were verified directly against the deployed MCP server via `ToolSearch` at authoring time, per this repo's process for resolving schema-vs-docs drift, rather than copied from the derived research doc.
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** SKILL.md, references/pull-requests.md, references/reviews.md, references/merging.md
- **Status:** `extracted`
## gitea-mcp-slim-go
- **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/pull/slim.go
- **Description:** Slim response shape structs from gitea-mcp source — defines exactly which fields the MCP server returns for PRs and reviews, including the `review_scomments` typo and the PR-response milestone-as-title-string quirk.
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** SKILL.md, references/pull-requests.md, references/reviews.md
- **Status:** `extracted`
## context7-websites-gitea
- **URL:** context7:/websites/gitea
- **Description:** Official Gitea docs mirror on Context7 — branch protection rules, PR review/merge gating behavior, and automatic issue/PR cross-reference linking. Backfills the external/best-practice gap left by the original docs.gitea.com fetch timeout.
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** SKILL.md, references/merging.md
- **Status:** `extracted`
## context7-gitea-tea-cli
- **URL:** context7:/git_gitea_com/gitea_tea
- **Description:** Official `tea` CLI (reference Gitea client) docs on Context7 — practitioner command patterns for PR review workflows.
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** references/merging.md
- **Status:** `extracted`

View File

@@ -0,0 +1,22 @@
# gitea-workflow
Human-facing entry point and router for the Gitea integration.
## What it does
This skill is the conversational front door to the Gitea suite — it replaces the old flat `/gitea` skill. On its own it never calls a Gitea MCP tool; it composes the six domain skills (`gitea-issues`, `gitea-labels-milestones`, `gitea-prs`, `gitea-branches`, `gitea-files`, `gitea-releases`). It handles the no-args status check-in (open issues + open PRs), resolves ambiguous issue-or-PR numbers before dispatching (issues and PRs share one number space), and points a user or agent to the right domain skill when it's unclear which one applies.
## Usage
```
/gitea-workflow
```
Invoke with no arguments for a status check-in, with a bare number to resolve and show issue or PR detail, or with a general request to be routed to the right domain skill.
## Files
| File | Purpose |
|------|---------|
| `SKILL.md` | Skill instructions for agents — Gotchas, status view, ambiguous-number resolution, and the domain-skill index |
| `references/sources.md` | Research sources backing the routing/status guidance |

View File

@@ -0,0 +1,74 @@
---
name: gitea-workflow
description: >
Use when a human wants a general or ambiguous Gitea status check or isn't sure which Gitea
domain skill applies — a no-args check-in ("what's going on in the repo", "any updates?"),
a bare-numbered reference that could be an issue or a PR ("what's the status of #42", "what's
happening with #17"), or a request to discover which Gitea capability handles a task. This is
the human-facing entry point and router for the Gitea integration — it replaces the old flat
`/gitea` invocation (now `/gitea-workflow`) and composes the six domain skills
(`gitea-issues`, `gitea-labels-milestones`, `gitea-prs`, `gitea-branches`, `gitea-files`,
`gitea-releases`) rather than calling any Gitea MCP tool directly. Do not use this skill when
the domain is already known and unambiguous — invoke the matching domain skill directly instead
(e.g. "create an issue" → `gitea-issues`, "merge PR #10" → `gitea-prs`, "cut a release" →
`gitea-releases`). Do not use for local git operations with no Gitea component (use
`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.
metadata:
category: integration
version: "0.1.0"
source_keys:
- gitea-mcp-repo
- gitea-mcp-slim-go
- context7-websites-gitea
---
## Gotchas
- **This skill never calls a Gitea MCP tool itself.** Every read or write goes through one of the six domain skills. If a request needs a raw `mcp__gitea__*` call that no domain skill exposes, that's a gap in a domain skill, not something to patch here.
- **Issues and PRs share one number space** — a bare number like `#42` could be either. Never guess from context clues alone; resolve it with a real call (see Step 2) before dispatching.
- **A 404 on the resolution call doesn't necessarily mean the number doesn't exist.** Gitea hides permission errors as not-found (documented in `gitea-issues`' Gotchas). If resolution 404s unexpectedly, say so and suggest checking token scope rather than reporting "no such issue or PR."
## Step 1 — Default status view (no args)
When invoked with no specific request, give a status check-in:
1. Invoke `gitea-issues` to list open issues (`state: "open"`).
2. Invoke `gitea-prs` to list open PRs (`state: "open"`).
3. Run both in parallel — they're independent reads.
4. Report as two sections, "Open Issues" and "Open Pull Requests", each as a compact list (number, title). This preserves the original flat `/gitea` skill's default behavior.
## Step 2 — Resolve an ambiguous number
When the user references a bare number without saying "issue" or "PR" (e.g. "what's going on with #42"):
1. Invoke `gitea-issues` to run `issue_read method: "get"` on that number.
2. Check the response's `is_pull` field:
- `true` → it's a PR. Invoke `gitea-prs` for full PR detail (status, diff, reviews as appropriate to the request) and present that instead.
- `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 — report the 404 and suggest verifying token scope (`write:issue`) per `gitea-issues`' Gotchas, since permission errors are hidden as not-found in Gitea.
Never dispatch to `gitea-issues` or `gitea-prs` based on guessing from phrasing alone ("that sounds like a bug" is not evidence) — always resolve first.
## Step 3 — Route explicit but domain-unclear requests
For requests that name a capability but not obviously which skill owns it, use this index:
| Skill | Covers |
|---|---|
| `gitea-issues` | List/read/create/update issues, comments, search across issues and PRs. Composes `gitea-labels-milestones` for label/milestone resolution. |
| `gitea-labels-milestones` | Label and milestone CRUD, label inference from conversation context, resolving names/titles to the numeric IDs writes require. Cross-cutting — used by both `gitea-issues` and `gitea-prs`. |
| `gitea-prs` | List/read/create/update/merge PRs, code reviews. Composes `gitea-labels-milestones` the same way `gitea-issues` does. |
| `gitea-branches` | Branch list/create/delete, plus commit history (list commits, get a single commit by SHA). |
| `gitea-files` | Read/write/delete individual files, list a directory, walk the full repo tree. |
| `gitea-releases` | Release and tag CRUD — draft/prerelease flags, release notes, semver tags. |
If a request clearly names one of these (e.g. "create a milestone" → `gitea-labels-milestones`, "read this file from the repo" → `gitea-files`), invoke that skill directly rather than routing through here. Use this table only when the user or an upstream agent is unsure which skill applies.
## Step 4 — Report
Present results in plain language. For the status view, two labeled sections. For a resolved ambiguous number, say which domain it turned out to be before showing detail ("That's a pull request:" / "That's an issue:"). For routing, name the skill and hand off — don't duplicate its output format, let it report.

View File

@@ -0,0 +1,33 @@
# Sources
## gitea-mcp-repo
- **URL:** https://gitea.com/gitea/gitea-mcp
- **Description:** Official gitea-mcp repository (v1.3.0) — `operation/*.go` source files documenting all 55 MCP tools. This skill's status view relies on `list_issues`/`list_pull_requests` semantics (via `gitea-issues`/`gitea-prs`), and its ambiguous-number resolution relies on `issue_read`'s `is_pull` field, both verified against this source at authoring time.
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** SKILL.md
- **Status:** `extracted`
## gitea-mcp-slim-go
- **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/issue/slim.go
- **Description:** Slim response shape structs from gitea-mcp source — confirms `is_pull` is present on a single-item `issue_read` response, the field this skill's resolution step depends on to distinguish an issue from a PR sharing the same number.
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** SKILL.md
- **Status:** `extracted`
## context7-websites-gitea
- **URL:** context7:/websites/gitea
- **Description:** Official Gitea docs mirror on Context7 — confirms issues and pull requests share a single per-repository number sequence, and that Gitea returns 404 for permission failures rather than a distinct 403, both facts this skill's resolution and error-handling steps depend on.
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** SKILL.md
- **Status:** `extracted`
## context7-gitea-tea-cli
- **URL:** context7:/git_gitea_com/gitea_tea
- **Description:** Official `tea` CLI docs on Context7 — practitioner conventions for issues, PRs, and releases. Consulted as part of the shared research pass but its content is domain-specific (PR/release workflow patterns), out of scope for pure status/routing behavior — no content from it was used in this skill.
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Contributing files:** (none)
- **Status:** `extracted`

33
plugins/gitea/sources.md Normal file
View File

@@ -0,0 +1,33 @@
# Sources
## gitea-mcp-repo
- **URL:** https://gitea.com/gitea/gitea-mcp
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Description:** Official gitea-mcp repository (v1.3.0); operation/*.go source files documenting all 55 MCP tools, their parameters, and CLI flags — informs the orchestrator's operation index and its `delete_release`/`delete_tag` id-vs-name and pagination-default hard rules.
- **Contributing files:** agents/gitea-orchestrate.md, agents/gitea-orchestrate.agent.md
- **Status:** `extracted`
## gitea-mcp-slim-go
- **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/issue/slim.go, https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/pull/slim.go, https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/repo/slim.go
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Description:** Slim response shape structs from gitea-mcp source; defines the `is_pull` field the orchestrator's Number resolution routine checks to disambiguate issue vs. PR numbers.
- **Contributing files:** agents/gitea-orchestrate.md, agents/gitea-orchestrate.agent.md
- **Status:** `extracted`
## context7-websites-gitea
- **URL:** context7:/websites/gitea
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Description:** Official Gitea docs mirror on Context7 — informs the default-branch protection hard rule and permission-errors-as-404 behavior the orchestrator surfaces via `not_found_or_forbidden`.
- **Contributing files:** agents/gitea-orchestrate.md, agents/gitea-orchestrate.agent.md
- **Status:** `extracted`
## context7-gitea-tea-cli
- **URL:** context7:/git_gitea_com/gitea_tea
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
- **Description:** Official `tea` CLI docs on Context7 — practitioner conventions for release/tag semver naming and merge strategy choices that inform the orchestrator's destructive-operation gating around `merge-pr` and `delete-release`/`delete-tag`.
- **Contributing files:** agents/gitea-orchestrate.md, agents/gitea-orchestrate.agent.md
- **Status:** `extracted`

View File

@@ -16,6 +16,7 @@ mapfile -t TEST_FILES < <(
find "$REPO_ROOT" -name "*.bats" \
-not -path "*/tests/bats/*" \
-not -path "*/test_helper/*" \
-not -path "*/.claude/worktrees/*" \
| sort
)

View File

@@ -33,6 +33,7 @@ run_bats
mapfile -t SCRIPTS < <(
find "$SEARCH_ROOT" -name "test-*.sh" \
-not -path "*/.git/*" \
-not -path "*/.claude/worktrees/*" \
| sort
)