| name | pipeline-list |
| description | List the issues in the Panopticon pipeline, grouped by phase (Ship · Review · Work · Plan) with their TITLES — the on-demand text form of what the dashboard shows. Two views: the default "resource" view mirrors the Command Deck project tree (issues with a live workspace/branch/agent/PR right now); `--phase` gives the "lifecycle" view that mirrors the Pipeline page (every issue by phase, including planned-but-not-started work). Use when the user asks "what's in the pipeline", "list the pipeline", "what are we working on", or wants the active issues by phase with names. For the dense per-issue status matrix use /pipeline-status; this is the grouped, titled list.
|
| triggers | ["/pipeline-list","what's in the pipeline","whats in the pipeline","list the pipeline","pipeline issues","pipeline by phase","active pipeline","what are we working on"] |
| allowed-tools | ["Bash","Read"] |
pipeline-list — Pipeline issues grouped by phase, with titles
Two views of "the pipeline", because they answer different questions:
| View | Flag | Source | Answers |
|---|
| Resource (default) | (none) | /api/issues/resource-allocated | "What has a live workspace / branch / agent / PR right now?" — the operational set. Mirrors the Command Deck project tree. Detects ready-to-merge (readyForMerge). |
| Lifecycle | --phase | /api/issues + getPipelineIssuePhase rule | "What is moving through the lifecycle, including planned-but-not-started work?" — the forward queue. Mirrors the Pipeline page (/pipeline). |
Both group by Ship · Review · Work · Plan and print ISSUE-ID — title.
The default (resource) view is usually what you want ("what's actually in
flight"); use --phase for planning/triage (it also surfaces the planned
backlog that has no workspace yet). --all additionally lists the
Verifying close-out queue (merged, awaiting human close-out — NOT active
work). Neither view includes the Todo backlog or closed/cancelled issues.
Why the API, not the DOM
The dashboard Pipeline list is virtualized — a Playwright/DOM scrape sees
only the rows in the viewport (slow + silently incomplete), and titles
cross-reference other issue IDs ("deferred from PAN-1229"), polluting naive ID
extraction. Don't scrape. This skill makes one read-only HTTP call to the
dashboard read model (the same data those surfaces render).
Run it
Dashboard must be up (normally :3011, falls back to :3010). This script IS
the skill:
python3 - "$@" <<'PY'
import json, sys, urllib.request
args = sys.argv[1:]
MODE_PHASE = "--phase" in args
SHOW_ALL = "--all" in args
def fetch(path):
for port in (3011, 3010):
try:
with urllib.request.urlopen(f"http://localhost:{port}{path}", timeout=6) as r:
return json.load(r)
except Exception:
continue
return None
PHASES = [("ship", "🚢 Ship"), ("review", "👀 Review"), ("work", "🔨 Work"), ("plan", "📋 Plan")]
if SHOW_ALL:
PHASES.append(("verifying", "✅ Verifying (awaiting close-out — NOT active pipeline)"))
buckets = {k: [] for k, _ in PHASES}
if MODE_PHASE:
issues = fetch("/api/issues")
if issues is None:
sys.exit("Dashboard API not reachable on :3011/:3010 — is `pan up` running?")
def phase(it):
cs = it.get("canonicalStatus") or it.get("state") or it.get("status")
if cs in ("done", "closed", "completed", "cancelled", "canceled"):
return None
if cs == "verifying_on_main":
return "verifying"
if it.get("mergeStatus") in ("queued", "merging", "verifying", "failed", "merged"):
return "ship"
if cs == "in_review":
return "review"
if cs == "in_progress":
return "work"
if it.get("hasPlan") is True or it.get("planningComplete") is True:
return "plan"
return None
for it in issues:
p = phase(it)
if p in buckets:
buckets[p].append((it.get("identifier") or it.get("id") or "?", (it.get("title") or "").strip()))
header = "Pipeline (lifecycle view — mirrors /pipeline)"
else:
ra = fetch("/api/issues/resource-allocated")
if ra is None:
sys.exit("Dashboard API not reachable on :3011/:3010 — is `pan up` running?")
def phase(it):
if it.get("readyForMerge") or it.get("mergeStatus") in ("queued", "merging", "verifying", "failed", "merged"):
return "ship"
sl = (it.get("stateLabel") or "").lower()
if "review" in sl:
return "review"
if "progress" in sl:
return "work"
if it.get("hasPlanning") or it.get("hasState"):
return "plan"
return "work"
for it in ra:
p = phase(it)
if p in buckets:
buckets[p].append((it.get("issueId") or "?", (it.get("title") or "").strip()))
header = "Pipeline (resource view — mirrors the Command Deck tree)"
print(header)
total = 0
for key, label in PHASES:
rows = sorted(buckets[key], key=lambda r: r[0])
print(f"\n{label} ({len(rows)})")
for ident, title in rows:
print(f" {ident} — {title[:90]}")
if key != "verifying":
total += len(rows)
active = " · ".join(f"{label.split(' ', 1)[1]} {len(buckets[k])}" for k, label in PHASES if k != "verifying")
print(f"\n———\n{total} issues in the pipeline ({active})")
PY
Notes
- Resource view is backed by the resource-discovery service
(
src/dashboard/server/services/resource-discovery.ts), which includes an
issue when it has ≥1 resourceSource (workspace, branch, tmux, docker, pr,
vbrief, beads, or active tracker state) and computes readyForMerge +
stateLabel. Same data the Command Deck fetchProjects() consumes.
- Lifecycle view ports
getPipelineIssuePhase
(src/dashboard/frontend/src/lib/pipeline-state.ts). It can't see
readyForMerge/review-status (those are RPC-snapshot only), so a "ready to
merge" issue shows under Review until its merge is actually queued, and Ship
reflects merge-in-flight only.
- Long-term: the clean fix is a first-class
pan pipeline verb / a
/api/issues/pipeline endpoint that runs getPipelineIssuePhase server-side
so the dashboard, CLI, and this skill share one implementation. Point this
skill at it when it exists.
- If
getPipelineIssuePhase or the resource-discovery fields change, update
this skill in the same commit (no automated cross-check, unlike pan-<verb>
wrappers).
- Dashboard down? The script exits with a clear message — fall back to
pan status / pan issues.