Files
reliquary/plugins/gitea/skills/gitea/SKILL.md
T
g4borg 68c112d2c8 Add gitea plugin
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>
2026-05-19 19:52:02 +02:00

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:

  1. git remote get-url origin in the current working directory. SSH and HTTPS forms both work. base_url, owner, and repo are parsed from it.
  2. 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.
  3. GITEA_TOKEN is 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 missing
  • 401 → token invalid or expired
  • 403 → 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:

  1. WORKPAD_FOLDER env var (read via printenv WORKPAD_FOLDER, or a just workpad-folder recipe if defined).
  2. 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

  1. Create an API token (Gitea → Settings → Applications → Manage Access Tokens; scopes: issue read/write, repository read/write).
  2. Put GITEA_TOKEN=... in a .env at the project root (gitignored).
  3. uv run ${CLAUDE_PLUGIN_ROOT}/skills/gitea/scripts/ping.py
  4. uv 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_FOLDER or ask.