diff --git a/docs/agents/GITEA-SETUP.md b/docs/agents/GITEA-SETUP.md new file mode 100644 index 00000000..d28a4c5c --- /dev/null +++ b/docs/agents/GITEA-SETUP.md @@ -0,0 +1,230 @@ +# Runbook: standing the Gitea working surface up + +**For the human. Work top to bottom โ€” later phases depend on earlier ones.** +[`WORKFLOW-gitea.md`](WORKFLOW-gitea.md) says *what* this is and why; this says +*how*, in order, with a check after each phase. + +Steps are marked **๐Ÿ‘ค you** (a decision or a credential only you can make) or +**๐Ÿค– me** (I do it once you have unblocked it). + +## Where things stand + +* โœ… `main` carries the play-tested port work and the rewritten briefs (`cd3a81af`). +* โœ… The briefs already describe this workflow. **They describe tooling that does + not exist yet** โ€” which is why the agents are stopped and must stay stopped + until Phase 7. +* โŒ Nothing exists on the instance: no agent users, no API tokens, no labels, no + branch protection, no MCP. + +โš ๏ธ **Do not start an agent before Phase 7.** Its brief will tell it to read +notifications and open issues, and it will have no tool that can. + +--- + +## Phase 1 ยท Identities ๐Ÿ‘ค + +The agents currently push as `fabi`, using your credential. That is the defect +this phase fixes, and it is not cosmetic: **Gitea does not let the author of a +pull request approve it.** While an agent *is* you, either you cannot approve its +PR or it can approve its own โ€” and there is no third possibility. The review gate +does not exist until the agents are distinct people. + +Two more reasons, once you are there anyway: 495 commits of decoder work are +currently attributed to **your** email, so blame is wrong; and separate +identities mean revoking one agent does not touch the other or you. + +**1.1 โ€” Create two users.** Site Administration โ†’ Identity & Access โ†’ User +Accounts โ†’ *Create User Account*. + +| | | +|---|---| +| usernames | `sylph-decoder`, `sylph-port` | +| email | anything you control and can tell apart โ€” `you+decoder@โ€ฆ`, `you+port@โ€ฆ` | +| "require password change on first login" | **off** โ€” they never log in interactively | + +**1.2 โ€” Add both to `fabi/Sylpheed` as collaborators.** Repo โ†’ Settings โ†’ +Collaborators โ†’ add each โ†’ permission **Write**. + +๐Ÿ”ด **Write, not Admin.** Admin can edit branch protection, which would let an +agent remove the rule that stops it merging. + +> **Check:** the repo's Collaborators list shows both, each reading `Write`. + +--- + +## Phase 2 ยท Branch protection ๐Ÿ‘ค + +**Do this before the agents hold tokens**, so there is no window in which they +can push to `main`. + +Repo โ†’ Settings โ†’ Branches โ†’ *Protected Branches* โ†’ add rule for `main`: + +| setting | value | why | +|---|---|---| +| Enable Push | **off** | nothing reaches `main` except through a PR | +| Require approvals | **1** | the human gate, made native | +| Dismiss stale approvals | **on** | an approval must describe the code that merges | +| Block merge on rejected reviews | **on** | "changes requested" has to mean something | + +> ### Check โ€” and actually run it, do not assume it +> +> The whole point of putting this in protection rather than in a document is +> that it does not depend on anyone's good behaviour. So verify it the same way: +> +> 1. As `sylph-port`, push a throwaway branch and open a PR into `main`. +> 2. Confirm **no Merge button** is offered to that account. +> 3. Confirm **you** can approve it, and that *it* cannot approve itself. +> 4. Close the PR, delete the branch. +> +> If step 2 offers a Merge button, stop โ€” the rest of this runbook assumes it +> does not. + +--- + +## Phase 3 ยท Tokens ๐Ÿ‘ค + +Three principals, three tokens. Settings โ†’ Applications โ†’ *Generate New Token* +while logged in **as that user**. + +| whose | scopes | goes in | +|---|---|---| +| **you** (`fabi`) | `write:issue`, `read:repository` | `~/.sylph-gitea-api-token` | +| `sylph-decoder` | `write:repository`, `write:issue`, `write:notification`, `read:user` | `~/.sylph-gitea-token-decoder` | +| `sylph-port` | same four | `~/.sylph-gitea-token-port` | + +```bash +printf '%s\n' '' > ~/.sylph-gitea-api-token && chmod 600 ~/.sylph-gitea-api-token +``` + +โš ๏ธ **Never paste a token into chat.** The files are mounted read-only into the +containers, exactly like `~/.sylph-claude-token`. + +๐Ÿ“Œ The existing `~/.sylph-git-credentials` is scoped `write:repository` and is +**refused by every issue endpoint** โ€” verified, not assumed: +`required=[read:issue], token scope=write:repository`. It stays as it is; these +are additional. + +> **Check:** `tools/gitea-setup --dry-run` prints "would create โ€ฆ" rather than a +> scope error. + +--- + +## Phase 4 ยท Labels and bundles ๐Ÿค– + +```bash +tools/gitea-setup --dry-run # read it first +tools/gitea-setup # idempotent; safe to re-run +``` + +Creates 12 labels (the `state/*` set, `agent/*`, `kind/*`) and 4 milestones +(Menus, Title screen, Graphics pipeline, Infrastructure). + +**No Kanban board yet, on purpose.** Gitea's board does not follow labels, so it +would be a second copy of the state to keep in sync by hand โ€” which is the exact +failure that produced a 1,227-line `BLOCKED.md`. **Labels are the truth**; a +saved issue filter gives the same view for nothing. Add a board later if the +filter turns out to be insufficient. + +> **Check:** the Issues page offers the `state/*` labels, and Milestones lists +> the four bundles. + +--- + +## Phase 5 ยท The MCP server ๐Ÿค– + +`gitea-mcp` **v1.7.0** โ€” `gitea-mcp_Linux_x86_64.tar.gz` from +`https://gitea.com/gitea/gitea-mcp/releases`. Confirmed flags: `-t stdio`, +`-H `, token via `GITEA_ACCESS_TOKEN`. + +Three edits per image, which I make: + +1. **`Dockerfile`** โ€” fetch and unpack the release binary to `/usr/local/bin`, + pinned to v1.7.0 with a checksum. +2. **`entrypoint.sh`** โ€” register it for that agent's own identity: + ```bash + claude mcp add -s user gitea -e "GITEA_ACCESS_TOKEN=$(cat "$GITEA_TOKEN_FILE")" \ + -- gitea-mcp -t stdio -H https://git.mc02.dev + ``` + User scope, not a committed `.mcp.json` โ€” the token differs per agent and none + of it belongs in git. +3. **`sylph-decoder` / `sylph-port`** โ€” mount the matching token file read-only. + +Then rebuild both images. โš ๏ธ `CARGO_BUILD_JOBS=4` and limited `-j`; a +full-parallel build has OOM-crashed this box. + +๐Ÿ“Œ **Worth trying, unverified:** the server takes `--tools` / `GITEA_TOOLS` to +filter which tools it exposes. If a merge tool can be excluded by name, that is +defence in depth behind Phase 2 โ€” belt *and* braces. I have not confirmed the +tool names, so this is an experiment at install time, **not** a substitute for +branch protection. + +> **Check:** in each container, `claude mcp list` shows `gitea` connected, and a +> read call returns this repo's labels. + +--- + +## Phase 6 ยท Seed the first items ๐Ÿค– + ๐Ÿ‘ค + +I migrate the live findings into issues โ€” **not** the 1,227 historical lines, +only what is actually open: + +| bundle | items | +|---|---| +| **Title screen** | F5 (does โ’ถ snap or accelerate?), F6 (`ptloop01/02` sweep onset), re-propose the F5/F6 work left off `main` | +| **Menus** | F1 (held-direction repeat rate โ€” Decoder measures, Port implements), F2 (SFX mix too loud), F3 (missing title audio), re-propose the OPTIONS menu work | + +Each gets a bundle, an owner label, a dependency edge where one waits on the +other, and โ€” for anything already written on the port branch โ€” a note that the +code exists and needs re-proposing as a reviewable PR, not rewriting. + +**๐Ÿ‘ค Your part:** approve the *shape* of each (`state/proposed` โ†’ +`state/approved`). This is the cheap gate โ€” before effort, not after. + +--- + +## Phase 7 ยท Restart, and verify the loop ๐Ÿค– + ๐Ÿ‘ค + +```bash +docker/decoder/sylph-decoder +docker/port/sylph-port +``` + +> ### Check โ€” the three things that must be true +> +> 1. Each agent's **first iteration reads its notifications.** If it does not, +> nothing addressed to it will ever arrive: **notifications are polled, and +> nothing pushes.** +> 2. Each opens a **pull request**, not a bare branch push, and labels its issue +> `state/needs-human` with a one-line "look at this". +> 3. Neither can merge. (Already proven in Phase 2; confirm it holds for a real +> PR.) + +--- + +## Still to build ๐Ÿค– + +Not blockers for Phase 7, but the workflow is not finished without them: + +* **`propose-work`**, superseding `push-work` โ€” push the branch *and* open the PR + with `Closes #N` *and* set the label, in one step. Today `push-work` does the + first third; the other two thirds being manual is how they get skipped. Its + existing refusals stay: no `main`, no force-push. +* **an attachment uploader** โ€” the MCP exposes `attachment_read` only, so putting + a screenshot on an issue needs a direct `POST /repos/{owner}/{repo}/issues/{index}/assets`. +* **`gitea-verify`** โ€” asserts protection is still on and the agents are still + Write-not-Admin. Phase 2 is checked once; this checks it every day. +* **wiki landing page** โ€” bundles in flight and what each agent is on. There is + currently no view of what is happening except container logs. + +## What I have not verified + +Said plainly, because a runbook that hides its soft spots is worse than one that +does not: + +* **that Gitea hides Approve from a PR's own author.** Widely true; Phase 2's + check tests it directly rather than trusting me. +* **the `--tools` filter names** (Phase 5) โ€” an experiment, not a control. +* **Gitea's Projects API**, which is why Phase 4 creates no board. +* **the exact Gitea version** โ€” the API was unreachable from my sandbox on the + last three attempts. Every screen named here has been stable for many + releases, but if a menu is not where I say it is, that is why. diff --git a/docs/agents/WORKFLOW-gitea.md b/docs/agents/WORKFLOW-gitea.md index e645999c..e0ae0911 100644 --- a/docs/agents/WORKFLOW-gitea.md +++ b/docs/agents/WORKFLOW-gitea.md @@ -4,6 +4,10 @@ person directs this project, and replaces `BLOCKED.md` as the way agents track what is open. +๐Ÿ“Œ This page is the **what and why**. The ordered **how** โ€” users, branch +protection, tokens, MCP, and the check after each step โ€” is +[`GITEA-SETUP.md`](GITEA-SETUP.md). + ## Why not a new tool We looked. The market has converged on **removing the human from the loop** โ€”