Files
gitea-infrastructure/.docs/DESIGN-gitea-agent-skill.md
Alex Mikhalev c6d425be63 feat(gitea-skill): Rewrite Gitea agent skill with verified API patterns
Rewrites SKILL.md with patterns verified against live Gitea 1.22.6:
- Milestones as project containers (project board API does not exist)
- Scoped workflow labels with mutual exclusivity
- Issue dependencies using IssueMeta format
- 1Password token retrieval via op read
- Default repo terraphim/agent-tasks with env var overrides

Adds setup-labels.sh for idempotent repo and label creation.
Includes research and design documents from disciplined development.
Adds pre-commit config adapted for infrastructure project.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 12:41:19 +01:00

22 KiB

Implementation Plan: Gitea Agent Skill for Project/Task Management

Phase: 2 - Disciplined Design Date: 2026-02-18 Status: DRAFT - Awaiting Approval Research Document: .docs/RESEARCH-gitea-agent-skill.md


1. Overview

Summary

Enhance the existing Gitea AI agent skill to support project and task management workflows for AI agents. The core insight from Phase 1 research is that Gitea 1.22.6 has NO project board REST API, so milestones serve as the API-backed project container. Labels implement a workflow state machine inspired by the br (beads_rust) pattern: ready -> in_progress -> done.

Approach

Option C from the research document: Dual-mode architecture combining gitea-mcp (official MCP server with 75+ tools) for standard operations with curl/jq shell helpers in the skill document for milestone management, issue dependencies, time tracking, and workflow orchestration -- areas where gitea-mcp has gaps.

Scope (5/25 Rule Applied)

Top 5 (Will Do):

  1. Rewrite SKILL.md with correct API endpoints (remove fake project board endpoints)
  2. Add milestone-based project management (create, list, progress tracking)
  3. Add label-based workflow state machine (ready/in_progress/blocked/done)
  4. Add shell helper functions with JSON output for agent consumption
  5. Add integration test script validating all operations against live Gitea

Next 20 (Will NOT Do):

  • Custom Gitea plugin for project boards
  • Gitea Actions workflow templates
  • Webhook-based event processing
  • Dashboard or web UI
  • Multi-instance Gitea federation
  • Custom MCP server wrapping Gitea API
  • Kanban board simulation via API
  • Automated code review integration
  • Release management automation
  • CI/CD pipeline integration

2. Architecture

Component Diagram

+--------------------------------------------------+
|                  AI Agent                          |
|  (Claude Code / MCP Client)                       |
+--------+------------------+----------------------+
         |                  |
         v                  v
+----------------+  +------------------+
| gitea-mcp      |  | SKILL.md         |
| (MCP Server)   |  | (Shell Helpers)  |
| - repos        |  | - milestones     |
| - issues CRUD  |  | - dependencies   |
| - PRs          |  | - workflow labels |
| - users/orgs   |  | - progress track |
| - branches     |  | - time tracking  |
| - files        |  | - setup-labels   |
+-------+--------+  +--------+---------+
        |                     |
        v                     v
+--------------------------------------------------+
|              Gitea REST API v1                      |
|         https://git.terraphim.cloud/api/v1         |
+--------------------------------------------------+
|              Gitea 1.22.6 Instance                 |
+--------------------------------------------------+

Data Flow

  1. Agent reads SKILL.md for available operations and patterns
  2. For standard CRUD (repos, issues, PRs): agent uses gitea-mcp tools
  3. For milestones, dependencies, workflow: agent uses curl/jq helpers from SKILL.md
  4. All helpers use GITEA_TOKEN from 1Password via op read
  5. All helpers output JSON for machine-readable agent consumption
  6. Labels encode workflow state; milestones encode project containers

Key Design Decisions

Decision Rationale
Milestones as projects Only API-backed grouping in Gitea 1.22.6; project board API does not exist
Labels for workflow state Lightweight, API-accessible, visible in UI, no custom code needed
curl/jq helpers (not scripts) Copy-paste into agent context; no installation; works everywhere
JSON output from all helpers Machine-readable for agent pipelines; parseable with jq
1Password op read for tokens Consistent with existing infrastructure; no plaintext secrets
Dual MCP + skill approach gitea-mcp covers 80% of operations; skill fills the 20% gap

Eliminated Options

Option Why Eliminated
Option A: Skill-only Ignores existing gitea-mcp with 75+ tools; duplicates work
Option B: MCP-only gitea-mcp lacks milestones, dependencies, workflow labels
Custom Gitea plugin Over-engineered; requires Go development and Gitea rebuilds
GitHub Projects API shim Wrong abstraction; Gitea is not GitHub
Database-backed state External dependency; Gitea already stores state in issues/labels

Simplicity Check

  • Could be explained in one paragraph? YES: "Use milestones as projects, labels as workflow states, curl/jq for API calls, gitea-mcp for standard ops"
  • Junior developer could implement from this plan? YES: all operations are curl commands with documented endpoints
  • No speculative features? YES: every feature maps to a concrete user request from the design brief
  • Every component has a clear owner? YES: SKILL.md owned by this repo; gitea-mcp is external dependency

3. File Changes

File 1: .agents/skills/gitea/SKILL.md (MODIFY)

What changes: Complete rewrite. Remove incorrect project board endpoints (lines 222-263). Restructure into: Configuration, Authentication, Core Operations (repos, issues, PRs, milestones, labels, releases), Agent Workflow (state machine, helpers), MCP Integration, Error Handling.

Why: Current file has non-existent API endpoints. Need milestone-based project management and workflow state machine for agent task tracking.

Size estimate: ~500 lines (currently ~366 lines)

File 2: .agents/skills/gitea/setup-labels.sh (NEW)

What changes: Shell script that creates the 12 workflow labels on a Gitea repository. Idempotent (checks for existing labels before creating). Uses GITEA_TOKEN and GITEA_URL environment variables.

Why: Labels are the foundation of the workflow state machine. Need automated setup rather than manual UI clicks.

Size estimate: ~80 lines

File 3: .agents/skills/gitea/test-gitea-skill.sh (NEW)

What changes: Integration test script that validates all skill operations against a live Gitea instance. Creates a test repo, runs all operations, validates JSON output, cleans up. Uses real API calls (no mocks).

Why: User instructions mandate no mocks. Need to verify all documented endpoints actually work with Gitea 1.22.6.

Size estimate: ~200 lines


4. API Design

Environment Variables

GITEA_URL="https://git.terraphim.cloud"   # Gitea instance URL
GITEA_TOKEN="$(op read op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential)"  # API token from 1Password
GITEA_OWNER="${GITEA_OWNER:-terraphim}"  # Org or user owning the repo
GITEA_REPO="${GITEA_REPO:-agent-tasks}"  # Default repo for task tracking (user-overridable)

Shell Helper Functions

All functions output JSON. All functions use these conventions:

  • Exit 0 on success, non-zero on failure
  • Print JSON to stdout
  • Print errors to stderr
  • Accept positional arguments (no flags)

4.1 gitea_api - Base API caller

# Usage: gitea_api METHOD ENDPOINT [DATA]
# Returns: JSON response from Gitea API
gitea_api() {
  local method="$1" endpoint="$2" data="${3:-}"
  local args=(-s -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json")
  if [ -n "$data" ]; then
    args+=(-X "$method" -d "$data")
  else
    args+=(-X "$method")
  fi
  curl "${args[@]}" "$GITEA_URL/api/v1$endpoint"
}

4.2 gitea_create_project - Create milestone as project

# Usage: gitea_create_project TITLE [DESCRIPTION] [DUE_DATE] [OWNER] [REPO]
# Returns: JSON milestone object with id, title, state, open_issues, closed_issues
# DUE_DATE format: 2026-03-01T00:00:00Z
# OWNER/REPO default to GITEA_OWNER/GITEA_REPO (terraphim/agent-tasks)
gitea_create_project() {
  local title="$1"
  local desc="${2:-}" due="${3:-}"
  local owner="${4:-$GITEA_OWNER}" repo="${5:-$GITEA_REPO}"
  local data
  data=$(jq -n --arg t "$title" --arg d "$desc" --arg due "$due" \
    '{title: $t, description: $d} + (if $due != "" then {due_on: $due} else {} end)')
  gitea_api POST "/repos/$owner/$repo/milestones" "$data"
}

4.3 gitea_create_task - Create issue with milestone and labels

# Usage: gitea_create_task TITLE BODY MILESTONE_ID [LABEL_IDS] [OWNER] [REPO]
# LABEL_IDS: comma-separated label IDs (e.g., "1,2,3")
# Returns: JSON issue object
gitea_create_task() {
  local title="$1" body="$2" milestone="$3"
  local labels="${4:-}"
  local owner="${5:-$GITEA_OWNER}" repo="${6:-$GITEA_REPO}"
  local data
  data=$(jq -n --arg t "$title" --arg b "$body" --argjson m "$milestone" \
    '{title: $t, body: $b, milestone: $m}')
  if [ -n "$labels" ]; then
    data=$(echo "$data" | jq --argjson l "[$labels]" '. + {labels: $l}')
  fi
  gitea_api POST "/repos/$owner/$repo/issues" "$data"
}

4.4 gitea_set_labels - Replace all labels on an issue

# Usage: gitea_set_labels ISSUE_INDEX LABEL_IDS [OWNER] [REPO]
# LABEL_IDS: comma-separated label IDs
# Returns: JSON array of label objects
gitea_set_labels() {
  local index="$1" labels="$2"
  local owner="${3:-$GITEA_OWNER}" repo="${4:-$GITEA_REPO}"
  gitea_api PUT "/repos/$owner/$repo/issues/$index/labels" "{\"labels\": [$labels]}"
}

4.5 gitea_ready - Mark task as ready for work

# Usage: gitea_ready ISSUE_INDEX [OWNER] [REPO]
# Adds "workflow:ready" label, removes other workflow labels
gitea_ready() {
  local index="$1"
  local owner="${2:-$GITEA_OWNER}" repo="${3:-$GITEA_REPO}"
  local ready_id
  ready_id=$(gitea_api GET "/repos/$owner/$repo/labels" | jq -r '.[] | select(.name=="workflow:ready") | .id')
  gitea_set_labels "$owner" "$repo" "$index" "$ready_id"
}

4.6 gitea_claim - Claim task (mark in-progress, assign self)

# Usage: gitea_claim ISSUE_INDEX [USERNAME] [OWNER] [REPO]
# Sets "workflow:in-progress" label, assigns user
gitea_claim() {
  local index="$1" user="${2:-}"
  local owner="${3:-$GITEA_OWNER}" repo="${4:-$GITEA_REPO}"
  local ip_id
  ip_id=$(gitea_api GET "/repos/$owner/$repo/labels" | jq -r '.[] | select(.name=="workflow:in-progress") | .id')
  gitea_set_labels "$owner" "$repo" "$index" "$ip_id"
  if [ -n "$user" ]; then
    gitea_api POST "/repos/$owner/$repo/issues/$index/assignees" "{\"assignees\": [\"$user\"]}"
  fi
}

4.7 gitea_close_task - Complete task

# Usage: gitea_close_task ISSUE_INDEX [COMMENT] [OWNER] [REPO]
# Sets "workflow:done" label, closes issue, optionally adds comment
gitea_close_task() {
  local index="$1" comment="${2:-}"
  local owner="${3:-$GITEA_OWNER}" repo="${4:-$GITEA_REPO}"
  local done_id
  done_id=$(gitea_api GET "/repos/$owner/$repo/labels" | jq -r '.[] | select(.name=="workflow:done") | .id')
  gitea_set_labels "$owner" "$repo" "$index" "$done_id"
  gitea_api PATCH "/repos/$owner/$repo/issues/$index" '{"state": "closed"}'
  if [ -n "$comment" ]; then
    local cdata
    cdata=$(jq -n --arg b "$comment" '{body: $b}')
    gitea_api POST "/repos/$owner/$repo/issues/$index/comments" "$cdata"
  fi
}

4.8 gitea_progress - Show project progress

# Usage: gitea_progress [MILESTONE_ID] [OWNER] [REPO]
# Returns: JSON with open/closed counts, percentage, task list
gitea_progress() {
  local milestone="${1:-}"
  local owner="${2:-$GITEA_OWNER}" repo="${3:-$GITEA_REPO}"
  if [ -n "$milestone" ]; then
    local ms
    ms=$(gitea_api GET "/repos/$owner/$repo/milestones/$milestone")
    echo "$ms" | jq '{
      milestone: .title,
      open: .open_issues,
      closed: .closed_issues,
      total: (.open_issues + .closed_issues),
      percent_complete: (if (.open_issues + .closed_issues) > 0
        then (.closed_issues * 100 / (.open_issues + .closed_issues))
        else 0 end)
    }'
  else
    gitea_api GET "/repos/$owner/$repo/milestones?state=open"
  fi
}

5. Label Scheme

Workflow Labels (mutually exclusive)

Label Color Description
workflow:ready #0e8a16 (green) Task is ready for an agent to pick up
workflow:in-progress #fbca04 (yellow) Task is actively being worked on
workflow:blocked #d93f0b (red) Task is blocked by a dependency
workflow:done #6f42c1 (purple) Task is complete

Priority Labels

Label Color Description
priority:critical #b60205 (dark red) Must be done immediately
priority:high #d93f0b (red) Should be done this cycle
priority:medium #fbca04 (yellow) Normal priority
priority:low #0e8a16 (green) Nice to have

Type Labels

Label Color Description
type:feature #1d76db (blue) New functionality
type:bug #d93f0b (red) Defect fix
type:task #5319e7 (violet) General task
type:research #006b75 (teal) Investigation/spike

6. Agent Workflow State Machine

                 create_task
                     |
                     v
             +---------------+
             | workflow:ready |<--------+
             +-------+-------+         |
                     |                  |
              gitea_claim         (unblock)
                     |                  |
                     v                  |
          +--------------------+  +------------------+
          | workflow:in-progress|->| workflow:blocked  |
          +---------+----------+  +------------------+
                    |
             gitea_close_task
                    |
                    v
            +---------------+
            | workflow:done  |
            | (issue closed) |
            +---------------+

Workflow Commands (br-inspired)

br Command Gitea Equivalent Description
br ready gitea_ready 1 Mark task #1 ready
br update ID --status in_progress gitea_claim 1 myuser Claim and start task #1
br close ID gitea_close_task 1 "Done" Complete task #1
br list --status ready gitea_api GET /repos/$GITEA_OWNER/$GITEA_REPO/issues?labels=workflow:ready List ready tasks
br status gitea_progress 1 Show milestone #1 progress

All helpers default to GITEA_OWNER=terraphim and GITEA_REPO=agent-tasks. Override with env vars or trailing arguments.


7. Test Strategy

Approach

Integration tests against the live Gitea instance at https://git.terraphim.cloud. No mocks. Each test creates its own resources and cleans up afterward. Tests run sequentially to avoid race conditions.

Test Cases

# Test Validates Expected Result
1 Create test repository POST /repos 201, JSON with repo name
2 Create labels via setup-labels.sh POST /repos/{owner}/{repo}/labels 12 labels created
3 Create milestone (project) gitea_create_project 201, JSON with milestone id
4 Create issue (task) with milestone gitea_create_task 201, JSON with issue number
5 Mark task ready gitea_ready Label set to workflow:ready
6 Claim task gitea_claim Label set to workflow:in-progress, assignee set
7 Check project progress gitea_progress JSON with 0% complete (1 open, 0 closed)
8 Close task gitea_close_task Issue state=closed, label=workflow:done
9 Check progress after close gitea_progress JSON with 100% complete
10 Delete test repository DELETE /repos/{owner}/{repo} 204, cleanup successful

Test Runner

# Run all tests
./test-gitea-skill.sh

# Requirements:
# - GITEA_TOKEN set (or op read available)
# - GITEA_URL set (defaults to https://git.terraphim.cloud)
# - curl, jq installed

Validation Criteria

  • All 10 tests pass against live Gitea 1.22.6
  • All helper functions return valid JSON (validated with jq)
  • Cleanup succeeds (no orphaned test repos)
  • No hardcoded secrets in any file

8. Implementation Steps

Step 1: Create setup-labels.sh (30 min)

Files: .agents/skills/gitea/setup-labels.sh

Actions:

  1. Create terraphim/agent-tasks repo if it doesn't exist (idempotent)
  2. Write script that creates all 12 labels
  3. Make idempotent (check existing labels first)
  4. Use GITEA_TOKEN, GITEA_URL, GITEA_OWNER, GITEA_REPO environment variables
  5. Output JSON summary of created/existing labels

Commit message: "Add label setup script for Gitea agent workflow"

Step 2: Rewrite SKILL.md (2 hours)

Files: .agents/skills/gitea/SKILL.md

Actions:

  1. Keep frontmatter and system prompt
  2. Update Configuration section with 1Password integration
  3. Keep correct existing sections (users, orgs, repos, issues, PRs, releases)
  4. Remove incorrect project board endpoints (lines 222-263)
  5. Add Milestones section (create, list, update, delete)
  6. Add Agent Workflow section (state machine, all 8 helper functions)
  7. Add MCP Integration section (gitea-mcp setup and usage)
  8. Add Dependencies section (issue blocking API)
  9. Update Error Handling section

Commit message: "Rewrite Gitea skill with milestone-based project management"

Step 3: Create test script (1 hour)

Files: .agents/skills/gitea/test-gitea-skill.sh

Actions:

  1. Write integration test runner
  2. Implement all 10 test cases
  3. Add setup/teardown (create/delete test repo)
  4. Add JSON validation for all outputs
  5. Add color-coded pass/fail output

Commit message: "Add integration test script for Gitea skill"

Step 4: Verify 1Password integration (30 min)

Actions (no file changes):

  1. Verify gitea-token item exists in TerraphimPlatform vault (or create it)
  2. Test op read op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential
  3. Verify token has required scopes (repo, admin:org, write:user)

Commit message: None (verification only; document findings in test output)

Step 5: Run tests and iterate (1 hour)

Actions:

  1. Run setup-labels.sh against a test repository
  2. Run test-gitea-skill.sh
  3. Fix any failing tests
  4. Verify cleanup succeeded

Commit message: "Fix issues found during integration testing" (if needed)

Total estimated time: ~5 hours


9. Risk Mitigation

Risk Likelihood Impact Mitigation
Gitea API changes in future version Low Medium Pin to 1.22.6 in docs; version check in test script
gitea-mcp adds milestone support Low Low Reduces need for curl helpers; update skill to prefer MCP
1Password token not configured Medium High Test script checks for token before running; clear error message
Label name collision with existing labels Low Low setup-labels.sh checks for existing labels; skips if present
Test repo cleanup fails Low Medium Test script has explicit cleanup step; documents manual cleanup
Rate limiting on bulk label creation Low Low Sequential creation with small delay if needed

Rollback Plan

All changes are in .agents/skills/gitea/ directory. Rollback = git revert the commits. No infrastructure changes. No database migrations. No service restarts needed.


10. Dependencies

Dependency Type Status
Gitea 1.22.6 running at git.terraphim.cloud Runtime Available
GITEA_TOKEN in 1Password TerraphimPlatform vault Secret Needs verification
curl Tool Available on bigbox
jq Tool Available on bigbox
gitea-mcp (optional) MCP Server Not yet installed; documented for agent use

11. Open Items (Updated After Live Verification)

  1. GITEA_TOKEN in 1Password: RESOLVED. Token exists at op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential. Authenticated user is root (admin). Update SKILL.md to use this path.

  2. gitea-mcp installation: The skill documents gitea-mcp setup but does not install it. Installation is a separate task (requires Go 1.24+ or pre-compiled binary).

  3. Issue dependencies API: RESOLVED. Works with IssueMeta body format: {"owner": "...", "repo": "...", "index": N}. Supports cross-repo dependencies. Update design helper functions to use correct format.

  4. Scoped labels: RESOLVED. Mutual exclusivity confirmed. Using exclusive: true on label creation + scope prefix (e.g., status/) enforces one-label-per-scope.

  5. Default tracking repo: RESOLVED. Default is terraphim/agent-tasks via GITEA_OWNER=terraphim and GITEA_REPO=agent-tasks. User can override both env vars to point at any repo. The agent-tasks repo will be created during setup if it doesn't exist.


12. Approval Checklist

Before proceeding to Phase 3 (Implementation), confirm:

  • Architecture (milestones as projects, labels as workflow) is acceptable
  • File change list is complete and correct
  • Shell helper function signatures are acceptable
  • Label scheme (12 labels, 3 categories) is acceptable
  • Test strategy (10 integration tests, no mocks) is acceptable
  • Implementation sequence (5 steps, ~5 hours) is reasonable

Appendix A: Gitea 1.22.6 Milestone API Reference

POST   /repos/{owner}/{repo}/milestones          - Create milestone
GET    /repos/{owner}/{repo}/milestones          - List milestones
GET    /repos/{owner}/{repo}/milestones/{id}     - Get milestone
PATCH  /repos/{owner}/{repo}/milestones/{id}     - Update milestone
DELETE /repos/{owner}/{repo}/milestones/{id}     - Delete milestone

Response fields: id, title, description, state (open/closed), open_issues, closed_issues, due_on, created_at, updated_at.

Appendix B: Gitea 1.22.6 Label API Reference

POST   /repos/{owner}/{repo}/labels              - Create label
GET    /repos/{owner}/{repo}/labels              - List labels
PATCH  /repos/{owner}/{repo}/labels/{id}         - Update label
DELETE /repos/{owner}/{repo}/labels/{id}         - Delete label
POST   /repos/{owner}/{repo}/issues/{index}/labels    - Add labels to issue
PUT    /repos/{owner}/{repo}/issues/{index}/labels    - Replace issue labels
DELETE /repos/{owner}/{repo}/issues/{index}/labels    - Clear issue labels
DELETE /repos/{owner}/{repo}/issues/{index}/labels/{id} - Remove label from issue

Appendix C: br Workflow Mapping Reference

br Concept Gitea Mapping
Bead Issue
Bead status Label (workflow:*)
Bead priority Label (priority:*)
Bead type Label (type:*)
Project/Sprint Milestone
Assignment Issue assignee
Dependencies Issue dependencies API
Progress Milestone open/closed ratio
Comments Issue comments
Close Issue state = closed + workflow:done label