6.7 KiB
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-lintwith project config - Tests: table-driven, in
_test.gonext to source,testifyfor assertions - Errors: wrap with
fmt.Errorf("operation: %w", err), no naked returns - Naming: stdlib conventions, no stuttering (
http.Clientnothttp.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
- Branch protection: always work on a feature branch, open a PR, never push directly to main
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
govulncheckbefore 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.
- 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.
- Minimum viable code. Solve with the smallest change that works. Nothing speculative, no "while we're here" cleanups, no premature abstractions. Simplicity first.
- Surgical changes. Touch only what the task requires. Leave unrelated code, files, and formatting alone. Diffs should be small and reviewable.
- 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:
- Read this file and all
SKILL.mdfiles in.skills/before starting work - Run
task checkbefore committing (lint + test + vet) - If unsure about a convention, check
DECISIONS.mdor ask - Never modify files outside the project root without explicit permission
- When adding a dependency, explain why in the commit message
- Always work on a feature branch and open a PR — never push directly to main
- For client projects: never send code or context to cloud APIs — use local models via LiteLLM
Current sprint — gitea-mcp v0.2 patch (2026-05-14)
Context
The main v0.2 batch (repo_create, repo_update, repo_mirror_push, repo_delete, repo_tree, repo_topics_update, file_read dir-fix, issue_get, release_create, create_project_from_template) was implemented and pushed directly to main.
This sprint fixes three remaining gaps found during code review on 2026-05-14.
These are blockers for hyperguild new-project.
Issues to fix (all three in one PR: fix/v02-patch)
#12 — repo_update: add archived and template fields
File: internal/gitea/repos.go → UpdateRepoArgs struct
File: internal/tools/repo_update.go → input schema + args struct
Add to UpdateRepoArgs:
Archived *bool
Template *bool
Add to tool input schema:
"archived": {
"type": "boolean",
"description": "Mark repo as archived (read-only). Requires confirm=<repo name>."
},
"template": {
"type": "boolean",
"description": "Toggle template repo flag."
}
Add confirm-guard for archived=true (same pattern as private=false):
if args.Archived != nil && *args.Archived {
if args.Confirm != args.Name {
return nil, fmt.Errorf("setting archived=true is irreversible: set confirm=%q to proceed", args.Name)
}
}
New test cases to add in repo_update_test.go:
TestRepoUpdateTool_Archive— happy path with confirmTestRepoUpdateTool_ArchiveRequiresConfirm— missing confirm returns errorTestRepoUpdateTool_SetTemplate— no confirm needed
#24 — create_project_from_template: make template selectable
File: internal/tools/create_project_from_template.go
Add optional template_name param to input schema:
"template_name": {
"type": "string",
"enum": ["template-go-web", "template-go-agent"],
"description": "Template repo to generate from. Defaults to template-go-web.",
"default": "template-go-web"
}
The tool should use args.TemplateName if set, fall back to the hardcoded default.
Remove the hardcoded template name from cmd/gitea-mcp/main.go constructor call —
the tool resolves it internally.
New test case: TestCreateProjectFromTemplate_AgentTemplate
#25 — pr_files_diff: fix same diff returned for all files
File: internal/tools/pr_files_diff.go
There is a loop bug where all file entries in the response contain the same diff (the first file's diff is reused for every subsequent file). Find the loop and ensure each iteration reads and assigns the correct diff for its own file.
Reproduce: call pr_files_diff on any PR with 3+ files, verify each file has
a distinct diff.
Definition of done
task checkpassesrepo_updateacceptsarchivedandtemplateparamsarchived=truerequiresconfirm=<repo name>create_project_from_templateacceptstemplate_nameparam, defaults totemplate-go-webpr_files_diffreturns distinct diff per file- All new test cases pass
- PR
fix/v02-patchmerged to main via PR (not direct push)
After this sprint
Next: hyperguild new-project v1 implementation.
See brain node adr-new-project-gitea-first-github-mirror for the full flow spec.
Also: verify end-to-end mirror flow (issue #19) once repo_mirror_push is confirmed working.