# Project context ## Identity - **Name**: gitea-mcp - **Owner**: Mathias - **Client**: personal - **Repo**: https://gitea.d-ma.be/mathias/gitea-mcp - **Status**: active ## Stack - **Primary language**: Go - **UI layer**: HTMX + Templ (when applicable) - **Fallback languages**: Python, TypeScript (justify in PR if used) - **Build**: Task (taskfile.dev), not Make - **Containers**: Docker (compose for dev, k3s for deploy) - **Target infra**: koala (GPU workloads), iguana (services), flamingo (edge) ## Conventions ### Code style - Go: follow `golines`, `gofumpt`, `golangci-lint` with project config - Tests: table-driven, in `_test.go` next to source, `testify` for assertions - Errors: wrap with `fmt.Errorf("operation: %w", err)`, no naked returns - Naming: stdlib conventions, no stuttering (`http.Client` not `http.HTTPClient`) ### Architecture preferences - Prefer standard library over frameworks (net/http over gin/echo) - Dependency injection via constructor functions, not containers - Configuration via environment variables, parsed at startup into a typed struct - Structured logging via `slog` ### Git - Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:` - Branch naming: `feat/short-description`, `fix/short-description` - PRs: one concern per PR, description explains *why* not *what* ### Security - No secrets in code, ever — use env vars or SOPS-encrypted files - Client data never leaves local network unless explicitly cleared - Dependencies: audit with `govulncheck` before adding ## Knowledge base access This project can query the shared knowledge base via MCP or HTTP: - **MCP endpoint**: `mcp://localhost:3100/knowledge` - **HTTP fallback**: `http://localhost:3100/api/v1/search` - **Scoping**: queries are filtered to collection `personal` + `public` ## Behavior rules These rules apply to every task in this project, regardless of harness. 1. **No assumptions.** Don't hide confusion — surface it. Surface tradeoffs explicitly. Think before coding; if the problem is unclear, ask or state assumptions before acting. 2. **Minimum viable code.** Solve with the smallest change that works. Nothing speculative, no "while we're here" cleanups, no premature abstractions. Simplicity first. 3. **Surgical changes.** Touch only what the task requires. Leave unrelated code, files, and formatting alone. Diffs should be small and reviewable. 4. **Goal-driven execution.** Define clear success criteria up front for every task. Loop — implement, verify, refine — until those criteria are met. Don't claim completion without evidence (tests pass, command output, observed behavior). ## Agent instructions When acting as a coding agent on this project: 1. Read this file and all `SKILL.md` files in `.skills/` before starting work 2. Run `task check` before committing (lint + test + vet) 3. If unsure about a convention, check `DECISIONS.md` or ask 4. Never modify files outside the project root without explicit permission 5. When adding a dependency, explain why in the commit message 6. For client projects: never send code or context to cloud APIs — use local models via LiteLLM ## Current sprint — gitea-mcp v0.2 (2026-05-14) ### Context This sprint implements new MCP tools needed for `hyperguild new-project` — the automated project creation flow triggered from claude.ai. See brain knowledge nodes `adr-new-project-gitea-first-github-mirror` and `roadmap-github-ingestion-pipeline` for full background. ### Issues to implement (priority order) **Batch 1 — blockers (do first, one PR: `feat/repo-crud`)** | Issue | Tool | Gitea API | |-------|------|-----------| | #13 | `repo_create` | POST /api/v1/user/repos or /api/v1/orgs/{org}/repos | | #16 | `repo_mirror_push` (add/list/delete) | POST/GET/DELETE /api/v1/repos/{owner}/{repo}/push_mirrors | | #12 | `repo_update` | PATCH /api/v1/repos/{owner}/{repo} | **Batch 2 — quality of life (second PR: `feat/repo-ux`)** | Issue | Tool | Gitea API | |-------|------|-----------| | #15 | `file_read` dir-path fix | existing endpoint, detect array vs object response | | #14 | `repo_tree` | GET /api/v1/repos/{owner}/{repo}/git/trees/{sha}?recursive=true | | #18 | `repo_topics_update` | PUT /api/v1/repos/{owner}/{repo}/topics | **Batch 3 — can wait** | Issue | Tool | Note | |-------|------|------| | #11 | `repo_delete` | HIGH risk — needs `confirm` param == repo name | | #17 | `release_create` | POST /api/v1/repos/{owner}/{repo}/releases | ### How to add a tool (pattern) Every tool = 4 files following `internal/tools/repo_get.go` exactly: 1. `internal/gitea/.go` — API client method (use PostJSON/PatchJSON/DeleteJSON) 2. `internal/tools/repo_.go` — tool handler with Descriptor() + Call() 3. `internal/tools/repo__test.go` — table-driven tests with httptest.NewServer 4. Registration in main — find where `NewRepoGet` is registered, add new tool same place Key rules: - Always call `t.a.Check(args.Owner)` before any API call (allowlist guard) - Use `textOK(result)` for success output - For `repo_mirror_push`: NEVER log or return `remote_password` in any output - For `repo_update` with `private: false` and `repo_delete`: require `confirm` param == repo name ### Token permissions needed New tools require these additional Gitea token scopes: - `write:repository` — repo_create, repo_update, repo_mirror_push, repo_topics_update, release_create - `delete_repo` — repo_delete Check current token: `curl -H "Authorization: token $GITEA_TOKEN" https://gitea.d-ma.be/api/v1/user` If scopes are missing, update token in Gitea settings before running tests. ### Definition of done - `task check` passes (all tools, all batches) - Each new tool manually callable via `claude mcp call` - PR #1 (batch 1) merged before starting batch 2 - Issue #19 (mirror flow e2e test) verified manually after batch 1 is deployed