From 4ca8e1f550fb9720c566e1b012fdee8422b730e5 Mon Sep 17 00:00:00 2001 From: Don Garrett Date: Fri, 2 Oct 2026 18:52:18 +0000 Subject: [PATCH] Drop Vikunja: Gitea issues are the one tracker for every agent Ops work lives in one infrastructure repository for both sites, with site labels; intake, labels and dependencies work as for nisse-dev, and agent-to-agent requests are cross-repo issues. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE --- docs/Architecture.md | 66 ++++++++++++++++++++++------------------ docs/Development-Plan.md | 4 +-- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/docs/Architecture.md b/docs/Architecture.md index 3b8d743..5aaea3d 100644 --- a/docs/Architecture.md +++ b/docs/Architecture.md @@ -138,15 +138,16 @@ Everything in this part is used by every agent. | **Scope** | What a work item operates on; context that outlives it | A repository | A site and service | - **Sources of work items:** duties, the operator (always), and other agents. A - request from another agent arrives through the receiving agent's normal intake - and carries no authority of its own: the receiver applies its own rules. + request from another agent is an issue assigned to the receiving agent, and + carries no authority of its own: the receiver applies its own rules. - **A duty run is read-only;** a finding that needs attention becomes a work item, deduplicated by a stable fingerprint so a repeat attaches to the open item. - **A work item is the unit of state:** its conversation, proposals, pending questions, pinned roles (L9) and transcript (L7). Its locally minted ID is also its correlation ID in logs. -- **An external record is linked when there is one** (a Gitea issue, a Vikunja - ticket); external truth wins on divergence (L8). +- **One tracker: Gitea issues,** for every agent. An issue assigned to an agent is + a work item for it, and the issue is the item's record (D1, O5). External truth + wins on divergence (L8). - **Work items don't nest:** a milestone is a phase of one; a delegation is an episode in one. @@ -159,10 +160,11 @@ Everything in this part is used by every agent. | **waiting on the operator** | an answer, a go-ahead, a review or a merge | | **blocked** | a recorded dependency to close | -- **Blocked comes from external truth:** a Gitea issue dependency, or another - agent's ticket. It becomes ready only when the dependency actually closes (P6); - the operator can remove the dependency. An agent that finds a blocker mid-work - proposes recording it, and records it only with the operator's agreement. +- **Blocked comes from external truth:** a Gitea issue dependency, including on an + issue in another repository, such as a request to another agent. It becomes + ready only when the dependency actually closes (P6); the operator can remove the + dependency. An agent that finds a blocker mid-work proposes recording it, and + records it only with the operator's agreement. **One active work item per agent; the rest are parked.** - **Switching happens only at safe points:** the active item is waiting, blocked or @@ -226,8 +228,8 @@ agreement: a restatement awaiting a go-ahead (D1), a design (D2), a step sequenc model's description (L11). - **Approvals expire** where the world can change underneath them (O2). -**Approval sources:** Matrix (L5), Gitea comments (D1) and Vikunja comments (O5), -each checked against its own operator allowlist. The first valid approval wins and +**Approval sources:** Matrix (L5) and Gitea comments (D1, O5), each checked +against its own operator allowlist. The first valid approval wins and is echoed to the other channels. The knowledge vault is never one (L10). **The trust dial:** how much the operator reviews after the fact, set by the @@ -293,8 +295,8 @@ verified and left open); it says what happened to a message it can't act on yet, rather than refusing; progress is prose at a readable rate, with raw tool activity on request; and it asks when unsure, including mid-implementation. -**Other channels:** Gitea and Vikunja carry work and records, read as structured -JSON (never through a chat bridge). Comments from allowlisted operators are +**Gitea carries work and records,** read as structured JSON (never through a chat +bridge). Comments from allowlisted operators are instructions or approvals; anything else is data (L11). **Outages delay, never fail.** Intake retries indefinitely with capped backoff and @@ -457,7 +459,7 @@ browses it in Obsidian. receive-only on it. So conflicts can't arise. - **Never an instruction or approval channel.** Work is never read out of the vault, and no agent writes there to make another act; agents coordinate through the - operator, Matrix or tickets (L1). The operator points to a note in conversation + operator, Matrix or issues (L1). The operator points to a note in conversation when it is input (L5). - **Corrections go through conversation** (L6). Break-glass: stop the agent, edit on the host, restart. @@ -710,13 +712,14 @@ see it or only harness operations use it (the push key). Anything the model's commands can see must be scoped for testing, never production. **Provisioning:** build VMs come from a template via Terraform; eventually at -`nisse-dev`'s request to `nisse-ops` (O5), until then by the operator. +`nisse-dev`'s request to `nisse-ops` (an issue in the infrastructure repository, +O5), until then by the operator. --- ## Part O — `nisse-ops` -Operates infrastructure across both sites, driven by tickets and duties, with +Operates infrastructure across both sites, driven by issues and duties, with stricter controls because live changes have no review step before they take effect. ### O1. How it differs @@ -727,7 +730,7 @@ stricter controls because live changes have no review step before they take effe | Scope | the assigned issue and its conversation | approved step sequences (O2) | | Class 3 | discuss | discuss, and exact-step approval | | Work shape | milestones → PRs | short reactive tasks → live changes | -| Intake | Gitea issues, Matrix | Vikunja tickets, alerts, duties, Matrix | +| Intake | issues in the project's repository, Matrix | issues in the infrastructure repository, alerts, duties, Matrix | | Reach | sealed build VMs | Tailscale, credentials, both sites | They are separate deployments over one library; one instance playing both would @@ -766,8 +769,8 @@ template with a trigger, rate limit and expiry, for a routine fix). | Class | Examples | |---|---| -| 1 | Metrics, logs, status, read-only MCP calls, tickets, the world model | -| 2 (in scope) | Approved steps with a known undo; its own world model and tickets | +| 1 | Metrics, logs, status, read-only MCP calls, issues, the world model | +| 2 (in scope) | Approved steps with a known undo; its own world model; commenting on and filing issues in the infrastructure repository | | 3 | Every other infrastructure write; browser actions on admin UIs (each confirmed); **anything on network gear**, the most conservative case, since a bad change can sever the path to fix it | ### O4. Interfaces @@ -778,15 +781,20 @@ template with a trigger, rate limit and expiry, for a routine fix). - **Event intake** as structured JSON (directly or via Alertmanager); curated updates go to `#ops`. -### O5. Tickets and duties +### O5. Issues and duties -- **A Vikunja ticket is a work item's record;** Matrix is the live conversation. - Flow: filed → picked up → discussed → status updates → closed with the result. -- **Tickets that trigger action are operator-scoped.** Tickets from duties (findings) - and from other agents' requests (L1, e.g. `nisse-dev` asking for a build VM) may - be picked up and planned, but any write needs a step sequence the operator - approves. Until standing approvals exist, that means every provisioning request. -- **Vikunja comments approve plans on their own ticket** (`approve rev-N`). +- **One infrastructure repository for both sites,** holding ops' issues (it need + hold no code). Sites are labels (`garrett-hall`, `hartman-hut`), so cross-site + work is one issue. Intake works as in D1: an issue assigned to the ops agent is a + work item and its record, labels steer, and Gitea dependencies mark it blocked. + Matrix is the live conversation. +- **Action is operator-scoped.** Issues from duties (findings, opened by ops itself + and deduplicated by fingerprint) and requests from other agents (L1, e.g. + `nisse-dev` asking for a build VM, which then waits blocked on that issue) may be + picked up and planned, but any write needs a step sequence the operator approves + (O2). Until standing approvals exist, that means every provisioning request. +- **Comments on the issue approve its plan** (`approve rev-N`), as an alternative to + Matrix (L3). ### O6. Deployment @@ -855,7 +863,7 @@ so every upstream action traces to one agent. ### X5. Supporting services All self-hosted: Matrix (Synapse), Gitea, LiteLLM, the local inference host, -Vikunja, Vaultwarden, LLDAP with Authelia, and Syncthing for the operator's copy of +Vaultwarden, LLDAP with Authelia, and Syncthing for the operator's copy of the vault. Each agent has its own account, token and room in each; nothing is shared between agents. @@ -872,8 +880,8 @@ shared between agents. - **More than one active work item:** needs per-item serialisation, an inference scheduler and per-item intents. Build VMs and threads already separate workspaces and conversations. -- **Whether pure conversations need an external record** (dev work on a repository - and ops tickets already have one). +- **Whether pure conversations need an external record** (work on a repository + already has its issue). - **Stacked PRs:** starting a milestone before the previous one merges, after experience with waiting (D4). - **Build VM collection:** how long idle, and whether it needs the operator's word. diff --git a/docs/Development-Plan.md b/docs/Development-Plan.md index 3a6b4ea..e104578 100644 --- a/docs/Development-Plan.md +++ b/docs/Development-Plan.md @@ -321,8 +321,8 @@ if the implementation differs. on the operator defaults to 10 minutes. When the driver chooses the next ready item and the choice fails or is invalid, fall back to the oldest. - **L3 revision stamping:** in Matrix, a reply is stamped with the revision whose - message had been sent when it arrived; on a Gitea issue or a Vikunja ticket, - with the latest proposal comment older than the reply. + message had been sent when it arrived; on a Gitea issue, with the latest + proposal comment older than the reply. - **L5 transport:** the `Transport` interface is send, ask and receive. Intake backoff is exponential, capped at a few minutes. - **L6 fitting order:** first shorten old tool results to their first and last