Skip to main content

Pipeline and Gates

Who a gate pages, how questions are routed, and what Needs attention is telling you.

Text Guide

Pipeline and Gates

A gate is a phase that exists to page a person. There are three, and each one is a per-project setting: Plan review, QA and Release. Set a gate to automatic and the work never enters that phase at all. See Task Workflow for the phases themselves.

The Roles

Five roles, configured per project under Project Settings → Question routing:

| Role | What it covers | |---|---| | Product owner | The Plan review gate. Approves plans. | | Tech owner | The QA and Release gates. Also where a denied agent permission request escalates, and where an exhausted automatic repair asks what to do. | | Client contact | The person outside the team a question can be put to. Tick Relays answers for an external client when they answer on someone else's behalf. | | Triager | New incoming requests. Decides whether a request becomes work. | | Operator | This project's pipeline faults on the Operations view, and who is emailed about them. Not a question recipient — the owner of the runtime, dispatch, reporting and integration failures. A project's developer is never this by default. Unset, it falls back to the organization's Technical contact, then an active owner or admin. |

Only organization owners and admins can change routing. Changing it does not re-route questions that are already open.

How a Question Finds a Person

FlightDesk pages the task's own people first — the QA assignee, the developer, the person who created it. The routed roles are the fallback for a task whose own people cannot answer, and they are the only answer for client contact and triager, which have no task-level equivalent.

A gate with no routed role and no active person on the task falls back to the task's human requester, then to the organization owner. A gate nobody holds is reported as a configuration fault on the Operations view rather than silently stalling — routing a role is not something the task's developer can do.

An agent asking a question supplies a proposed default along with it, so a question that goes unanswered is not automatically a blocked task. A permission decision is different: it is explicitly blocking and carries no default. Projects cap how many rounds of questions one task may go through (Question rounds per task, default 2).

Open questions are listed at /questions in the sidebar.

Needs Attention

The Command Center (/app/command-center) opens on a Needs attention view: every task that is asking something of a person, oldest ask first. It is a presentation of facts the API computes — a gate waiting on you, a blocking question, a decision on a task — not a second set of rules.

Three things are worth knowing:

  • Finished work asks nothing. A task in a Done phase never appears, whatever happened on the way. Its history is still on the task page.
  • Mine vs. Everyone. By default you see what is addressed to you. Owners and admins can switch the scope to everyone.
  • A pipeline fault is not your attention. A silent agent, a hung turn, an unrouted gate: these are still detected and the task still says it is delayed, but they do not appear here. Nobody on a task can inspect a runtime or re-arm a wait, so they go to The Operations View (below, and at /app/operations) instead, with an operator who can. The header strip carries the count and links there.

Conditions, and Who They Are For

FlightDesk notices around twenty distinct conditions on a task — a turn that went quiet, an agent that never picked up its work, a rebase it could not finish. Every one of them is still detected and still recorded, so a task's delayed or blocked status is always truthful and its history is complete. What differs is who the condition is for, because that is what decides whether anybody is being asked to do anything:

| Audience | What you see | Examples | |---|---|---| | The task's own people | The panel that decision already has | a new request to triage; a hold to release; a scope change to review; a skipped check to confirm | | An operator | One factual line on the task, with a Details link, and one row on the Operations view | a silent or disconnected agent; a hung turn; a turn that finished without reporting; a wait with nothing armed; a gate that routes to nobody; a box that cannot start a turn | | Nobody, yet | One factual line on the task | it has been quiet; a machine wait past its time limit |

There is no generic triage box and no mandatory clear note on an ordinary task. A line like "Planning delayed: agent unavailable" is the whole of what a developer sees, and nothing is asked of them.

When a person really is needed

Four conditions are the point at which FlightDesk has run out of ways to move the work itself: an automatic rebase that gave up, automatic fixes that stopped, a session request its own recovery turn could not answer, and a turn that failed with no automatic retries left. Each opens one blocking question for the technical owner, naming the decision — rebase this head by hand or abandon it — and quoting what was already tried.

Three properties matter:

  • Answering the question is the clear. The condition closes with the answer, the work re-evaluates, and there is no second "clear triage" step. A condition still live afterwards asks once more, not in a loop.
  • Repetition asks nothing twice. The question is keyed to the condition, so a sweep reaching the same pull-request head again reuses the open question. One question, one email, one notification.
  • A crashed agent cannot suppress it. The question is opened by FlightDesk's own server, attributed to the agent but not asked by it, so escalation never depends on the agent that failed being able to speak.

A question that could not be routed to anybody becomes a configuration fault for an operator, rather than an exception or silence. Work is never blocked on a missing operator.

Holds

Two conditions stop work, and only a person releases them: a native Claude approval resolved without the FlightDesk decision a human was asked for, and a native prompt the Claude Bridge cannot classify. While either is open, FlightDesk dispatches no further turn on that task. This is how an unrecognised prompt is contained: rather than guessing at a permission card, FlightDesk holds the task and asks.

Releasing a hold still requires a note, and still only from a person. It is the one place a note is mandatory, because it is the one place where clearing the row is itself the decision. An agent key cannot do it, and no button on the Operations view can do it either.

A task shows its most severe open condition as its summary, so a harmless "quiet for four hours" cannot mask a hung turn.

The Operations View

/app/operations is where the pipeline's own failures live, for whoever operates FlightDesk. Organization owners and admins see it; a project member is told whose it is rather than shown an empty page.

One row per cause, not per task. An agent box that loses its Claude login delays every task it was going to take; this is one row naming the agent, the box, what the runtime reported, how many conditions it explains, and all of those tasks — each linking back to its task page. Correlation is on the narrowest identity available (the session for a session condition, else the agent, else the box, else the project), so two unrelated faults are never merged into one row — and one unreadable Claude session is never mistaken for a broken box.

Five categories: dispatch (a turn released that nothing took, or none that could be), runtime (the machine or the session), reporting (a turn ran and FlightDesk never learned what it did), integration (something FlightDesk talks to answered unusably) and configuration (work parks with nobody to move it).

Each row is owned by the project's operator role, then the organization's Technical contact, then an active owner, then an active admin — and when that is nobody, the row says so in as many words rather than hiding. Nothing is ever blocked on a missing operator.

Who Gets Told

A row nobody looks at is not an alert. When FlightDesk raises an incident for a condition that stays broken until a person acts — a box that cannot run a turn (an expired Claude login, nobody logged in, Claude Code missing, the agent's folder gone) or a Claude session it cannot read, reach or re-point — it emails and notifies the resolved contact, in this precedence:

  1. the project's operator question role — the narrowest and most deliberate answer;
  2. Organization → Technical contact, set in organization settings by an owner or admin;
  3. an active organization owner, then an active admin — a last resort, not a default.

Every candidate must be an active person who is still a member of that organization. A deactivated or departed contact is skipped, and the route that was actually used is recorded and shown — on the Operations row and in the email itself ("You were paged as an organization owner (no technical contact is set)"). A fallback nobody can see is a fallback nobody notices is wrong. When nothing resolves, the gap becomes its own configuration fault rather than a dropped alert.

The other categories — a turn that is slow to report, a dispatch nothing picked up, a wait with nothing armed, a gate routed to nobody — get their Operations row and no email. They resolve themselves within a sweep or two often enough that paging on them would train the recipient to ignore the channel, which is the only failure mode an alert cannot recover from.

When. Three failures on the same session inside thirty minutes page somebody. A condition that is confidently permanent pages immediately and skips the count: a Claude page that Claude Bridge has already tried its one fix on and still cannot read, an unauthenticated Claude, a session that is genuinely gone, and any box fault. A single timeout that a retry resolves tells nobody anything.

Once. One email per incident per recipient, then reminders at 2 hours, 6 hours and daily, five at most, widening to the organization's owners and admins if nobody responds. Acknowledging the incident stops the reminders. Concurrent failures cannot produce a second email, and neither can an ordinary restart: the recipient row is unique per incident, the notification is latched on the incident, and the send is recorded before the row stands down. One narrow case is not closable without an idempotency key the mail providers do not offer — a process that dies between the provider accepting the mail and that record committing can produce one repeat, no sooner than half an hour later. The alternative, recording the send first, would turn every such crash into an incident nobody was told about, which for an alert is the worse way to be wrong.

What the email says: the agent and box, the safe error code and reason, when it first and last failed, how many times, the tasks it is delaying, a link to Operations, and the next action. What it never says: a credential, a token, raw page or dialog text, or a log tail. Diagnostics are bounded and allowlisted where they enter FlightDesk, so there is nothing wider for the email to quote.

Each person can turn these off independently of the "work is waiting on you" emails, under personal notification settings.

Session Conditions

A failed Claude session operation is read through Claude Bridge 0.1.19's error code, never through its prose. Only the exact codes SESSION_NOT_FOUND and INVALID_SESSION_ID mean the session is gone. PAGE_UNREADABLE, TIMEOUT, NOT_AUTHENTICATED, SESSION_ARCHIVED and any code FlightDesk does not recognise are inconclusive: the session, its pull request and its history are left as they are, and nothing is replaced. A report with no code at all — from a runtime older than 0.1.19 — is inconclusive too. (The one exception is a best-effort archive, which still completes on the old "unknown session" wording during the fleet rollout, and records on the task that the evidence was prose rather than proof.)

Claude Bridge owns page recovery, and it gets one attempt. On PAGE_UNREADABLE it opens a missing tab, reloads a crashed page or presses Escape on a dialog, then retries the command once. FlightDesk consumes the result and adds nothing: no second reload, no repeated Escape, no retry loop. A success carrying recovered is noted on the task timeline and raises nothing. A failure carrying details.recovery means the bridge could not restore access — so a person is paged at once, and the Operations row says which fix was tried.

A successful read that notes a pageIssue while its API-derived state is still valid is a note, not a fault. A missing scraped field never means a session does not exist.

Mixed fleet versions. Every participating machine needs both the 0.1.19 extension and a restarted 0.1.19 daemon — the daemon carries the codes too, so an extension-only rollout changes nothing. Until a box has both, its reports arrive codeless and take the inconclusive path, which is safe but tells FlightDesk less.

Three controls, deliberately distinct:

  • Acknowledge — "I have seen this". Records who and when, and changes nothing else: no hold released, no turn retried, no task moved.
  • Retry work — resets the affected tasks' automatic re-dispatch counters and re-surfaces the turns released while they were stuck. A task holding agent turns is reported as left alone, not quietly started.
  • Close fault — the row goes. The task conditions it explained stay exactly as they are, because each is released by the condition itself ending.

A note is optional on acknowledging and closing. The acts are audited either way, and a required note only ever produced the word "fixed".

Faults close themselves, on evidence. When the last condition a fault explained ends — the agent comes back, the turn reports, the gate is routed — the row closes with no action from anybody. For a session condition the evidence is an operation that actually worked on that session, or Claude Bridge's own recovery record. A heartbeat closes nothing: the incident behind this had six agents polling happily while one session failed seven times in two hours. The same condition recurring after a verified recovery opens a new row with its own raise time and its own alert, so a recurrence is visibly not a duplicate, and the closed row keeps its whole history — who was told, when, who acknowledged it and what closed it.