Compare commits
22 Commits
v2.0.1
...
dd934d3b07
| Author | SHA1 | Date | |
|---|---|---|---|
| dd934d3b07 | |||
| 2102c8c917 | |||
| bc42a99ad2 | |||
| 0f138f27db | |||
| c47436d6d3 | |||
| bc094819a5 | |||
| 21b052b353 | |||
| 98980d3d1f | |||
| e455c68fe4 | |||
| 22d15cf734 | |||
| 14369ae103 | |||
| 696079cf3e | |||
| a17f65db22 | |||
| 7d30c454ca | |||
| 0c7dd04a46 | |||
| 3de8ff5d15 | |||
| fd837b87d9 | |||
| a3853f78b1 | |||
| 5854961c1f | |||
| 4e98df7445 | |||
| 0d2a6cd839 | |||
| 12f60f42b7 |
109
docs/adr/0011-gitea-skill-deep-modules.md
Normal file
109
docs/adr/0011-gitea-skill-deep-modules.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Gitea skill splits into deep modules under `plugins/gitea/`, replacing the flat `plugins/bin/skills/gitea/`
|
||||
|
||||
The gitea skill originated under kyberforge (`b9c73cc`), moved to `plugins/bin/skills/gitea/`
|
||||
(`4f603cd`), and covers only 5 of gitea-mcp's ~15 tool domains (issues, labels, milestones, PRs,
|
||||
branches) in one flat `SKILL.md` mixing routing logic with execution detail. Meanwhile
|
||||
`plugins/gitea/` already existed as a plugin scaffold holding comprehensive research docs (all 55
|
||||
MCP tool schemas, code-derived from gitea-mcp source, at
|
||||
`plugins/gitea/docs/research/docs/gitea/`) but empty `skills/`, `agents/`, and `.mcp.json`. This
|
||||
ADR records the decisions from a grill-with-docs session on issue #6 that splits the flat skill
|
||||
into deep modules and relocates it to `plugins/gitea/`.
|
||||
|
||||
**Relocation.** The new deep-module skill structure is built in `plugins/gitea/`, not
|
||||
`plugins/bin/`, making the gitea plugin self-contained — bundling its own skills, agents, and MCP
|
||||
config — matching this repo's Plugin glossary definition (the deployable unit that bundles skills,
|
||||
agents, hooks, and MCP servers into a single installable directory) and mirroring the existing
|
||||
`plugins/git/` plugin's shape. The old flat skill stays at `plugins/bin/skills/gitea/` untouched
|
||||
for now, kept as a reference/fallback — not deleted in this pass; removal is a future cleanup once
|
||||
the new structure is validated in practice.
|
||||
|
||||
**Scope expansion.** Coverage expands beyond the original 5 domains to 3 new domains verified
|
||||
working with the current token scope (`write:issue`, `write:repository`) per
|
||||
`plugins/bin/skills/gitea/references/token-access.md`: Files (get/create/update/delete file, dir
|
||||
contents, repo tree), Commits (list/get), and Releases & Tags (full CRUD). Domains not added:
|
||||
repo/org listing, user identity, notifications, and packages are blocked by token scope
|
||||
(`read:user`, `read:organization`, `read:notification`, `read:package`); Actions/CI (list_runs and
|
||||
secrets return 403, writes untested) and Wiki (404 on this repo, writes untested) are partially
|
||||
broken or unverified. All are deferred to future issues once scope is expanded or the domain is
|
||||
verified safe elsewhere.
|
||||
|
||||
**Domain skill split.** The flat skill becomes 6 domain skills plus a workflow orchestrator and an
|
||||
agent counterpart, composed per the Skill composition pattern:
|
||||
|
||||
- `gitea-issues` — issues only (list/read/write/search); closes out 4 enrichments deferred from
|
||||
issue #6 comment #848 — milestone assignment on create, assignee on create (documented
|
||||
workaround since `get_me`/`read:user` is blocked), dependency-linking convention ("Depends on
|
||||
#N" in body, since gitea-mcp has no native dependency field) — and delegates label inference to
|
||||
`gitea-labels-milestones`.
|
||||
- `gitea-labels-milestones` — split out as its own shared skill since labels/milestones are
|
||||
cross-cutting (apply to both issues and PRs), rather than bundled under `gitea-issues`; owns the
|
||||
label inference guide (context-pattern → Kind/*/Priority/*/Status/* taxonomy mapping).
|
||||
- `gitea-prs` — pull requests + reviews, composes `gitea-labels-milestones` for label/milestone
|
||||
application.
|
||||
- `gitea-branches` — branches + commits bundled together (commits are read-only history within
|
||||
branches, a natural pairing).
|
||||
- `gitea-files` — new domain.
|
||||
- `gitea-releases` — releases + tags bundled together.
|
||||
- `gitea-workflow` — thin human-facing orchestrator mirroring `git-workflow`
|
||||
(`plugins/git/skills/git-workflow/`). Preserves the original flat skill's default no-args status
|
||||
view (composes `gitea-issues` + `gitea-prs`) and routes ambiguous requests to the right domain
|
||||
skill. Named `gitea-workflow`, not bare `gitea`, for naming consistency with the other 6 skills,
|
||||
despite breaking the old `/gitea` invocation muscle memory — an explicit accepted tradeoff.
|
||||
- `gitea-orchestrate` (agent, not skill) — agent-facing deterministic counterpart mirroring
|
||||
`git-orchestrate`, for multi-step composition when the caller is an agent rather than a human.
|
||||
|
||||
**Reference-file signature sourcing.** Each new skill's `references/*.md` restates verified MCP
|
||||
call signatures cross-checked live via `ToolSearch` at authoring time, not copied from
|
||||
`api-reference.md`, which could drift from the deployed MCP server version. This resolves issue #6
|
||||
comment #849's root-cause question about the original `type` parameter bug, which happened
|
||||
because the skill was authored from Gitea REST API docs instead of the actual MCP tool schema.
|
||||
This is applied manually during this authoring pass; the `kyberforge:skill-author` meta-skill
|
||||
itself is not changed — comment #849's "option 2" process fix is considered and explicitly
|
||||
deferred as out of scope for this PR.
|
||||
|
||||
**MCP config deferred.** `plugins/gitea/.mcp.json` is deliberately left as an empty `mcpServers`
|
||||
block — the real gitea-mcp server config continues to live in the user's `~/.claude.json` rather
|
||||
than being wired into the plugin manifest. This means the gitea plugin is not yet installable
|
||||
standalone via `claude plugin install gitea@holocron` without manual MCP setup. A follow-up Gitea
|
||||
issue tracks closing this gap.
|
||||
|
||||
**Research backfill.** The existing research docs
|
||||
(`plugins/gitea/docs/research/docs/gitea/`) are 100% code-derived from gitea-mcp source with zero
|
||||
external/best-practice content (the original docs.gitea.com fetch timed out and was never
|
||||
retried). Context7 has `/websites/gitea` (official docs mirror) and `/git_gitea_com/gitea_tea` (Tea
|
||||
CLI) available now — backfilled via a parallel research pass before skill-authoring, so the
|
||||
Provenance chain (`source_keys` → `sources.md` → research doc) has real external sources for
|
||||
workflow/convention guidance, not just API mechanics.
|
||||
|
||||
**Authoring route.** All 8 artifacts (7 skills + 1 agent) are authored via `kyberforge:forge`, not
|
||||
direct `skill-author`/`agent-author` calls, even though `forge`'s own routing rule would normally
|
||||
bypass itself here since the target artifact types are already known — chosen deliberately for
|
||||
uniform audit/recheck coverage across every artifact.
|
||||
|
||||
## Considered options
|
||||
|
||||
**5-skill split, labels+milestones bundled under `gitea-issues` (rejected)** — simpler, one fewer
|
||||
skill, but re-buries label/milestone logic inside an issues-specific skill even though PRs need it
|
||||
equally, forcing `gitea-prs` to either duplicate the guide or reach into `gitea-issues`'
|
||||
`references/` — breaking the self-contained skill boundary.
|
||||
|
||||
**8-skill split, one skill per raw API domain, no bundling (rejected)** — e.g. separate
|
||||
`gitea-commits` and `gitea-tags` skills. Rejected as over-fragmentation: commits are read-only
|
||||
history naturally scoped to branches, and tags are naturally scoped to releases, so bundling
|
||||
avoids two near-empty skills each routing to a single tool family.
|
||||
|
||||
## Consequences
|
||||
|
||||
- `plugins/gitea/` gains `skills/gitea-issues/`, `skills/gitea-labels-milestones/`,
|
||||
`skills/gitea-prs/`, `skills/gitea-branches/`, `skills/gitea-files/`, `skills/gitea-releases/`,
|
||||
`skills/gitea-workflow/`, and `agents/gitea-orchestrate.md` (+ Copilot counterpart), each with
|
||||
its own `references/` and provenance records.
|
||||
- `plugins/gitea/.mcp.json` stays an empty `mcpServers` block until the follow-up issue wires in
|
||||
the real gitea-mcp server config; the plugin is not standalone-installable until then.
|
||||
- `plugins/bin/skills/gitea/` remains in place, unreferenced by new work, until a future cleanup
|
||||
issue removes it once the new structure is validated in practice.
|
||||
- Follow-up issues are needed for: the deferred domains (Actions/CI, Wiki, Notifications,
|
||||
Packages, User/Org), the `.mcp.json` wiring gap, and the eventual removal of
|
||||
`plugins/bin/skills/gitea/`.
|
||||
- Future domain-plugin work in this repo can point to this ADR as the template for splitting an
|
||||
MCP-wrapping skill into deep modules.
|
||||
@@ -10,9 +10,10 @@
|
||||
"issues",
|
||||
"prs",
|
||||
"milestones",
|
||||
"releases"
|
||||
"releases",
|
||||
"branches"
|
||||
],
|
||||
"license": "MIT",
|
||||
"name": "gitea",
|
||||
"version": "1.0.0"
|
||||
"version": "1.3.0"
|
||||
}
|
||||
|
||||
79
plugins/gitea/agents/gitea-orchestrate.agent.md
Normal file
79
plugins/gitea/agents/gitea-orchestrate.agent.md
Normal 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.
|
||||
95
plugins/gitea/agents/gitea-orchestrate.md
Normal file
95
plugins/gitea/agents/gitea-orchestrate.md
Normal 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>"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -20,3 +20,17 @@
|
||||
- **Description:** Gitea REST API swagger documentation covering underlying endpoints for issues, PRs, labels, milestones, and branches
|
||||
- **Contributing files:** (see notes below)
|
||||
- **Status:** `no content extracted` — source fetch timed out; all reference content derived from gitea-mcp source files which are authoritative for MCP tool usage
|
||||
|
||||
## 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, 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
|
||||
|
||||
- **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, including semver tag/release conventions, draft/prerelease flags, and release-notes-from-file conventions.
|
||||
- **Contributing files:** workflow-conventions.md
|
||||
- **Status:** `extracted`
|
||||
|
||||
@@ -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`:
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
topic: workflow-conventions
|
||||
source_keys:
|
||||
- context7-websites-gitea
|
||||
- context7-gitea-tea-cli
|
||||
---
|
||||
|
||||
# Gitea Workflow Conventions
|
||||
|
||||
Practitioner conventions and platform behavior that inform *how* to use the mechanics already
|
||||
documented in `api-reference.md` — not additional tool schemas.
|
||||
|
||||
## Scoped, exclusive labels
|
||||
|
||||
Gitea labels support a scoped-label convention: a `/` delimiter in the label name (e.g.
|
||||
`Priority/High`) plus an `exclusive: true` flag means only one label from that scope can be applied
|
||||
to an issue or PR at a time — applying a new `Priority/*` label automatically replaces the previous
|
||||
one. This is exactly the `Kind/*` / `Priority/*` / `Status/*` taxonomy already used in this repo's
|
||||
own label set, confirming the taxonomy follows Gitea's native scoped-label convention rather than an
|
||||
ad hoc naming scheme. When defining or inferring labels, a scope prefix implies mutual exclusivity —
|
||||
label inference logic should replace, not add to, existing labels in the same scope.
|
||||
|
||||
Repositories can also seed a predefined label set at creation time from a YAML label file
|
||||
(`name`, `color`, `description`, `exclusive`), which is where the base `Kind/Priority/Status` sets
|
||||
typically originate.
|
||||
|
||||
## Milestone and label state as first-class transitions
|
||||
|
||||
Both issues and PRs treat labeling and milestoning as discrete state-transition events
|
||||
(`label_updated`/`label_cleared`, `milestoned`/`demilestoned`), not passive metadata fields. This
|
||||
reinforces treating `gitea-labels-milestones` as a shared skill: the same transition semantics apply
|
||||
whether the target is an issue or a PR.
|
||||
|
||||
## Automatic cross-reference linking
|
||||
|
||||
Gitea auto-renders issue/PR references in body text without any API call: `#1234` and `!1234` both
|
||||
resolve to issue/PR 1234 in the same repo (issues and PRs share one number space, consistent with
|
||||
`data-model.md`); cross-repo references use `owner/repo#1234` (issue) or `owner/repo!1234` (PR). This
|
||||
directly validates the dependency-linking convention decided for `gitea-issues` (issue #6, comment
|
||||
#848): writing `Depends on #N` in an issue body is not just a text convention — Gitea renders it as
|
||||
a real clickable cross-reference automatically, with no separate API call required. For
|
||||
external-issue-tracker repos, the same syntax renders as an external link instead, so the skill
|
||||
should assume same-repo internal linking unless told otherwise.
|
||||
|
||||
## Pull request review workflow
|
||||
|
||||
The reviewer flow is: comment, request changes, or approve; the author pushes updates to the same
|
||||
branch, which the PR auto-tracks; maintainers merge once approved. Protected branches can layer
|
||||
additional constraints on top of this base flow:
|
||||
|
||||
- An allowlist of users/teams may be required to approve before merge is possible.
|
||||
- A minimum approval count can be enforced.
|
||||
- Stale approvals (approvals given before new commits were pushed) can be auto-dismissed or ignored.
|
||||
- Merge can be blocked if any review requests changes, if requested reviewers haven't reviewed yet,
|
||||
or if the branch is outdated relative to its base.
|
||||
- Repository admins are not exempt from these rules by default — an explicit
|
||||
"administrators must follow branch protection rules" setting is what removes their force-merge
|
||||
bypass.
|
||||
|
||||
A skill that merges PRs should treat "CI passing" and "reviews satisfied" as two independently
|
||||
checkable gates — `get_status` covers CI, but review/approval state and branch-protection
|
||||
constraints are a separate check the merge call itself will enforce server-side and return as an
|
||||
error if unmet.
|
||||
|
||||
## Release and tag conventions
|
||||
|
||||
Releases are conceptually separate from tags but always tied to one: a release wraps a tag with a
|
||||
title, notes, and optional binary assets. Practitioner convention (per the `tea` CLI, the reference
|
||||
Gitea client) is:
|
||||
|
||||
- Tag names are semver-style, typically `v`-prefixed (`v1.2.0`, `v2.0.0-beta.1`).
|
||||
- Release notes are commonly sourced from a changelog file rather than typed inline.
|
||||
- Draft and prerelease are separate boolean flags, not states inferred from the tag name — a
|
||||
prerelease is anything with a `-beta`/`-rc` style suffix by convention, but Gitea does not enforce
|
||||
this; the skill should treat `draft`/`prerelease` as flags the caller sets explicitly rather than
|
||||
something to infer from the tag string.
|
||||
- Deleting a release does not delete its tag by default — the two are separate destructive
|
||||
operations (confirmed by `delete_release` taking a numeric release ID per `troubleshooting.md`,
|
||||
distinct from `delete_tag`).
|
||||
|
||||
## File editing: direct commit vs. PR
|
||||
|
||||
Gitea's own UI defaults to prompting for a target branch when creating/editing a file directly
|
||||
through the web interface, and supports pre-filling a new file's path and content via query
|
||||
parameters — reflecting that direct-commit file edits are a first-class, expected workflow (not just
|
||||
an API escape hatch). This supports `create_or_update_file`/`delete_file` being used directly against
|
||||
a working branch as a normal editing action, with the SHA-currency requirement (`troubleshooting.md`)
|
||||
being the main gotcha rather than direct-commit being an anti-pattern to avoid.
|
||||
@@ -11,7 +11,8 @@
|
||||
"issues",
|
||||
"prs",
|
||||
"milestones",
|
||||
"releases"
|
||||
"releases",
|
||||
"branches"
|
||||
],
|
||||
"license": "MIT",
|
||||
"mcpServers": ".mcp.json",
|
||||
@@ -19,5 +20,5 @@
|
||||
"skills": [
|
||||
"skills/"
|
||||
],
|
||||
"version": "1.0.0"
|
||||
"version": "1.3.0"
|
||||
}
|
||||
|
||||
35
plugins/gitea/skills/gitea-branches/README.md
Normal file
35
plugins/gitea/skills/gitea-branches/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# gitea-branches
|
||||
|
||||
Manage Gitea repository branches and inspect commit history via the Gitea MCP server.
|
||||
|
||||
## What it does
|
||||
|
||||
This skill handles branch lifecycle operations (list, create, delete) and read-only commit
|
||||
history (list commits, get a single commit's full detail) against a Gitea repository. It resolves
|
||||
`owner`/`repo` from the git remote, dispatches to the right MCP tool, and applies safety and
|
||||
pagination conventions specific to Gitea's API (e.g. refusing to delete a protected branch without
|
||||
explicit confirmation, and treating unexpected 404s as possible masked 403s).
|
||||
|
||||
## Before you start
|
||||
|
||||
Requires a Gitea MCP server configured with a token. `list_branches`, `list_commits`, and
|
||||
`get_commit` work with `write:issue` alone; `create_branch` and `delete_branch` need
|
||||
`write:repository`. Requires a git remote named `origin` pointing at the Gitea instance.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/gitea-branches
|
||||
```
|
||||
|
||||
Describe your task: list/create/delete a branch, or list/inspect commits. 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/branches.md` | Verified call signatures and mechanics for list/create/delete branch |
|
||||
| `references/commits.md` | Verified call signatures and mechanics for list/get commit |
|
||||
| `references/sources.md` | Research sources backing the branch/commit guidance |
|
||||
66
plugins/gitea/skills/gitea-branches/SKILL.md
Normal file
66
plugins/gitea/skills/gitea-branches/SKILL.md
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
name: gitea-branches
|
||||
|
||||
description: >
|
||||
Use when managing Gitea repository branches — listing, creating, or deleting
|
||||
branches — or inspecting commit history within a Gitea repo: listing commits
|
||||
(optionally filtered by branch or file path) or getting full detail for a
|
||||
single commit by SHA. Triggers on "list branches", "create a branch",
|
||||
"delete a branch", "what commits are on this branch", "show commit <sha>",
|
||||
"what changed in that commit" — even if the user doesn't say "Gitea"
|
||||
explicitly, as long as the repo's remote is a Gitea instance. Do not use for
|
||||
local git branch/commit operations on your working copy (use git-branches or
|
||||
git-history) or for PR-side branch references like cross-repo fork PR heads
|
||||
(use gitea-prs).
|
||||
|
||||
compatibility: Requires Gitea MCP server configured with a token; list_branches, list_commits, and get_commit work with write:issue alone, create_branch and delete_branch require write:repository. Requires git remote "origin" pointing to the Gitea instance.
|
||||
|
||||
metadata:
|
||||
category: integration
|
||||
version: "0.1.0"
|
||||
source_keys:
|
||||
- gitea-mcp-repo
|
||||
- gitea-mcp-slim-go
|
||||
- context7-websites-gitea
|
||||
|
||||
allowed-tools: Bash mcp__gitea__list_branches mcp__gitea__create_branch mcp__gitea__delete_branch mcp__gitea__list_commits mcp__gitea__get_commit
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Never delete a protected branch (`main`/`master` by name, or `protected: true` from `list_branches`) without explicit confirmation.** `delete_branch` is a direct API call, not a local `git push` — there is no client-side force-push guard protecting it. Name-matching `main`/`master` is a convenient default but not authoritative — a repo can protect a differently-named default branch. When in doubt, call `list_branches` first and check `protected` on the target; treat deletion of any protected branch as a hard refusal unless the user explicitly confirms in the conversation.
|
||||
- **404 may actually mean 403.** Gitea hides permission errors as not-found to avoid leaking resource existence. If any of these five tools returns 404 unexpectedly, check token scope (see `references/branches.md` / `references/commits.md`) before concluding the branch or commit doesn't exist.
|
||||
- **Pagination is manual.** `list_branches` and `list_commits` return one page at a time — no auto-pagination in the MCP layer. When you need a complete list, iterate `page: 1, 2, ...` until the returned count is less than `per_page`.
|
||||
- **Owner/repo always come from the git remote, never from `get_me`.** Resolve them via `git remote get-url origin` (Step 1 below). `get_me`/`list_my_repos` are blocked under the token scopes this skill assumes.
|
||||
- **`create_branch`'s source is `old_branch`, not "wherever gitea-mcp feels like."** Omitting `old_branch` forks from the repo's server-side default branch — not necessarily the branch you're currently working on locally. If you want to branch from your current checkout, pass `old_branch` explicitly.
|
||||
|
||||
## Step 1 — Resolve owner and repo
|
||||
|
||||
Before any tool call, extract `owner` and `repo` from the git remote:
|
||||
|
||||
```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-branches` or `/gitea-branches list` | List branches |
|
||||
| `/gitea-branches create <name> [from <base>]` | Create branch |
|
||||
| `/gitea-branches delete <name>` | Delete branch |
|
||||
| `/gitea-branches commits [on <branch>] [touching <path>]` | List commit history |
|
||||
| `/gitea-branches commit <sha>` | Get full detail for one commit |
|
||||
|
||||
For branch operations (list/create/delete), read `references/branches.md`.
|
||||
For commit operations (list/get), read `references/commits.md`.
|
||||
|
||||
## Step 3 — Report
|
||||
|
||||
For reads: display branches as name + protected flag; display commits as SHA (short), message summary, author, date.
|
||||
|
||||
For writes (create/delete): confirm the action taken, the branch name, and (for create) the base it forked from.
|
||||
|
||||
For errors: surface the HTTP code and message. If a 404 is unexpected, re-check token scope per the Gotchas above before reporting "not found" to the user.
|
||||
78
plugins/gitea/skills/gitea-branches/references/branches.md
Normal file
78
plugins/gitea/skills/gitea-branches/references/branches.md
Normal file
@@ -0,0 +1,78 @@
|
||||
---
|
||||
topic: branches
|
||||
source_keys:
|
||||
- gitea-mcp-repo
|
||||
- gitea-mcp-slim-go
|
||||
---
|
||||
|
||||
# Branch operations
|
||||
|
||||
Call signatures below were verified live against the deployed `gitea-mcp` server via `ToolSearch`
|
||||
at authoring time, not copied from research docs — this is deliberate: research docs are generated
|
||||
from source code at a point in time and can drift from the server actually deployed. Re-verify
|
||||
against the live schema if these tools appear to behave differently than documented here.
|
||||
|
||||
## `list_branches`
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (string, required)
|
||||
- `repo` (string, required)
|
||||
- `page` (number, optional, default: `1`)
|
||||
- `per_page` (number, optional, default: `30`)
|
||||
|
||||
**Call:**
|
||||
```
|
||||
list_branches owner: <owner> repo: <repo>
|
||||
```
|
||||
|
||||
**Response:** one object per branch: `name`, `protected` (bool), `commit_sha` (present when the
|
||||
underlying commit data is available).
|
||||
|
||||
Paginate if you need the full list (see Gotchas in SKILL.md) — iterate `page` until the returned
|
||||
count is less than `per_page`.
|
||||
|
||||
## `create_branch`
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (string, required)
|
||||
- `repo` (string, required)
|
||||
- `branch` (string, required) — new branch name
|
||||
- `old_branch` (string, optional) — source branch; if omitted, defaults to the repo's default
|
||||
branch server-side (not necessarily your current local checkout)
|
||||
|
||||
**Call:**
|
||||
```
|
||||
create_branch owner: <owner> repo: <repo> branch: <new-name> old_branch: <source-branch>
|
||||
```
|
||||
|
||||
Default dispatch: if the user gives a base ("branch off of X", "from X"), pass it as `old_branch`.
|
||||
If they don't specify a base and you're mid-task on a local branch, pass your current branch
|
||||
(`git branch --show-current`) as `old_branch` so the new branch forks from where you're actually
|
||||
working, rather than silently falling back to the repo default. If neither applies (e.g. a fresh
|
||||
top-level request with no working branch context), omit `old_branch` and let it default server-side.
|
||||
|
||||
A branch name collision returns `409 Conflict`.
|
||||
|
||||
## `delete_branch`
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (string, required)
|
||||
- `repo` (string, required)
|
||||
- `branch` (string, required)
|
||||
|
||||
**Call:**
|
||||
```
|
||||
delete_branch owner: <owner> repo: <repo> branch: <name>
|
||||
```
|
||||
|
||||
Before calling this, see the hard-refusal Gotcha in SKILL.md. If the target branch's name isn't
|
||||
obviously a scratch/feature branch, call `list_branches` first and check `protected` on the
|
||||
matching entry — name-matching `main`/`master` alone isn't authoritative, since a repo can protect
|
||||
a differently-named default branch. Confirm explicitly with the user before deleting anything
|
||||
protected, every time, regardless of how the request is phrased.
|
||||
|
||||
## Token scope
|
||||
|
||||
`list_branches` works with `write:issue` alone. `create_branch` and `delete_branch` need
|
||||
`write:repository`. All three are verified working empirically under a token with both scopes
|
||||
(`write:issue` + `write:repository`).
|
||||
67
plugins/gitea/skills/gitea-branches/references/commits.md
Normal file
67
plugins/gitea/skills/gitea-branches/references/commits.md
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
topic: commits
|
||||
source_keys:
|
||||
- gitea-mcp-repo
|
||||
- gitea-mcp-slim-go
|
||||
---
|
||||
|
||||
# Commit operations
|
||||
|
||||
Read-only commit history, scoped to a repo (optionally to one branch or one path). Call signatures
|
||||
below were verified live against the deployed `gitea-mcp` server via `ToolSearch` at authoring time,
|
||||
not copied from research docs, for the same drift-avoidance reason noted in `references/branches.md`.
|
||||
|
||||
This domain has no prior skill precedent — it's new coverage added alongside branches because commit
|
||||
history is naturally scoped to a branch (a "what happened on this branch" question), not because it
|
||||
shares any tool family with branch create/delete.
|
||||
|
||||
## `list_commits`
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (string, required)
|
||||
- `repo` (string, required)
|
||||
- `sha` (string, optional) — starting SHA or branch name; if omitted, gitea-mcp uses the repo's
|
||||
default branch
|
||||
- `path` (string, optional) — restrict results to commits that touched this file/path
|
||||
- `page` (number, optional, default: `1`, minimum: `1`)
|
||||
- `per_page` (number, optional, default: `30`, minimum: `1`)
|
||||
|
||||
**Call:**
|
||||
```
|
||||
list_commits owner: <owner> repo: <repo> sha: <branch-or-sha> path: <optional-path>
|
||||
```
|
||||
|
||||
Dispatch defaults:
|
||||
- "commits on `<branch>`" → pass `<branch>` as `sha`.
|
||||
- "commits touching `<path>`" (no branch mentioned) → pass `path` alone, `sha` omitted (defaults to
|
||||
the repo's default branch).
|
||||
- Both given → pass both; the result is history for that path, walked from that branch/SHA.
|
||||
- Neither given → omit both; this returns default-branch history, which is a reasonable default for
|
||||
an open-ended "what's the recent history here" question.
|
||||
|
||||
**Response:** one object per commit: `sha`, `html_url`, `created`, `message` (when available),
|
||||
`author` (`{name, email, date}`, when available).
|
||||
|
||||
Paginate per the manual-pagination Gotcha in SKILL.md if you need more than one page of history.
|
||||
|
||||
## `get_commit`
|
||||
|
||||
**Parameters:**
|
||||
- `owner` (string, required)
|
||||
- `repo` (string, required)
|
||||
- `sha` (string, required)
|
||||
|
||||
**Call:**
|
||||
```
|
||||
get_commit owner: <owner> repo: <repo> sha: <commit-sha>
|
||||
```
|
||||
|
||||
**Response:** same shape as a `list_commits` entry, but always fully populated (`message` and
|
||||
`author` are guaranteed present, not conditional). Use this when the user asks about one specific
|
||||
commit by SHA rather than browsing history — `list_commits` entries may omit `message`/`author` in
|
||||
edge cases, `get_commit` will not.
|
||||
|
||||
## Token scope
|
||||
|
||||
Both tools are read-only and work with `write:issue` alone (no `write:repository` needed), verified
|
||||
empirically against the deployed server.
|
||||
41
plugins/gitea/skills/gitea-branches/references/sources.md
Normal file
41
plugins/gitea/skills/gitea-branches/references/sources.md
Normal 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/branches.md` and `references/commits.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` below. 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 research docs cited here informed gotchas, response shapes, and workflow context, not the
|
||||
parameter lists themselves.
|
||||
|
||||
## 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. Informed the dispatch table and pagination / 404-may-mean-403 gotchas in SKILL.md, and the list/create/delete branch and list/get commit mechanics (including 409 conflict and default-branch fallback behavior) in references/branches.md and references/commits.md.
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||
- **Contributing files:** SKILL.md, references/branches.md, references/commits.md
|
||||
- **Status:** `extracted`
|
||||
|
||||
## gitea-mcp-slim-go
|
||||
|
||||
- **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/repo/slim.go
|
||||
- **Description:** Slim response shape structs from gitea-mcp source; defines exactly which fields the MCP server returns for branches (name, protected, commit_sha) and commits (sha, html_url, created, message, author), and informed get_commit's always-populated guarantee vs. list_commits' conditional fields.
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||
- **Contributing files:** references/branches.md, references/commits.md
|
||||
- **Status:** `extracted`
|
||||
|
||||
## context7-websites-gitea
|
||||
|
||||
- **URL:** context7:/websites/gitea
|
||||
- **Description:** Official Gitea docs mirror on Context7 — informed the protected-branch gotcha in SKILL.md (protected branches can block server-side operations regardless of client-side checks; admins aren't exempt by default).
|
||||
- **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 (semver tags, draft/prerelease flags). Consulted as part of the shared research pass but its content is scoped to releases/tags, out of scope for branches/commits — no content from it was used in this skill.
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||
- **Contributing files:** (none)
|
||||
- **Status:** `extracted`
|
||||
23
plugins/gitea/skills/gitea-files/README.md
Normal file
23
plugins/gitea/skills/gitea-files/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# gitea-files
|
||||
|
||||
Read and write individual files and directory/repository trees in a Gitea repository via the Gitea MCP server.
|
||||
|
||||
## What it does
|
||||
|
||||
This skill handles file-domain operations within the Gitea integration suite: reading a single file's contents, listing one directory level, walking a full repository tree (optionally recursive), creating or updating a file, and deleting a file. It owns the SHA-based optimistic-concurrency pattern that Gitea requires for file writes — the domain's sharpest gotcha — and defers branch creation, commit history, and pull request mechanics to `gitea-branches` and `gitea-prs`.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/gitea-files
|
||||
```
|
||||
|
||||
Describe the file task: read a file or directory, walk a tree, create/update a file, or delete a file. Provide `owner`/`repo`/branch (or ask the user if not given) — this skill does not resolve them from a git remote itself.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Skill instructions for agents |
|
||||
| `references/examples.md` | Canonical call sequences: branch + file + PR, recovering a missing SHA before an update, deleting a file |
|
||||
| `references/sources.md` | Research sources backing the SHA/concurrency and direct-commit-vs-PR guidance |
|
||||
53
plugins/gitea/skills/gitea-files/SKILL.md
Normal file
53
plugins/gitea/skills/gitea-files/SKILL.md
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
name: gitea-files
|
||||
|
||||
description: >
|
||||
Use when reading or writing individual files or directory trees in a Gitea repository via the
|
||||
Gitea MCP server: reading a file's contents, listing a directory, walking a full repository
|
||||
tree, creating a new file, updating an existing file, or deleting a file. Triggers on "read this
|
||||
file from the repo", "what's in this directory", "show me the repo tree", "create/update a file
|
||||
in Gitea", "commit this file to the branch", "delete this file from the repo" — even when the
|
||||
user doesn't say "Gitea" explicitly, as long as the target is a Gitea-hosted repository. Do not
|
||||
use for local filesystem file operations (use Read/Write/Edit), for branch or commit history
|
||||
(use gitea-branches), or for opening a pull request around a file change (use gitea-prs after
|
||||
the file write completes here).
|
||||
|
||||
compatibility: Requires the Gitea MCP server configured with a token scoped to at least
|
||||
write:repository. Tested with a token holding write:issue + write:repository; write:issue
|
||||
is not actually required for any of this domain's five tools.
|
||||
|
||||
metadata:
|
||||
category: gitea
|
||||
source_keys:
|
||||
- gitea-mcp-repo
|
||||
- gitea-mcp-slim-go
|
||||
- context7-websites-gitea
|
||||
|
||||
allowed-tools: mcp__gitea__get_file_contents mcp__gitea__get_dir_contents mcp__gitea__get_repository_tree mcp__gitea__create_or_update_file mcp__gitea__delete_file
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **SHA is the concurrency token for every write — and it lives at the top level of `get_file_contents`'s response, not nested under `content`.** `create_or_update_file` without `sha` is always treated as a *create*: if the path already exists, Gitea returns HTTP 409. `delete_file` has no optional path at all — omitting `sha` returns HTTP 422. The safe sequence for any update or delete is always: call `get_file_contents` first, read the top-level `sha` field, then pass that exact value to the write call. Never guess or reuse a stale SHA — a mismatched SHA is rejected the same as a missing one.
|
||||
- **`get_dir_contents` and `get_repository_tree` are not SHA sources for a specific file's write.** `get_dir_contents` entries carry no `sha` at all. `get_repository_tree` entries do carry a `sha` (a blob/tree hash), but fetching it means an extra round trip with no content — `get_file_contents` is the canonical path since it returns the decoded content and the write-ready `sha` in one call.
|
||||
- **`owner` and `repo` are always caller-supplied inputs, never resolved here.** This skill doesn't infer them from a git remote. If invoked directly by a human, ask for them if not stated. If invoked by `gitea-workflow` or an orchestrating agent, expect them to already be resolved and passed in.
|
||||
- **Direct commits to a branch are a first-class action, not a workaround.** Gitea's own web UI defaults to editing files directly against a branch — `create_or_update_file`/`delete_file` used that way is normal, not an API escape hatch to avoid. The SHA-currency requirement above is the actual risk to manage, not the act of committing directly.
|
||||
- **`ref` (reads) vs. `branch_name` (writes) are different parameters for the same concept.** `get_file_contents`, `get_dir_contents`, and `get_repository_tree` (as `tree_sha`) all accept a branch name, tag, or commit SHA to select what to read. `create_or_update_file` and `delete_file` instead take `branch_name` — the branch the commit lands on. Don't conflate the two when chaining a read into a write.
|
||||
- **Content is base64.** `create_or_update_file`'s `content` parameter is base64-encoded file content, not raw text — encode before calling. `get_file_contents`'s response content is likewise base64-encoded (decode after reading), unless `withLines: true` is passed for a numbered-line view.
|
||||
|
||||
## Reading
|
||||
|
||||
- **Single file:** `get_file_contents(owner, repo, ref, path)`. Pass `withLines: true` only when you need line numbers for referencing specific lines (e.g. quoting a snippet back to the user); omit it for a normal content fetch.
|
||||
- **One directory level:** `get_dir_contents(owner, repo, ref, path)` — returns immediate entries only (name, path, type, size), no recursion, no SHA, no content.
|
||||
- **Whole tree:** `get_repository_tree(owner, repo, tree_sha, recursive)` — `tree_sha` accepts a SHA, branch, or tag name despite the name. Set `recursive: true` to walk subdirectories in one call. Response includes `truncated: true` when a page doesn't hold every entry — page through with `page`/`per_page` (default `page: 1`, `per_page: 30`) until you get fewer results than `per_page`.
|
||||
|
||||
## Writing
|
||||
|
||||
- **Creating a new file:** call `create_or_update_file(owner, repo, path, content, message, branch_name)` with `sha` omitted entirely.
|
||||
- **Updating an existing file:** call `get_file_contents(owner, repo, ref: branch_name, path)` first, take the top-level `sha`, then call `create_or_update_file(..., sha: <that value>)`.
|
||||
- **Deleting a file:** call `get_file_contents` first the same way, then `delete_file(owner, repo, path, message, branch_name, sha: <that value>)` — `sha` is required, no create-style fallback exists.
|
||||
- **Creating a new branch as part of the write:** pass `new_branch_name` on `create_or_update_file` to branch off before the commit lands, instead of calling a separate branch-creation step.
|
||||
|
||||
If the change needs review before merging, or targets a protected branch, hand off to `gitea-prs` after the write lands here to open the pull request — this skill's scope ends at the commit.
|
||||
|
||||
If you need the full multi-call sequence rather than the single-call summary above — e.g. branching off as part of a file push ahead of opening a PR, or recovering a SHA you didn't capture earlier — read `references/examples.md`.
|
||||
65
plugins/gitea/skills/gitea-files/references/examples.md
Normal file
65
plugins/gitea/skills/gitea-files/references/examples.md
Normal file
@@ -0,0 +1,65 @@
|
||||
---
|
||||
source_keys:
|
||||
- gitea-mcp-repo
|
||||
- gitea-mcp-slim-go
|
||||
---
|
||||
|
||||
# Canonical call sequences
|
||||
|
||||
## Push a file to a new branch, then open a PR
|
||||
|
||||
```
|
||||
1. get_repository_tree or get_file_contents on the base branch — only needed if the
|
||||
new file is actually replacing an existing one; skip for a brand-new path.
|
||||
|
||||
2. create_or_update_file
|
||||
owner, repo
|
||||
path: "docs/example.md"
|
||||
content: "<base64-encoded content>"
|
||||
message: "docs: add example"
|
||||
branch_name: "main"
|
||||
new_branch_name: "feat/add-example" ← branches off before the commit lands
|
||||
(sha omitted — this is a new file)
|
||||
|
||||
3. Hand off to gitea-prs to open a PR from "feat/add-example" into "main".
|
||||
```
|
||||
|
||||
`new_branch_name` on `create_or_update_file` replaces a separate branch-creation call — the branch is created and the commit lands on it in one step.
|
||||
|
||||
## Update a file when you don't already have its SHA
|
||||
|
||||
SHA is mandatory for updates. If it wasn't captured earlier in the conversation:
|
||||
|
||||
```
|
||||
1. get_file_contents
|
||||
owner, repo
|
||||
ref: "main"
|
||||
path: "docs/example.md"
|
||||
→ read the top-level `sha` field (not content.sha)
|
||||
|
||||
2. create_or_update_file
|
||||
owner, repo
|
||||
path: "docs/example.md"
|
||||
content: "<new base64-encoded content>"
|
||||
message: "docs: update example"
|
||||
branch_name: "main"
|
||||
sha: "<sha from step 1>"
|
||||
```
|
||||
|
||||
Do not guess or omit the SHA — the write either fails (409 on create-path fallback) or is rejected outright.
|
||||
|
||||
## Delete a file
|
||||
|
||||
Same SHA-first pattern, no fallback path:
|
||||
|
||||
```
|
||||
1. get_file_contents owner, repo, ref: "main", path: "docs/old-example.md"
|
||||
→ read the top-level `sha` field
|
||||
|
||||
2. delete_file
|
||||
owner, repo
|
||||
path: "docs/old-example.md"
|
||||
message: "docs: remove old example"
|
||||
branch_name: "main"
|
||||
sha: "<sha from step 1>"
|
||||
```
|
||||
36
plugins/gitea/skills/gitea-files/references/sources.md
Normal file
36
plugins/gitea/skills/gitea-files/references/sources.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Sources
|
||||
|
||||
## gitea-mcp-repo
|
||||
|
||||
**Description:** Official gitea-mcp repository (v1.3.0); operation/*.go source files documenting all 55 MCP tools, their parameters, and CLI flags.
|
||||
|
||||
**Source:** https://gitea.com/gitea/gitea-mcp
|
||||
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||
|
||||
**Contributing files:**
|
||||
- SKILL.md (Gotchas, Reading, Writing — tool parameters and SHA/concurrency behavior, cross-checked live against the deployed MCP tool schemas via ToolSearch)
|
||||
- references/examples.md (canonical call sequences)
|
||||
|
||||
## gitea-mcp-slim-go
|
||||
|
||||
**Description:** Slim response shape structs from gitea-mcp source; defines exactly which fields the MCP server returns for files (top-level `sha`, no nested `content.sha`) and directory/tree entries.
|
||||
|
||||
**Source:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/repo/slim.go
|
||||
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||
|
||||
**Contributing files:**
|
||||
- SKILL.md (Gotchas — top-level `sha` field location, `get_dir_contents`/`get_repository_tree` not being usable SHA sources for a file write)
|
||||
- references/examples.md (SHA-first update/delete sequences)
|
||||
|
||||
## context7-websites-gitea
|
||||
|
||||
**Description:** Official Gitea docs mirror on Context7 (docs.gitea.com content) — confirms direct-commit file editing through the web UI is a first-class, expected workflow rather than an API-only escape hatch.
|
||||
|
||||
**Source:** context7:/websites/gitea
|
||||
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||
|
||||
**Contributing files:**
|
||||
- SKILL.md (Gotchas — "Direct commits to a branch are a first-class action, not a workaround")
|
||||
42
plugins/gitea/skills/gitea-issues/README.md
Normal file
42
plugins/gitea/skills/gitea-issues/README.md
Normal 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 |
|
||||
105
plugins/gitea/skills/gitea-issues/SKILL.md
Normal file
105
plugins/gitea/skills/gitea-issues/SKILL.md
Normal 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.
|
||||
92
plugins/gitea/skills/gitea-issues/references/enrichments.md
Normal file
92
plugins/gitea/skills/gitea-issues/references/enrichments.md
Normal 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.
|
||||
123
plugins/gitea/skills/gitea-issues/references/issues.md
Normal file
123
plugins/gitea/skills/gitea-issues/references/issues.md
Normal 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`.
|
||||
39
plugins/gitea/skills/gitea-issues/references/search.md
Normal file
39
plugins/gitea/skills/gitea-issues/references/search.md
Normal 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`.
|
||||
41
plugins/gitea/skills/gitea-issues/references/sources.md
Normal file
41
plugins/gitea/skills/gitea-issues/references/sources.md
Normal 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`
|
||||
25
plugins/gitea/skills/gitea-labels-milestones/README.md
Normal file
25
plugins/gitea/skills/gitea-labels-milestones/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# gitea-labels-milestones
|
||||
|
||||
Read and write Gitea labels and milestones, and resolve label/milestone identity for the skills that apply them to issues and PRs.
|
||||
|
||||
## What it does
|
||||
|
||||
This skill handles label and milestone CRUD (`label_read`/`label_write`, `milestone_read`/`milestone_write`) — listing repo or org labels, creating/editing/deleting a label, resolving a label name to the numeric ID required for any write, and listing/creating/updating/closing/deleting a milestone. It also owns label inference: mapping conversation context (bug report, feature request, urgency language) to this repo's `Kind/*`/`Priority/*`/`Status/*` taxonomy. It is a cross-cutting shared skill composed by `gitea-issues` and `gitea-prs`, which call into it for label/milestone resolution before their own `issue_write`/`pull_request_write` calls apply the resolved IDs.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/gitea-labels-milestones
|
||||
```
|
||||
|
||||
Describe the label or milestone task: list labels, resolve a name to an ID, create/edit/delete a label, or list/create/update/close/delete a milestone. For applying already-resolved labels or a milestone to a specific issue or PR, use `gitea-issues` or `gitea-prs` instead.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Skill instructions for agents — dispatch table and Gotchas |
|
||||
| `references/labels.md` | Execution detail for `label_read`/`label_write` |
|
||||
| `references/milestones.md` | Execution detail for `milestone_read`/`milestone_write` |
|
||||
| `references/label-inference.md` | Context-pattern → `Kind/*`/`Priority/*`/`Status/*` label inference guide |
|
||||
| `references/sources.md` | Research sources backing the label/milestone guidance |
|
||||
58
plugins/gitea/skills/gitea-labels-milestones/SKILL.md
Normal file
58
plugins/gitea/skills/gitea-labels-milestones/SKILL.md
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
name: gitea-labels-milestones
|
||||
|
||||
description: >
|
||||
Use when reading or writing Gitea labels or milestones — listing repo/org labels, creating,
|
||||
editing, or deleting a label, resolving label names to the numeric IDs required for applying
|
||||
them to an issue or PR, or listing, creating, updating, closing, or deleting a milestone. This is
|
||||
a cross-cutting shared skill: `gitea-issues` and `gitea-prs` both compose it whenever they need to
|
||||
apply labels or assign a milestone, rather than duplicating label/milestone logic. Also use for
|
||||
label inference — mapping a bug report, feature request, or urgency signal in conversation
|
||||
context to the repo's `Kind/*`/`Priority/*`/`Status/*` label taxonomy. Do not use for applying
|
||||
already-resolved label IDs or milestone IDs to a specific issue or PR — that write goes through
|
||||
`issue_write`/`pull_request_write` in `gitea-issues`/`gitea-prs`, not here.
|
||||
|
||||
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__label_read mcp__gitea__label_write mcp__gitea__milestone_read mcp__gitea__milestone_write
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Label writes take IDs, reads return names.** `label_read` is the only tool that returns full label objects (`id`, `name`, `color`, `description`). Issue/PR responses slim labels down to name strings. Before any label is applied to an issue or PR (in `gitea-issues`/`gitea-prs`), resolve names → IDs here via `label_read method: "list_repo_labels"` — never pass a name string where an ID is expected.
|
||||
- **Milestones are referenced by ID everywhere, never by title.** `milestone_write` update/delete take `id`. The one place titles show up as the sole handle is the `pull_request_read` response (see next gotcha).
|
||||
- **Milestone representation differs between issues and PRs.** `issue_read` returns `milestone: {id, title}` — an object. `pull_request_read` returns `milestone: "title string"` — title only, no ID. You cannot recover a milestone ID from a PR response directly; call `milestone_read method: "list"` and match by title instead.
|
||||
- **Repo labels and org labels are separate pools, never mixed in one call.** `label_read`/`label_write` take either `owner`+`repo` (repo-scoped methods) or `org` (org-scoped methods) — passing both or neither for a given method is a caller error, not something the schema enforces for you. Repo and org labels can both apply to the same issue, but you list/create/edit them through different method values.
|
||||
- **`milestone_write` accepts `"update"` and `"edit"` as the same operation.** Both method values map to the identical update call. Prefer `"update"` for consistency with `issue_write`/`pull_request_write`.
|
||||
- **A `/` in a label name plus `exclusive: true` means mutual exclusivity, not just a naming convention.** This repo's `Kind/*`, `Priority/*`, `Status/*` labels follow Gitea's native scoped-label feature: applying a new label within a scope (e.g. `Priority/High`) is expected to replace any existing label in that same scope, not add alongside it. Label inference (see `references/label-inference.md`) must respect this — replace, don't stack.
|
||||
- **Pagination is manual on every list call.** `label_read` and `milestone_read` both default to `per_page: 30`. Iterate `page: 1, 2, ...` until the result count is less than `per_page` — there is no cursor or auto-pagination.
|
||||
- **Schema requiredness differs between the two tool families.** `milestone_read`/`milestone_write` have `owner` and `repo` as hard-required parameters (the call fails validation without them). `label_read`/`label_write` only hard-require `method` — `owner`/`repo`/`org` are functionally required per method but not schema-enforced, so passing none produces a runtime error from Gitea, not a client-side validation error.
|
||||
|
||||
## Dispatch
|
||||
|
||||
| Task | Tool | method |
|
||||
|---|---|---|
|
||||
| List repo labels | `label_read` | `"list_repo_labels"` |
|
||||
| Get one repo label by ID | `label_read` | `"get_repo_label"` |
|
||||
| List org labels | `label_read` | `"list_org_labels"` |
|
||||
| Create a repo/org label | `label_write` | `"create_repo_label"` / `"create_org_label"` |
|
||||
| Edit a repo/org label | `label_write` | `"edit_repo_label"` / `"edit_org_label"` |
|
||||
| Delete a repo/org label | `label_write` | `"delete_repo_label"` / `"delete_org_label"` |
|
||||
| List milestones | `milestone_read` | `"list"` |
|
||||
| Get one milestone by ID | `milestone_read` | `"get"` |
|
||||
| Create a milestone | `milestone_write` | `"create"` |
|
||||
| Update / close a milestone | `milestone_write` | `"update"` |
|
||||
| Delete a milestone | `milestone_write` | `"delete"` |
|
||||
|
||||
For full parameter detail and step-by-step call sequences, read `references/labels.md` (label operations) or `references/milestones.md` (milestone operations). For mapping conversation context to a label to apply, read `references/label-inference.md`.
|
||||
|
||||
Applying resolved label IDs or a milestone ID to a specific issue or PR is out of scope here — that's `issue_write`/`pull_request_write` in the composing skill (`gitea-issues`/`gitea-prs`).
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
topic: label-inference
|
||||
source_keys:
|
||||
- context7-websites-gitea
|
||||
- gitea-mcp-repo
|
||||
---
|
||||
|
||||
# Label inference guide
|
||||
|
||||
Maps context-pattern signals from conversation content (an issue being drafted, a bug report, a PR
|
||||
description) to this repo's `Kind/*` / `Priority/*` / `Status/*` label taxonomy. Used by
|
||||
`gitea-issues` and `gitea-prs` before creating or updating an issue/PR, and directly when the user
|
||||
asks to label something without naming exact labels.
|
||||
|
||||
## Scoped labels are mutually exclusive — replace, don't stack
|
||||
|
||||
Each of `Kind/*`, `Priority/*`, `Status/*` is a Gitea scoped-label group (the `/` delimiter plus
|
||||
`exclusive: true` on the label). Applying a new label within a scope is expected to replace any
|
||||
existing label in that same scope on the target issue/PR, not add alongside it. When inference
|
||||
selects a `Priority/High` label and the issue already carries `Priority/Medium`, the write should
|
||||
result in only `Priority/High` remaining — use `replace_labels` scoped to that group's labels, or at
|
||||
minimum remove the superseded label before adding the new one. Never leave two labels from the same
|
||||
scope applied at once.
|
||||
|
||||
## Signal → label mapping
|
||||
|
||||
**`Kind/*`** (what kind of work this is):
|
||||
|
||||
| Signal in context | Label |
|
||||
|---|---|
|
||||
| Bug report, error, crash, unexpected behavior, "broken", "doesn't work" | `Kind/Bug` |
|
||||
| New capability, "add support for", net-new functionality | `Kind/Feature` |
|
||||
| Improvement to existing behavior, "make X better", refactor with behavior change | `Kind/Enhancement` |
|
||||
| Docs-only change, README/comment/guide updates | `Kind/Documentation` |
|
||||
| Vulnerability, credential exposure, injection risk, auth bypass | `Kind/Security` |
|
||||
|
||||
**`Priority/*`** (urgency):
|
||||
|
||||
| Signal in context | Label |
|
||||
|---|---|
|
||||
| "blocking", "critical", "urgent", production-down | `Priority/Critical` |
|
||||
| "soon", "high priority", "should do this sprint" | `Priority/High` |
|
||||
| No urgency signal present | `Priority/Medium` (default) |
|
||||
|
||||
**`Status/*`** (workflow state):
|
||||
|
||||
| Signal in context | Label |
|
||||
|---|---|
|
||||
| Explicit statement that the work is blocked on something else | `Status/Blocked` |
|
||||
|
||||
## Procedure
|
||||
|
||||
1. Read the conversation context (issue/PR title, body, or the triggering discussion) for the
|
||||
signals above.
|
||||
2. Call `label_read method: "list_repo_labels"` (see `references/labels.md`) to get the current
|
||||
label set with IDs — inference must never guess an ID, only a name, then resolve it.
|
||||
3. Match inferred label names against the resolved list (case-insensitive). If a scope group
|
||||
already has a different label applied on the target and a new one is inferred for that same
|
||||
scope, plan to replace rather than add (see above).
|
||||
4. **Low-confidence inference omits the label.** If no signal confidently maps to a `Kind/*` value,
|
||||
do not guess — omit `Kind/*` entirely rather than default to one. `Priority/Medium` is the one
|
||||
exception: it's the explicit default when no urgency signal is present, not a guess.
|
||||
5. Hand the resolved IDs (plus which scopes to replace) to the caller's `issue_write`/
|
||||
`pull_request_write` call — this skill does not apply labels to an issue or PR itself.
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
topic: labels
|
||||
source_keys:
|
||||
- gitea-mcp-repo
|
||||
- gitea-mcp-slim-go
|
||||
---
|
||||
|
||||
# Label operations
|
||||
|
||||
Execution detail for `label_read` and `label_write`. Both tools operate on either **repo-scoped**
|
||||
or **org-scoped** labels — never both in one call. Pick the method family (`*_repo_label*` vs.
|
||||
`*_org_label*`) that matches the target, and pass `owner`+`repo` or `org` accordingly.
|
||||
|
||||
## Verified live schemas
|
||||
|
||||
`label_read` — required: `method`.
|
||||
|
||||
| Param | Type | Notes |
|
||||
|---|---|---|
|
||||
| `method` | string (enum) | `"list_repo_labels"` \| `"get_repo_label"` \| `"list_org_labels"` |
|
||||
| `owner` | string | for repo methods |
|
||||
| `repo` | string | for repo methods |
|
||||
| `org` | string | for org methods |
|
||||
| `id` | number | label ID, required for `"get_repo_label"` |
|
||||
| `page` | number | default `1` |
|
||||
| `per_page` | number | default `30` |
|
||||
|
||||
`label_write` — required: `method`.
|
||||
|
||||
| Param | Type | Notes |
|
||||
|---|---|---|
|
||||
| `method` | string (enum) | `"create_repo_label"` \| `"edit_repo_label"` \| `"delete_repo_label"` \| `"create_org_label"` \| `"edit_org_label"` \| `"delete_org_label"` |
|
||||
| `owner` | string | for repo methods |
|
||||
| `repo` | string | for repo methods |
|
||||
| `org` | string | for org methods |
|
||||
| `id` | number | for edit/delete |
|
||||
| `name` | string | required for create |
|
||||
| `color` | string | hex `#RRGGBB`, required for create |
|
||||
| `description` | string | optional |
|
||||
| `exclusive` | boolean | org labels only |
|
||||
| `is_archived` | boolean | repo labels only |
|
||||
|
||||
Note: unlike `milestone_read`/`milestone_write`, `owner`/`repo`/`org` are **not** schema-required on
|
||||
either label tool — only `method` is. Passing none for a repo/org method still fails, just as a
|
||||
runtime error from Gitea rather than a client-side validation error.
|
||||
|
||||
## List repo labels
|
||||
|
||||
```
|
||||
label_read method: "list_repo_labels" owner: <owner> repo: <repo> per_page: 50
|
||||
```
|
||||
|
||||
Paginate (`page: 1, 2, ...`) until the returned count is less than `per_page`. This is the only way
|
||||
to build a complete name → ID map — there is no lookup-by-name endpoint.
|
||||
|
||||
## Get one label
|
||||
|
||||
```
|
||||
label_read method: "get_repo_label" owner: <owner> repo: <repo> id: <id>
|
||||
```
|
||||
|
||||
## Resolve a name to an ID
|
||||
|
||||
There is no direct name lookup. List all repo labels (paginating if needed), scan for a
|
||||
case-insensitive name match, and extract `id`. This is the required first step before any label
|
||||
application on an issue or PR — the actual `add_labels`/`replace_labels`/`remove_label` call lives
|
||||
in `gitea-issues`/`gitea-prs` via `issue_write`/`pull_request_write`, which take numeric IDs only.
|
||||
|
||||
## Create a label
|
||||
|
||||
```
|
||||
label_write method: "create_repo_label"
|
||||
owner: <owner> repo: <repo>
|
||||
name: "Kind/Bug"
|
||||
color: "#d73a4a"
|
||||
description: "Confirmed bug"
|
||||
```
|
||||
|
||||
For an org label, use `method: "create_org_label"` with `org:` instead of `owner`/`repo`, and
|
||||
`exclusive: true` if the label belongs to a mutually-exclusive scope group.
|
||||
|
||||
## Edit a label
|
||||
|
||||
```
|
||||
label_write method: "edit_repo_label" owner: <owner> repo: <repo> id: <id> color: "#ff0000"
|
||||
```
|
||||
|
||||
Only pass the fields being changed — `id` plus any of `name`/`color`/`description`/`is_archived`.
|
||||
|
||||
## Delete a label
|
||||
|
||||
```
|
||||
label_write method: "delete_repo_label" owner: <owner> repo: <repo> id: <id>
|
||||
```
|
||||
|
||||
Deleting a label does not remove it from historical issue/PR timeline events — it disappears only
|
||||
from current label lists.
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
topic: milestones
|
||||
source_keys:
|
||||
- gitea-mcp-repo
|
||||
- gitea-mcp-slim-go
|
||||
---
|
||||
|
||||
# Milestone operations
|
||||
|
||||
Execution detail for `milestone_read` and `milestone_write`. Milestones are always repo-scoped —
|
||||
there is no org-level milestone concept, unlike labels.
|
||||
|
||||
## Verified live schemas
|
||||
|
||||
`milestone_read` — required: `method`, `owner`, `repo`.
|
||||
|
||||
| Param | Type | Notes |
|
||||
|---|---|---|
|
||||
| `method` | string (enum) | `"get"` \| `"list"` |
|
||||
| `owner` | string | required |
|
||||
| `repo` | string | required |
|
||||
| `id` | number | milestone ID, required for `"get"` |
|
||||
| `name` | string | title filter, for `"list"` |
|
||||
| `state` | string | default `"all"` — conventional values `"open"`/`"closed"`/`"all"`, but **not enforced by an enum in the live schema** (plain string). Any other value is passed through to Gitea rather than rejected client-side. |
|
||||
| `page` | number | default `1` |
|
||||
| `per_page` | number | default `30` |
|
||||
|
||||
`milestone_write` — required: `method`, `owner`, `repo`.
|
||||
|
||||
| Param | Type | Notes |
|
||||
|---|---|---|
|
||||
| `method` | string (enum) | `"create"` \| `"update"` \| `"edit"` \| `"delete"` — `"update"`/`"edit"` are aliases for the same operation; prefer `"update"` |
|
||||
| `owner` | string | required |
|
||||
| `repo` | string | required |
|
||||
| `id` | number | required for update/delete |
|
||||
| `title` | string | required for create |
|
||||
| `description` | string | optional |
|
||||
| `due_on` | string | due date — the live tool schema only describes this as an opaque "due date" string with no enforced format; ISO 8601 (e.g. `"2025-03-01T00:00:00Z"`) is the conventional value Gitea's REST API accepts, not something confirmed by the live MCP schema itself |
|
||||
| `state` | string (enum) | `"open"` \| `"closed"` — **this one is schema-enforced**, unlike `milestone_read`'s `state` |
|
||||
|
||||
Note: unlike `label_read`/`label_write`, both milestone tools hard-require `owner` and `repo` at the
|
||||
schema level — there's no scope variant to omit them for.
|
||||
|
||||
## List milestones
|
||||
|
||||
```
|
||||
milestone_read method: "list" owner: <owner> repo: <repo> state: "open"
|
||||
```
|
||||
|
||||
Report each as: id, title, state, due date, open/closed issue counts.
|
||||
|
||||
## Get one milestone
|
||||
|
||||
```
|
||||
milestone_read method: "get" owner: <owner> repo: <repo> id: <id>
|
||||
```
|
||||
|
||||
## Resolve a milestone ID from a title
|
||||
|
||||
Needed whenever the only handle available is a title — e.g. a `pull_request_read` response, which
|
||||
returns `milestone` as a bare title string rather than `{id, title}`. Call:
|
||||
|
||||
```
|
||||
milestone_read method: "list" owner: <owner> repo: <repo> name: <title>
|
||||
```
|
||||
|
||||
and take the `id` of the matching result. If `name` filtering returns no match (e.g. due to a
|
||||
title typo or case mismatch), fall back to listing without the filter and matching manually.
|
||||
|
||||
## Create a milestone
|
||||
|
||||
```
|
||||
milestone_write method: "create"
|
||||
owner: <owner> repo: <repo>
|
||||
title: "v1.0"
|
||||
description: "First stable release"
|
||||
due_on: "2025-03-01T00:00:00Z"
|
||||
```
|
||||
|
||||
Report the returned ID — the caller (`gitea-issues`/`gitea-prs`) needs it to assign issues/PRs to
|
||||
this milestone via `issue_write`/`pull_request_write`.
|
||||
|
||||
## Update or close a milestone
|
||||
|
||||
```
|
||||
milestone_write method: "update" owner: <owner> repo: <repo> id: <id> state: "closed"
|
||||
```
|
||||
|
||||
Only pass the fields being changed — `id` plus any of `title`/`description`/`due_on`/`state`.
|
||||
|
||||
## Delete a milestone
|
||||
|
||||
```
|
||||
milestone_write method: "delete" owner: <owner> repo: <repo> id: <id>
|
||||
```
|
||||
|
||||
Deleting a milestone does not delete or unassign the issues/PRs that referenced it — they simply
|
||||
lose the milestone reference.
|
||||
@@ -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
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||
- **Contributing files:** SKILL.md, references/labels.md, references/milestones.md, references/label-inference.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
|
||||
- **Description:** Slim response shape structs from gitea-mcp source; defines exactly which fields the MCP server returns for issues, PRs, branches, commits, tags, releases, and files — including the label name-vs-ID and milestone object-vs-string representation quirks this skill's Gotchas document
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||
- **Contributing files:** SKILL.md, references/labels.md, references/milestones.md
|
||||
- **Status:** `extracted`
|
||||
|
||||
## context7-websites-gitea
|
||||
|
||||
- **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
|
||||
- **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 labels and milestones
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||
- **Contributing files:** SKILL.md
|
||||
- **Status:** `extracted`
|
||||
25
plugins/gitea/skills/gitea-prs/README.md
Normal file
25
plugins/gitea/skills/gitea-prs/README.md
Normal 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 |
|
||||
68
plugins/gitea/skills/gitea-prs/SKILL.md
Normal file
68
plugins/gitea/skills/gitea-prs/SKILL.md
Normal 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`.
|
||||
41
plugins/gitea/skills/gitea-prs/references/merging.md
Normal file
41
plugins/gitea/skills/gitea-prs/references/merging.md
Normal 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.
|
||||
75
plugins/gitea/skills/gitea-prs/references/pull-requests.md
Normal file
75
plugins/gitea/skills/gitea-prs/references/pull-requests.md
Normal 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.
|
||||
43
plugins/gitea/skills/gitea-prs/references/reviews.md
Normal file
43
plugins/gitea/skills/gitea-prs/references/reviews.md
Normal 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.
|
||||
33
plugins/gitea/skills/gitea-prs/references/sources.md
Normal file
33
plugins/gitea/skills/gitea-prs/references/sources.md
Normal 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`
|
||||
24
plugins/gitea/skills/gitea-releases/README.md
Normal file
24
plugins/gitea/skills/gitea-releases/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# gitea-releases
|
||||
|
||||
Manage Gitea releases and tags — list, create, and delete releases (with draft/prerelease flags and notes) and their underlying tags.
|
||||
|
||||
## What it does
|
||||
|
||||
This skill handles release and tag operations for a Gitea repository. It creates releases from a tag/target commitish with title, notes, and draft/prerelease flags; lists and paginates releases and tags; retrieves the latest release; and deletes releases and tags as separate, independent destructive operations. It resolves the numeric release id required for deletion instead of assuming a tag name will work.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/gitea-releases
|
||||
```
|
||||
|
||||
Describe your release/tag task: list releases, get the latest release, create a release (with a tag, target, and title), or delete a release or tag. The skill handles resolving the numeric release id where required and keeps release/tag deletion as distinct operations.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Skill instructions for agents |
|
||||
| `references/call-signatures.md` | Verified tool parameters and response shapes for all 9 release/tag tools |
|
||||
| `references/conventions.md` | Semver/draft/prerelease practitioner conventions and pagination behavior |
|
||||
| `references/sources.md` | Research sources backing the call signatures and conventions |
|
||||
52
plugins/gitea/skills/gitea-releases/SKILL.md
Normal file
52
plugins/gitea/skills/gitea-releases/SKILL.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: gitea-releases
|
||||
|
||||
description: >
|
||||
Use when managing Gitea releases and tags for a repository: listing, creating, or deleting
|
||||
releases (with draft/prerelease flags and release notes), and listing, creating, or deleting the
|
||||
underlying git tags. Use even if the user doesn't say "release" explicitly — "cut a v1.2.0",
|
||||
"publish a prerelease", "tag this commit", or "what's the latest release" all apply. Do not use
|
||||
for git branch or commit history operations (use gitea-branches) or for issue/PR management (use
|
||||
gitea-issues / gitea-prs).
|
||||
|
||||
metadata:
|
||||
category: gitea
|
||||
source_keys:
|
||||
- gitea-mcp-repo
|
||||
- gitea-mcp-slim-go
|
||||
- context7-websites-gitea
|
||||
- context7-gitea-tea-cli
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **`delete_release` takes a numeric `id`, never a tag name.** `delete_tag` is the mirror opposite — it takes the `tag_name` string, never a numeric id. These two tools are asymmetric on purpose; passing a tag name to `delete_release` or a numeric id to `delete_tag` fails. Always resolve the numeric release id via `list_releases` or `get_release` first if you only have a tag name in hand.
|
||||
- **Deleting a release does not delete its tag.** They are separate destructive operations against separate resources — a release is a wrapper (title, notes, draft/prerelease flags, assets) around a tag, not the tag itself. If the intent is to remove both, call `delete_release` and `delete_tag` separately.
|
||||
- **`list_releases`/`list_tags` default to `per_page: 20`**, unlike most other gitea-mcp tools which default to 30. There is no auto-pagination in the MCP layer — to get a complete result set, loop `page` upward until a page returns fewer than `per_page` results.
|
||||
- **`draft`/`is_pre_release` are explicit booleans the caller sets on `create_release` — never inferred from `tag_name`.** Practitioner convention (per the `tea` CLI) uses `-beta`/`-rc` suffixes for prereleases (e.g. `v2.0.0-beta.1`), but Gitea does not enforce or infer this from the tag string. If the user names a tag that looks like a prerelease, set `is_pre_release: true` explicitly rather than assuming the flag is redundant with the name.
|
||||
- **Tag names are conventionally semver, `v`-prefixed** (`v1.2.0`, `v2.0.0-beta.1`), but this is a practitioner convention, not a Gitea constraint — don't reject or rewrite a caller-supplied tag name that doesn't follow it.
|
||||
|
||||
## Dispatch table
|
||||
|
||||
| Action | Tool | Required params | Optional params |
|
||||
|---|---|---|---|
|
||||
| List releases | `list_releases` | `owner`, `repo` | `is_draft`, `is_pre_release`, `page` (default 1), `per_page` (default 20) |
|
||||
| Get one release | `get_release` | `owner`, `repo`, `id` (number) | — |
|
||||
| Get latest release | `get_latest_release` | `owner`, `repo` | — |
|
||||
| Create release | `create_release` | `owner`, `repo`, `tag_name`, `target`, `title` | `body`, `is_draft`, `is_pre_release` |
|
||||
| Delete release | `delete_release` | `owner`, `repo`, `id` (number) | — |
|
||||
| List tags | `list_tags` | `owner`, `repo` | `page` (default 1), `per_page` (default 20) |
|
||||
| Get one tag | `get_tag` | `owner`, `repo`, `tag_name` | — |
|
||||
| Create tag | `create_tag` | `owner`, `repo`, `tag_name` | `target`, `message` |
|
||||
| Delete tag | `delete_tag` | `owner`, `repo`, `tag_name` | — |
|
||||
|
||||
`target` (on `create_release`/`create_tag`) is a commitish — a branch name, existing tag, or commit SHA — the point the new tag is cut from. See `references/call-signatures.md` for response shapes.
|
||||
|
||||
## Workflow
|
||||
|
||||
- [ ] **Creating a release:** Call `create_release` directly with `tag_name` + `target` + `title` — it creates the underlying tag automatically if `tag_name` doesn't already exist, so a separate `create_tag` call is only needed when you want to tag a commit without wrapping it in a release yet. Set `is_pre_release`/`is_draft` explicitly per the Gotchas above; don't leave them to default inference.
|
||||
- [ ] **Deleting a release safely:** Resolve the numeric id first — call `list_releases` (paginate if needed, see Gotchas) or `get_release` if the id is already known, find the entry matching the target `tag_name`, then call `delete_release` with that `id`. Never pass `tag_name` to `delete_release`.
|
||||
- [ ] **Deleting a tag along with its release:** Delete the release first (frees the id lookup), then call `delete_tag` with the `tag_name` separately — confirm both are intended before proceeding, since each is an independent irreversible operation.
|
||||
- [ ] **Listing completely:** If the caller needs all releases or tags (not just the first page), loop `page: 1, 2, 3...` until a response has fewer than `per_page` entries.
|
||||
|
||||
If exact response field shapes or additional conventions are needed, read `references/call-signatures.md` and `references/conventions.md`.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
topic: call-signatures
|
||||
source_keys:
|
||||
- gitea-mcp-repo
|
||||
- gitea-mcp-slim-go
|
||||
---
|
||||
|
||||
# Release and tag call signatures
|
||||
|
||||
Verified against the live MCP tool schemas at authoring time (not copied from upstream API docs,
|
||||
which can drift from the deployed gitea-mcp version). `owner` and `repo` are required strings on
|
||||
every tool below and are omitted from the per-tool lists for brevity.
|
||||
|
||||
## Releases
|
||||
|
||||
**`list_releases`**
|
||||
- Optional: `is_draft` (boolean), `is_pre_release` (boolean), `page` (number, default 1), `per_page` (number, default 20)
|
||||
- Returns an array of release objects (shape below), one page at a time.
|
||||
|
||||
**`get_release`**
|
||||
- Required: `id` (number) — the release's numeric id, not its tag name.
|
||||
- Returns a single release object.
|
||||
|
||||
**`get_latest_release`**
|
||||
- No parameters beyond `owner`/`repo`.
|
||||
- Returns a single release object for the most recently published (non-draft, non-prerelease by Gitea's own "latest" definition) release.
|
||||
|
||||
**`create_release`**
|
||||
- Required: `tag_name` (string), `target` (string — branch, tag, or commit SHA to cut the tag from), `title` (string)
|
||||
- Optional: `body` (string — release notes), `is_draft` (boolean), `is_pre_release` (boolean)
|
||||
- If `tag_name` doesn't already exist as a tag, Gitea creates it against `target` as part of this call.
|
||||
|
||||
**`delete_release`**
|
||||
- Required: `id` (number) — same numeric id as `get_release`. Does not accept `tag_name`.
|
||||
- Does not delete the underlying tag.
|
||||
|
||||
**Release object shape** (returned by list/get/create/latest):
|
||||
```
|
||||
id, tag_name, target, title, body, draft, prerelease, html_url, author, created_at, published_at
|
||||
```
|
||||
`author` is the creator's login. `body` holds the release notes.
|
||||
|
||||
## Tags
|
||||
|
||||
**`list_tags`**
|
||||
- Optional: `page` (number, default 1), `per_page` (number, default 20)
|
||||
- Returns an array of `{ name, commit_sha }` — no `message` field on list responses.
|
||||
|
||||
**`get_tag`**
|
||||
- Required: `tag_name` (string)
|
||||
- Returns `{ name, message, commit_sha }` — the only tag call that returns `message`.
|
||||
|
||||
**`create_tag`**
|
||||
- Required: `tag_name` (string)
|
||||
- Optional: `target` (string — commitish to tag; if omitted, Gitea tags the default branch tip), `message` (string — annotated tag message)
|
||||
|
||||
**`delete_tag`**
|
||||
- Required: `tag_name` (string). Does not accept a numeric id.
|
||||
- Does not delete any release wrapping the tag.
|
||||
|
||||
## Pagination
|
||||
|
||||
None of the list tools auto-paginate. To collect a full result set, call with `page: 1`, then
|
||||
`page: 2`, etc., stopping when a page returns fewer items than `per_page`. `list_releases` and
|
||||
`list_tags` default `per_page` to 20 — lower than the 30-default used by most other gitea-mcp list
|
||||
tools, so a caller assuming 30 will under-count pages needed for a fixed total.
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
topic: conventions
|
||||
source_keys:
|
||||
- context7-websites-gitea
|
||||
- context7-gitea-tea-cli
|
||||
---
|
||||
|
||||
# Release and tag conventions
|
||||
|
||||
Practitioner conventions that inform *how* to use the mechanics in `call-signatures.md` — not
|
||||
additional tool schemas.
|
||||
|
||||
## Release wraps a tag, not the reverse
|
||||
|
||||
A release is a title, body (notes), and draft/prerelease flags layered on top of an existing or
|
||||
newly-created tag. The tag is the git-level object (a name pointing at a commit); the release is a
|
||||
Gitea-level metadata wrapper around it. This is why `delete_release` and `delete_tag` are separate
|
||||
calls with separate identifiers (numeric id vs. tag name) — removing the wrapper never implies
|
||||
removing the underlying pointer, and vice versa.
|
||||
|
||||
## Semver tag naming
|
||||
|
||||
Per the `tea` CLI (the reference Gitea client), tag names conventionally follow semver with a `v`
|
||||
prefix: `v1.2.0`, `v2.0.0-beta.1`. This is a convention observed by tooling and humans, not a
|
||||
Gitea-enforced constraint — the API accepts any string as `tag_name`. Don't validate or rewrite a
|
||||
caller-supplied tag name against semver; just pass it through.
|
||||
|
||||
## Draft and prerelease are explicit flags
|
||||
|
||||
`draft` and `is_pre_release`/`prerelease` are booleans the caller sets directly on `create_release`
|
||||
— Gitea does not infer either from the tag name, even though the `-beta`/`-rc` suffix convention
|
||||
above is commonly used to signal a prerelease to humans. When a user asks to "cut a beta" or
|
||||
"publish a release candidate," set `is_pre_release: true` explicitly in the same call rather than
|
||||
relying on the tag string to carry that meaning.
|
||||
|
||||
## Release notes sourcing
|
||||
|
||||
Practitioner convention (per `tea`) is to source release notes (`body`) from a changelog file
|
||||
rather than typing them inline for each release — useful context when a caller asks to "generate"
|
||||
or "use the changelog for" release notes rather than write them from scratch.
|
||||
48
plugins/gitea/skills/gitea-releases/references/sources.md
Normal file
48
plugins/gitea/skills/gitea-releases/references/sources.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 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.
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/api-reference.md (Releases and Tags section); plugins/gitea/docs/research/docs/gitea/troubleshooting.md (`delete_release` numeric-id gotcha, `per_page` defaults)
|
||||
|
||||
**Contributing files:**
|
||||
- SKILL.md (Dispatch table, Gotchas)
|
||||
- references/call-signatures.md
|
||||
|
||||
**Status:** `extracted`
|
||||
|
||||
## gitea-mcp-slim-go
|
||||
|
||||
- **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/repo/slim.go
|
||||
- **Description:** Slim response shape structs from gitea-mcp source; defines exactly which fields the MCP server returns for tags and releases.
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/api-reference.md (Releases and Tags response shapes)
|
||||
|
||||
**Contributing files:**
|
||||
- references/call-signatures.md (release/tag object shapes)
|
||||
|
||||
**Status:** `extracted`
|
||||
|
||||
## context7-websites-gitea
|
||||
|
||||
- **URL:** context7:/websites/gitea
|
||||
- **Description:** Official Gitea docs mirror on Context7 (docs.gitea.com content) — release and tag semantics, draft/prerelease behavior.
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/workflow-conventions.md (Release and tag conventions section)
|
||||
|
||||
**Contributing files:**
|
||||
- SKILL.md (Gotchas — draft/prerelease as explicit flags)
|
||||
- references/conventions.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 release/tag command patterns, semver tag conventions, draft/prerelease flags, release-notes-from-file conventions.
|
||||
- **Research doc:** plugins/gitea/docs/research/docs/gitea/workflow-conventions.md (Release and tag conventions section)
|
||||
|
||||
**Contributing files:**
|
||||
- SKILL.md (Gotchas — semver tag naming)
|
||||
- references/conventions.md
|
||||
|
||||
**Status:** `extracted`
|
||||
22
plugins/gitea/skills/gitea-workflow/README.md
Normal file
22
plugins/gitea/skills/gitea-workflow/README.md
Normal 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 |
|
||||
74
plugins/gitea/skills/gitea-workflow/SKILL.md
Normal file
74
plugins/gitea/skills/gitea-workflow/SKILL.md
Normal 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.
|
||||
33
plugins/gitea/skills/gitea-workflow/references/sources.md
Normal file
33
plugins/gitea/skills/gitea-workflow/references/sources.md
Normal 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
33
plugins/gitea/sources.md
Normal 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`
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ run_bats
|
||||
mapfile -t SCRIPTS < <(
|
||||
find "$SEARCH_ROOT" -name "test-*.sh" \
|
||||
-not -path "*/.git/*" \
|
||||
-not -path "*/.claude/worktrees/*" \
|
||||
| sort
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user