Syncs Kiro specs to Gitea milestones + one issue per phase, and buglog.json entries to Gitea issues. Idempotent (safe to re-run). Validated against nexa/xce: admin-config-tool spec + 14 bugs synced.
7.4 KiB
name: gitea-sync description: Sync cc-sdd specs and OpenWolf buglog to Gitea milestones/issues in nexa/xce argument-hint: [--dry-run] [--spec ] [--bugs] [--since ] triggers:
- /gitea-sync
- sync to gitea
- gitea sync
- synchronize specs to gitea
Gitea Sync Skill
Sync cc-sdd specs (.kiro/specs/) and OpenWolf buglog (.wolf/buglog.json) to
Gitea issues in nexa/xce. Files are ground truth — Gitea is a read-only mirror.
Sync state (issue numbers) is stored in source files for idempotency.
Invocation
/gitea-sync # sync all specs + all bugs
/gitea-sync --spec admin-config-tool # sync one spec
/gitea-sync --bugs --since 2026-07-18 # sync recent bugs only
/gitea-sync --dry-run # preview without making changes
Procedure
0. Parse arguments
--dry-run: only report what would change, don't call MCP write tools--spec <name>: sync only one spec directory--bugs: sync bugs only (skip specs)--since <YYYY-MM-DD>: only sync bugs withlast_seen >=this date
1. Ensure labels exist
These labels must exist in nexa/xce. Use mcp__gitea__label_read to list
existing labels, then mcp__gitea__label_write with method create_repo_label
for any missing ones:
| Name | Color | Description |
|---|---|---|
phase:requirements |
6C5CE7 |
Spec requirements phase |
phase:design |
6C5CE7 |
Spec design phase |
phase:tasks |
6C5CE7 |
Spec tasks phase |
phase:implementation |
F39C12 |
Spec implementation phase |
phase:complete |
27AE60 |
Spec complete |
spec |
3498DB |
Spec-tracked issue |
bug |
E74C3C |
Bug-tracked issue |
bug:fixed |
27AE60 |
Bug resolved |
blocked |
E74C3C |
Blocked on dependency |
2. Sync Specs
For each spec directory in .kiro/specs/ (or just --spec <name>):
-
Read
spec.json. If it hasgitea.milestone_idandgitea.issueswith all three keys (requirements_design,implementation,validation), skip creation — the spec is already synced. Check phase states and update issue open/closed state if needed (step 2d). -
If not synced: a. Create milestone: Use
mcp__gitea__milestone_writemethodcreate. Title = spec name. Description = one-line summary + phase + blockers. b. Create three phase issues under that milestone viamcp__gitea__issue_writemethodcreate:Key Title Labels Initial State requirements_design[{spec}] Requirements & Designspec, phase:requirements, phase:design closed if both approved, else open implementation[{spec}] Implementationspec, phase:implementation open validation[{spec}] Validation & Closurespec, phase:complete open Body format for each issue (build from spec files):
Requirements & Design body: Phase status, requirements summary table (extract
## Requirements Summaryfromrequirements.md), blockers list, link to spec files.Implementation body: Tasks generated/ready status, task checklist (extract
- [ ]/- [x]fromtasks.mdif it exists), blockers list.Validation body: Acceptance gate checklist, deferred future-spec items.
c. Write sync state back to
spec.json:"gitea": { "milestone_id": <id>, "issues": { "requirements_design": <number>, "implementation": <number>, "validation": <number> } }d. Phase state updates (for already-synced specs): Check
spec.jsonapprovals. If requirements AND design are approved → close the requirements_design issue viamcp__gitea__issue_writemethodupdatewithstate: "closed". If implementation approved → close implementation and validation issues. If all approved → close milestone viamcp__gitea__milestone_writemethodupdate.
3. Sync Bugs
Read .wolf/buglog.json. For each entry:
-
Skip if:
- Entry has
gitea_issuefield (already synced) AND bug was already fixed when synced (no state change needed). - Filter: if
--since <date>provided, skip entries withlast_seen < <date>.
- Entry has
-
Create issue for entries without
gitea_issue: Usemcp__gitea__issue_writemethodcreate.Title:
[<bug-id>] <first sentence of error_message>(max 120 chars)Body:
## Error <error_message> ## Root Cause <root_cause> ## Fix <fix> (or "*Not yet fixed*" if empty) ## Affected Files - <file> (split on commas) ## Tags `tag1` `tag2` ... ## Related Bugs - <related> --- *Synced from `.wolf/buglog.json`*Labels: Start with
["bug"]. Iffixis populated, addbug:fixed. Map known tags to labels:asan/ubsan→ createbug:asanlabel,SEGV/double-free/UAF→bug:crash,race/toctou→bug:race,ha/raft/election/failover→bug:ha,data-loss→bug:data-loss.State:
"closed"iffixis populated,"open"otherwise.Milestone: None (bugs span specs).
-
Close fixed bugs: For entries WITH
gitea_issuewherefixis now populated (was empty before — we track by checking if the Gitea issue is still open). Usemcp__gitea__issue_writemethodupdatewithstate: "closed". -
Write
gitea_issueback to the buglog entry: add"gitea_issue": <issue_number>to the entry in.wolf/buglog.json. Read the full file, modify the matching entry, write back withjson.dumps(data, indent=2).
4. Report
Print summary: "Specs: N synced, M skipped | Bugs: X created, Y closed, Z skipped"
Important Rules
- Files are ground truth. Never read Gitea state to update local files. The gitea_issue/milestone_id fields in local files only store sync mappings.
- Idempotent. Items with existing
gitea_issueorgiteastate are skipped unless their phase/fix state changed. - Labels: Check existing labels before creating. Use label IDs (not names)
in issue create calls — fetch with
mcp__gitea__label_readfirst. - Rate limiting: Batch issue creation — create issues sequentially (a few per turn) to stay within API limits.
- Buglog is large (~13K lines). Always use
--sincefilter for practical runs (e.g.,--since 2026-07-18). Without--since, sync ALL bugs. - Private repo:
nexa/xceis private. MCP auth must have access.
Gitea MCP Tool Reference
| Action | Tool | Method |
|---|---|---|
| List labels | mcp__gitea__label_read |
list_repo_labels |
| Create label | mcp__gitea__label_write |
create_repo_label |
| List milestones | mcp__gitea__milestone_read |
list |
| Create milestone | mcp__gitea__milestone_write |
create |
| List issues | mcp__gitea__issue_read |
get (single) or use list |
| Create issue | mcp__gitea__issue_write |
create |
| Update issue | mcp__gitea__issue_write |
update |
For listing issues by milestone, use mcp__gitea__issue_read with method: "get"
and state: "all". The Gitea MCP may have limited filtering — for bulk listing,
check the milestone's open_issues/closed_issues counters.
Note: issue state: "closed" may not work on create — if the issue is created
as "open", immediately update it with method: "update" + state: "closed".