chore: re-sync context adapters after rebase
Upstream .context/PROJECT.md gained a branch-protection rule + an extra agent instruction. Pure regeneration via scripts/context-sync.sh to make task check pass before force-push. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,7 +49,6 @@ These rules apply to every task across every project, regardless of harness.
|
|||||||
| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — |
|
| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — |
|
||||||
| Logging | slog (structured) | — | — |
|
| Logging | slog (structured) | — | — |
|
||||||
| Testing | Table-driven, testify | — | — |
|
| Testing | Table-driven, testify | — | — |
|
||||||
| Agents (Go) | google.golang.org/adk + pkg/litellm adapter | — | — |
|
|
||||||
|
|
||||||
Exploratory: Rust, Zig — I'll tell you when I want these.
|
Exploratory: Rust, Zig — I'll tell you when I want these.
|
||||||
|
|
||||||
@@ -61,7 +60,7 @@ Exploratory: Rust, Zig — I'll tell you when I want these.
|
|||||||
- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs
|
- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs
|
||||||
- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), one concern per PR, PR describes *why* not *what*
|
- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), one concern per PR, PR describes *why* not *what*
|
||||||
- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config
|
- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config
|
||||||
- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc, google.golang.org/adk (agent projects only) are pre-approved; anything else needs justification in the commit message
|
- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc are pre-approved; anything else needs justification in the commit message
|
||||||
|
|
||||||
## Infrastructure
|
## Infrastructure
|
||||||
|
|
||||||
@@ -211,6 +210,7 @@ Key skills:
|
|||||||
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`
|
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`
|
||||||
- Branch naming: `feat/short-description`, `fix/short-description`
|
- Branch naming: `feat/short-description`, `fix/short-description`
|
||||||
- PRs: one concern per PR, description explains *why* not *what*
|
- 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
|
### Security
|
||||||
- No secrets in code, ever — use env vars or SOPS-encrypted files
|
- No secrets in code, ever — use env vars or SOPS-encrypted files
|
||||||
@@ -248,68 +248,98 @@ When acting as a coding agent on this project:
|
|||||||
3. If unsure about a convention, check `DECISIONS.md` or ask
|
3. If unsure about a convention, check `DECISIONS.md` or ask
|
||||||
4. Never modify files outside the project root without explicit permission
|
4. Never modify files outside the project root without explicit permission
|
||||||
5. When adding a dependency, explain why in the commit message
|
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
|
6. Always work on a feature branch and open a PR — never push directly to main
|
||||||
|
7. 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)
|
## Current sprint — gitea-mcp v0.2 patch (2026-05-14)
|
||||||
|
|
||||||
### Context
|
### Context
|
||||||
This sprint implements new MCP tools needed for `hyperguild new-project` —
|
The main v0.2 batch (repo_create, repo_update, repo_mirror_push, repo_delete,
|
||||||
the automated project creation flow triggered from claude.ai. See brain knowledge
|
repo_tree, repo_topics_update, file_read dir-fix, issue_get, release_create,
|
||||||
nodes `adr-new-project-gitea-first-github-mirror` and `roadmap-github-ingestion-pipeline`
|
create_project_from_template) was implemented and pushed directly to main.
|
||||||
for full background.
|
|
||||||
|
|
||||||
### Issues to implement (priority order)
|
This sprint fixes three remaining gaps found during code review on 2026-05-14.
|
||||||
|
These are blockers for `hyperguild new-project`.
|
||||||
|
|
||||||
**Batch 1 — blockers (do first, one PR: `feat/repo-crud`)**
|
### Issues to fix (all three in one PR: `fix/v02-patch`)
|
||||||
|
|
||||||
| Issue | Tool | Gitea API |
|
#### #12 — repo_update: add `archived` and `template` fields
|
||||||
|-------|------|-----------|
|
**File:** `internal/gitea/repos.go` → `UpdateRepoArgs` struct
|
||||||
| #13 | `repo_create` | POST /api/v1/user/repos or /api/v1/orgs/{org}/repos |
|
**File:** `internal/tools/repo_update.go` → input schema + args struct
|
||||||
| #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`)**
|
Add to `UpdateRepoArgs`:
|
||||||
|
```go
|
||||||
|
Archived *bool
|
||||||
|
Template *bool
|
||||||
|
```
|
||||||
|
|
||||||
| Issue | Tool | Gitea API |
|
Add to tool input schema:
|
||||||
|-------|------|-----------|
|
```json
|
||||||
| #15 | `file_read` dir-path fix | existing endpoint, detect array vs object response |
|
"archived": {
|
||||||
| #14 | `repo_tree` | GET /api/v1/repos/{owner}/{repo}/git/trees/{sha}?recursive=true |
|
"type": "boolean",
|
||||||
| #18 | `repo_topics_update` | PUT /api/v1/repos/{owner}/{repo}/topics |
|
"description": "Mark repo as archived (read-only). Requires confirm=<repo name>."
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Toggle template repo flag."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
**Batch 3 — can wait**
|
Add confirm-guard for `archived=true` (same pattern as `private=false`):
|
||||||
|
```go
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
| Issue | Tool | Note |
|
New test cases to add in `repo_update_test.go`:
|
||||||
|-------|------|------|
|
- `TestRepoUpdateTool_Archive` — happy path with confirm
|
||||||
| #11 | `repo_delete` | HIGH risk — needs `confirm` param == repo name |
|
- `TestRepoUpdateTool_ArchiveRequiresConfirm` — missing confirm returns error
|
||||||
| #17 | `release_create` | POST /api/v1/repos/{owner}/{repo}/releases |
|
- `TestRepoUpdateTool_SetTemplate` — no confirm needed
|
||||||
|
|
||||||
### How to add a tool (pattern)
|
#### #24 — create_project_from_template: make template selectable
|
||||||
|
**File:** `internal/tools/create_project_from_template.go`
|
||||||
|
|
||||||
Every tool = 4 files following `internal/tools/repo_get.go` exactly:
|
Add optional `template_name` param to input schema:
|
||||||
|
```json
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
1. `internal/gitea/<domain>.go` — API client method (use PostJSON/PatchJSON/DeleteJSON)
|
The tool should use `args.TemplateName` if set, fall back to the hardcoded default.
|
||||||
2. `internal/tools/repo_<name>.go` — tool handler with Descriptor() + Call()
|
Remove the hardcoded template name from `cmd/gitea-mcp/main.go` constructor call —
|
||||||
3. `internal/tools/repo_<name>_test.go` — table-driven tests with httptest.NewServer
|
the tool resolves it internally.
|
||||||
4. Registration in main — find where `NewRepoGet` is registered, add new tool same place
|
|
||||||
|
|
||||||
Key rules:
|
New test case: `TestCreateProjectFromTemplate_AgentTemplate`
|
||||||
- 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
|
#### #25 — pr_files_diff: fix same diff returned for all files
|
||||||
|
**File:** `internal/tools/pr_files_diff.go`
|
||||||
|
|
||||||
New tools require these additional Gitea token scopes:
|
There is a loop bug where all file entries in the response contain the same diff
|
||||||
- `write:repository` — repo_create, repo_update, repo_mirror_push, repo_topics_update, release_create
|
(the first file's diff is reused for every subsequent file). Find the loop and
|
||||||
- `delete_repo` — repo_delete
|
ensure each iteration reads and assigns the correct diff for its own file.
|
||||||
|
|
||||||
Check current token: `curl -H "Authorization: token $GITEA_TOKEN" https://gitea.d-ma.be/api/v1/user`
|
Reproduce: call `pr_files_diff` on any PR with 3+ files, verify each file has
|
||||||
If scopes are missing, update token in Gitea settings before running tests.
|
a distinct diff.
|
||||||
|
|
||||||
### Definition of done
|
### Definition of done
|
||||||
|
|
||||||
- `task check` passes (all tools, all batches)
|
- [ ] `task check` passes
|
||||||
- Each new tool manually callable via `claude mcp call`
|
- [ ] `repo_update` accepts `archived` and `template` params
|
||||||
- PR #1 (batch 1) merged before starting batch 2
|
- [ ] `archived=true` requires `confirm=<repo name>`
|
||||||
- Issue #19 (mirror flow e2e test) verified manually after batch 1 is deployed
|
- [ ] `create_project_from_template` accepts `template_name` param, defaults to `template-go-web`
|
||||||
|
- [ ] `pr_files_diff` returns distinct diff per file
|
||||||
|
- [ ] All new test cases pass
|
||||||
|
- [ ] PR `fix/v02-patch` merged 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.
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ These rules apply to every task across every project, regardless of harness.
|
|||||||
| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — |
|
| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — |
|
||||||
| Logging | slog (structured) | — | — |
|
| Logging | slog (structured) | — | — |
|
||||||
| Testing | Table-driven, testify | — | — |
|
| Testing | Table-driven, testify | — | — |
|
||||||
| Agents (Go) | google.golang.org/adk + pkg/litellm adapter | — | — |
|
|
||||||
|
|
||||||
Exploratory: Rust, Zig — I'll tell you when I want these.
|
Exploratory: Rust, Zig — I'll tell you when I want these.
|
||||||
|
|
||||||
@@ -66,7 +65,7 @@ Exploratory: Rust, Zig — I'll tell you when I want these.
|
|||||||
- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs
|
- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs
|
||||||
- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), one concern per PR, PR describes *why* not *what*
|
- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), one concern per PR, PR describes *why* not *what*
|
||||||
- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config
|
- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config
|
||||||
- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc, google.golang.org/adk (agent projects only) are pre-approved; anything else needs justification in the commit message
|
- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc are pre-approved; anything else needs justification in the commit message
|
||||||
|
|
||||||
## Infrastructure
|
## Infrastructure
|
||||||
|
|
||||||
@@ -216,6 +215,7 @@ Key skills:
|
|||||||
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`
|
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`
|
||||||
- Branch naming: `feat/short-description`, `fix/short-description`
|
- Branch naming: `feat/short-description`, `fix/short-description`
|
||||||
- PRs: one concern per PR, description explains *why* not *what*
|
- 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
|
### Security
|
||||||
- No secrets in code, ever — use env vars or SOPS-encrypted files
|
- No secrets in code, ever — use env vars or SOPS-encrypted files
|
||||||
@@ -253,70 +253,100 @@ When acting as a coding agent on this project:
|
|||||||
3. If unsure about a convention, check `DECISIONS.md` or ask
|
3. If unsure about a convention, check `DECISIONS.md` or ask
|
||||||
4. Never modify files outside the project root without explicit permission
|
4. Never modify files outside the project root without explicit permission
|
||||||
5. When adding a dependency, explain why in the commit message
|
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
|
6. Always work on a feature branch and open a PR — never push directly to main
|
||||||
|
7. 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)
|
## Current sprint — gitea-mcp v0.2 patch (2026-05-14)
|
||||||
|
|
||||||
### Context
|
### Context
|
||||||
This sprint implements new MCP tools needed for `hyperguild new-project` —
|
The main v0.2 batch (repo_create, repo_update, repo_mirror_push, repo_delete,
|
||||||
the automated project creation flow triggered from claude.ai. See brain knowledge
|
repo_tree, repo_topics_update, file_read dir-fix, issue_get, release_create,
|
||||||
nodes `adr-new-project-gitea-first-github-mirror` and `roadmap-github-ingestion-pipeline`
|
create_project_from_template) was implemented and pushed directly to main.
|
||||||
for full background.
|
|
||||||
|
|
||||||
### Issues to implement (priority order)
|
This sprint fixes three remaining gaps found during code review on 2026-05-14.
|
||||||
|
These are blockers for `hyperguild new-project`.
|
||||||
|
|
||||||
**Batch 1 — blockers (do first, one PR: `feat/repo-crud`)**
|
### Issues to fix (all three in one PR: `fix/v02-patch`)
|
||||||
|
|
||||||
| Issue | Tool | Gitea API |
|
#### #12 — repo_update: add `archived` and `template` fields
|
||||||
|-------|------|-----------|
|
**File:** `internal/gitea/repos.go` → `UpdateRepoArgs` struct
|
||||||
| #13 | `repo_create` | POST /api/v1/user/repos or /api/v1/orgs/{org}/repos |
|
**File:** `internal/tools/repo_update.go` → input schema + args struct
|
||||||
| #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`)**
|
Add to `UpdateRepoArgs`:
|
||||||
|
```go
|
||||||
|
Archived *bool
|
||||||
|
Template *bool
|
||||||
|
```
|
||||||
|
|
||||||
| Issue | Tool | Gitea API |
|
Add to tool input schema:
|
||||||
|-------|------|-----------|
|
```json
|
||||||
| #15 | `file_read` dir-path fix | existing endpoint, detect array vs object response |
|
"archived": {
|
||||||
| #14 | `repo_tree` | GET /api/v1/repos/{owner}/{repo}/git/trees/{sha}?recursive=true |
|
"type": "boolean",
|
||||||
| #18 | `repo_topics_update` | PUT /api/v1/repos/{owner}/{repo}/topics |
|
"description": "Mark repo as archived (read-only). Requires confirm=<repo name>."
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Toggle template repo flag."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
**Batch 3 — can wait**
|
Add confirm-guard for `archived=true` (same pattern as `private=false`):
|
||||||
|
```go
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
| Issue | Tool | Note |
|
New test cases to add in `repo_update_test.go`:
|
||||||
|-------|------|------|
|
- `TestRepoUpdateTool_Archive` — happy path with confirm
|
||||||
| #11 | `repo_delete` | HIGH risk — needs `confirm` param == repo name |
|
- `TestRepoUpdateTool_ArchiveRequiresConfirm` — missing confirm returns error
|
||||||
| #17 | `release_create` | POST /api/v1/repos/{owner}/{repo}/releases |
|
- `TestRepoUpdateTool_SetTemplate` — no confirm needed
|
||||||
|
|
||||||
### How to add a tool (pattern)
|
#### #24 — create_project_from_template: make template selectable
|
||||||
|
**File:** `internal/tools/create_project_from_template.go`
|
||||||
|
|
||||||
Every tool = 4 files following `internal/tools/repo_get.go` exactly:
|
Add optional `template_name` param to input schema:
|
||||||
|
```json
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
1. `internal/gitea/<domain>.go` — API client method (use PostJSON/PatchJSON/DeleteJSON)
|
The tool should use `args.TemplateName` if set, fall back to the hardcoded default.
|
||||||
2. `internal/tools/repo_<name>.go` — tool handler with Descriptor() + Call()
|
Remove the hardcoded template name from `cmd/gitea-mcp/main.go` constructor call —
|
||||||
3. `internal/tools/repo_<name>_test.go` — table-driven tests with httptest.NewServer
|
the tool resolves it internally.
|
||||||
4. Registration in main — find where `NewRepoGet` is registered, add new tool same place
|
|
||||||
|
|
||||||
Key rules:
|
New test case: `TestCreateProjectFromTemplate_AgentTemplate`
|
||||||
- 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
|
#### #25 — pr_files_diff: fix same diff returned for all files
|
||||||
|
**File:** `internal/tools/pr_files_diff.go`
|
||||||
|
|
||||||
New tools require these additional Gitea token scopes:
|
There is a loop bug where all file entries in the response contain the same diff
|
||||||
- `write:repository` — repo_create, repo_update, repo_mirror_push, repo_topics_update, release_create
|
(the first file's diff is reused for every subsequent file). Find the loop and
|
||||||
- `delete_repo` — repo_delete
|
ensure each iteration reads and assigns the correct diff for its own file.
|
||||||
|
|
||||||
Check current token: `curl -H "Authorization: token $GITEA_TOKEN" https://gitea.d-ma.be/api/v1/user`
|
Reproduce: call `pr_files_diff` on any PR with 3+ files, verify each file has
|
||||||
If scopes are missing, update token in Gitea settings before running tests.
|
a distinct diff.
|
||||||
|
|
||||||
### Definition of done
|
### Definition of done
|
||||||
|
|
||||||
- `task check` passes (all tools, all batches)
|
- [ ] `task check` passes
|
||||||
- Each new tool manually callable via `claude mcp call`
|
- [ ] `repo_update` accepts `archived` and `template` params
|
||||||
- PR #1 (batch 1) merged before starting batch 2
|
- [ ] `archived=true` requires `confirm=<repo name>`
|
||||||
- Issue #19 (mirror flow e2e test) verified manually after batch 1 is deployed
|
- [ ] `create_project_from_template` accepts `template_name` param, defaults to `template-go-web`
|
||||||
|
- [ ] `pr_files_diff` returns distinct diff per file
|
||||||
|
- [ ] All new test cases pass
|
||||||
|
- [ ] PR `fix/v02-patch` merged 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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
124
.cursorrules
124
.cursorrules
@@ -52,7 +52,6 @@ These rules apply to every task across every project, regardless of harness.
|
|||||||
| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — |
|
| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — |
|
||||||
| Logging | slog (structured) | — | — |
|
| Logging | slog (structured) | — | — |
|
||||||
| Testing | Table-driven, testify | — | — |
|
| Testing | Table-driven, testify | — | — |
|
||||||
| Agents (Go) | google.golang.org/adk + pkg/litellm adapter | — | — |
|
|
||||||
|
|
||||||
Exploratory: Rust, Zig — I'll tell you when I want these.
|
Exploratory: Rust, Zig — I'll tell you when I want these.
|
||||||
|
|
||||||
@@ -64,7 +63,7 @@ Exploratory: Rust, Zig — I'll tell you when I want these.
|
|||||||
- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs
|
- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs
|
||||||
- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), one concern per PR, PR describes *why* not *what*
|
- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), one concern per PR, PR describes *why* not *what*
|
||||||
- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config
|
- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config
|
||||||
- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc, google.golang.org/adk (agent projects only) are pre-approved; anything else needs justification in the commit message
|
- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc are pre-approved; anything else needs justification in the commit message
|
||||||
|
|
||||||
## Infrastructure
|
## Infrastructure
|
||||||
|
|
||||||
@@ -214,6 +213,7 @@ Key skills:
|
|||||||
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`
|
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`
|
||||||
- Branch naming: `feat/short-description`, `fix/short-description`
|
- Branch naming: `feat/short-description`, `fix/short-description`
|
||||||
- PRs: one concern per PR, description explains *why* not *what*
|
- 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
|
### Security
|
||||||
- No secrets in code, ever — use env vars or SOPS-encrypted files
|
- No secrets in code, ever — use env vars or SOPS-encrypted files
|
||||||
@@ -251,68 +251,98 @@ When acting as a coding agent on this project:
|
|||||||
3. If unsure about a convention, check `DECISIONS.md` or ask
|
3. If unsure about a convention, check `DECISIONS.md` or ask
|
||||||
4. Never modify files outside the project root without explicit permission
|
4. Never modify files outside the project root without explicit permission
|
||||||
5. When adding a dependency, explain why in the commit message
|
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
|
6. Always work on a feature branch and open a PR — never push directly to main
|
||||||
|
7. 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)
|
## Current sprint — gitea-mcp v0.2 patch (2026-05-14)
|
||||||
|
|
||||||
### Context
|
### Context
|
||||||
This sprint implements new MCP tools needed for `hyperguild new-project` —
|
The main v0.2 batch (repo_create, repo_update, repo_mirror_push, repo_delete,
|
||||||
the automated project creation flow triggered from claude.ai. See brain knowledge
|
repo_tree, repo_topics_update, file_read dir-fix, issue_get, release_create,
|
||||||
nodes `adr-new-project-gitea-first-github-mirror` and `roadmap-github-ingestion-pipeline`
|
create_project_from_template) was implemented and pushed directly to main.
|
||||||
for full background.
|
|
||||||
|
|
||||||
### Issues to implement (priority order)
|
This sprint fixes three remaining gaps found during code review on 2026-05-14.
|
||||||
|
These are blockers for `hyperguild new-project`.
|
||||||
|
|
||||||
**Batch 1 — blockers (do first, one PR: `feat/repo-crud`)**
|
### Issues to fix (all three in one PR: `fix/v02-patch`)
|
||||||
|
|
||||||
| Issue | Tool | Gitea API |
|
#### #12 — repo_update: add `archived` and `template` fields
|
||||||
|-------|------|-----------|
|
**File:** `internal/gitea/repos.go` → `UpdateRepoArgs` struct
|
||||||
| #13 | `repo_create` | POST /api/v1/user/repos or /api/v1/orgs/{org}/repos |
|
**File:** `internal/tools/repo_update.go` → input schema + args struct
|
||||||
| #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`)**
|
Add to `UpdateRepoArgs`:
|
||||||
|
```go
|
||||||
|
Archived *bool
|
||||||
|
Template *bool
|
||||||
|
```
|
||||||
|
|
||||||
| Issue | Tool | Gitea API |
|
Add to tool input schema:
|
||||||
|-------|------|-----------|
|
```json
|
||||||
| #15 | `file_read` dir-path fix | existing endpoint, detect array vs object response |
|
"archived": {
|
||||||
| #14 | `repo_tree` | GET /api/v1/repos/{owner}/{repo}/git/trees/{sha}?recursive=true |
|
"type": "boolean",
|
||||||
| #18 | `repo_topics_update` | PUT /api/v1/repos/{owner}/{repo}/topics |
|
"description": "Mark repo as archived (read-only). Requires confirm=<repo name>."
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Toggle template repo flag."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
**Batch 3 — can wait**
|
Add confirm-guard for `archived=true` (same pattern as `private=false`):
|
||||||
|
```go
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
| Issue | Tool | Note |
|
New test cases to add in `repo_update_test.go`:
|
||||||
|-------|------|------|
|
- `TestRepoUpdateTool_Archive` — happy path with confirm
|
||||||
| #11 | `repo_delete` | HIGH risk — needs `confirm` param == repo name |
|
- `TestRepoUpdateTool_ArchiveRequiresConfirm` — missing confirm returns error
|
||||||
| #17 | `release_create` | POST /api/v1/repos/{owner}/{repo}/releases |
|
- `TestRepoUpdateTool_SetTemplate` — no confirm needed
|
||||||
|
|
||||||
### How to add a tool (pattern)
|
#### #24 — create_project_from_template: make template selectable
|
||||||
|
**File:** `internal/tools/create_project_from_template.go`
|
||||||
|
|
||||||
Every tool = 4 files following `internal/tools/repo_get.go` exactly:
|
Add optional `template_name` param to input schema:
|
||||||
|
```json
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
1. `internal/gitea/<domain>.go` — API client method (use PostJSON/PatchJSON/DeleteJSON)
|
The tool should use `args.TemplateName` if set, fall back to the hardcoded default.
|
||||||
2. `internal/tools/repo_<name>.go` — tool handler with Descriptor() + Call()
|
Remove the hardcoded template name from `cmd/gitea-mcp/main.go` constructor call —
|
||||||
3. `internal/tools/repo_<name>_test.go` — table-driven tests with httptest.NewServer
|
the tool resolves it internally.
|
||||||
4. Registration in main — find where `NewRepoGet` is registered, add new tool same place
|
|
||||||
|
|
||||||
Key rules:
|
New test case: `TestCreateProjectFromTemplate_AgentTemplate`
|
||||||
- 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
|
#### #25 — pr_files_diff: fix same diff returned for all files
|
||||||
|
**File:** `internal/tools/pr_files_diff.go`
|
||||||
|
|
||||||
New tools require these additional Gitea token scopes:
|
There is a loop bug where all file entries in the response contain the same diff
|
||||||
- `write:repository` — repo_create, repo_update, repo_mirror_push, repo_topics_update, release_create
|
(the first file's diff is reused for every subsequent file). Find the loop and
|
||||||
- `delete_repo` — repo_delete
|
ensure each iteration reads and assigns the correct diff for its own file.
|
||||||
|
|
||||||
Check current token: `curl -H "Authorization: token $GITEA_TOKEN" https://gitea.d-ma.be/api/v1/user`
|
Reproduce: call `pr_files_diff` on any PR with 3+ files, verify each file has
|
||||||
If scopes are missing, update token in Gitea settings before running tests.
|
a distinct diff.
|
||||||
|
|
||||||
### Definition of done
|
### Definition of done
|
||||||
|
|
||||||
- `task check` passes (all tools, all batches)
|
- [ ] `task check` passes
|
||||||
- Each new tool manually callable via `claude mcp call`
|
- [ ] `repo_update` accepts `archived` and `template` params
|
||||||
- PR #1 (batch 1) merged before starting batch 2
|
- [ ] `archived=true` requires `confirm=<repo name>`
|
||||||
- Issue #19 (mirror flow e2e test) verified manually after batch 1 is deployed
|
- [ ] `create_project_from_template` accepts `template_name` param, defaults to `template-go-web`
|
||||||
|
- [ ] `pr_files_diff` returns distinct diff per file
|
||||||
|
- [ ] All new test cases pass
|
||||||
|
- [ ] PR `fix/v02-patch` merged 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.
|
||||||
|
|||||||
124
AGENTS.md
124
AGENTS.md
@@ -49,7 +49,6 @@ These rules apply to every task across every project, regardless of harness.
|
|||||||
| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — |
|
| Search | pgvector (vector), BM25 | Qdrant (when >1M vectors or hybrid retrieval) | — |
|
||||||
| Logging | slog (structured) | — | — |
|
| Logging | slog (structured) | — | — |
|
||||||
| Testing | Table-driven, testify | — | — |
|
| Testing | Table-driven, testify | — | — |
|
||||||
| Agents (Go) | google.golang.org/adk + pkg/litellm adapter | — | — |
|
|
||||||
|
|
||||||
Exploratory: Rust, Zig — I'll tell you when I want these.
|
Exploratory: Rust, Zig — I'll tell you when I want these.
|
||||||
|
|
||||||
@@ -61,7 +60,7 @@ Exploratory: Rust, Zig — I'll tell you when I want these.
|
|||||||
- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs
|
- **Architecture**: prefer stdlib over frameworks, constructor injection, env-var config parsed into typed structs
|
||||||
- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), one concern per PR, PR describes *why* not *what*
|
- **Git**: conventional commits (`feat:`, `fix:`, `chore:`), one concern per PR, PR describes *why* not *what*
|
||||||
- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config
|
- **Security**: no secrets in code, govulncheck before adding deps, SOPS for encrypted config
|
||||||
- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc, google.golang.org/adk (agent projects only) are pre-approved; anything else needs justification in the commit message
|
- **Dependencies**: prefer stdlib. testify, slog, templ, sqlc are pre-approved; anything else needs justification in the commit message
|
||||||
|
|
||||||
## Infrastructure
|
## Infrastructure
|
||||||
|
|
||||||
@@ -211,6 +210,7 @@ Key skills:
|
|||||||
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`
|
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`
|
||||||
- Branch naming: `feat/short-description`, `fix/short-description`
|
- Branch naming: `feat/short-description`, `fix/short-description`
|
||||||
- PRs: one concern per PR, description explains *why* not *what*
|
- 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
|
### Security
|
||||||
- No secrets in code, ever — use env vars or SOPS-encrypted files
|
- No secrets in code, ever — use env vars or SOPS-encrypted files
|
||||||
@@ -248,68 +248,98 @@ When acting as a coding agent on this project:
|
|||||||
3. If unsure about a convention, check `DECISIONS.md` or ask
|
3. If unsure about a convention, check `DECISIONS.md` or ask
|
||||||
4. Never modify files outside the project root without explicit permission
|
4. Never modify files outside the project root without explicit permission
|
||||||
5. When adding a dependency, explain why in the commit message
|
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
|
6. Always work on a feature branch and open a PR — never push directly to main
|
||||||
|
7. 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)
|
## Current sprint — gitea-mcp v0.2 patch (2026-05-14)
|
||||||
|
|
||||||
### Context
|
### Context
|
||||||
This sprint implements new MCP tools needed for `hyperguild new-project` —
|
The main v0.2 batch (repo_create, repo_update, repo_mirror_push, repo_delete,
|
||||||
the automated project creation flow triggered from claude.ai. See brain knowledge
|
repo_tree, repo_topics_update, file_read dir-fix, issue_get, release_create,
|
||||||
nodes `adr-new-project-gitea-first-github-mirror` and `roadmap-github-ingestion-pipeline`
|
create_project_from_template) was implemented and pushed directly to main.
|
||||||
for full background.
|
|
||||||
|
|
||||||
### Issues to implement (priority order)
|
This sprint fixes three remaining gaps found during code review on 2026-05-14.
|
||||||
|
These are blockers for `hyperguild new-project`.
|
||||||
|
|
||||||
**Batch 1 — blockers (do first, one PR: `feat/repo-crud`)**
|
### Issues to fix (all three in one PR: `fix/v02-patch`)
|
||||||
|
|
||||||
| Issue | Tool | Gitea API |
|
#### #12 — repo_update: add `archived` and `template` fields
|
||||||
|-------|------|-----------|
|
**File:** `internal/gitea/repos.go` → `UpdateRepoArgs` struct
|
||||||
| #13 | `repo_create` | POST /api/v1/user/repos or /api/v1/orgs/{org}/repos |
|
**File:** `internal/tools/repo_update.go` → input schema + args struct
|
||||||
| #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`)**
|
Add to `UpdateRepoArgs`:
|
||||||
|
```go
|
||||||
|
Archived *bool
|
||||||
|
Template *bool
|
||||||
|
```
|
||||||
|
|
||||||
| Issue | Tool | Gitea API |
|
Add to tool input schema:
|
||||||
|-------|------|-----------|
|
```json
|
||||||
| #15 | `file_read` dir-path fix | existing endpoint, detect array vs object response |
|
"archived": {
|
||||||
| #14 | `repo_tree` | GET /api/v1/repos/{owner}/{repo}/git/trees/{sha}?recursive=true |
|
"type": "boolean",
|
||||||
| #18 | `repo_topics_update` | PUT /api/v1/repos/{owner}/{repo}/topics |
|
"description": "Mark repo as archived (read-only). Requires confirm=<repo name>."
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Toggle template repo flag."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
**Batch 3 — can wait**
|
Add confirm-guard for `archived=true` (same pattern as `private=false`):
|
||||||
|
```go
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
| Issue | Tool | Note |
|
New test cases to add in `repo_update_test.go`:
|
||||||
|-------|------|------|
|
- `TestRepoUpdateTool_Archive` — happy path with confirm
|
||||||
| #11 | `repo_delete` | HIGH risk — needs `confirm` param == repo name |
|
- `TestRepoUpdateTool_ArchiveRequiresConfirm` — missing confirm returns error
|
||||||
| #17 | `release_create` | POST /api/v1/repos/{owner}/{repo}/releases |
|
- `TestRepoUpdateTool_SetTemplate` — no confirm needed
|
||||||
|
|
||||||
### How to add a tool (pattern)
|
#### #24 — create_project_from_template: make template selectable
|
||||||
|
**File:** `internal/tools/create_project_from_template.go`
|
||||||
|
|
||||||
Every tool = 4 files following `internal/tools/repo_get.go` exactly:
|
Add optional `template_name` param to input schema:
|
||||||
|
```json
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
1. `internal/gitea/<domain>.go` — API client method (use PostJSON/PatchJSON/DeleteJSON)
|
The tool should use `args.TemplateName` if set, fall back to the hardcoded default.
|
||||||
2. `internal/tools/repo_<name>.go` — tool handler with Descriptor() + Call()
|
Remove the hardcoded template name from `cmd/gitea-mcp/main.go` constructor call —
|
||||||
3. `internal/tools/repo_<name>_test.go` — table-driven tests with httptest.NewServer
|
the tool resolves it internally.
|
||||||
4. Registration in main — find where `NewRepoGet` is registered, add new tool same place
|
|
||||||
|
|
||||||
Key rules:
|
New test case: `TestCreateProjectFromTemplate_AgentTemplate`
|
||||||
- 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
|
#### #25 — pr_files_diff: fix same diff returned for all files
|
||||||
|
**File:** `internal/tools/pr_files_diff.go`
|
||||||
|
|
||||||
New tools require these additional Gitea token scopes:
|
There is a loop bug where all file entries in the response contain the same diff
|
||||||
- `write:repository` — repo_create, repo_update, repo_mirror_push, repo_topics_update, release_create
|
(the first file's diff is reused for every subsequent file). Find the loop and
|
||||||
- `delete_repo` — repo_delete
|
ensure each iteration reads and assigns the correct diff for its own file.
|
||||||
|
|
||||||
Check current token: `curl -H "Authorization: token $GITEA_TOKEN" https://gitea.d-ma.be/api/v1/user`
|
Reproduce: call `pr_files_diff` on any PR with 3+ files, verify each file has
|
||||||
If scopes are missing, update token in Gitea settings before running tests.
|
a distinct diff.
|
||||||
|
|
||||||
### Definition of done
|
### Definition of done
|
||||||
|
|
||||||
- `task check` passes (all tools, all batches)
|
- [ ] `task check` passes
|
||||||
- Each new tool manually callable via `claude mcp call`
|
- [ ] `repo_update` accepts `archived` and `template` params
|
||||||
- PR #1 (batch 1) merged before starting batch 2
|
- [ ] `archived=true` requires `confirm=<repo name>`
|
||||||
- Issue #19 (mirror flow e2e test) verified manually after batch 1 is deployed
|
- [ ] `create_project_from_template` accepts `template_name` param, defaults to `template-go-web`
|
||||||
|
- [ ] `pr_files_diff` returns distinct diff per file
|
||||||
|
- [ ] All new test cases pass
|
||||||
|
- [ ] PR `fix/v02-patch` merged 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.
|
||||||
|
|||||||
121
CLAUDE.md
121
CLAUDE.md
@@ -39,6 +39,7 @@
|
|||||||
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`
|
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`
|
||||||
- Branch naming: `feat/short-description`, `fix/short-description`
|
- Branch naming: `feat/short-description`, `fix/short-description`
|
||||||
- PRs: one concern per PR, description explains *why* not *what*
|
- 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
|
### Security
|
||||||
- No secrets in code, ever — use env vars or SOPS-encrypted files
|
- No secrets in code, ever — use env vars or SOPS-encrypted files
|
||||||
@@ -76,68 +77,98 @@ When acting as a coding agent on this project:
|
|||||||
3. If unsure about a convention, check `DECISIONS.md` or ask
|
3. If unsure about a convention, check `DECISIONS.md` or ask
|
||||||
4. Never modify files outside the project root without explicit permission
|
4. Never modify files outside the project root without explicit permission
|
||||||
5. When adding a dependency, explain why in the commit message
|
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
|
6. Always work on a feature branch and open a PR — never push directly to main
|
||||||
|
7. 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)
|
## Current sprint — gitea-mcp v0.2 patch (2026-05-14)
|
||||||
|
|
||||||
### Context
|
### Context
|
||||||
This sprint implements new MCP tools needed for `hyperguild new-project` —
|
The main v0.2 batch (repo_create, repo_update, repo_mirror_push, repo_delete,
|
||||||
the automated project creation flow triggered from claude.ai. See brain knowledge
|
repo_tree, repo_topics_update, file_read dir-fix, issue_get, release_create,
|
||||||
nodes `adr-new-project-gitea-first-github-mirror` and `roadmap-github-ingestion-pipeline`
|
create_project_from_template) was implemented and pushed directly to main.
|
||||||
for full background.
|
|
||||||
|
|
||||||
### Issues to implement (priority order)
|
This sprint fixes three remaining gaps found during code review on 2026-05-14.
|
||||||
|
These are blockers for `hyperguild new-project`.
|
||||||
|
|
||||||
**Batch 1 — blockers (do first, one PR: `feat/repo-crud`)**
|
### Issues to fix (all three in one PR: `fix/v02-patch`)
|
||||||
|
|
||||||
| Issue | Tool | Gitea API |
|
#### #12 — repo_update: add `archived` and `template` fields
|
||||||
|-------|------|-----------|
|
**File:** `internal/gitea/repos.go` → `UpdateRepoArgs` struct
|
||||||
| #13 | `repo_create` | POST /api/v1/user/repos or /api/v1/orgs/{org}/repos |
|
**File:** `internal/tools/repo_update.go` → input schema + args struct
|
||||||
| #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`)**
|
Add to `UpdateRepoArgs`:
|
||||||
|
```go
|
||||||
|
Archived *bool
|
||||||
|
Template *bool
|
||||||
|
```
|
||||||
|
|
||||||
| Issue | Tool | Gitea API |
|
Add to tool input schema:
|
||||||
|-------|------|-----------|
|
```json
|
||||||
| #15 | `file_read` dir-path fix | existing endpoint, detect array vs object response |
|
"archived": {
|
||||||
| #14 | `repo_tree` | GET /api/v1/repos/{owner}/{repo}/git/trees/{sha}?recursive=true |
|
"type": "boolean",
|
||||||
| #18 | `repo_topics_update` | PUT /api/v1/repos/{owner}/{repo}/topics |
|
"description": "Mark repo as archived (read-only). Requires confirm=<repo name>."
|
||||||
|
},
|
||||||
|
"template": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Toggle template repo flag."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
**Batch 3 — can wait**
|
Add confirm-guard for `archived=true` (same pattern as `private=false`):
|
||||||
|
```go
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
| Issue | Tool | Note |
|
New test cases to add in `repo_update_test.go`:
|
||||||
|-------|------|------|
|
- `TestRepoUpdateTool_Archive` — happy path with confirm
|
||||||
| #11 | `repo_delete` | HIGH risk — needs `confirm` param == repo name |
|
- `TestRepoUpdateTool_ArchiveRequiresConfirm` — missing confirm returns error
|
||||||
| #17 | `release_create` | POST /api/v1/repos/{owner}/{repo}/releases |
|
- `TestRepoUpdateTool_SetTemplate` — no confirm needed
|
||||||
|
|
||||||
### How to add a tool (pattern)
|
#### #24 — create_project_from_template: make template selectable
|
||||||
|
**File:** `internal/tools/create_project_from_template.go`
|
||||||
|
|
||||||
Every tool = 4 files following `internal/tools/repo_get.go` exactly:
|
Add optional `template_name` param to input schema:
|
||||||
|
```json
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
1. `internal/gitea/<domain>.go` — API client method (use PostJSON/PatchJSON/DeleteJSON)
|
The tool should use `args.TemplateName` if set, fall back to the hardcoded default.
|
||||||
2. `internal/tools/repo_<name>.go` — tool handler with Descriptor() + Call()
|
Remove the hardcoded template name from `cmd/gitea-mcp/main.go` constructor call —
|
||||||
3. `internal/tools/repo_<name>_test.go` — table-driven tests with httptest.NewServer
|
the tool resolves it internally.
|
||||||
4. Registration in main — find where `NewRepoGet` is registered, add new tool same place
|
|
||||||
|
|
||||||
Key rules:
|
New test case: `TestCreateProjectFromTemplate_AgentTemplate`
|
||||||
- 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
|
#### #25 — pr_files_diff: fix same diff returned for all files
|
||||||
|
**File:** `internal/tools/pr_files_diff.go`
|
||||||
|
|
||||||
New tools require these additional Gitea token scopes:
|
There is a loop bug where all file entries in the response contain the same diff
|
||||||
- `write:repository` — repo_create, repo_update, repo_mirror_push, repo_topics_update, release_create
|
(the first file's diff is reused for every subsequent file). Find the loop and
|
||||||
- `delete_repo` — repo_delete
|
ensure each iteration reads and assigns the correct diff for its own file.
|
||||||
|
|
||||||
Check current token: `curl -H "Authorization: token $GITEA_TOKEN" https://gitea.d-ma.be/api/v1/user`
|
Reproduce: call `pr_files_diff` on any PR with 3+ files, verify each file has
|
||||||
If scopes are missing, update token in Gitea settings before running tests.
|
a distinct diff.
|
||||||
|
|
||||||
### Definition of done
|
### Definition of done
|
||||||
|
|
||||||
- `task check` passes (all tools, all batches)
|
- [ ] `task check` passes
|
||||||
- Each new tool manually callable via `claude mcp call`
|
- [ ] `repo_update` accepts `archived` and `template` params
|
||||||
- PR #1 (batch 1) merged before starting batch 2
|
- [ ] `archived=true` requires `confirm=<repo name>`
|
||||||
- Issue #19 (mirror flow e2e test) verified manually after batch 1 is deployed
|
- [ ] `create_project_from_template` accepts `template_name` param, defaults to `template-go-web`
|
||||||
|
- [ ] `pr_files_diff` returns distinct diff per file
|
||||||
|
- [ ] All new test cases pass
|
||||||
|
- [ ] PR `fix/v02-patch` merged 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.
|
||||||
|
|||||||
Reference in New Issue
Block a user