{"id":"uppidi-fleet","repo":"xpufx/paseo","url":"https://github.com/xpufx/paseo/tree/main/plugins/uppidi-fleet","package":"@xpufx/paseo-uppidi-fleet","npm":{"package":"@xpufx/paseo-uppidi-fleet","version":"0.1.0","integrity":"sha512-QlY+IL7dBZNxJ8nUuObzfIdDcGQtTV0dnUZ8caD7Mqxc5+ZYWarHcmUW7eM51JLcgwaGe5Th+bEFJWAEVJT4Qw==","publishedAt":"2026-09-26T02:07:05.045Z","downloadsLast30Days":0},"name":"uppidi-fleet","description":"Full-lifecycle autonomous engineering fleet for Paseo","categories":["automation","monitoring","productivity","orchestration","git"],"platforms":[],"caveats":["WIP progress. Many moving parts."],"images":["https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-wide.jpg","https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-agents-fleet.jpg","https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-work-queue.jpg","https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-nextgen.jpg","https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-settings.jpg"],"themes":[],"health":{"manifestValid":true,"hasReadme":true,"hasLicense":true,"hasTests":true,"hasTypecheckScript":true,"updatedRecently":true},"scannedAt":"2026-09-26T16:47:21.269Z","addedAt":"2026-09-26T16:43:34Z","npmSecurity":{"status":"passed","blockingFindings":0,"advisoryFindings":0,"scannedAt":"2026-09-26T16:46:47.259Z","version":"0.1.0","integrity":"sha512-QlY+IL7dBZNxJ8nUuObzfIdDcGQtTV0dnUZ8caD7Mqxc5+ZYWarHcmUW7eM51JLcgwaGe5Th+bEFJWAEVJT4Qw=="},"path":"plugins/uppidi-fleet","version":"0.1.0","security":{"status":"passed","blockingFindings":0,"advisoryFindings":0,"scannedAt":"2026-09-26T16:46:47.259Z","commit":"e0c1e6c74dfd0e59e6fdbeed62479643a4fc71c1"},"license":"MIT","paseoVersionRequirement":">=0.8.0","descriptionNodes":[{"type":"text","text":"Full-lifecycle autonomous engineering fleet for Paseo"}],"caveatNodes":[[{"type":"text","text":"WIP progress. Many moving parts."}]],"manifest":{"id":"uppidi-fleet","requirements":{"paseo":">=0.8.0"}},"repoMeta":{"stars":2,"defaultBranch":"main","pushedAt":"2026-09-26T10:20:09Z"},"owner":{"login":"xpufx","avatarUrl":"https://avatars.githubusercontent.com/u/25581961?v=4"},"readmeText":"# Uppidi Fleet\n\n**An opinionated, full-lifecycle autonomous engineering fleet for Paseo, driven by a Forgejo/Gitea-family board.**\n\n`uppidi-fleet` turns a Forgejo issue tracker into the control plane for a small\nfleet of AI agents. A human operator files and steers tickets on the board; a\n**Front Desk** agent talks to the operator; one **orchestrator** per repository\ntriages, decomposes, and dispatches; ephemeral **coding workers** implement;\nand a **Cockpit** surface inside Paseo shows the whole thing — queues, agents,\nboards, and router health — in one place.\n\n> [!IMPORTANT]\n> **Uppidi Fleet is a work in progress.** It requires manual install of some\n> components and occasional intervention by humans. All features may not work\n> 100% reliably.\n\n| Uppidi Fleet Cockpit |\n| :---: |\n| <a href=\"https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-wide.jpg\"><img src=\"https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-wide.jpg\" alt=\"Uppidi Fleet Cockpit — the full surface: agent tree, board, queues and router health\" width=\"100%\" /></a> |\n\n| Agents & Fleet | Work Queue | Next-gen Cockpit | Settings |\n| :---: | :---: | :---: | :---: |\n| <a href=\"https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-agents-fleet.jpg\"><img src=\"https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-agents-fleet.jpg\" alt=\"Agents & Fleet — the hierarchical agent tree with deterministic state badges\" width=\"100%\" /></a> | <a href=\"https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-work-queue.jpg\"><img src=\"https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-work-queue.jpg\" alt=\"Work Queue — open issues, Fleet Needs Attention board and filter presets\" width=\"100%\" /></a> | <a href=\"https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-nextgen.jpg\"><img src=\"https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-nextgen.jpg\" alt=\"Next-gen Cockpit — the redesigned fleet surface\" width=\"100%\" /></a> | <a href=\"https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-settings.jpg\"><img src=\"https://raw.githubusercontent.com/xpufx/paseo/main/plugins/uppidi-fleet/screenshots/uppidi-fleet-settings.jpg\" alt=\"Settings — hook service control, listen host and port\" width=\"100%\" /></a> |\n\nThis README is written for a **third party** who has never used the system and\nwants to stand one up for their own forge, repositories, models, and team\nrules. It explains the architecture, how the skills work and how to rewrite\nthem, how the bundled webhook router receives Forgejo events, how to set up the\nwebhooks and action workflows, how to seed the board labels, and — importantly —\nwhich pieces you must supply because the plugin does not ship them ([§10](#10-gap-analysis--what-the-plugin-does-not-ship)).\n\n> **Placeholders everywhere.** Hosts, repos, paths, agent identities, and model\n> names below are examples (`forge.example.com`, `your-org/your-repo`). Replace\n> them with your own. Everything here is generic; nothing is a supported\n> configuration.\n\n---\n\n## Table of contents\n\n1. [The concept in one picture](#1-the-concept-in-one-picture)\n2. [Prerequisites](#2-prerequisites)\n3. [Install the plugin](#3-install-the-plugin)\n4. [The Cockpit surface](#4-the-cockpit-surface)\n5. [Board labels: taxonomy and install](#5-board-labels-taxonomy-and-install)\n6. [Skills: how the fleet thinks](#6-skills-how-the-fleet-thinks)\n7. [The webhook router (backend daemon)](#7-the-webhook-router-backend-daemon)\n8. [Configuring webhooks on the Forgejo side](#8-configuring-webhooks-on-the-forgejo-side)\n9. [Forgejo Actions & automated board hygiene](#9-forgejo-actions--automated-board-hygiene)\n10. [Gap analysis — what the plugin does not ship](#10-gap-analysis--what-the-plugin-does-not-ship)\n11. [End-to-end walkthrough](#11-end-to-end-walkthrough)\n12. [Runtime state & file map](#12-runtime-state--file-map)\n13. [Development](#13-development)\n14. [License](#14-license)\n\n---\n\n## 1. The concept in one picture\n\n```\n  Forgejo board (source of truth)\n  ┌───────────────────────────────────────────────────────────────┐\n  │ issues · PRs · comments · scoped labels                       │\n  │   state/  priority/  attention/  spec/  target/  verify/      │\n  └───────────────────────────────┬───────────────────────────────┘\n                                  │ webhooks (POST /forgejo)\n                                  ▼\n  ┌───────────────────────────────────────────────────────────────┐\n  │ bundled hook router  (server/hook-router.ts)                  │\n  │   classify: routine repo events → that repo's Orchestrator    │\n  │             frontdesk events    → Front Desk                  │\n  └───────────────┬───────────────────────────────┬───────────────┘\n                  │ per-repo queue                │ frontdesk queue\n        routine repo events            frontdesk-directed events\n        (attention/*, comments,        (attention/frontdesk,\n         labels, PRs, pushes)           attention/2-user, /frontdesk)\n                  │                               │\n                  ▼                               ▼\n  ┌───────────────────────────────┐   ┌───────────────────────────┐\n  │ Orchestrator (one per repo)   │   │ Front Desk (operator      │\n  │ triage · shape · dispatch ·   │   │ liaison + triage intake)  │\n  │ review · merge                │   └─────────────▲─────────────┘\n  └───────────────┬───────────────┘                 │ operator chat\n                  │ dispatch                        │\n                  ▼                             operator\n  ┌───────────────────────────────┐\n  │ coding workers (ephemeral)    │\n  │ one isolated worktree each    │\n  └───────────────────────────────┘\n\n  Cockpit UI (Paseo sidebar + workspace panel): agent tree, board, queues, router\n  health, role models, and Front Desk / orchestrator spawn controls.\n```\n\nFour moving parts:\n\n1. **The forge** stores all durable state (issues, comments, labels, commits)\n   and emits webhook events when that state changes.\n2. **The bundled hook router** receives those events, classifies them, queues\n   them per repository, and delivers them over Paseo's transport: routine\n   repository events go **directly to that repository's orchestrator**, while\n   frontdesk-directed events (`attention/frontdesk`, `attention/2-user`, a\n   `/frontdesk` comment) go to the **Front Desk**. This is the piece that wakes\n   an idle fleet.\n3. **The agents** do the work. Three roles: **Front Desk** (the operator-facing\n   liaison and triage intake — it only receives frontdesk-directed events),\n   **orchestrator** (one per repo; triage + dispatch + review), and **coding\n   workers** (ephemeral, one worktree each). Their behaviour is encoded in\n   *Skills*, not in the plugin.\n4. **The Cockpit** is the Paseo surface that renders the board, the agent tree,\n   the router queues, and controls for spawning Front Desk/orchestrators,\n   muting repos, and editing role models.\n\n### The roles\n\n| Role | How many | Owns | Never does |\n| --- | --- | --- | --- |\n| **Front Desk** | 0–1 per fleet | Operator-facing liaison and triage intake; takes frontdesk-directed events; routes escalations; registers with the router | Implement code; receive routine per-repo webhooks |\n| **Orchestrator** | one per enrolled repo | Triage, shaping, dispatch, PR pre-flight/merge, board hygiene | Edit source files or check out feature branches itself |\n| **Coding worker** | one per ticket (ephemeral) | Implements in an isolated git worktree, opens a PR | Touch a checkout the operator is using; scan/self-claim |\n\n### The board lifecycle\n\nA ticket's life is expressed entirely through scoped labels (see\n[§5](#5-board-labels-taxonomy-and-install)):\n\n```\n state/0-triage → state/1-wip → state/2-review → state/3-verify → state/4-done\n attention/0-orchestrator ↔ attention/1-agent ↔ attention/2-user ↔ attention/3-ignore\n```\n\n`attention/*` is the operator's steering channel; `state/*` is the execution\nlifecycle; `priority/*` orders the queue; `spec/*` is pre-code shaping.\nApplying a label inside a scope evicts the previous one **if the label was\ncreated with `exclusive: true`** — that is the whole mechanism, and it is why\nthe label seed in [§5](#5-board-labels-taxonomy-and-install) matters.\n\n> [!IMPORTANT]\n> **Operator Attention Policy**: Only `attention/2-user` (or `attention/user`) signals\n> that human operator intervention is required. `state/3-verify` or `state/2-review`\n> represent execution milestones and **never** imply operator attention or suppress\n> orchestrator sweeps unless explicitly paired with `attention/2-user`.\n\n---\n\n## 2. Prerequisites\n\n| Requirement | Notes |\n| --- | --- |\n| **Paseo** ≥ 0.8.0 | The plugin manifest requires it (`paseo-plugin.json`). |\n| **A Forgejo or Gitea-family host** | Any `forgejo`/`gitea` instance; the API used is `/api/v1`. |\n| **Repository access token** | A PAT with issue write scope (see below). |\n| **An agent provider + model** | Any provider Paseo supports, per role. |\n| **A host runner** | **Required** for label triage and repository sweeps (the Forgejo Actions workflows in [§9](#9-forgejo-actions--automated-board-hygiene)). A Forgejo Actions runner with the host backend is preferred. |\n| **A git host remote named for your forge** | The CLI wrappers resolve board context from `origin`. |\n\nMinimum Forgejo/Gitea PAT scopes for the write surfaces:\n`read:user`, `read:repository`, and `write:issue` (add `write:repository` if\nlabel management still returns 403). A token that is accepted but under-scoped\nis reported as *\"token lacks write scope\"* rather than silently failing.\n\n---\n\n## 3. Install the plugin\n\nInstall from npm (Paseo 0.9+):\n\n```sh\npaseo plugin add npm:@xpufx/paseo-uppidi-fleet\n```\n\nOr install directly from the Git repository:\n\n```sh\npaseo plugin add xpufx/paseo --path plugins/uppidi-fleet\n```\n\n> [!NOTE]\n> The npm package is `@xpufx/paseo-uppidi-fleet`; the plugin still installs and\n> displays as **`uppidi-fleet`**, which is the `id` in its\n> `paseo-plugin.json`. Pre-0.9 Paseos install from the repository path instead.\n\nAfter install, the plugin appears as a sidebar item and a workspace panel named\n**Uppidi Fleet**, plus a settings screen. The server entry\n([`index.server.ts`](./index.server.ts)) registers all RPC handlers and starts\nthe bundled webhook router automatically via `startHookRouter(server)`.\n\n---\n\n## 4. The Cockpit surface\n\nThe plugin registers one primary surface with three tabs:\n\n| Tab | What it shows |\n| --- | --- |\n| **Agents & Fleet** (tree) | Hierarchical view: projects → orchestrators → workers, with deterministic state badges (working / running / permission-prompt / attention-required / sleeping / idle / quota / failed), worktree names, parentage, and per-repo enrolment/mute flags. Hosts the `+ Create Front Desk`, `+ Add Orchestrator`, `Replace`, archive, and repo-mute controls. |\n| **Work Queue** (dashboard) | Open issues from the board with status, owner, and labels; a **Fleet Needs Attention** board at the top surfaces blocked agents, filter presets (Needs Attention, Triage/Review, In Progress, Verify). Also the collapsible Hook Service, Hook Queues, log tail, Agent Role Models, CI Runner fleet, and fleet-metrics sections. |\n| **Settings** | Hook service management (start/stop/restart, listen host + port), links into role-model editing. |\n\nKey behaviours:\n\n- **Blocked agents are surfaced prominently (#534)**: an agent sitting at a\n  pending permission prompt (`pendingPermissions.length > 0`) renders a pulsing\n  `AttentionBeacon` warning (`⚠️ Permission Needed: <tool/action>`) with a\n  copyable Front Desk adjudication command (`paseo permit allow <agent> <req>`);\n  an agent flagged   `requiresAttention` (e.g. an interactive ask question)\n  renders an `Awaiting Input` badge carrying the daemon reason. The Cockpit\n  header shows a fleet-wide `⚠️ N Need Attention` badge and the **Fleet Needs\n  Attention** board lists every blocked agent with one-click access. The\n  canonical subagent lifecycle state (`waiting_for_input`, …) and its structured\n  `blockDetail` (required permission id + scope) ride the same payload — see\n  [§13.6](#136-subagent-lifecycle-contract-reactive-wakeups--capability-grants).\n- **Router health** is shown in the header (`Router Active` / `Router Starting` / `Router Disconnected`).\n- **Dispatch is handled via the orchestrator protocol**, not from the UI: the\n  orchestrator Skill creates and drives each worker's isolated worktree.\n- The issue list is fetched by `uppidi-fleet.issues` from the forge API — see\n  the host/repo caveat in [§10](#10-gap-analysis--what-the-plugin-does-not-ship).\n\n---\n\n## 5. Board labels: taxonomy and install\n\nThe plugin and the Skills both assume a **scoped label vocabulary**: a label\nwhose name contains `/`, where the last `/` separates `scope` from `value`\n(`state/1-wip`). Labels created with `exclusive: true` are single-occupancy per\nscope — applying one evicts the other at the forge DB level.\n\n### 5.1 Scopes the workflow uses\n\n| Scope | Values | Meaning |\n| --- | --- | --- |\n| `state/` | `0-triage`, `1-wip`, `2-review`, `3-verify`, `4-done` | Execution lifecycle (non-binding; does not signal human attention) |\n| `attention/` | `0-orchestrator`, `1-agent`, `2-user`, `3-ignore` (+ optional `frontdesk`) | Who acts next (`attention/2-user` is the sole human operator signal) |\n| `priority/` | `0-SOS`, `1-high`, `2-normal`, `3-low`, `4-backburner` | Queue ordering |\n| `spec/` | `0-needed`, `1-checklist`, `2-approved` | Pre-code shaping |\n| `target/` | one per managed component, e.g. `target/daemon`, `target/uppidi-fleet` | Which subsystem a ticket concerns |\n| `verify/` | `automated-ok`, `needs-device` | Verification classification |\n| `flag/` | `stop-work` (circuit breaker) | Binding stop |\n\nAdditional scopes seen on a mature board (`kind/`, `dep/`, `linked/`, `size/`,\n`review/`, `upstream/`, `format/`) are optional and team-specific.\n\n### 5.2 The shipped seed\n\nA generic, apply-able seed for the four core scopes plus `flag/stop-work`\nalready exists at\n[`plugins/forges/examples/labels/label-base.yaml`](../forges/examples/labels/label-base.yaml).\nIt is a YAML label template in the format Forgejo/Gitea read.\n\n**Important:** the plugin does **not** install labels for you. The former\nin-UI label-set installer was removed as operator-gated (see\n[§10](#10-gap-analysis--what-the-plugin-does-not-ship)). You seed them\nyourself.\n\n### 5.3 Install approaches\n\n**A. As an instance label template (Forgejo ≥ 1.19).** Copy the YAML into the\ninstance's custom label directory so it is selectable when creating repos:\n\n```sh\nsudo cp plugins/forges/examples/labels/label-base.yaml \\\n        \"$FORGEJO_CUSTOM/options/label/agent-workflow.yaml\"\n```\n\nLabel templates apply at **repository creation time** only.\n\n**B. To an existing repo via the API.** This is the practical path. The\nfollowing loop reads a local `labels.yaml` (with `labels:` list, each item\n`name` / `color` / `exclusive` / `description`) and creates each label:\n\n```sh\nFORGEJO_URL=https://forge.example.com\nOWNER=your-org\nREPO=your-repo\nTOKEN=<your-personal-access-token>\n\njq -c '.labels[]' plugins/forges/examples/labels/label-base.yaml | while read -r label; do\n  curl -sS -X POST \\\n    -H \"Authorization: token ${TOKEN}\" \\\n    -H \"Content-Type: application/json\" \\\n    -d \"$(jq -n --argjson l \"$label\" \\\n          '{name:$l.name,color:$l.color,description:$l.description,exclusive:$l.exclusive}')\" \\\n    \"${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/labels\"\ndone\n```\n\nTo seed `target/` and `verify/` (not in the shipped file), extend the YAML or\nadd them ad hoc, e.g. `verify/automated-ok`, `verify/needs-device`, and one\n`target/<component>` per sub"}