mirror of
https://github.com/terraphim/gitea-infrastructure.git
synced 2026-07-16 00:00:32 +02:00
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>
This commit is contained in:
+409
-309
@@ -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 <username> \
|
||||
--password <password> \
|
||||
--email <email> \
|
||||
--admin \
|
||||
--access-token
|
||||
```
|
||||
--username <user> --password <pass> --email <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
|
||||
|
||||
Executable
+132
@@ -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 ---"
|
||||
@@ -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 |
|
||||
@@ -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": <milestone_id>, "labels": [<label_ids>], "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": <id>` 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.
|
||||
|
||||
@@ -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/.*
|
||||
)
|
||||
@@ -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"
|
||||
}
|
||||
Reference in New Issue
Block a user