# 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) ```bash # 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: ```bash source ~/op_zesticai_non_prod.sh ``` 2. Inject secrets and deploy: ```bash 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: ```bash 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 ```bash ssh bigbox docker compose ps docker logs gitea ``` ### Check S3 connectivity ```bash ssh bigbox docker exec gitea curl -s http://s3storage:8333/ ``` ### Reset PostgreSQL password ```bash ssh bigbox docker compose exec db psql -U gitea -c "ALTER USER gitea WITH PASSWORD 'newpassword';" ``` ### View S3 buckets ```bash ssh bigbox curl -s http://localhost:8888/bucket/ ``` ## Backup To back up the Gitea data: ```bash # 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`: ```yaml image: gitea/gitea:NEW_VERSION ``` 2. Re-inject secrets and deploy: ```bash 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 ```bash 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: ```bash 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 ```bash 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 ```bash 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