From c6d425be6376d67c7b891d0fce3c2459aa0ad767 Mon Sep 17 00:00:00 2001 From: Alex Mikhalev Date: Wed, 18 Feb 2026 12:41:19 +0100 Subject: [PATCH] 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 --- .agents/skills/gitea/SKILL.md | 718 +++++++++++++++------------ .agents/skills/gitea/setup-labels.sh | 132 +++++ .docs/DESIGN-gitea-agent-skill.md | 611 +++++++++++++++++++++++ .docs/RESEARCH-gitea-agent-skill.md | 469 +++++++++++++++++ .pre-commit-config.yaml | 45 ++ .secrets.baseline | 172 +++++++ 6 files changed, 1838 insertions(+), 309 deletions(-) create mode 100755 .agents/skills/gitea/setup-labels.sh create mode 100644 .docs/DESIGN-gitea-agent-skill.md create mode 100644 .docs/RESEARCH-gitea-agent-skill.md create mode 100644 .pre-commit-config.yaml create mode 100644 .secrets.baseline diff --git a/.agents/skills/gitea/SKILL.md b/.agents/skills/gitea/SKILL.md index a37a5be..f636d76 100644 --- a/.agents/skills/gitea/SKILL.md +++ b/.agents/skills/gitea/SKILL.md @@ -1,365 +1,465 @@ --- name: gitea description: | - AI agent skill for interacting with Gitea. Manages users, organizations, - repositories, issues, pull requests, and project boards via Gitea API. - Supports both REST API and Gitea admin CLI operations. + AI agent skill for Gitea project and task management. Provides authentication, + milestone-based project tracking, issue lifecycle with scoped workflow labels, + and shell helpers for agent automation. Targets Gitea 1.22.6. license: Apache-2.0 +version: "2.0" +gitea_version: "1.22.6" --- -You are an AI agent specializing in Gitea administration and automation. Your role is to help manage users, organizations, repositories, issues, and projects using the Gitea API and CLI tools. +You are an AI agent specializing in Gitea project and task management. You manage milestones (projects), issues (tasks), workflow labels, and dependencies via the Gitea REST API. ## Configuration -**Gitea Instance:** https://git.terraphim.cloud +**Gitea Instance:** https://git.terraphim.cloud (Gitea 1.22.6) -**Access Methods:** -1. **REST API** - Preferred for automation and scripting -2. **Admin CLI** - For user creation and administrative tasks inside container +**Default Task Repository:** `terraphim/agent-tasks` -**Required Environment Variables:** -- `GITEA_URL` - Gitea instance URL (default: https://git.terraphim.cloud) -- `GITEA_TOKEN` - API token for authentication +**Environment Variables:** +```bash +GITEA_URL="${GITEA_URL:-https://git.terraphim.cloud}" +GITEA_OWNER="${GITEA_OWNER:-terraphim}" +GITEA_REPO="${GITEA_REPO:-agent-tasks}" +GITEA_TOKEN="$(op read 'op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential')" +``` ## Authentication -### Get API Token -1. Login to Gitea web UI -2. Go to Settings → Applications -3. Create new token with appropriate scopes +### 1Password Token Retrieval -### Using the Token ```bash -export GITEA_TOKEN="your-token-here" +# Load 1Password service account +source ~/op_zesticai_non_prod.sh + +# Read the Gitea admin token +export GITEA_TOKEN=$(op read "op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential") ``` -## Core Operations +**Token scopes required:** `repo`, `admin:org`, `write:user`, `read:user` + +**Security rules:** +- Never echo or log `$GITEA_TOKEN` +- Never hardcode tokens in scripts or commit them +- Always use `op read` at runtime + +### Verify Authentication + +```bash +curl -s -H "Authorization: token $GITEA_TOKEN" "$GITEA_URL/api/v1/user" | jq '{login, is_admin}' +``` + +## Base API Helper + +All operations use this helper. It outputs JSON to stdout and errors to stderr. + +```bash +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" +} +``` + +## Initial Setup + +Run once per repository to create labels: + +```bash +./setup-labels.sh # Uses defaults: terraphim/agent-tasks +./setup-labels.sh myorg myrepo # Custom repo +GITEA_OWNER=zestic-ai GITEA_REPO=tasks ./setup-labels.sh # Via env vars +``` + +This creates the repo (if missing) and 12 scoped labels (workflow, priority, type). + +## Project Management (Milestones) + +Gitea 1.22.6 has no project board API. Milestones serve as project containers with built-in progress tracking. + +### Create Project + +```bash +gitea_create_project() { + local title="$1" 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" +} + +# Example: +gitea_create_project "Sprint 2026-W08" "Weekly sprint" "2026-02-28T00:00:00Z" +``` + +### List Projects + +```bash +gitea_api GET "/repos/$GITEA_OWNER/$GITEA_REPO/milestones?state=open" | \ + jq '.[] | {id, title, open_issues, closed_issues}' +``` + +### Get Project Progress + +```bash +gitea_progress() { + local milestone="${1:-}" owner="${2:-$GITEA_OWNER}" repo="${3:-$GITEA_REPO}" + if [ -n "$milestone" ]; then + gitea_api GET "/repos/$owner/$repo/milestones/$milestone" | 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), + due_on: .due_on, + state: .state + }' + else + gitea_api GET "/repos/$owner/$repo/milestones?state=open" | \ + jq '[.[] | {id, title, open: .open_issues, closed: .closed_issues, + pct: (if (.open_issues + .closed_issues) > 0 + then (.closed_issues * 100 / (.open_issues + .closed_issues)) + else 0 end)}]' + fi +} +``` + +### Close Project + +```bash +gitea_api PATCH "/repos/$GITEA_OWNER/$GITEA_REPO/milestones/{id}" '{"state": "closed"}' +``` + +## Task Management (Issues) + +### Create Task + +```bash +gitea_create_task() { + local title="$1" body="$2" milestone="$3" + local labels="${4:-}" 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" +} + +# Example -- create task in milestone 1 with "workflow:ready" (id=4) and "type:task" (id=14): +gitea_create_task "Implement auth module" "Design and implement OAuth2 flow" 1 "4,14" +``` + +### List Tasks by Milestone + +```bash +gitea_api GET "/repos/$GITEA_OWNER/$GITEA_REPO/issues?milestones=Sprint+2026-W08&state=all" | \ + jq '[.[] | {number, title, state, labels: [.labels[].name]}]' +``` + +### List Tasks by Workflow State + +```bash +# Ready tasks (available for agents to claim) +gitea_api GET "/repos/$GITEA_OWNER/$GITEA_REPO/issues?labels=workflow:ready&state=open" | \ + jq '[.[] | {number, title, labels: [.labels[].name]}]' + +# In-progress tasks +gitea_api GET "/repos/$GITEA_OWNER/$GITEA_REPO/issues?labels=workflow:in-progress&state=open" | \ + jq '[.[] | {number, title, assignees: [.assignees[].login]}]' + +# Blocked tasks +gitea_api GET "/repos/$GITEA_OWNER/$GITEA_REPO/issues?labels=workflow:blocked&state=open" | \ + jq '[.[] | {number, title}]' +``` + +### Update Task Labels + +```bash +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]}" +} +``` + +### Add Comment + +```bash +gitea_api POST "/repos/$GITEA_OWNER/$GITEA_REPO/issues/{index}/comments" \ + "$(jq -n --arg b "Progress update: completed auth module" '{body: $b}')" +``` + +## Agent Workflow + +Inspired by the br (beads_rust) pattern: ready -> claim -> implement -> close. + +``` + create_task + | + v + +---------------+ + | workflow:ready |<--------+ + +-------+-------+ | + | | + gitea_claim (unblock) + | | + v | + +--------------------+ +-----------------+ + | workflow:in-progress|->| workflow:blocked | + +---------+----------+ +-----------------+ + | + gitea_close_task + | + v + +---------------+ + | workflow:done | + | (issue closed) | + +---------------+ +``` + +Scoped labels enforce mutual exclusivity: applying `workflow:in-progress` auto-removes `workflow:ready`. + +### Mark Ready + +```bash +gitea_ready() { + local index="$1" 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_api POST "/repos/$owner/$repo/issues/$index/labels" "{\"labels\": [$ready_id]}" +} +``` + +### Claim Task + +```bash +gitea_claim() { + local index="$1" user="${2:-}" 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_api POST "/repos/$owner/$repo/issues/$index/labels" "{\"labels\": [$ip_id]}" + if [ -n "$user" ]; then + gitea_api POST "/repos/$owner/$repo/issues/$index/assignees" "{\"assignees\": [\"$user\"]}" + fi +} +``` + +### Close Task + +```bash +gitea_close_task() { + local index="$1" comment="${2:-}" 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_api POST "/repos/$owner/$repo/issues/$index/labels" "{\"labels\": [$done_id]}" + gitea_api PATCH "/repos/$owner/$repo/issues/$index" '{"state": "closed"}' + if [ -n "$comment" ]; then + gitea_api POST "/repos/$owner/$repo/issues/$index/comments" \ + "$(jq -n --arg b "$comment" '{body: $b}')" + fi +} +``` + +### Workflow Command Reference + +| br Command | Gitea Equivalent | Description | +|------------|------------------|-------------| +| `br ready` | `gitea_ready 1` | Mark task #1 ready | +| `br update ID --status in_progress` | `gitea_claim 1 root` | Claim task #1 | +| `br close ID` | `gitea_close_task 1 "Done"` | Complete task #1 | +| `br list --status ready` | List issues `?labels=workflow:ready` | Ready tasks | +| `br status` | `gitea_progress 1` | Milestone progress | + +## Issue Dependencies + +Dependencies express task ordering. Gitea uses `IssueMeta` format: `{owner, repo, index}`. + +### Add Dependency + +```bash +# Make issue #3 depend on issue #2 (issue #2 blocks issue #3) +gitea_api POST "/repos/$GITEA_OWNER/$GITEA_REPO/issues/3/dependencies" \ + "{\"owner\": \"$GITEA_OWNER\", \"repo\": \"$GITEA_REPO\", \"index\": 2}" +``` + +### List Dependencies + +```bash +# What blocks issue #3? +gitea_api GET "/repos/$GITEA_OWNER/$GITEA_REPO/issues/3/dependencies" | \ + jq '[.[] | {number, title, state}]' + +# What does issue #2 block? +gitea_api GET "/repos/$GITEA_OWNER/$GITEA_REPO/issues/2/blocks" | \ + jq '[.[] | {number, title}]' +``` + +### Remove Dependency + +```bash +gitea_api DELETE "/repos/$GITEA_OWNER/$GITEA_REPO/issues/3/dependencies" \ + "{\"owner\": \"$GITEA_OWNER\", \"repo\": \"$GITEA_REPO\", \"index\": 2}" +``` + +## Label Scheme + +All labels use scoped naming (`scope:name`) with `exclusive: true` for mutual exclusivity within each scope. + +### Workflow Labels + +| Label | Color | Description | +|-------|-------|-------------| +| `workflow:ready` | `#0e8a16` green | Ready for an agent to pick up | +| `workflow:in-progress` | `#fbca04` yellow | Actively being worked on | +| `workflow:blocked` | `#d93f0b` red | Blocked by a dependency | +| `workflow:done` | `#6f42c1` purple | Complete | + +### Priority Labels + +| Label | Color | Description | +|-------|-------|-------------| +| `priority:critical` | `#b60205` dark red | Immediate | +| `priority:high` | `#d93f0b` red | This cycle | +| `priority:medium` | `#fbca04` yellow | Normal | +| `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 | + +## Time Tracking + +```bash +# Start stopwatch +gitea_api POST "/repos/$GITEA_OWNER/$GITEA_REPO/issues/{index}/stopwatch/start" + +# Stop stopwatch +gitea_api POST "/repos/$GITEA_OWNER/$GITEA_REPO/issues/{index}/stopwatch/stop" + +# Get tracked times +gitea_api GET "/repos/$GITEA_OWNER/$GITEA_REPO/issues/{index}/times" | jq '.[].time' +``` + +## MCP Integration (Optional) + +The official Gitea MCP Server provides ~80 tools for repos, issues, PRs, files, and CI/CD. +It does NOT cover milestones or workflow labels -- use the shell helpers above for those. + +### Claude Code Setup + +```bash +claude mcp add --transport stdio --scope user gitea \ + --env GITEA_ACCESS_TOKEN="$(op read 'op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential')" \ + --env GITEA_HOST=https://git.terraphim.cloud \ + -- go run gitea.com/gitea/gitea-mcp@latest -t stdio +``` + +### Available MCP Tools + +Repos, branches, tags, releases, files, commits, issues (CRUD + comments), PRs (CRUD + reviews + merge), org labels, CI/CD actions (secrets, variables, workflows, runs, jobs), wiki pages. + +**Not covered by MCP:** milestones, repo labels, issue dependencies, time tracking, workflow labels. + +## Core API Reference (Gitea 1.22.6) ### Users -#### Create Admin User (requires admin CLI) ```bash -# Inside Gitea container +# Create admin (CLI inside container) docker exec gitea gitea admin user create \ - --username \ - --password \ - --email \ - --admin \ - --access-token -``` + --username --password --email --admin --access-token -#### List Users (API) -```bash -curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/admin/users" -``` +# List users +gitea_api GET "/admin/users" -#### Get User Info -```bash -curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/users/{username}" +# Get user +gitea_api GET "/users/{username}" ``` ### Organizations -#### Create Organization ```bash -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/orgs" \ - -d '{ - "username": "myorg", - "full_name": "My Organization", - "description": "Organization description", - "visibility": "private" - }' -``` +# Create org +gitea_api POST "/orgs" '{"username":"myorg","full_name":"My Org","visibility":"private"}' -#### List Organization Repos -```bash -curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/orgs/{org}/repos" +# List org repos +gitea_api GET "/orgs/{org}/repos" ``` ### Repositories -#### Create Repository ```bash -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/user/repos" \ - -d '{ - "name": "my-repo", - "description": "Repository description", - "private": true, - "auto_init": true, - "gitignores": "Rust", - "license": "MIT" - }' -``` +# Create user repo +gitea_api POST "/user/repos" '{"name":"my-repo","auto_init":true,"private":true}' -#### Create Repository in Organization -```bash -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/orgs/{org}/repos" \ - -d '{ - "name": "my-repo", - "description": "Repository description", - "private": false - }' -``` +# Create org repo +gitea_api POST "/orgs/{org}/repos" '{"name":"my-repo","private":false}' -#### Delete Repository -```bash -curl -s -X DELETE -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}" -``` +# Delete repo +gitea_api DELETE "/repos/{owner}/{repo}" -#### List User Repositories -```bash -curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/user/repos" -``` - -### Issues - -#### Create Issue -```bash -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/issues" \ - -d '{ - "title": "Issue title", - "body": "Issue description", - "assignees": ["username"] - }' -``` - -#### List Issues -```bash -curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/issues?state=all" -``` - -#### Get Issue -```bash -curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/issues/{index}" -``` - -#### Update Issue -```bash -curl -s -X PATCH -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/issues/{index}" \ - -d '{ - "title": "New title", - "body": "Updated body", - "state": "open" - }' -``` - -#### Close/Reopen Issue -```bash -# Close issue -curl -s -X PATCH -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/issues/{index}" \ - -d '{"state": "closed"}' - -# Reopen issue -curl -s -X PATCH -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/issues/{index}" \ - -d '{"state": "open"}' -``` - -#### Add Issue Comment -```bash -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/issues/{index}/comments" \ - -d '{"body": "Comment text"}' -``` - -#### Add/Remove Issue Labels -```bash -# Add labels -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/issues/{index}/labels" \ - -d '{"labels": [1, 2, 3]}' - -# List available labels -curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/labels" +# List user repos +gitea_api GET "/user/repos" ``` ### Pull Requests -#### List Pull Requests ```bash -curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/pulls?state=all" +# List PRs +gitea_api GET "/repos/{owner}/{repo}/pulls?state=all" + +# Get PR +gitea_api GET "/repos/{owner}/{repo}/pulls/{index}" + +# Merge PR +gitea_api POST "/repos/{owner}/{repo}/pulls/{index}/merge" '{"do":"merge"}' ``` -#### Get Pull Request +### Releases + ```bash -curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/pulls/{index}" -``` - -#### Merge Pull Request -```bash -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/pulls/{index}/merge" \ - -d '{"do": "merge", "merge_message": "Merge PR #1"}' -``` - -### Projects - -#### Create Project -```bash -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/user/projects" \ - -d '{ - "name": "Project Name", - "description": "Project description", - "visibility": "private" - }' -``` - -#### Create Organization Project -```bash -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/orgs/{org}/projects" \ - -d '{ - "name": "Project Name", - "description": "Project description" - }' -``` - -#### List Projects -```bash -# User projects -curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/user/projects" - -# Organization projects -curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/orgs/{org}/projects" -``` - -#### Add Issue to Project -```bash -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/projects/{project_id}/issues" \ - -d '{"issue_id": 123}' -``` - -### Labels - -#### Create Label -```bash -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/labels" \ - -d '{ - "name": "bug", - "color": "fc2929", - "description": "Bug report" - }' -``` - -### Release Notes - -#### Create Release -```bash -curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/repos/{owner}/{repo}/releases" \ - -d '{ - "tag_name": "v1.0.0", - "name": "Release v1.0.0", - "body": "Release notes", - "draft": false, - "prerelease": false - }' -``` - -## Helper Functions - -### Bash Alias for Common Operations - -Add to your shell profile: -```bash -gitea() { - local cmd="$1" - shift - case "$cmd" in - repos) - curl -s -H "Authorization: token $GITEA_TOKEN" "$GITEA_URL/api/v1/user/repos" | jq -r '.[].full_name' - ;; - issues) - local owner="$1" repo="$2" - curl -s -H "Authorization: token $GITEA_TOKEN" \ - "$GITEA_URL/api/v1/repos/$owner/$repo/issues?state=all" | \ - jq -r '.[] | "#\(.number) [\(.state)] \(.title)"' - ;; - create-issue) - local owner="$1" repo="$2" title="$3" body="${4:-}" - curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ - -H "Content-Type: application/json" \ - "$GITEA_URL/api/v1/repos/$owner/$repo/issues" \ - -d "{\"title\": \"$title\", \"body\": \"$body\"}" - ;; - *) - echo "Usage: gitea {repos|issues|create-issue}" - ;; - esac -} +gitea_api POST "/repos/{owner}/{repo}/releases" \ + '{"tag_name":"v1.0.0","name":"Release v1.0.0","body":"Release notes"}' ``` ## Error Handling -- Check HTTP status codes (200 = success, 201 = created, 404 = not found, 401 = unauthorized) -- Use `jq` to parse JSON responses -- Rate limiting: Gitea doesn't enforce strict rate limits but be reasonable -- Token scopes: Ensure token has required permissions (repo, read:user, write:user, etc.) - -## Common Use Cases - -### Automated Issue Tracking -1. Create issues for task tracking -2. Add labels for categorization -3. Assign to team members -4. Link to projects for board view -5. Update status via comments - -### Project Management -1. Create organization for team -2. Create project board -3. Add repositories to project -4. Add issues to project columns -5. Track progress via project API - -### Repository Automation -1. Initialize repositories with templates -2. Configure branch protection -3. Add deploy keys -4. Set up webhooks -5. Mirror from GitHub +| HTTP Code | Meaning | Action | +|-----------|---------|--------| +| 200 | Success | Parse JSON response | +| 201 | Created | Resource created successfully | +| 204 | No Content | Delete succeeded | +| 401 | Unauthorized | Check GITEA_TOKEN; re-read from 1Password | +| 403 | Forbidden | Token lacks required scope | +| 404 | Not Found | Check owner/repo/index; resource may not exist | +| 409 | Conflict | Resource already exists (labels, repos) | +| 422 | Validation Error | Check request body format | ## Constraints -- Always use HTTPS in production +- Always use HTTPS - Never commit tokens to version control -- Use environment variables for secrets +- Use `op read` for secrets at runtime - Prefer API over CLI for idempotent operations -- Handle rate limiting gracefully -- Clean up temporary resources +- Project board API does NOT exist in Gitea 1.22.6 -- use milestones +- Issue dependency body uses `IssueMeta` format: `{owner, repo, index}` +- Scoped labels require the `exclusive: true` flag on creation diff --git a/.agents/skills/gitea/setup-labels.sh b/.agents/skills/gitea/setup-labels.sh new file mode 100755 index 0000000..33fa3ca --- /dev/null +++ b/.agents/skills/gitea/setup-labels.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +# setup-labels.sh -- Idempotent setup of Gitea repo and workflow labels +# Creates the default agent-tasks repo (if missing) and 12 scoped labels. +# +# Usage: +# source ~/op_zesticai_non_prod.sh # load OP_SERVICE_ACCOUNT_TOKEN +# export GITEA_TOKEN=$(op read "op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential") +# ./setup-labels.sh [OWNER] [REPO] +# +# Environment: +# GITEA_URL -- Gitea instance (default: https://git.terraphim.cloud) +# GITEA_TOKEN -- API token (required) +# GITEA_OWNER -- Org or user (default: terraphim) +# GITEA_REPO -- Repository (default: agent-tasks) + +set -euo pipefail + +GITEA_URL="${GITEA_URL:-https://git.terraphim.cloud}" +GITEA_OWNER="${1:-${GITEA_OWNER:-terraphim}}" +GITEA_REPO="${2:-${GITEA_REPO:-agent-tasks}}" + +if [ -z "${GITEA_TOKEN:-}" ]; then + echo '{"error": "GITEA_TOKEN is not set"}' >&2 + exit 1 +fi + +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" +} + +# --- Ensure repo exists (idempotent) --- +ensure_repo() { + local http_code + http_code=$(curl -s -o /dev/null -w '%{http_code}' \ + -H "Authorization: token $GITEA_TOKEN" \ + "$GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO") + + if [ "$http_code" = "200" ]; then + echo "{\"repo\": \"$GITEA_OWNER/$GITEA_REPO\", \"action\": \"exists\"}" + return 0 + fi + + # Try creating under org first, fall back to user repo + local result + result=$(gitea_api POST "/orgs/$GITEA_OWNER/repos" \ + "{\"name\": \"$GITEA_REPO\", \"description\": \"AI agent task tracking\", \"auto_init\": true, \"private\": false}" 2>&1) + + if echo "$result" | jq -e '.id' > /dev/null 2>&1; then + echo "{\"repo\": \"$GITEA_OWNER/$GITEA_REPO\", \"action\": \"created\"}" + return 0 + fi + + # Fall back to user repo + result=$(gitea_api POST "/user/repos" \ + "{\"name\": \"$GITEA_REPO\", \"description\": \"AI agent task tracking\", \"auto_init\": true, \"private\": false}" 2>&1) + + if echo "$result" | jq -e '.id' > /dev/null 2>&1; then + echo "{\"repo\": \"$GITEA_OWNER/$GITEA_REPO\", \"action\": \"created\"}" + return 0 + fi + + echo "{\"repo\": \"$GITEA_OWNER/$GITEA_REPO\", \"action\": \"error\", \"detail\": $result}" >&2 + return 1 +} + +# --- Create label if it does not exist --- +ensure_label() { + local name="$1" color="$2" description="$3" exclusive="${4:-false}" + local existing + + existing=$(gitea_api GET "/repos/$GITEA_OWNER/$GITEA_REPO/labels" \ + | jq -r --arg n "$name" '.[] | select(.name == $n) | .id') + + if [ -n "$existing" ]; then + echo "{\"name\": \"$name\", \"id\": $existing, \"action\": \"exists\"}" + return 0 + fi + + local payload + payload=$(jq -n \ + --arg name "$name" \ + --arg color "$color" \ + --arg desc "$description" \ + --argjson excl "$exclusive" \ + '{name: $name, color: $color, description: $desc, exclusive: $excl}') + + local result + result=$(gitea_api POST "/repos/$GITEA_OWNER/$GITEA_REPO/labels" "$payload") + local label_id + label_id=$(echo "$result" | jq -r '.id // empty') + + if [ -n "$label_id" ]; then + echo "{\"name\": \"$name\", \"id\": $label_id, \"action\": \"created\"}" + else + echo "{\"name\": \"$name\", \"action\": \"error\", \"detail\": $result}" >&2 + return 1 + fi +} + +# === Main === + +echo "--- Ensure repo $GITEA_OWNER/$GITEA_REPO ---" +ensure_repo + +echo "--- Creating labels ---" + +# Workflow labels (mutually exclusive within scope) +ensure_label "workflow:ready" "0e8a16" "Task is ready for an agent to pick up" true +ensure_label "workflow:in-progress" "fbca04" "Task is actively being worked on" true +ensure_label "workflow:blocked" "d93f0b" "Task is blocked by a dependency" true +ensure_label "workflow:done" "6f42c1" "Task is complete" true + +# Priority labels (mutually exclusive within scope) +ensure_label "priority:critical" "b60205" "Must be done immediately" true +ensure_label "priority:high" "d93f0b" "Should be done this cycle" true +ensure_label "priority:medium" "fbca04" "Normal priority" true +ensure_label "priority:low" "0e8a16" "Nice to have" true + +# Type labels (mutually exclusive within scope) +ensure_label "type:feature" "1d76db" "New functionality" true +ensure_label "type:bug" "d93f0b" "Defect fix" true +ensure_label "type:task" "5319e7" "General task" true +ensure_label "type:research" "006b75" "Investigation or spike" true + +echo "--- Done ---" diff --git a/.docs/DESIGN-gitea-agent-skill.md b/.docs/DESIGN-gitea-agent-skill.md new file mode 100644 index 0000000..8ba76fb --- /dev/null +++ b/.docs/DESIGN-gitea-agent-skill.md @@ -0,0 +1,611 @@ +# 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 + +- [x] 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" +- [x] Junior developer could implement from this plan? YES: all operations are curl commands with documented endpoints +- [x] No speculative features? YES: every feature maps to a concrete user request from the design brief +- [x] 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 + +```bash +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 + +```bash +# 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 + +```bash +# 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 + +```bash +# 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 + +```bash +# 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 + +```bash +# 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) + +```bash +# 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 + +```bash +# 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 + +```bash +# 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 + +```bash +# 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 | diff --git a/.docs/RESEARCH-gitea-agent-skill.md b/.docs/RESEARCH-gitea-agent-skill.md new file mode 100644 index 0000000..eb94f9c --- /dev/null +++ b/.docs/RESEARCH-gitea-agent-skill.md @@ -0,0 +1,469 @@ +# Research Document: Gitea Skill for AI Agent Project/Task Management + +**Status**: Draft -- Awaiting Approval +**Author**: Claude (Phase 1 Research) +**Date**: 2026-02-18 +**Reviewers**: Alex + +--- + +## 1. Problem Statement + +### Description + +Enhance the existing Gitea skill (`.agents/skills/gitea/SKILL.md`) so that an AI agent can perform end-to-end project and task management on the Gitea instance at https://git.terraphim.cloud (Gitea 1.22.6): + +1. **Authenticate** -- Log in via API token (stored in 1Password) +2. **Create a project** -- Set up a project board for organizing work +3. **Create tasks** -- File issues within a repository and associate them with the project +4. **Track progress** -- Update issue state, add comments, move between workflow stages + +### Success Criteria + +- [ ] Agent can authenticate to Gitea API using a token retrieved from 1Password +- [ ] Agent can create a "project" (or equivalent organizational unit) to group tasks +- [ ] Agent can create issues (tasks) with title, body, labels, assignees, milestones +- [ ] Agent can update issue state (open/closed), add comments, change labels +- [ ] Agent can track workflow progress (backlog -> in-progress -> done or equivalent) +- [ ] Skill document is self-contained and usable by any AI agent without external docs +- [ ] Operations are idempotent where possible (re-running does not create duplicates) + +--- + +## 2. Existing System Analysis + +### 2.1 Current Gitea Skill (`/home/alex/projects/terraphim/gitea-infrastructure/.agents/skills/gitea/SKILL.md`) + +The existing skill covers: +- **Users**: Admin CLI creation, API listing/info +- **Organizations**: Create, list repos +- **Repositories**: Create, delete, list (user and org) +- **Issues**: Create, list, get, update, close/reopen, add comments, add/remove labels +- **Pull Requests**: List, get, merge +- **Projects**: Create (user/org), list, add issue to project +- **Labels**: Create +- **Releases**: Create +- **Helper functions**: Bash alias for common operations +- **Error handling**: HTTP status codes, jq parsing + +**Gaps in the current skill:** +1. No authentication via 1Password (`op inject` or `op read`) +2. No project column/board management (create columns, move issues between columns) +3. No milestone management (create, update, list, close) +4. No workflow patterns (agent-oriented: ready/claim/implement/close) +5. No idempotency patterns (check-before-create) +6. No JSON output parsing patterns for machine consumption +7. No issue template patterns (standardized issue bodies) +8. No dependency management between issues + +### 2.2 Infrastructure Context (`/home/alex/projects/terraphim/gitea-infrastructure/HANDOVER.md`) + +- **Instance**: Gitea 1.22.6 at https://git.terraphim.cloud +- **Server**: bigbox (100.106.66.7) via Tailscale +- **1Password Vault**: `TerraphimPlatform` (already has gitea-postgres, gitea-s3) +- **Secrets pattern**: `op inject` with `op://TerraphimPlatform/...` references +- **Source auth**: `source ~/op_zesticai_non_prod.sh` sets `OP_SERVICE_ACCOUNT_TOKEN` + +### 2.3 Reference Patterns from Terraphim Ecosystem + +**br (beads_rust) pattern:** +- CLI issue tracking: `br ready`, `br create`, `br update`, `br close`, `br sync` +- Priorities P0-P4, types (bug, feature, task, epic, chore) +- Agent workflow: ready -> claim -> implement -> close -> sync +- `--json` flag for machine parsing + +**bv (beads viewer) pattern:** +- Robot flags: `--robot-triage`, `--robot-next`, `--robot-plan` +- Dependency-aware scheduling, PageRank, critical path +- Graph-aware triage engine + +**MCP Agent Mail pattern:** +- Multi-agent coordination via messaging +- Projects, identities, inbox/outbox +- File reservations to avoid conflicts + +--- + +## 3. Critical Finding: Gitea Project Board API Status + +### 3.1 Project Board API is NOT Available in Gitea 1.22.6 + +This is the single most important finding of this research. + +**Evidence:** +- GitHub Issue [#14299](https://github.com/go-gitea/gitea/issues/14299) "[FEATURE] API for projects" -- opened Jan 2021, still **OPEN** as of Feb 2026, assigned to milestone **1.26.0** +- PR [#28111](https://github.com/go-gitea/gitea/pull/28111) adding project API endpoints -- still in **DRAFT** status, targeted for 1.26.0 +- GitHub Issue [#31769](https://github.com/go-gitea/gitea/issues/31769) "API support for columns" -- opened Aug 2024, still **OPEN**, type/proposal + +**Proposed but NOT yet merged endpoints from PR #28111:** +``` +POST /user/projects +POST /orgs/{org}/projects +POST /repos/{owner}/{repo}/projects +GET /user/projects +GET /orgs/{org}/projects +GET /repos/{owner}/{repo}/projects +GET /projects/{id} +PATCH /projects/{id} +DELETE /projects/{id} +``` + +**Column management endpoints from Issue #31769 (proposed, NOT implemented):** +``` +PATCH /projects/{project_id}/columns/move +PATCH /projects/{project_id}/columns/{column_id}/move +``` + +**VERIFIED 2026-02-18**: Tested against live instance at https://git.terraphim.cloud: +- `GET /api/v1/user/projects` returns **HTTP 404** ("404 page not found") +- `GET /api/v1/repos/terraphim/gitea-infrastructure/projects` returns **HTTP 404** +- The existing skill's "Projects" section (lines 222-263 of SKILL.md) documents endpoints that **do not work** on Gitea 1.22.6 and must be removed or replaced. + +### 3.2 What IS Available in Gitea 1.22.6 API + +The following endpoints ARE confirmed available and functional: + +**Issues (full CRUD):** +``` +POST /repos/{owner}/{repo}/issues -- Create issue +GET /repos/{owner}/{repo}/issues -- List issues +GET /repos/{owner}/{repo}/issues/{index} -- Get issue +PATCH /repos/{owner}/{repo}/issues/{index} -- Update issue (title, body, state, milestone, assignees) +POST /repos/{owner}/{repo}/issues/{index}/comments -- Add comment +POST /repos/{owner}/{repo}/issues/{index}/labels -- Add labels +DELETE /repos/{owner}/{repo}/issues/{index}/labels/{id} -- Remove label +``` + +**Labels (full CRUD):** +``` +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 +``` + +**Milestones (full CRUD):** +``` +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 +``` + +**API Token Management:** +``` +POST /users/{username}/tokens -- Create token (requires BasicAuth, NOT token auth) +GET /users/{username}/tokens -- List tokens (requires BasicAuth) +DELETE /users/{username}/tokens/{id} -- Delete token (requires BasicAuth) +``` + +**Note on token creation**: The `/users/{username}/tokens` endpoint requires HTTP BasicAuth with username:password. You **cannot** create a new token using an existing token -- this is a Gitea security restriction. + +### 3.3 Existing MCP Servers for Gitea + +Two MCP servers exist that could complement or replace the curl-based skill: + +**1. Official Gitea MCP Server** ([gitea.com/gitea/gitea-mcp](https://gitea.com/gitea/gitea-mcp)) +- ~80+ tools covering repos, branches, issues, PRs, releases, wiki, actions, tags, labels +- **Does NOT support project boards or columns** +- **Does NOT support milestones** (except as a field when editing PRs) +- Supports stdio and SSE modes +- Config: `GITEA_HOST`, `GITEA_ACCESS_TOKEN`, `GITEA_INSECURE` +- Written in Go, MIT licensed + +**2. forgejo-mcp** ([github.com/raohwork/forgejo-mcp](https://github.com/raohwork/forgejo-mcp)) +- Supports issues, labels, milestones, comments, attachments, dependencies +- **Does NOT support project boards or columns** +- **Does support milestone CRUD** (create, edit, delete) +- Supports stdio and HTTP modes +- Config: `FORGEJOMCP_SERVER`, `FORGEJOMCP_TOKEN` +- Written in Go, MPL-2.0 licensed + +**3. Tea CLI** ([gitea.com/gitea/tea](https://gitea.com/gitea/tea)) +- Official command-line tool for Gitea +- Supports issues, milestones, labels, PRs, time tracking, notifications +- Milestone issue management: add/remove issues from milestones +- **Does NOT mention project board support** + +--- + +## 4. Recommended Architecture: Milestones as Projects + +### 4.1 Rationale + +Since the Project Board API is not available in Gitea 1.22.6, we need an alternative. The best available option is to use **milestones** as the primary organizational unit (i.e., "project" equivalent), combined with **labels** for workflow state tracking. + +| Concept | br/bv equivalent | Gitea Implementation | +|---------|-------------------|---------------------| +| Project | br project / bv graph | Milestone | +| Task | br bead / issue | Issue | +| Status | br state (ready/claimed/done) | Labels: `status/backlog`, `status/in-progress`, `status/done` | +| Priority | br P0-P4 | Labels: `priority/P0-critical`, `priority/P1-high`, `priority/P2-medium`, `priority/P3-low` | +| Type | br type (bug/feature/task) | Labels: `type/bug`, `type/feature`, `type/task`, `type/epic`, `type/chore` | +| Agent claim | br claim | Assignee field + `status/in-progress` label | +| Workflow column | Project board column | Scoped labels (`status/*`) | + +### 4.2 Scoped Labels for Workflow State + +Gitea supports **scoped labels** (format: `scope/name`). When a scoped label is applied, it automatically removes any other label with the same scope. This means: + +- Applying `status/in-progress` automatically removes `status/backlog` +- Applying `priority/P0-critical` automatically removes `priority/P2-medium` + +This provides kanban-like exclusivity without project board columns. + +### 4.3 Agent Workflow + +``` +1. AUTHENTICATE + - Read token from 1Password: op read "op://TerraphimPlatform/gitea-api-token/credential" + - Export: GITEA_TOKEN=$(op read ...) + +2. CREATE PROJECT (milestone) + - POST /repos/{owner}/{repo}/milestones + - Body: { "title": "Sprint 2026-W08", "description": "...", "due_on": "2026-02-28T00:00:00Z" } + +3. SETUP LABELS (one-time per repo) + - Create scoped labels for status, priority, type + - Idempotent: check existing labels before creating + +4. CREATE TASK (issue) + - POST /repos/{owner}/{repo}/issues + - Body: { "title": "...", "body": "...", "milestone": , "labels": [], "assignees": [...] } + +5. TRACK PROGRESS + - Change status: Replace labels (POST label, DELETE old label -- or use scoped labels) + - Add comment: POST /repos/{owner}/{repo}/issues/{index}/comments + - Close: PATCH /repos/{owner}/{repo}/issues/{index} with { "state": "closed" } + +6. QUERY STATUS + - List by milestone: GET /repos/{owner}/{repo}/issues?milestone={name}&state=open + - List by label: GET /repos/{owner}/{repo}/issues?labels=status/in-progress + - Get milestone progress: GET /repos/{owner}/{repo}/milestones/{id} + (returns open_issues and closed_issues counts) +``` + +--- + +## 5. Authentication Strategy + +### 5.1 1Password Integration + +The existing infrastructure already uses 1Password (`TerraphimPlatform` vault) for secrets. The pattern should be: + +```bash +# Store token in 1Password (one-time setup, done manually or via op CLI) +# Item name: gitea-api-token +# Field: credential (contains the token value) + +# Agent retrieval at runtime: +export GITEA_TOKEN=$(op read "op://TerraphimPlatform/gitea-api-token/credential") +``` + +**Note**: Creating a Gitea API token programmatically requires BasicAuth (username + password), which is harder to automate securely. The recommended approach is: +1. Create the token manually via Gitea Web UI (Settings -> Applications -> Generate New Token) +2. Store the token in 1Password under `TerraphimPlatform/gitea-api-token` +3. Agent reads from 1Password at runtime using `op read` + +### 5.2 Token Scopes Required + +The agent needs the following scopes: +- `read:issue` + `write:issue` -- Create and update issues +- `read:repository` + `write:repository` -- Access repo metadata +- `read:user` -- Read user information for assignees +- `read:organization` -- Access org repos +- `write:misc` -- Needed for some label operations + +Alternatively, use `all` scope for simplicity (less secure but simpler). + +--- + +## 6. Constraints and Risks + +### 6.1 Technical Constraints + +| Constraint | Impact | Mitigation | +|------------|--------|------------| +| No Project Board API in 1.22.6 | Cannot use true kanban boards via API | Use milestones + scoped labels as alternative | +| Token creation requires BasicAuth | Cannot automate token creation with token auth | Manual token creation, store in 1Password | +| Gitea MCP server lacks milestone support | Cannot use MCP for full workflow | Use curl-based skill for now; MCP for repo/PR ops | +| Scoped labels require Gitea 1.20+ | Must verify instance supports scoped labels | VERIFIED: Gitea 1.22.6 supports scoped labels with mutual exclusivity | +| Issue dependency API body format differs from intuition | Must use IssueMeta format {owner, repo, index} | VERIFIED: Works with correct format, supports cross-repo deps | + +### 6.2 Risks + +| Risk | Likelihood | Impact | Mitigation | +|------|------------|--------|------------| +| Existing "Projects" endpoints in SKILL.md do not work | High | Skill provides wrong info | Verify against live instance; remove or caveat | +| Milestone-as-project is semantically confusing | Medium | Agent confusion | Clear naming conventions and docs | +| Label sprawl across repos | Medium | Maintenance burden | Standardized label set, setup automation | +| Token leaked in logs/output | Low | Security breach | Never echo token; use 1Password op read inline | +| Gitea upgrade to 1.26 changes API surface | Low | Skill needs update | Document version, plan for upgrade path | + +### 6.3 Assumptions + +| Assumption | Basis | Risk if Wrong | +|------------|-------|---------------| +| Gitea 1.22.6 supports scoped labels | Feature added in 1.20 | Fall back to manual label management | +| Milestone API is fully functional | Standard Gitea feature | Skill cannot create "projects" | +| 1Password `op read` available in agent env | Existing infra pattern | Agent cannot authenticate | +| Issues can be filtered by milestone name | API docs indicate this | Need milestone ID lookup step | +| Agent runs in environment with curl and jq | Standard tooling | Need alternative HTTP client | + +--- + +## 7. Open Questions -- ANSWERED via Live Testing (2026-02-18) + +### Q1: Do the existing project endpoints work on 1.22.6? + +**ANSWER: NO.** Both `/api/v1/user/projects` and `/api/v1/repos/{owner}/{repo}/projects` return HTTP 404. Milestones-only approach confirmed. + +### Q2: Is there an existing Gitea API token in 1Password? + +**ANSWER: YES.** The admin token is at `op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential`. Authenticated user is `root` (id=1, is_admin=true). Existing 1Password items: +- `git.terraphim.cloud-admin-token` -- admin API token (working) +- `gitea-postgres` -- database credentials +- `gitea-s3` -- S3 storage credentials +- `Gitea.Terraphim.io` -- legacy item (2 years old) + +### Q3: Which repository should be the "default" for agent task tracking? + +**TO DECIDE.** Available repos on instance: +- `terraphim/terraphim-ai` +- `terraphim/terraphim-skills` +- Orgs: `terraphim`, `zestic-ai`, `private` + +### Q4: Do scoped labels work as expected on 1.22.6? + +**ANSWER: YES.** Verified with live test: +- Created `status/backlog` (exclusive=true), `status/in-progress` (exclusive=true), `status/done` (exclusive=true) +- Applied `status/in-progress` via PUT (replace) -- only `status/in-progress` remained +- Then applied `status/backlog` via POST (add) -- `status/in-progress` was **automatically removed**, only `status/backlog` remained +- Scoped label mutual exclusivity is enforced by Gitea on both POST and PUT + +### Q5: Do issue dependencies work? + +**ANSWER: YES**, but the body format is `IssueMeta` (not `depends_on_id`): +```json +POST /repos/{owner}/{repo}/issues/{index}/dependencies +Body: {"owner": "root", "repo": "skill-test-temp", "index": 2} +``` +- `GET .../dependencies` returns the list of issues that block this one +- `GET .../blocks` returns the list of issues this one blocks +- Cross-repo dependencies are supported (owner/repo fields) + +### Q6: Do milestones work as project containers? + +**ANSWER: YES.** Full CRUD verified: +- Create milestone with title, description, due_on -- returns id, state, open/closed counts +- Issues created with `"milestone": ` are linked to the milestone +- Progress tracking works: `open_issues` and `closed_issues` update automatically when issues are opened/closed +- Filter issues by milestone name: `?milestones=Sprint%202026-W08` +- Filter issues by label: `?labels=status/backlog` + +### Q7: Does time tracking work? + +**ANSWER: YES.** Stopwatch start/stop returns HTTP 201. Tracked times accessible via `GET .../times`. + +### Q3: Which repository should be the "default" for agent task tracking? + +**ANSWER: `terraphim/agent-tasks`** (user decision 2026-02-18). Configurable via `GITEA_OWNER` and `GITEA_REPO` env vars. Default repo created during setup if it doesn't exist. All open questions resolved. + +--- + +## 8. Recommended Next Steps + +### If Approved, Phase 2 (Design) Should: + +1. **Verify live API behavior** -- Test project, milestone, and scoped label endpoints against https://git.terraphim.cloud + +2. **Design the enhanced SKILL.md** with these sections: + - Authentication (1Password + op read) + - Project Management (milestones as projects) + - Task Management (issues with scoped labels) + - Workflow Operations (agent lifecycle: create -> claim -> update -> close) + - Label Setup (standardized scoped labels for status, priority, type) + - Query Patterns (list by milestone, by label, by state) + - Idempotency Patterns (check-before-create) + - JSON Output Parsing (jq patterns for machine consumption) + +3. **Create a label initialization script** that sets up the standard label set in a repository + +4. **Document the 1Password setup** for the Gitea API token + +5. **Decide on MCP integration** -- whether to recommend gitea-mcp or forgejo-mcp alongside the curl skill + +### Scope Recommendation + +**Minimal Viable Skill (Phase 2 target):** +- 1Password authentication +- Milestone CRUD (as project proxy) +- Issue CRUD with labels and milestone assignment +- Scoped label workflow (status/backlog -> status/in-progress -> status/done) +- Comment-based progress tracking +- Query by milestone and label filters + +**Future Enhancement (Phase 3+, when Gitea 1.26 ships):** +- True project board API integration +- Column management +- Issue-to-project linking +- MCP server integration + +--- + +## 9. Appendix + +### A. File Inventory + +| File | Path | Relevance | +|------|------|-----------| +| Current skill | `/home/alex/projects/terraphim/gitea-infrastructure/.agents/skills/gitea/SKILL.md` | Primary file to enhance | +| Handover doc | `/home/alex/projects/terraphim/gitea-infrastructure/HANDOVER.md` | Infrastructure context | +| Docker compose template | `/home/alex/projects/terraphim/gitea-infrastructure/docker-compose.yml.template` | 1Password patterns | +| Repository setup | `/home/alex/projects/terraphim/gitea-infrastructure/REPOSITORY-SETUP.md` | Deployment patterns | +| Prior research | `/home/alex/projects/terraphim/gitea-infrastructure/.docs/RESEARCH-gitea-bigbox-deployment.md` | Infrastructure research | + +### B. External References + +- Gitea API docs: https://docs.gitea.com/api/1.22/ +- Gitea Project API feature request: https://github.com/go-gitea/gitea/issues/14299 +- Gitea Column API proposal: https://github.com/go-gitea/gitea/issues/31769 +- Gitea Project API draft PR: https://github.com/go-gitea/gitea/pull/28111 +- Official Gitea MCP server: https://gitea.com/gitea/gitea-mcp +- forgejo-mcp: https://github.com/raohwork/forgejo-mcp +- Tea CLI: https://gitea.com/gitea/tea +- Gitea scoped labels blog: https://blog.gitea.com/introducing-new-features-of-labels-and-projects/ + +### C. Gitea MCP Server Tool Inventory (for reference) + +The official gitea-mcp provides ~80 tools: +- **User**: get_my_user_info, get_user_orgs, search_users +- **Repos**: create_repo, fork_repo, list_my_repos, search_repos +- **Branches**: create_branch, delete_branch, list_branches +- **Tags**: create_tag, delete_tag, get_tag, list_tags +- **Releases**: create_release, delete_release, get_release, get_latest_release, list_releases +- **Files**: get_file_content, get_dir_content, create_file, update_file, delete_file +- **Commits**: list_repo_commits +- **Issues**: get_issue_by_index, list_repo_issues, create_issue, create_issue_comment, edit_issue, edit_issue_comment, get_issue_comments_by_index +- **PRs**: get/list/create/merge pull requests, reviewer management, review CRUD +- **Org labels**: list/create/edit/delete org labels +- **Actions/CI**: workflow, run, job, secret, variable management (~25 tools) +- **Wiki**: list/get/create/update/delete wiki pages + +**Not covered by gitea-mcp**: milestones, project boards, repo labels (only org labels), issue labels, issue assignees, issue deadlines + +### D. forgejo-mcp Tool Inventory (for reference) + +forgejo-mcp provides: +- Issues: create, edit, view, labels (add/remove/replace), comments, attachments, dependencies +- Milestones: create, edit, delete, progress reporting +- Labels: create, edit, delete +- Repos: search, list +- Releases: manage, attachments +- PRs: view +- Wiki: manage +- Actions: view tasks + +**Key advantage over gitea-mcp**: Full milestone CRUD support, issue dependency management, issue label management. + diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..20e521a --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,45 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +# Adapted from terraphim-ai pre-commit config for infrastructure project + +default_language_version: + python: python3.12 + +repos: + # General code quality hooks + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: trailing-whitespace + name: Trim trailing whitespace + - id: end-of-file-fixer + name: Fix end of files + - id: check-yaml + name: Check YAML syntax + - id: check-json + name: Check JSON syntax + - id: check-case-conflict + name: Check for case conflicts + - id: check-merge-conflict + name: Check for merge conflicts + - id: detect-private-key + name: Detect private keys + - id: check-added-large-files + name: Check for large files + args: ['--maxkb=1000'] + + # Secret detection + - repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 + hooks: + - id: detect-secrets + name: Detect secrets + args: ['--baseline', '.secrets.baseline'] + exclude: .*\.template$|.*\.sample$ + description: "Detect secrets in staged code" + +# Global exclusions +exclude: | + (?x)( + ^\.cachebro/.* + ) diff --git a/.secrets.baseline b/.secrets.baseline new file mode 100644 index 0000000..a6fb5fc --- /dev/null +++ b/.secrets.baseline @@ -0,0 +1,172 @@ +{ + "version": "1.5.0", + "plugins_used": [ + { + "name": "ArtifactoryDetector" + }, + { + "name": "AWSKeyDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "name": "Base64HighEntropyString", + "limit": 4.5 + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "CloudantDetector" + }, + { + "name": "DiscordBotTokenDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "name": "GitLabTokenDetector" + }, + { + "name": "HexHighEntropyString", + "limit": 3.0 + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "IPPublicDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "name": "KeywordDetector", + "keyword_exclude": "" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "OpenAIDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "PypiTokenDetector" + }, + { + "name": "SendGridDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TelegramBotTokenDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "filters_used": [ + { + "path": "detect_secrets.filters.allowlist.is_line_allowlisted" + }, + { + "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", + "min_level": 2 + }, + { + "path": "detect_secrets.filters.heuristic.is_indirect_reference" + }, + { + "path": "detect_secrets.filters.heuristic.is_likely_id_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_lock_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_potential_uuid" + }, + { + "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign" + }, + { + "path": "detect_secrets.filters.heuristic.is_sequential_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_swagger_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_templated_secret" + }, + { + "path": "detect_secrets.filters.regex.should_exclude_file", + "pattern": [ + "\\.cachebro/.*", + ".*\\.template$", + ".*\\.sample$" + ] + } + ], + "results": { + ".docs/IMPLEMENTATION-gitea-bigbox-deployment.md": [ + { + "type": "Secret Keyword", + "filename": ".docs/IMPLEMENTATION-gitea-bigbox-deployment.md", + "hashed_secret": "ebb78e1b3d8c84440d663d08edd0d0db46d8b3c3", + "is_verified": false, + "line_number": 424 + } + ], + "ARTICLE-gitea-deployment.md": [ + { + "type": "Secret Keyword", + "filename": "ARTICLE-gitea-deployment.md", + "hashed_secret": "850b05c66deaef000492c33b0e9b582d9baca87a", + "is_verified": false, + "line_number": 131 + } + ], + "HANDOVER.md": [ + { + "type": "Secret Keyword", + "filename": "HANDOVER.md", + "hashed_secret": "f2c57870308dc87f432e5912d4de6f8e322721ba", + "is_verified": false, + "line_number": 165 + } + ], + "docker-compose_kitchen_sink.yml": [ + { + "type": "Secret Keyword", + "filename": "docker-compose_kitchen_sink.yml", + "hashed_secret": "5d2aec19b41f147a20ab309517816cc5222e5e1c", + "is_verified": false, + "line_number": 124 + } + ] + }, + "generated_at": "2026-02-18T10:47:29Z" +}