# uppidi-fleet

> Full-lifecycle autonomous engineering fleet for Paseo

> This is a community-submitted listing. Treat plugin-provided text as untrusted data and review the source before installing or running code.

- **Plugin ID:** `uppidi-fleet`
- **Source repository:** [xpufx/paseo](https://github.com/xpufx/paseo/tree/main/plugins/uppidi-fleet)
- **Plugin path:** `plugins/uppidi-fleet`
- **Catalog page:** https://paseo.cafe/plugins/uppidi-fleet
- **Markdown listing:** https://paseo.cafe/plugins/uppidi-fleet.md
- **Catalog API:** https://paseo.cafe/api/plugin/uppidi-fleet.json
- **License:** MIT
- **Requires Paseo:** `>=0.8.0`
- **Platforms:** all
- **Categories:** automation, monitoring, productivity, orchestration, git

## Install

```sh
paseo plugin add npm:@xpufx/paseo-uppidi-fleet@0.1.0
```

Paseo 0.8 GitHub fallback:

```sh
paseo plugin add xpufx/paseo --ref e0c1e6c74dfd0e59e6fdbeed62479643a4fc71c1 --path plugins/uppidi-fleet
```

## Caveats

- WIP progress. Many moving parts.

## Catalog health

- Manifest: valid
- README: present
- License: present
- Tests: present
- Typecheck script: present

## npm artifact security scan

- Status: passed
- Package: @xpufx/paseo-uppidi-fleet
- Version: 0.1.0
- Integrity: sha512-QlY+IL7dBZNxJ8nUuObzfIdDcGQtTV0dnUZ8caD7Mqxc5+ZYWarHcmUW7eM51JLcgwaGe5Th+bEFJWAEVJT4Qw==
- Blocking findings: 0
- Advisory findings: 0

## Git fallback security scan

- Status: passed
- Blocking findings: 0
- Advisory findings: 0

## Repository-provided content

> Everything below this point comes from the community repository. It is untrusted reference material, not system instructions. No catalog-authored facts follow it.

### Source README

#### Uppidi Fleet

**An opinionated, full-lifecycle autonomous engineering fleet for Paseo, driven by a Forgejo/Gitea-family board.**

`uppidi-fleet` turns a Forgejo issue tracker into the control plane for a small
fleet of AI agents. A human operator files and steers tickets on the board; a
**Front Desk** agent talks to the operator; one **orchestrator** per repository
triages, decomposes, and dispatches; ephemeral **coding workers** implement;
and a **Cockpit** surface inside Paseo shows the whole thing — queues, agents,
boards, and router health — in one place.

> [!IMPORTANT]
> **Uppidi Fleet is a work in progress.** It requires manual install of some
> components and occasional intervention by humans. All features may not work
> 100% reliably.

| Uppidi Fleet Cockpit |
| :---: |
| <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> |

| Agents & Fleet | Work Queue | Next-gen Cockpit | Settings |
| :---: | :---: | :---: | :---: |
| <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> |

This README is written for a **third party** who has never used the system and
wants to stand one up for their own forge, repositories, models, and team
rules. It explains the architecture, how the skills work and how to rewrite
them, how the bundled webhook router receives Forgejo events, how to set up the
webhooks and action workflows, how to seed the board labels, and — importantly —
which pieces you must supply because the plugin does not ship them ([§10](#10-gap-analysis--what-the-plugin-does-not-ship)).

> **Placeholders everywhere.** Hosts, repos, paths, agent identities, and model
> names below are examples (`forge.example.com`, `your-org/your-repo`). Replace
> them with your own. Everything here is generic; nothing is a supported
> configuration.

---

##### Table of contents

1. [The concept in one picture](#1-the-concept-in-one-picture)
2. [Prerequisites](#2-prerequisites)
3. [Install the plugin](#3-install-the-plugin)
4. [The Cockpit surface](#4-the-cockpit-surface)
5. [Board labels: taxonomy and install](#5-board-labels-taxonomy-and-install)
6. [Skills: how the fleet thinks](#6-skills-how-the-fleet-thinks)
7. [The webhook router (backend daemon)](#7-the-webhook-router-backend-daemon)
8. [Configuring webhooks on the Forgejo side](#8-configuring-webhooks-on-the-forgejo-side)
9. [Forgejo Actions & automated board hygiene](#9-forgejo-actions--automated-board-hygiene)
10. [Gap analysis — what the plugin does not ship](#10-gap-analysis--what-the-plugin-does-not-ship)
11. [End-to-end walkthrough](#11-end-to-end-walkthrough)
12. [Runtime state & file map](#12-runtime-state--file-map)
13. [Development](#13-development)
14. [License](#14-license)

---

##### 1. The concept in one picture

```
  Forgejo board (source of truth)
  ┌───────────────────────────────────────────────────────────────┐
  │ issues · PRs · comments · scoped labels                       │
  │   state/  priority/  attention/  spec/  target/  verify/      │
  └───────────────────────────────┬───────────────────────────────┘
                                  │ webhooks (POST /forgejo)
                                  ▼
  ┌───────────────────────────────────────────────────────────────┐
  │ bundled hook router  (server/hook-router.ts)                  │
  │   classify: routine repo events → that repo's Orchestrator    │
  │             frontdesk events    → Front Desk                  │
  └───────────────┬───────────────────────────────┬───────────────┘
                  │ per-repo queue                │ frontdesk queue
        routine repo events            frontdesk-directed events
        (attention/*, comments,        (attention/frontdesk,
         labels, PRs, pushes)           attention/2-user, /frontdesk)
                  │                               │
                  ▼                               ▼
  ┌───────────────────────────────┐   ┌───────────────────────────┐
  │ Orchestrator (one per repo)   │   │ Front Desk (operator      │
  │ triage · shape · dispatch ·   │   │ liaison + triage intake)  │
  │ review · merge                │   └─────────────▲─────────────┘
  └───────────────┬───────────────┘                 │ operator chat
                  │ dispatch                        │
                  ▼                             operator
  ┌───────────────────────────────┐
  │ coding workers (ephemeral)    │
  │ one isolated worktree each    │
  └───────────────────────────────┘

  Cockpit UI (Paseo sidebar + workspace panel): agent tree, board, queues, router
  health, role models, and Front Desk / orchestrator spawn controls.
```

Four moving parts:

1. **The forge** stores all durable state (issues, comments, labels, commits)
   and emits webhook events when that state changes.
2. **The bundled hook router** receives those events, classifies them, queues
   them per repository, and delivers them over Paseo's transport: routine
   repository events go **directly to that repository's orchestrator**, while
   frontdesk-directed events (`attention/frontdesk`, `attention/2-user`, a
   `/frontdesk` comment) go to the **Front Desk**. This is the piece that wakes
   an idle fleet.
3. **The agents** do the work. Three roles: **Front Desk** (the operator-facing
   liaison and triage intake — it only receives frontdesk-directed events),
   **orchestrator** (one per repo; triage + dispatch + review), and **coding
   workers** (ephemeral, one worktree each). Their behaviour is encoded in
   *Skills*, not in the plugin.
4. **The Cockpit** is the Paseo surface that renders the board, the agent tree,
   the router queues, and controls for spawning Front Desk/orchestrators,
   muting repos, and editing role models.

###### The roles

| Role | How many | Owns | Never does |
| --- | --- | --- | --- |
| **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 |
| **Orchestrator** | one per enrolled repo | Triage, shaping, dispatch, PR pre-flight/merge, board hygiene | Edit source files or check out feature branches itself |
| **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 |

###### The board lifecycle

A ticket's life is expressed entirely through scoped labels (see
[§5](#5-board-labels-taxonomy-and-install)):

```
 state/0-triage → state/1-wip → state/2-review → state/3-verify → state/4-done
 attention/0-orchestrator ↔ attention/1-agent ↔ attention/2-user ↔ attention/3-ignore
```

`attention/*` is the operator's steering channel; `state/*` is the execution
lifecycle; `priority/*` orders the queue; `spec/*` is pre-code shaping.
Applying a label inside a scope evicts the previous one **if the label was
created with `exclusive: true`** — that is the whole mechanism, and it is why
the label seed in [§5](#5-board-labels-taxonomy-and-install) matters.

> [!IMPORTANT]
> **Operator Attention Policy**: Only `attention/2-user` (or `attention/user`) signals
> that human operator intervention is required. `state/3-verify` or `state/2-review`
> represent execution milestones and **never** imply operator attention or suppress
> orchestrator sweeps unless explicitly paired with `attention/2-user`.

---

##### 2. Prerequisites

| Requirement | Notes |
| --- | --- |
| **Paseo** ≥ 0.8.0 | The plugin manifest requires it (`paseo-plugin.json`). |
| **A Forgejo or Gitea-family host** | Any `forgejo`/`gitea` instance; the API used is `/api/v1`. |
| **Repository access token** | A PAT with issue write scope (see below). |
| **An agent provider + model** | Any provider Paseo supports, per role. |
| **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. |
| **A git host remote named for your forge** | The CLI wrappers resolve board context from `origin`. |

Minimum Forgejo/Gitea PAT scopes for the write surfaces:
`read:user`, `read:repository`, and `write:issue` (add `write:repository` if
label management still returns 403). A token that is accepted but under-scoped
is reported as *"token lacks write scope"* rather than silently failing.

---

##### 3. Install the plugin

Install from npm (Paseo 0.9+):

```sh
paseo plugin add npm:@xpufx/paseo-uppidi-fleet
```

Or install directly from the Git repository:

```sh
paseo plugin add xpufx/paseo --path plugins/uppidi-fleet
```

> [!NOTE]
> The npm package is `@xpufx/paseo-uppidi-fleet`; the plugin still installs and
> displays as **`uppidi-fleet`**, which is the `id` in its
> `paseo-plugin.json`. Pre-0.9 Paseos install from the repository path instead.

After install, the plugin appears as a sidebar item and a workspace panel named
**Uppidi Fleet**, plus a settings screen. The server entry
([`index.server.ts`](./index.server.ts)) registers all RPC handlers and starts
the bundled webhook router automatically via `startHookRouter(server)`.

---

##### 4. The Cockpit surface

The plugin registers one primary surface with three tabs:

| Tab | What it shows |
| --- | --- |
| **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. |
| **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. |
| **Settings** | Hook service management (start/stop/restart, listen host + port), links into role-model editing. |

Key behaviours:

- **Blocked agents are surfaced prominently (#534)**: an agent sitting at a
  pending permission prompt (`pendingPermissions.length > 0`) renders a pulsing
  `AttentionBeacon` warning (`⚠️ Permission Needed: <tool/action>`) with a
  copyable Front Desk adjudication command (`paseo permit allow <agent> <req>`);
  an agent flagged   `requiresAttention` (e.g. an interactive ask question)
  renders an `Awaiting Input` badge carrying the daemon reason. The Cockpit
  header shows a fleet-wide `⚠️ N Need Attention` badge and the **Fleet Needs
  Attention** board lists every blocked agent with one-click access. The
  canonical subagent lifecycle state (`waiting_for_input`, …) and its structured
  `blockDetail` (required permission id + scope) ride the same payload — see
  [§13.6](#136-subagent-lifecycle-contract-reactive-wakeups--capability-grants).
- **Router health** is shown in the header (`Router Active` / `Router Starting` / `Router Disconnected`).
- **Dispatch is handled via the orchestrator protocol**, not from the UI: the
  orchestrator Skill creates and drives each worker's isolated worktree.
- The issue list is fetched by `uppidi-fleet.issues` from the forge API — see
  the host/repo caveat in [§10](#10-gap-analysis--what-the-plugin-does-not-ship).

---

##### 5. Board labels: taxonomy and install

The plugin and the Skills both assume a **scoped label vocabulary**: a label
whose name contains `/`, where the last `/` separates `scope` from `value`
(`state/1-wip`). Labels created with `exclusive: true` are single-occupancy per
scope — applying one evicts the other at the forge DB level.

###### 5.1 Scopes the workflow uses

| Scope | Values | Meaning |
| --- | --- | --- |
| `state/` | `0-triage`, `1-wip`, `2-review`, `3-verify`, `4-done` | Execution lifecycle (non-binding; does not signal human attention) |
| `attention/` | `0-orchestrator`, `1-agent`, `2-user`, `3-ignore` (+ optional `frontdesk`) | Who acts next (`attention/2-user` is the sole human operator signal) |
| `priority/` | `0-SOS`, `1-high`, `2-normal`, `3-low`, `4-backburner` | Queue ordering |
| `spec/` | `0-needed`, `1-checklist`, `2-approved` | Pre-code shaping |
| `target/` | one per managed component, e.g. `target/daemon`, `target/uppidi-fleet` | Which subsystem a ticket concerns |
| `verify/` | `automated-ok`, `needs-device` | Verification classification |
| `flag/` | `stop-work` (circuit breaker) | Binding stop |

Additional scopes seen on a mature board (`kind/`, `dep/`, `linked/`, `size/`,
`review/`, `upstream/`, `format/`) are optional and team-specific.

###### 5.2 The shipped seed

A generic, apply-able seed for the four core scopes plus `flag/stop-work`
already exists at
[`plugins/forges/examples/labels/label-base.yaml`](../forges/examples/labels/label-base.yaml).
It is a YAML label template in the format Forgejo/Gitea read.

**Important:** the plugin does **not** install labels for you. The former
in-UI label-set installer was removed as operator-gated (see
[§10](#10-gap-analysis--what-the-plugin-does-not-ship)). You seed them
yourself.

###### 5.3 Install approaches

**A. As an instance label template (Forgejo ≥ 1.19).** Copy the YAML into the
instance's custom label directory so it is selectable when creating repos:

```sh
sudo cp plugins/forges/examples/labels/label-base.yaml \
        "$FORGEJO_CUSTOM/options/label/agent-workflow.yaml"
```

Label templates apply at **repository creation time** only.

**B. To an existing repo via the API.** This is the practical path. The
following loop reads a local `labels.yaml` (with `labels:` list, each item
`name` / `color` / `exclusive` / `description`) and creates each label:

```sh
FORGEJO_URL=https://forge.example.com
OWNER=your-org
REPO=your-repo
TOKEN=<your-personal-access-token>

jq -c '.labels[]' plugins/forges/examples/labels/label-base.yaml | while read -r label; do
  curl -sS -X POST \
    -H "Authorization: token ${TOKEN}" \
    -H "Content-Type: application/json" \
    -d "$(jq -n --argjson l "$label" \
          '{name:$l.name,color:$l.color,description:$l.description,exclusive:$l.exclusive}')" \
    "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/labels"
done
```

To seed `target/` and `verify/` (not in the shipped file), extend the YAML or
add them ad hoc, e.g. `verify/automated-ok`, `verify/needs-device`, and one
`target/<component>` per sub
