feat(kyberforge): add gitea dispatch skill with research docs
Adds the gitea skill to kyberforge — a dispatch skill for managing Defame1297/holocron via Gitea MCP from within Claude Code. Covers issues, PRs, milestones, labels, branches, and status. Owner/repo derived from git remote at runtime; no config required. Also adds research docs (api-reference, data-model, examples, overview, troubleshooting) and token-access reference used during authoring and available for runtime scope lookups. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
38
plugins/kyberforge/skills/gitea/README.md
Normal file
38
plugins/kyberforge/skills/gitea/README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# gitea
|
||||
|
||||
Dispatch skill for managing a Gitea repo — issues, PRs, milestones, labels, and branches — from within Claude Code.
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `SKILL.md` | Skill definition — dispatch table, gotchas, execution steps |
|
||||
| `references/token-access.md` | Token scope inventory — what works vs. what needs additional scopes |
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/gitea # status: open issues + open PRs
|
||||
/gitea issue # create issue from conversation context
|
||||
/gitea issue <N> # get issue details
|
||||
/gitea issue close <N> # close issue
|
||||
/gitea issue comment <N> # add comment from conversation context
|
||||
/gitea label <N> Kind/Bug # apply labels by name (resolves IDs automatically)
|
||||
/gitea milestone # list milestones
|
||||
/gitea milestone create <title> # create milestone
|
||||
/gitea pr # create PR from current branch → main
|
||||
/gitea pr <N> # get PR status and diff summary
|
||||
/gitea pr merge <N> # squash-merge PR, delete branch
|
||||
/gitea branch # list branches
|
||||
/gitea branch create <name> # create branch from current branch
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Gitea MCP server configured in `~/.claude.json` with `write:issue` and `write:repository` token scopes
|
||||
- `git remote origin` pointing to the Gitea instance (used to derive owner/repo at runtime)
|
||||
|
||||
## Scope (v1)
|
||||
|
||||
In scope: issues, milestones, labels, PRs, branches, status.
|
||||
Out of scope: releases, CI/Actions, wiki, file operations, notifications, packages, time tracking.
|
||||
141
plugins/kyberforge/skills/gitea/SKILL.md
Normal file
141
plugins/kyberforge/skills/gitea/SKILL.md
Normal file
@@ -0,0 +1,141 @@
|
||||
---
|
||||
name: gitea
|
||||
description: >
|
||||
Use when the user wants to interact with Gitea — create or update issues,
|
||||
open or merge pull requests, manage labels and milestones, list branches,
|
||||
or check repo status. Triggers on: "create an issue", "open a PR", "what's
|
||||
open", "label this issue", "create a milestone", "merge the PR", "list
|
||||
branches", "close this issue" — even when the user doesn't say "Gitea"
|
||||
explicitly. Owner and repo are derived automatically from the git remote;
|
||||
no config required. Do not use for releases, CI/Actions, wiki, file
|
||||
operations, notifications, or package management — those are out of scope.
|
||||
compatibility: Requires Gitea MCP server configured in ~/.claude.json with write:issue and write:repository token scopes. Requires git remote "origin" pointing to the Gitea instance.
|
||||
allowed-tools: Bash mcp__gitea__list_issues mcp__gitea__search_issues mcp__gitea__issue_read mcp__gitea__issue_write mcp__gitea__label_read mcp__gitea__label_write mcp__gitea__milestone_read mcp__gitea__milestone_write mcp__gitea__list_pull_requests mcp__gitea__pull_request_read mcp__gitea__pull_request_write mcp__gitea__list_branches mcp__gitea__create_branch
|
||||
metadata:
|
||||
category: integration
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Label writes take IDs, reads return names.** `issue_write` (add_labels, replace_labels) requires `labels: [3, 7]` (numeric IDs). Issue and PR responses return `labels: ["bug", "enhancement"]` (name strings). These are never interchangeable. Always call `label_read method: "list_repo_labels"` first and resolve names → IDs before any label write.
|
||||
- **Issues and PRs share a number space.** `#5` might be an issue or a PR — there is only one counter per repo. `list_issues` returns both unless you pass `type: "issues"` or `type: "pulls"`. Check `is_pull` on a single-item `issue_read` response to determine the type.
|
||||
- **Milestone write takes ID, not title.** `issue_write` takes `milestone: <numeric id>`. The title is not accepted. In `issue_read` responses the milestone is `{id, title}`, but in `pull_request_read` responses it's a bare title string — you cannot recover the ID from a PR response. Call `milestone_read method: "list"` and match by title if you need the ID from a PR context.
|
||||
- **`get_me` is unavailable** with the current token (`write:issue, write:repository` only — `read:user` is missing). Owner and repo must always be derived from the git remote, never from `get_me` or `list_my_repos`.
|
||||
- **Issues are not auto-closed when a PR merges.** Unlike GitHub, Gitea does not close linked issues on merge. Close explicitly with `issue_write method: "update" state: "closed"` after merging.
|
||||
- **Pagination is manual.** List tools return one page at a time — no auto-pagination. When building complete datasets (e.g. all labels for name→ID mapping), iterate `page: 1, 2, ...` until result count < `per_page`.
|
||||
- **`pull_request_read method: "get"` returns `review_scomments`, not `review_comments`.** This is a source-level typo in gitea-mcp v1.3.0. Do not access `review_comments` — it will always be undefined. Use `review_scomments`.
|
||||
- **Cross-repo fork PRs require `head` as `"fork-owner:branch-name"`.** A bare branch name causes Gitea to search the base repo and return 422. The `pr create` dispatch assumes same-repo PRs (bare branch name). For fork-based PRs, pass `head` explicitly in the `owner:branch` format.
|
||||
- **`draft: true` on PR create prepends `WIP:` to the title.** There is no first-class draft field — Gitea implements draft PRs via title prefix. To un-draft, call `pull_request_write method: "update"` and pass the title without the `WIP:` prefix. This differs from GitHub's draft PR model.
|
||||
- **HTTP 404 may mean 403.** Gitea hides permission errors as not-found to avoid leaking resource existence. If a tool call returns 404 unexpectedly, check `references/token-access.md` before assuming the resource does not exist.
|
||||
|
||||
## 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
|
||||
|
||||
Route on the first argument:
|
||||
|
||||
| Invocation | Action |
|
||||
|---|---|
|
||||
| `/gitea` (no args) | **Status** — list open issues + open PRs |
|
||||
| `/gitea issue` | Create issue from conversation context |
|
||||
| `/gitea issue <N>` | Get issue details |
|
||||
| `/gitea issue close <N>` | Close issue |
|
||||
| `/gitea issue comment <N>` | Add comment from conversation context |
|
||||
| `/gitea label <N> <names...>` | Apply named labels to issue/PR |
|
||||
| `/gitea milestone` | List milestones |
|
||||
| `/gitea milestone create <title>` | Create milestone |
|
||||
| `/gitea pr` | Create PR from current branch → main |
|
||||
| `/gitea pr <N>` | Get PR status and diff summary |
|
||||
| `/gitea pr merge <N>` | Merge PR (squash, delete branch) |
|
||||
| `/gitea branch` | List branches |
|
||||
| `/gitea branch create <name>` | Create branch from current branch |
|
||||
|
||||
## Step 3 — Execute
|
||||
|
||||
### Status (default)
|
||||
|
||||
Call `list_issues` twice in parallel — once with `type: "issues"` and once with `type: "pulls"`, both `state: "open"`. Report as two sections.
|
||||
|
||||
### issue (create)
|
||||
|
||||
Extract title and body from conversation context. Use the most recent task, bug description, grill output, or explicit statement. If no body text is available from context, fall back to empty string. Fire immediately — no confirmation step.
|
||||
|
||||
Set `ref` to the current branch name (`git branch --show-current`) if a branch is already checked out for this work.
|
||||
|
||||
Call `issue_write method: "create" title: <extracted> body: <extracted or ""> ref: <current-branch-if-applicable>`.
|
||||
|
||||
### issue <N>
|
||||
|
||||
Call `issue_read method: "get" issue_number: <N>`. If the response includes `is_pull: true`, the number refers to a PR — report it as such and offer `pr <N>` for a full PR summary.
|
||||
|
||||
### issue close <N>
|
||||
|
||||
Call `issue_write method: "update" issue_number: <N> state: "closed"`. There is no `method: "close"` — using a non-existent method will error.
|
||||
|
||||
### issue comment <N>
|
||||
|
||||
Extract the comment body from conversation context (same sourcing as issue create). Call `issue_write method: "add_comment" issue_number: <N> body: <extracted>`.
|
||||
|
||||
### label <N> <names...>
|
||||
|
||||
1. Call `label_read method: "list_repo_labels"` — paginate until complete if > 30 labels.
|
||||
2. Match each provided name (case-insensitive) against the label list → collect IDs.
|
||||
3. Call `issue_write method: "add_labels" issue_number: <N> labels: [<matched IDs>]`.
|
||||
4. Report applied labels and warn on any names that did not match, listing available labels.
|
||||
|
||||
Do not fail the operation because of unmatched names — apply what matches.
|
||||
|
||||
### milestone
|
||||
|
||||
Call `milestone_read method: "list"`. Report each milestone as: id, title, state (open/closed), open issue count, closed issue count.
|
||||
|
||||
### pr (create)
|
||||
|
||||
1. `git branch --show-current` → head branch.
|
||||
2. Title: extract from conversation context; fall back to the last commit message (`git log -1 --pretty=%s`).
|
||||
3. Body: extract from conversation; fall back to empty.
|
||||
4. Call `pull_request_write method: "create" head: <branch> base: "main" title: <derived in step 2> body: <derived in step 3>`.
|
||||
|
||||
Note: this dispatch assumes a same-repo PR (bare branch name for `head`). For cross-repo fork PRs, `head` must be `"fork-owner:branch-name"` — see Gotchas.
|
||||
|
||||
### pr <N>
|
||||
|
||||
Call `pull_request_read method: "get"` and `pull_request_read method: "get_status"` in parallel (both take `pull_number: <N>`). Report: title, state, draft/merged flag, head → base, labels, CI status from get_status. Note: `milestone` in PR responses is a bare title string, not an object — you cannot extract a milestone ID from it.
|
||||
|
||||
### pr merge <N>
|
||||
|
||||
First call `pull_request_read method: "get_status" pull_number: <N>`. If CI status is failing, report it and warn the user — but do not block the merge unless they say to stop.
|
||||
|
||||
Then call `pull_request_write method: "merge" pull_number: <N> merge_style: "squash" delete_branch: true`. To use a different merge style, the user must specify it explicitly.
|
||||
|
||||
### milestone create <title>
|
||||
|
||||
Call `milestone_write method: "create" title: <title>`. Report the created milestone ID — it will be needed for assigning issues.
|
||||
|
||||
### branch
|
||||
|
||||
Call `list_branches`. Report each branch as: name, protected (bool).
|
||||
|
||||
### branch create <name>
|
||||
|
||||
Get the current local branch: `git branch --show-current`. Call `create_branch branch: <name> old_branch: <current-branch>`. This forks the new branch from where you are, not from the repo's default branch. If the user specifies a different base explicitly, use that instead.
|
||||
|
||||
## Step 4 — Report
|
||||
|
||||
For reads: display results as a compact table or numbered list — include number, title, labels, and milestone for issues/PRs.
|
||||
|
||||
For writes: confirm what was created/updated with the Gitea issue/PR number and URL if returned.
|
||||
|
||||
For errors: surface the HTTP code and message. 404 from some endpoints may actually mean insufficient token scope (Gitea hides 403 as 404 to avoid leaking resource existence).
|
||||
|
||||
If label resolution fails partially, always report which names were applied and which were skipped.
|
||||
|
||||
If token scope issues are suspected, read `references/token-access.md` for the full scope inventory.
|
||||
94
plugins/kyberforge/skills/gitea/references/token-access.md
Normal file
94
plugins/kyberforge/skills/gitea/references/token-access.md
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
topic: token-access
|
||||
description: Gitea MCP token scope inventory — what works with the configured token vs. what requires additional scopes
|
||||
---
|
||||
|
||||
# Gitea MCP Token Access
|
||||
|
||||
## Current token scope
|
||||
- write:issue
|
||||
- write:repository
|
||||
|
||||
## What works
|
||||
|
||||
### Repository discovery
|
||||
| Tool | Works | Notes |
|
||||
| -------------------------| ----------| ----------------------------|
|
||||
| `search_repos` | ✅ | Finds repos by keyword |
|
||||
| `list_my_repos` | ❌ | Needs `read:user` |
|
||||
| `list_org_repos` | ❌ | Needs `read:user` (inferred from `get_user_orgs` failure) |
|
||||
| `get_repository_tree` | ✅ | With `write:repository` |
|
||||
| `get_dir_contents` | ✅ | With `write:repository` |
|
||||
| `get_file_contents` | ✅ | With `write:repository` |
|
||||
| `create_or_update_file` | ✅ | Core `write:repository` op |
|
||||
| `delete_file` | ✅ | Core `write:repository` op |
|
||||
|
||||
### Issues
|
||||
| Tool | Works | Notes |
|
||||
| ------------------------------------------------------------------------| -------| -----------------------------|
|
||||
| `list_issues` | ✅ | Full list with state filter |
|
||||
| `search_issues` | ✅ | Cross-repo search |
|
||||
| `issue_read` (get) | ✅ | |
|
||||
| `issue_read` (get_comments) | ✅ | |
|
||||
| `issue_read` (get_labels) | ✅ | |
|
||||
| `issue_write` (create) | ✅ | Core `write:issue` op |
|
||||
| `issue_write` (update) | ✅ | |
|
||||
| `issue_write` (add_comment) | ✅ | |
|
||||
| `issue_write` (edit_comment) | ✅ | |
|
||||
| `issue_write` (add_labels, remove_label, replace_labels, clear_labels) | ✅ | |
|
||||
| `label_read` | ✅ | |
|
||||
| `label_write` | ✅ | |
|
||||
| `milestone_read` | ✅ | |
|
||||
| `milestone_write` | ✅ | |
|
||||
|
||||
### Pull Requests
|
||||
| Tool | Works | Notes |
|
||||
|---|---|---|
|
||||
| `list_pull_requests` | ✅ | |
|
||||
| `pull_request_read` (get, get_diff, get_files, get_status, get_reviews) | ✅ | |
|
||||
| `pull_request_write` (create, update, close, reopen, merge, update_branch) | ✅ | Needs `write:repository` |
|
||||
| `pull_request_review_write` | ✅ | |
|
||||
|
||||
### Branches & Commits
|
||||
| Tool | Works | Notes |
|
||||
|---|---|---|
|
||||
| `list_branches` | ✅ | |
|
||||
| `create_branch` | ✅ | `write:repository` |
|
||||
| `delete_branch` | ✅ | `write:repository` |
|
||||
| `list_commits` | ✅ | |
|
||||
| `get_commit` | ✅ | |
|
||||
|
||||
### Releases & Tags
|
||||
| Tool | Works | Notes |
|
||||
|---|---|---|
|
||||
| `list_releases`, `get_release`, `get_latest_release` | ✅ | |
|
||||
| `create_release`, `delete_release` | ✅ | `write:repository` |
|
||||
| `list_tags`, `get_tag`, `create_tag`, `delete_tag` | ✅ | `write:repository` |
|
||||
|
||||
### Actions (CI)
|
||||
| Tool | Works | Notes |
|
||||
|---|---|---|
|
||||
| `actions_config_read` (list_repo_secrets) | ❌ | "user should be the owner of the repo" — token auth not accepted for secrets |
|
||||
| `actions_config_write` | untested (write — not tested to avoid side effects) | |
|
||||
| `actions_run_read` (list_workflows) | ✅ empty | No workflows defined; returns `{total_count:0,workflows:[]}` |
|
||||
| `actions_run_read` (list_runs) | ❌ | "user should be the owner of the repo" — 403 |
|
||||
| `actions_run_write` | untested (write — not tested to avoid side effects) | |
|
||||
|
||||
### User & Identity
|
||||
| Tool | Works | Notes |
|
||||
|---|---|---|
|
||||
| `get_me` | ❌ | Needs `read:user` |
|
||||
| `search_users` | ❌ | Needs `read:user` |
|
||||
| `get_user_orgs` | ❌ | Needs `read:user` and `read:organization` |
|
||||
|
||||
### Other
|
||||
| Tool | Works | Notes |
|
||||
| ---------------------------------------| -----------------------------------------------------| ------------------------------------------|
|
||||
| `wiki_read` | ❌ | 404 — wiki not enabled for this repo |
|
||||
| `wiki_write` | untested (write — not tested to avoid side effects) | |
|
||||
| `notification_read` | ❌ | Needs `read:notification` scope |
|
||||
| `notification_write` | untested (write — not tested to avoid side effects) | |
|
||||
| `timetracking_read` (list_repo_times) | ✅ empty | No tracked times; returns string message |
|
||||
| `timetracking_write` | untested (write — not tested to avoid side effects) | |
|
||||
| `package_read` | ❌ | Needs `read:package` scope |
|
||||
| `package_write` | untested (write — not tested to avoid side effects) | |
|
||||
Reference in New Issue
Block a user