Files
Radix-Skills/skills/devops/gitea-issue-agent/SKILL.md
T
dennis 236053cd7f Initial import: 10 Radix skills across 3 categories
Kategoriserer danske regnskabs-/ERP-skills, ERP-data-afstemnings-
skill og to devops-workflows (gitea-issue-agent, kanban-workflows)
som Radix-medlemmers AI-agenter kan dele.

Struktur:
  skills/<kategori>/<skill-navn>/SKILL.md
  skills/<kategori>/<skill-navn>/{references,templates,scripts}/

Indekseret af index.json (genereret af scripts/rebuild_index.py).
Kør `python3 scripts/rebuild_index.py --check` i CI for at fange
synkroniseringsfejl.
2026-06-15 14:41:04 +02:00

13 KiB

name, description, version, author, license, metadata
name description version author license metadata
gitea-issue-agent Build a Hermes-managed autonomous issue handler for a self-hosted Gitea instance — scan issues, analyze text + screenshot attachments, post a proposal for human approval, implement, test, push a branch, and open a Gitea PR. Use when the user wants Hermes to act on Gitea issues end-to-end with a human-in-the-loop approval gate, especially with image/visual context in the issue text. 0.1.0 Hermes Agent MIT
hermes
tags related_skills
gitea
issues
automation
hermes-plugin
pr-workflow
agent-loop
approval-gate
gitea-tea-macos-setup
software-engineering-workflows

Gitea Issue Agent

End-to-end workflow for an autonomous Gitea issue handler that lives inside Hermes. Combines:

  • A Hermes plugin exposing Gitea REST API tools (status, scan, get, fetch images, comment, create PR).
  • A skill that orchestrates the human-in-the-loop loop: propose → wait for approval → implement → test → push → open PR.
  • An optional cron job that triggers the loop on a schedule.

When to use

  • User wants Hermes to monitor issues across one or more Gitea repos and propose fixes autonomously.
  • Issue text often includes screenshots or design mock-ups (image support is a first-class requirement).
  • A human (the user) must approve each fix before code is written.
  • Push and PR creation should target a working branch the user can review and merge manually.

Do not use for: GitHub (use the gitea-equivalent catalog MCP for that), issues that are just questions/discussions (no code work expected), or workflows where the user wants fully autonomous implementation with no human gate.

Architecture

                ┌────────────────────────────────────────┐
                │  ~/.hermes/plugins/gitea-issue-agent/  │
   Cron tick →  │  ├ plugin.yaml                         │
                │  ├ __init__.py   (registers 7 tools)   │
                │  └ README.md                            │
                └─────────────┬──────────────────────────┘
                              │ exposes
                              ▼
   gitea_agent_status        gitea_issue_agent_scan
   gitea_list_repositories   gitea_get_issue
   gitea_fetch_issue_images  gitea_comment_issue
                             gitea_create_pull_request
                              │ consumed by
                              ▼
                ┌────────────────────────────────────────┐
                │  Hermes skill  gitea-issue-agent-loop  │
                │  (orchestrates: scan → propose → wait   │
                │   → implement → test → push → PR)      │
                └─────────────┬──────────────────────────┘
                              │ triggers
                              ▼
                ┌────────────────────────────────────────┐
                │  Cron job (optional)  "every 30m"      │
                │  "Scan Gitea issues, propose solutions │
                │   for new ones, implement approved."   │
                └────────────────────────────────────────┘

The plugin does not implement the loop — it only exposes the API surface. The loop lives in the skill and the cron prompt. This separation keeps the plugin small and lets the loop evolve without code changes to the plugin.

Required environment variables

Add to ~/.hermes/.env and restart the gateway:

GITEA_BASE_URL=https://git.example.dk
GITEA_TOKEN=*** service-bruger PAT, scope: read+write issues/PRs/attachments>
GITEA_APPROVER_LOGIN=<the user's Gitea login, e.g. "dennis">
GITEA_DEFAULT_BASE_BRANCH=main
# Optional: comma-separated allowlist. If empty, /user/repos is scanned.
GITEA_REPOS=owner/repo1,owner/repo2
GITEA_AGENT_REPO_LIMIT=200
GITEA_AGENT_ISSUE_LIMIT_PER_REPO=50

Two Gitea identities, kept separate:

  • GITEA_TOKEN → service-bruger account (e.g. hermes-issues). Posts comments and PRs as a bot.
  • tea CLI → the user's personal token, e.g. dennis. Used for local git push of branches the user owns.

Mixing them causes comments to look like they came from the human personally. See references/identity-and-safety.md.

Tool set (the plugin registers these)

Tool Purpose
gitea_agent_status Verify config + API connectivity; reports authenticated_user.
gitea_list_repositories List repos visible to the token (or GITEA_REPOS allowlist).
gitea_issue_agent_scan Scan open issues, classify each as new / awaiting_approval / approved / pr_ready. Returns short summary + image count.
gitea_get_issue Fetch one issue + comments + image links + classification status.
gitea_fetch_issue_images Download all screenshots/attachments from the issue + comments to a local cache, so vision_analyze can inspect them.
gitea_comment_issue Post a comment; optional marker arg (proposal or pr_ready) prepends an HTML marker the scanner uses to track state.
gitea_create_pull_request Open a PR from an already-pushed branch. The branch must be created and pushed by the agent via git/terminal first.

Every tool returns JSON of the shape {"success": true, ...} or {"success": false, "error": "..."}. JSON is the only contract; the agent's loop should branch on success and surface error verbatim.

The workflow (the loop the skill/cron implements)

  1. Scan: gitea_issue_agent_scan to find status == "new" issues.
  2. For each new issue:
    1. gitea_get_issue for full text + comments.
    2. gitea_fetch_issue_images to download any screenshots to ~/.hermes/cache/gitea-issue-agent/<owner>/<repo>/<index>/.
    3. vision_analyze on each image (loaded into context) so the proposal is grounded in what the screenshot actually shows.
    4. Draft a proposal (in Danish if the user is Danish-speaking) covering:
      • summary of the bug/feature
      • root-cause hypothesis
      • proposed change (files, tests, branch name)
      • explicit approval request
    5. gitea_comment_issue with marker="proposal". The plugin prepends the <!-- hermes:gitea-issue-agent v1 status=proposal --> marker so the next scan classifies this issue as awaiting_approval.
  3. Stop and wait for approval. Do not implement. The skill exits cleanly; the cron re-scans later and the human will have either:
    • Posted an approval comment (matched by APPROVAL_RE against GITEA_APPROVER_LOGIN), or
    • Applied one of the approval labels (hermes-approved, approved-by-dennis, dennis-approved).
  4. On the next scan, issues that satisfy the approval rule are classified as approved. The skill then:
    1. cd into the local clone of the repo (clone it first via git clone if not present — tea clone will fail on non-standard SSH ports, see gitea-tea-macos-setup).
    2. Create a branch hermes/issue-<n>-<slug>.
    3. Implement, run tests, commit, push (with token in URL or via ~/.netrc).
    4. gitea_create_pull_request with head=hermes/issue-<n>-<slug>, base=main, body linking to the issue, draft=true.
    5. gitea_comment_issue with marker="pr_ready" and the PR URL.
  5. Stop. The user reviews the PR in Gitea and merges by hand.

The two state markers (proposal, pr_ready) are the only state machine. They survive Gitea restarts, plugin reloads, and Hermes restarts, because they live in the issue's comment history.

Approval semantics (default)

  • A comment from GITEA_APPROVER_LOGIN matching (?is)(@?hermes|agent|bot).{0,80}(godkend|approved|ok|go) counts as approval. Danish is first-class because the user is Danish-speaking.
  • Any of these labels applied by a maintainer also counts: hermes-approved, approved-by-dennis, dennis-approved.
  • Approval is only counted if it is after the latest proposal comment. Re-approving an old proposal does nothing.
  • If GITEA_APPROVER_LOGIN is not set, free-form approval comments are ignored — only labels count. This is the safe default until the user has decided which login should be allowed to approve.

For a longer rationale, see references/identity-and-safety.md.

Install checklist (do these in order)

  1. Decide on a service-bruger name (e.g. hermes-issues) and create a Gitea PAT for it with repository (read+write) + issue (write) scope.
  2. Tell the user the env vars they need to set in ~/.hermes/.env (see above). The agent cannot edit .env itself — Hermes blocks it at the tool layer. See references/identity-and-safety.md for why.
  3. Drop the plugin files into ~/.hermes/plugins/gitea-issue-agent/ (plugin.yaml + __init__.py + README.md).
  4. Tell the user to add - gitea-issue-agent under plugins.enabled in ~/.hermes/config.yaml. The agent cannot edit config.yaml either — same reason.
  5. Restart the gateway: hermes gateway restart.
  6. Verify with hermes chat -q "Kald gitea_agent_status" -t gitea_issue_agentapi_ok: true, authenticated_user: hermes-issues (or whatever the service-bruger is named).
  7. Verify the local CLI path: tea login add --name <user> --url ..., tea whoami, then git clone any visible repo (don't rely on tea clone — see gitea-tea-macos-setup for the SSH-port-2224 trap).
  8. Only then create the cron job, and only after the user has approved running it unattended.

Verification

Use the bundled script scripts/verify-plugin-and-gitea.sh to confirm the plugin is loaded, the API is reachable, and at least one repo is visible. It should print OK lines and exit 0.

Pitfalls (learned)

  • Hermes blocks the agent from writing to ~/.hermes/config.yaml and ~/.hermes/.env. The right move when blocked is to give the user the exact one-line edit and stop. Do not try execute_code, patch, or write_file a different way — the guard fires on all of them. See references/identity-and-safety.md.
  • tea clone fails opaquely when SSH is on a non-standard port (e.g. 2224). Use git clone with the HTTPS clone_url from the Gitea API. Strip the token from origin immediately.
  • Stale osxkeychain credentials can sabotage git push even when the token is correct. Switch to ~/.netrc with chmod 600. See the troubleshooting reference in gitea-tea-macos-setup.
  • Service-bruger identity matters. The plugin's authenticated_user field should NOT be your personal login. If it is, create a separate service-bruger or you'll get bot comments attributed to you.
  • Free-form approval comments must be gated by a known login (or by maintainer-applied labels) — otherwise a co-worker saying "looks good!" could trigger an autonomous push.
  • First run: verify, don't cron. Always run a manual scan + a manually-approved test issue before scheduling cron. A cron job firing off PRs in the user's name is the failure mode to avoid.
  • Image analysis is mandatory for screenshot issues. The plugin extracts image URLs and downloads them locally; the skill MUST call vision_analyze on each before writing the proposal, otherwise the proposal will be blind to what the screenshot shows.
  • Plugin state is in issue comments, not in plugin memory. The proposal/PR markers make the workflow restart-safe.
  • gitea-tea-macos-setup — the local tea + git + osxkeychain setup that the agent relies on. Includes the SSH-port-2224 trap and the getlogin(2) gotcha.
  • software-engineering-workflows — the plan / spike / TDD / debugging patterns the implement-and-test phase of the loop should follow.
  • software-development/simplify-code — useful to invoke on the agent's own code changes before opening the PR.

Files in this skill

  • scripts/verify-plugin-and-gitea.sh — one-shot verification of the full setup (plugin loaded + API reachable + repos visible + clone works). Run it after every change to the env or plugin.
  • references/identity-and-safety.md — service-bruger vs personal identity split, Hermes safety-guard reality, approval-gate design rationale.
  • templates/proposal-comment.md — starter template for the gitea_comment_issue body when posting a proposal. Copy, fill in the issue-specific bits, send.