Files
Alex Mikhalev dfaf019916 docs: Update handover with session 4 and 1Password SA lessons
- Document service account read-only limitation
- Add session 4 log (1Password token update, task tracking)
- Track expired token fix in cto-executive-system#8

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

15 KiB

Gitea Infrastructure Handover Document

Overview

Self-hosted Gitea instance running on bigbox server with S3 storage, PostgreSQL, and Prometheus monitoring.

URL: https://git.terraphim.cloud GitHub Mirror: https://github.com/terraphim/gitea-infrastructure

Architecture

┌─────────────────────────────────────────────────────────────┐
│                        Internet                              │
└─────────────────────────┬───────────────────────────────────┘
                          │ HTTPS (port 443)
                          ▼
┌─────────────────────────────────────────────────────────────┐
│                     Caddy Reverse Proxy                      │
│                  (terraphim.cloud, existing)                 │
└─────────────────────────┬───────────────────────────────────┘
                          │ git.terraphim.cloud -> localhost:3000
                          ▼
┌─────────────────────────────────────────────────────────────┐
│                     Docker Network (gitea)                   │
├─────────────────────────────────────────────────────────────┤
│  Gitea (port 3000)  │  PostgreSQL  │  SeaweedFS (S3)        │
│  - Attachments      │  (port 5432) │  - S3 (port 8333)      │
│  - Avatars          │              │  - Filer (port 8888)    │
│  - LFS              │              │  - Volume (port 8080)     │
│                     │              │  - Master (port 9333)   │
└─────────────────────────────────────────────────────────────┘
         │                    │                    │
         │                    │                    │
         ▼                    ▼                    ▼
┌─────────────────────────────────────────────────────────────┐
│                    Tailscale Network                         │
│           Prometheus (100.106.66.7:9000) - internal         │
│           S3 (100.106.66.7:8333) - internal only             │
└─────────────────────────────────────────────────────────────┘

Services

Service Port Access Description
Gitea 3000 localhost (via Caddy) Git web UI
Gitea SSH 22/222 Public Git over SSH
PostgreSQL 5432 Docker internal Database
SeaweedFS S3 8333 Tailscale only S3-compatible storage
SeaweedFS Filer 8888 Docker internal File interface
Prometheus 9000 Tailscale only Metrics

Server Access

Server: bigbox (100.106.66.7)

# SSH to bigbox
ssh bigbox

# Navigate to stack directory
cd ~/gitea-stack

# View container status
docker compose ps

# View logs
docker compose logs -f gitea

# Restart Gitea
docker compose restart server

# Stop entire stack
docker compose down

# Start stack
docker compose up -d

1Password Secrets

Vault: TerraphimPlatform

Item Purpose
gitea-postgres PostgreSQL password
gitea-s3 S3 access key and secret key

Re-deploying with 1Password

  1. Source the 1Password authentication:

    source ~/op_zesticai_non_prod.sh
    
  2. Inject secrets and deploy:

    cd ~/gitea-stack
    op inject --in-file ../gitea_config/docker-compose.yml.template --out-file docker-compose.yml
    docker compose up -d
    

Storage Configuration

S3 Buckets

  • gitea - Attachments, avatars, repository files
  • gitea-lfs - Git LFS objects

Gitea Storage Settings

The following storage types are configured to use S3 (Minio):

  • [attachment] - File attachments
  • [picture] - Avatars and images
  • [lfs] - Git LFS objects
  • [storage] - Default storage configuration

Local storage is used for:

  • Git repositories (/data/git/repositories)
  • Database (PostgreSQL)

Caddy Configuration

Caddy is already running on bigbox. The git route is appended to /etc/caddy/Caddyfile:

git.terraphim.cloud {
    reverse_proxy localhost:3000
}

To update Caddy config:

ssh bigbox
sudo vim /etc/caddy/Caddyfile
sudo caddy reload

Monitoring

Prometheus: http://100.106.66.7:9000 (Tailscale only)

Scrape targets configured in prometheus/prometheus.yml.

Troubleshooting

Check Gitea status

ssh bigbox
docker compose ps
docker logs gitea

Check S3 connectivity

ssh bigbox
docker exec gitea curl -s http://s3storage:8333/

Reset PostgreSQL password

ssh bigbox
docker compose exec db psql -U gitea -c "ALTER USER gitea WITH PASSWORD 'newpassword';"

View S3 buckets

ssh bigbox
curl -s http://localhost:8888/bucket/

Backup

To back up the Gitea data:

# On bigbox
cd ~/gitea-stack
docker compose stop
tar -czf gitea-backup-$(date +%Y%m%d).tar.gz gitea/ postgres/ seaweedfs/
docker compose start

Updates

To update Gitea to a new version:

  1. Edit docker-compose.yml.template:

    image: gitea/gitea:NEW_VERSION
    
  2. Re-inject secrets and deploy:

    source ~/op_zesticai_non_prod.sh
    op inject --in-file ../gitea_config/docker-compose.yml.template --out-file docker-compose.yml
    docker compose up -d --build
    

GitHub -> Gitea Mirroring

Gitea is configured as a pull mirror from GitHub. No GitHub Actions or manual push needed.

How it works: Gitea polls GitHub every hour and pulls new commits automatically.

Setting Value
Source https://github.com/terraphim/gitea-infrastructure (private)
Mirror https://git.terraphim.cloud/terraphim/gitea-infrastructure
Interval 1 hour
Auth GitHub token stored in Gitea migration config

Manual Sync

source ~/op_zesticai_non_prod.sh
export GITEA_TOKEN=$(op read "op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential")
curl -s -X POST "https://git.terraphim.cloud/api/v1/repos/terraphim/gitea-infrastructure/mirror-sync" \
  -H "Authorization: token $GITEA_TOKEN"

Recreating the Mirror

If the mirror breaks (e.g., GitHub token expires), delete and recreate:

source ~/op_zesticai_non_prod.sh
GITEA_TOKEN=$(op read "op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential")
GH_TOKEN=$(gh auth token)

# Delete existing
curl -s -X DELETE "https://git.terraphim.cloud/api/v1/repos/terraphim/gitea-infrastructure" \
  -H "Authorization: token $GITEA_TOKEN"

sleep 10

# Recreate as pull mirror
curl -s -X POST "https://git.terraphim.cloud/api/v1/repos/migrate" \
  -H "Authorization: token $GITEA_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"clone_addr\": \"https://github.com/terraphim/gitea-infrastructure\",
    \"repo_name\": \"gitea-infrastructure\",
    \"repo_owner\": \"terraphim\",
    \"service\": \"github\",
    \"auth_token\": \"$GH_TOKEN\",
    \"mirror\": true,
    \"mirror_interval\": \"1h\"
  }"

Key Constraints

  • The Gitea repo is read-only (mirror). All pushes go to GitHub only.
  • An existing repo cannot be converted to a mirror -- must delete and recreate via POST /repos/migrate.
  • service: "github" requires a valid GitHub token for private repos. service: "git" fails with "terminal prompts disabled".
  • The 1Password item github.personal.token is expired. Use gh auth token instead.

AI Agent Skill (Gitea Task Management)

Added 2026-02-18. Provides AI agents with project and task management via Gitea API.

Architecture

Dual-mode: gitea-mcp (75+ tools for standard CRUD) + curl/jq shell helpers (milestones, workflow labels, dependencies -- areas where gitea-mcp has gaps).

Key Constraint

Gitea 1.22.6 has NO project board REST API. Milestones serve as project containers with built-in progress tracking.

Files

File Description
.agents/skills/gitea/SKILL.md Agent skill document with all helpers
.agents/skills/gitea/setup-labels.sh Idempotent repo + 12 label creation
.agents/skills/gitea/test-gitea-skill.sh 10 integration tests (26 assertions)
.docs/RESEARCH-gitea-agent-skill.md Phase 1 research (verified against live)
.docs/DESIGN-gitea-agent-skill.md Phase 2 design document

Default Task Repository

terraphim/agent-tasks -- overridable via GITEA_OWNER and GITEA_REPO env vars.

Authentication

source ~/op_zesticai_non_prod.sh
export GITEA_TOKEN=$(op read "op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential")

Workflow Labels

12 scoped labels across 3 scopes (workflow, priority, type). Workflow state machine: ready -> in-progress -> blocked -> done.

Running Tests

source ~/op_zesticai_non_prod.sh
export GITEA_TOKEN=$(op read "op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential")
.agents/skills/gitea/test-gitea-skill.sh

All 26 assertions pass against live Gitea 1.22.6 as of 2026-02-18.

Critical API Gotchas

  1. Label exclusivity is UI-only -- API POST /labels just appends. Must use PUT with label swap pattern (get current, filter workflow:*, add new, PUT all).
  2. Assignees -- Use PATCH /issues/{index} with {"assignees": [...]}. The POST /issues/{index}/assignees endpoint does not exist in 1.22.6.
  3. Issue dependencies -- Body uses IssueMeta format: {"owner": "...", "repo": "...", "index": N} (NOT {"depends_on_id": N}).

Pre-commit Hooks

Added .pre-commit-config.yaml with:

  • Trailing whitespace, end-of-file fixer, YAML/JSON check
  • Merge conflict and private key detection
  • Secret detection via detect-secrets (baseline at .secrets.baseline)

Key Files

File Description
docker-compose.yml.template Template with 1Password references
Caddyfile Caddy reverse proxy config
deploy-to-bigbox.sh Deployment script
s3_config.json.template SeaweedFS S3 config template
prometheus/prometheus.yml Prometheus scrape config
MIRRORING-GUIDE.md Gitea pull mirror setup (replaced GitHub Actions)
.agents/skills/gitea/SKILL.md AI agent Gitea skill
.agents/skills/gitea/setup-labels.sh Label setup script
.agents/skills/gitea/test-gitea-skill.sh Integration tests
.pre-commit-config.yaml Pre-commit hook config
ARTICLE-agent-task-management.md CTO voice article (~2800 words)
ARTICLE-agent-task-consolidation.md Technical reference article (~6000 words)
lessons-learned.md Session discoveries and pitfalls

Articles

Two comparison articles documenting the migration from beads/br/agent-mail to Gitea:

File Style Words
ARTICLE-agent-task-management.md CTO voice (bold, narrative) ~2800
ARTICLE-agent-task-consolidation.md Technical reference (comprehensive) ~6000

Both cover: 1Password integration, Gitea + SeaweedFS infrastructure, all three API gotchas with fix patterns, and honest tradeoff analysis. All commands verified working against live instance.

Gitea Mirror

Gitea pulls from GitHub automatically (1-hour interval). No GitHub Actions needed.

Role URL
Primary (push here) https://github.com/terraphim/gitea-infrastructure
Mirror (auto-synced) https://git.terraphim.cloud/terraphim/gitea-infrastructure

GitHub Actions workflows (sync-to-gitea.yml, mirror-check.yml) were removed -- Gitea's native pull mirror replaces them.

Session Log (2026-02-18)

Session 1: Gitea Agent Skill Implementation

  • Rewrote Gitea agent skill with verified API patterns (milestones, workflow labels, dependencies)
  • Created setup-labels.sh for idempotent repo + label creation
  • Created test-gitea-skill.sh with 10 tests (26 assertions), all passing
  • Found and fixed 3 API behavior bugs (label exclusivity, assignee endpoint, dependency format)
  • Added pre-commit hooks and fixed trailing whitespace across 15 files
  • Conducted disciplined research and design phases with live API verification

Session 2: Articles and Publishing

  • Wrote two comparison articles (CTO voice + technical reference) comparing beads/br/agent-mail with Gitea replacement
  • All code snippets, commands, and configurations verified against live Gitea instance
  • Pushed all commits to GitHub origin/main

Session 3: Replace GitHub Actions with Gitea Pull Mirror

  • Removed sync-to-gitea.yml and mirror-check.yml GitHub Actions workflows
  • Deleted manually-pushed Gitea repo, recreated as native pull mirror via POST /repos/migrate
  • Discovered github.personal.token in 1Password is expired (401); used gh auth token instead
  • Discovered Gitea creates empty mirror repos on failed async clones (silent failure)
  • Discovered service: "git" fails for private repos; service: "github" with valid token works
  • Mirror interval set to 1 hour, manual sync available via API
  • Rewrote MIRRORING-GUIDE.md with pull mirror approach and all gotchas
  • Updated HANDOVER.md and lessons-learned.md

Session 4: 1Password Token Update and Task Tracking

  • Attempted to update github.personal.token via op item edit -- blocked by service account read-only permissions
  • Confirmed op_zesticai_non_prod.sh sources a SERVICE_ACCOUNT with no write access to TerraphimPlatform vault
  • Created GitHub issue to track the fix: https://github.com/AlexMikhalev/cto-executive-system/issues/8

All Commits (pushed to GitHub, auto-synced to Gitea)

  • 57eabbb refactor: Replace GitHub Actions mirroring with Gitea native pull mirror
  • 0e69456 docs: Update handover with articles, publishing, and new lessons learned
  • 62e2275 docs: Add articles comparing beads/br/agent-mail with Gitea replacement
  • 4ff1821 docs: Update handover and add lessons learned
  • b67284e chore: Fix trailing whitespace across project files
  • 66b305d feat(gitea-skill): Add integration tests and fix workflow label swap
  • 1fd202d feat(gitea-skill): Rewrite Gitea agent skill with verified API patterns

Next Steps

  1. Update github.personal.token in 1Password manually (service account is read-only) -- tracked in https://github.com/AlexMikhalev/cto-executive-system/issues/8
  2. Grant write access to op_zesticai_non_prod service account on TerraphimPlatform vault
  3. Consider adding gitea-mcp or forgejo-mcp as MCP server for Claude Code (see SKILL.md MCP Integration section)
  4. Create first real milestone and tasks in terraphim/agent-tasks for a project

Contacts

  • Infrastructure owner: Alex
  • 1Password vault: TerraphimPlatform