# The working surface: Gitea issues, pull requests, and where things live **Set by the human, 2026-09-04.** Replaces chat and Remote Control as the way a 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** β€” `agent-kanban`'s own tagline is *"Take human out of the loop"* β€” and this project is built entirely around a human gate. Meanwhile every candidate adds a second store of truth to keep in sync with git, and **documents drifting out of sync is this project's defining failure mode**: a 1,227-line `BLOCKED.md` whose anti-staleness convention was constant by construction, 41 % of citations not resolving, 21 inter-agent messages sent into a void with no delivery feedback. Gitea is already deployed, already holds the code, and its first-party MCP server (`gitea/gitea-mcp` v1.7.0) exposes issues, labels, milestones, pull requests, attachments and notifications. So: **no new store.** ## The four surfaces, and what belongs in each | surface | holds | why not somewhere else | |---|---|---| | **Issues** | work items, asks between agents, defects | durable, stateful, owned, and **dependency edges close themselves** when the blocking issue closes β€” the thing prose could never do | | **Pull requests** | every change to `main` | the human gate becomes **native** instead of a label convention | | **Git (`docs/`)** | RE findings, decisions, evidence | a finding must be versioned **with the code that consumes it** | | **Wiki** | orientation for a person: runbook, navigation, container notes | browsable and branch-independent, but **unreviewed** β€” see below | ### Issues = bundles and items Milestones are **bundles** (the human defines them). Issues are **items** (agents propose, the human approves). Labels carry the state: ``` state/proposed β†’ state/approved β†’ state/in-progress β†’ state/needs-human β†’ closed β†˜ state/blocked ``` `state/needs-human` is the one the whole model turns on, and the one no off-the-shelf tool models. Its issue body must say **what to look at** and **what pass and fail look like** β€” a person should be able to judge it in under a minute without reading anything else. ⚠️ **`state/blocked` uses Gitea's dependency edges, not prose.** *"The Port is blocked on the Decoder answering X"* becomes a queryable link that resolves itself. That is the single highest-value change here after PRs. ### Pull requests = how work reaches `main` **Adopted 2026-09-04, the human's proposal, and it is a bigger improvement than it looks.** Today agents commit to long-lived `auto/*` branches that a human merges by hand β€” and those branches have drifted **280 and 373 commits** apart, which is unreviewable by construction. One PR per item, closing its issue: * the review surface is a **diff in a browser**, not a human reading commits in a terminal; * `Closes #123` binds the change to the item, so "what did this fix" stops being archaeology; * **PRs enforce the sizing rule.** An item too big to review in one sitting was too big to be an item. The discipline stops depending on an agent's judgement. πŸ”΄ **Agents must not merge their own pull requests.** The MCP's `pull_request_write` includes `merge` and the tool cannot be split, so this cannot be left to instruction β€” it goes in **branch protection on `main`**. Same principle that fixed the build-jobs cap: policy belongs where the agent cannot reach it, not in a document asking it not to. ⚠️ **"Requiring review" is not the rule that does it.** Gitea stops an author approving their own pull request; it does not stop *the other agent* approving it, and it never blocked merging in the first place β€” `Enable Push: off` blocks pushes. The rule that holds is the pair of whitelists: **approvals whitelisted to the human**, so an agent's approval does not count, and **merges whitelisted to the human**, so an approved PR is still merged by a person. See [`GITEA-SETUP.md`](GITEA-SETUP.md) Phase 2. ### πŸ”΄ The wiki is NOT for the RE corpus The human suggested it for RE findings. **Half right, and the wrong half is worth saying plainly**, because it would undo two things we paid for: 1. **A finding's value is that it sits next to its evidence, versioned with the code that consumes it.** *"Decoded, with a disc-wide check"* is backed by a test in this repository. A wiki is a **separate git repo**, so a decode correction and the exporter change that depends on it could never be one atomic commit, or one reviewable PR. 2. **Wiki edits bypass review.** The `REFUTED.md` R1 reclassification changed the file both agents read to decide what *not* to try. It was a reviewed commit with a stated rationale. As a wiki edit it would have been an unreviewed mutation of shared ground truth by whoever typed last. So the corpus stays in `docs/`, reached through PRs. **What the wiki IS good for** β€” human-facing orientation that is not evidence and should not be branch-dependent: * the runbook (`docs/port/RUNNING.md`'s content β€” how to actually play the port) * `docs/game/navigation.md` β€” how the game is navigated, written for a person * container notes, credentials setup, the things a human reads once * a landing page: current bundles, what each agent is on, links into git That last one addresses a real gap: **there is no view of what is happening** except container logs and multi-megabyte transcripts. ### Where files go β€” three needs, three homes Currently everything transient goes to `/exchange`, and a human cannot browse it at all. | the file is | goes to | |---|---| | agent β†’ agent, transient, no human involved | **`/exchange`** via `share`, unchanged β€” it records sender, time, commit and dirty-tree | | **evidence a human must look at** (a screenshot, a film, a capture behind a `state/needs-human` item) | **attached to the issue** it is evidence for | | evidence a finding cites | **git**, beside the finding. It is the proof | Attaching to the issue is strictly better than both alternatives for the middle case: it travels with the item, a person sees it in the browser, and it cannot be orphaned from the claim it supports. ⚠️ The MCP exposes `attachment_read` only β€” **uploading needs a direct REST call** (`POST /repos/{owner}/{repo}/issues/{index}/assets`). Worth a small helper rather than each agent re-deriving it. ### Notifications = the wake-up, with delivery you can inspect `notification_read` / `notification_write` replace the message channel that lost **21 consecutive messages to a stale session ID with no error of any kind**. An `@mention` on an issue is durable, addressed by *name*, and has a read state a supervisor can inspect. The old rule still stands and gets easier: **the message carries a pointer β€” now an issue number β€” and the repository holds what was found.** ## What does not change * Findings are still classified **decoded / measured / undecodable**. * An agent still cannot verify its way out of its own role. * `REFUTED.md` is still the file to grep before proposing anything, and entries still name their `⟨instrument⟩`. * The oracle is still the real game in Xenia Canary.