Ports dirigent's gitea scripts into a self-contained reliquary plugin. Scripts run via uv with PEP 723 inline deps — no project venv needed. Gitea connection inferred from `git remote get-url origin` with env-var overrides; only GITEA_TOKEN is mandatory. Workpad path and tickets directory are parameterized so the plugin works in any project. Label set externalized to labels.default.json with project-level override via .gitea-labels.json. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.1 KiB
name, description
| name | description |
|---|---|
| gitea | Use when working with Gitea tickets — fetching ticket context, creating issues from workpad goals, posting plans or reports as comments, listing/searching issues, closing issues, or scaffolding standard labels for a new repo. |
Gitea Ticket Integration
Bidirectional integration between the workpad and a Gitea instance. All operations are CLI scripts shipped with this plugin; nothing needs to be installed in the user's project.
Configuration
The scripts derive Gitea connection settings in this order:
git remote get-url originin the current working directory. SSH and HTTPS forms both work.base_url,owner, andrepoare parsed from it.- Env vars (
GITEA_URL,GITEA_OWNER,GITEA_REPO) override anything inferred from the remote. Useful for mirrors or when the API host differs from the clone host. GITEA_TOKENis always required from env or.env— never inferable.
The scripts call python-dotenv, which finds a .env in CWD (or any parent). So a project typically only needs GITEA_TOKEN set somewhere; everything else flows from the git remote.
Step 1: Verify connectivity
Always run this before any other Gitea operation:
uv run ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/ping.py
Prints the resolved URL/repo and Connection: OK on success.
On failure, stop. Tell the user what's wrong:
missing required configuration→ which fields are missing401→ token invalid or expired403→ token lacks scopes (issue + repository read/write)404→ wrong owner/repo, or token can't see a private repo- Connection refused → check
GITEA_URL(or the remote) includes the protocol
Do not retry or work around auth failures.
Workpad path
Most ticket-related scripts need a workpad path. Resolve it once at the start of the session:
WORKPAD_FOLDERenv var (read viaprintenv WORKPAD_FOLDER, or ajust workpad-folderrecipe if defined).- If unset, ask the user where the workpad is. Don't guess.
Then pass --workpad <resolved-path> to every script that takes it. If the user keeps tickets outside the workpad, use --tickets-dir <path> instead (overrides the <workpad>/tickets/ default).
Available scripts
All invocations use uv run ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/<name>.py. Each script carries inline PEP 723 dependencies — uv builds an isolated env on first run and caches it.
fetch_ticket.py <number> --workpad <path> [--tickets-dir <path>] [--no-comments]
Pulls a ticket as structured markdown to <tickets-dir>/<number>/context.md (default tickets dir = <workpad>/tickets). Includes labels, assignees, milestone, description, and all comments unless --no-comments.
start_ticket.py <number> --workpad <path> [--tickets-dir <path>] [--slug SLUG] [--no-checkout]
Recommended entry point when starting work on a ticket. Fetches the ticket, creates a branch ticket/<number>-<slug> from current HEAD, writes context.md to the tickets dir. Slug is derived from the title if not given. Warns if the current branch isn't main/master. Fails if the branch already exists locally or on the remote.
create_ticket.py (--from-goal <file> | --title <str> [--body <str>]) [--labels "l1,l2"]
Creates an issue. With --from-goal <file>, the first # heading in the markdown becomes the title and the rest becomes the body. Unmatched labels are warned and skipped.
post_comment.py <number> (<file> | --stdin) [--header "## Title"]
Posts a markdown file (or stdin) as a comment on an existing issue. Use this after writing a plan, report, or design that should live on the ticket.
list_tickets.py [--state open|closed|all] [--labels "l1,l2"] [--milestone NAME]
Lists matching issues. Defaults to open.
close_ticket.py <number> [<number> ...]
Closes one or more issues by number. Gitea also auto-closes when a commit on the default branch contains closes #N, fixes #N, or resolves #N — prefer that for natural workflow closes.
setup_labels.py
Creates the standard label set in the repo (or a project-defined set if .gitea-labels.json exists in CWD — total replacement, not merge). Skips labels that already exist. Run once when bootstrapping a new Gitea project.
Common workflows
Start work on an existing ticket
uv run ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/start_ticket.py 42 --workpad <workpad>
Then read <workpad>/tickets/42/context.md to understand the ticket.
Turn a workpad goal into a ticket
uv run ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/create_ticket.py \
--from-goal <workpad>/goals/my-feature.md \
--labels "✨ feature,📋 workpad"
Post a plan back to the ticket
uv run ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/post_comment.py 42 \
<workpad>/plans/2026-05-19-10-my-plan.md \
--header "## Implementation Plan"
Bootstrap a new Gitea project
- Create an API token (Gitea → Settings → Applications → Manage Access Tokens; scopes:
issueread/write,repositoryread/write). - Put
GITEA_TOKEN=...in a.envat the project root (gitignored). uv run ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/ping.pyuv run ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/setup_labels.py
That's it — URL/owner/repo come from git remote get-url origin.
Error recovery
| Error | Action |
|---|---|
| Missing configuration | Stop. Report exactly which fields are missing. |
| 401 Unauthorized | Stop. Token expired/invalid. User must regenerate. |
| 403 Forbidden | Stop. Token lacks scopes. User must update permissions. |
| 404 Not Found | Check owner/repo match the Gitea instance. May also mean ticket doesn't exist. |
| Connection refused | Check URL protocol (https://) and that the host is reachable. |
On any auth or config error, do not retry. Report and stop.
What NOT to do
- Don't hardcode URLs or tokens in scripts or comments.
- Don't attempt to work around auth failures.
- Don't modify the plugin's scripts from within a user session — that's a separate plugin-development task.
- Don't skip the connectivity check.
- Don't guess the workpad path — read
WORKPAD_FOLDERor ask.