Claude
Skills
Sign in
Back

pm-status

Included with Lifetime
$97 forever

Use this skill when the user asks "where are we", "what's in progress", "what should I work on next", "project status", "catch me up", "what's open", "what's stale", "what's stuck", "anything dragging", "old in-progress issues", "what's been sitting", "what needs triage", "any untriaged issues", "what's not labeled", "what needs my attention", or "anything I missed". Provides a cache-first session briefing with in-progress issues (with HITL/AFK execution-mode prefix), next suggested work, **stale-issue detection** (issues stuck in-progress longer than --stale-days, default 30), a **triage view** with four buckets (in-triage / untriaged / unknown-tag / needs-info), and delta sync on demand. Supports --refresh for full re-pull. Do NOT include past session history unless the user explicitly asks. This skill is whole-backlog BREADTH ("across everything, where are things?"). For DEPTH on one named parent/epic/project — its child issues' commit-by-commit progress, a phase ledger, or resuming where you left off — use pm-ledger instead, even if the user says "status" or "progress".

General

What this skill does


# PM Status Briefing

Deliver a concise, actionable briefing of current project state using a cache-first approach with delta sync on demand.

## Usage

```
/pm [--refresh] [--scope <expr>] [--stale-days <int>] [--needs-info-days <int>]
```

- `--refresh` *(flag, optional)* — force a full re-pull from the issue tracker, ignoring cache freshness.
- `--scope <expr>` *(string, optional)* — scope the briefing; grammar `repo:org/foo`, `team:KEY[+subteams]`, `project:KEY[+deps[:upstream|downstream]]`, `workspace:NAME`, or `all`. Defaults to the active project's workspace.
- `--stale-days <int>` *(int, optional)* — in-progress age (days) before an issue is flagged STALE. Default 30.
- `--needs-info-days <int>` *(int, optional)* — days without movement before an operator-assigned issue lands in the Needs-info triage bucket. Default 7.

Read-only briefing: this skill only reads cache and syncs from the tracker — it makes no tracker writes.

All cache operations go through one CLI: `node "$CLAUDE_PLUGIN_ROOT/hooks/bin/pm-cache.js" <verb>`. Every verb prints a single JSON object to stdout and uses exit code to signal success/failure. Don't embed `node -e` snippets — the CLI is the only supported entry point.

## Scope-aware briefings (v0.21.0+)

When the user passes `--scope <expr>`, run the scope-based flow instead of the legacy per-slug flow. Scope grammar:

| Form | Meaning |
|---|---|
| `repo:org/foo` | One repo (back-compat) |
| `team:ENG` | Issues with team_key == ENG |
| `team:ENG+subteams` | ENG + transitive children |
| `project:CHK[+deps[:upstream|downstream]]` | Project, optionally with dependency tree |
| `workspace:nthplus` | Whole workspace |
| `all` | Every known workspace |

Default scope when no `--scope` is given: `workspace:<active-project's-workspace>` if in a registered repo, else prompt the user. Skills like `/pm-report` document the same grammar.

**Scope-based flow:** skip Steps 2-5 below; run `portfolio-sync --workspace <ws>` for each touched workspace, then `scope-briefing --scope <expr>` to get the merged issue set. Apply the same Step 6 formatting (in-progress / stale / up-next) over the resolved issues.

```bash
node "$CLAUDE_PLUGIN_ROOT/hooks/bin/pm-cache.js" portfolio-sync \
  --workspace "<workspace>" --mode delta
node "$CLAUDE_PLUGIN_ROOT/hooks/bin/pm-cache.js" scope-briefing \
  --scope "<expression>"
```

The rest of this skill describes the **legacy per-slug flow**, still used when no `--scope` is passed and the Active Project has a slug.

## Step 1: Check for --refresh Flag

If the user invoked `/pm --refresh`, skip directly to **Step 5** (Force Full Sync). The --refresh flag forces a complete re-pull from the issue tracker regardless of cache freshness.

## Step 2: Read Cache Status

```bash
node "$CLAUDE_PLUGIN_ROOT/hooks/bin/pm-cache.js" status --slug "<slug>"
```

Replace `<slug>` with the project slug from the **Active Project** context.

The CLI returns one of:
- `{ ok: true, tier: "NONE", hasData: false, ... }` — never synced; skip to **Step 5**
- `{ ok: true, tier: "FRESH" | "STALE" | "EXPIRED", message, lastSyncedAt, provider, ... }`
- `{ ok: false, error, code: "NOT_CONFIGURED" }` — missing `projects.json`; tell the user to run `/pm-setup` and stop.

## Step 3: Decide Sync Path

- **FRESH** (synced < 1h ago): skip to **Step 6** (no sync needed).
- **STALE** (synced > 1h, full sync within TTL): run **Step 4** (delta sync), then **Step 6**.
- **EXPIRED** (full sync older than TTL): run **Step 5** (full sync), then **Step 6**.
- **NONE** (no cache yet): run **Step 5**.

## Step 4: Delta Sync

**For GitHub projects** (issue_tracker is "github"):

```bash
node "$CLAUDE_PLUGIN_ROOT/hooks/bin/pm-cache.js" delta-sync \
  --slug "<slug>" --provider github --repo "<org/repo>"
```

**For Linear projects** (uses GraphQL transport — requires `LINEAR_API_KEY` or `project.local.json`):

```bash
node "$CLAUDE_PLUGIN_ROOT/hooks/bin/pm-cache.js" delta-sync \
  --slug "<slug>" --provider linear \
  --team-key "<team_key>" \
  [--project-name "<project_name>"]
```

Omit `--project-name` if `linear_project_name` is unset for the project.

All paths return:
```json
{ "ok": true, "syncType": "delta", "provider": "...", "changes": [...],
  "changeSummary": "...", "deltaCount": N, "totalCount": M }
```

After running delta sync, display `changeSummary` to the user (it already says "No changes since last sync" when empty), then proceed to **Step 6**.

## Step 5: Force Full Sync (--refresh, EXPIRED, or No Cache)

**For GitHub projects:**

```bash
node "$CLAUDE_PLUGIN_ROOT/hooks/bin/pm-cache.js" full-sync \
  --slug "<slug>" --provider github --repo "<org/repo>"
```

**For Linear projects** (uses GraphQL transport — requires `LINEAR_API_KEY` or `project.local.json`):

```bash
node "$CLAUDE_PLUGIN_ROOT/hooks/bin/pm-cache.js" full-sync \
  --slug "<slug>" --provider linear \
  --team-key "<team_key>" \
  [--project-name "<project_name>"]
```

All paths return:
```json
{ "ok": true, "syncType": "full", "provider": "...", "issueCount": N, "syncedAt": "..." }
```

Proceed to **Step 6**.

## Step 6: Format the Briefing

```bash
node "$CLAUDE_PLUGIN_ROOT/hooks/bin/pm-cache.js" briefing --slug "<slug>"
```

Returns `{ ok: true, freshness, issues, stale_threshold_days, stale_issues }`.

Output format (keep it tight — no padding, no extra explanation):

```
Project: <displayName> · <org/repo> · gh: <gh_user> · <workspace> / <team_key> · <project_name if set>
Synced: <freshness>

IN PROGRESS
  <ID> · [<mode>] <title> (<priority label>)
  <ID> · [<mode>] <title>

TRIAGE — needs operator attention   (only shown if any bucket below is non-empty)
  In Triage (<N>): <ID> · <title> (<priority label>)   ← Linear-native Triage state
  Untriaged (<N>):  <ID> · <title>           ← no recognized type tag
  Unknown tag (<N>): <ID> · <title> [tagged "<X>"]   ← tag not in active manifest
  Needs info (<N>): <ID> · <title>  <ageDays>d · <assignee>

STALE (in-progress > <stale_threshold_days> days — only shown if stale_issues is non-empty)
  <ID> · [<mode>] <title>  <ageDays>d (<anchor>) · <assignee or "(unassigned)">
  ...

UNPROJECTED — team-tagged but unassigned to a project, often from auto-integrations
  <ID> · [<mode>] <title> (<priority label>) · created <YYYY-MM-DD>
  ...

WIP AGING  0-3d: <n> · 4-7d: <n> · 8-14d: <n> · 15-30d: <n> · 30d+: <n> (mean <X>d)

UP NEXT
  <ID> · [<mode>] <title> (<priority label>)
  <ID> · [<mode>] <title>
```

Rules:
- Show at most 5 in-progress issues (status === "started")
- Show at most 3 suggested next issues (status === "unstarted"). **Issues with `status === "triage"` are excluded from both IN PROGRESS and UP NEXT** — they belong in the TRIAGE section's "In Triage" bucket, not in ready work (NTH-562).
- **`<mode>` column.** Show `[hitl]`, `[afk]`, or `[??]` if the execution-mode label is missing. The `[??]` is itself the signal that the issue needs triage — it tells the operator "this one slipped past Step 2b of pm-issues and needs a label applied." The mode prefix appears in IN PROGRESS, STALE, and UP NEXT views so the operator can see at a glance which work is agent-runnable vs needs them at the wheel.
- **TRIAGE section: omit entirely if all four buckets are empty.** When any bucket has entries, show only the non-empty ones with their count. See "Triage view" below for the bucket definitions.
- **STALE section: omit entirely if `stale_issues` is empty.** When present, show all entries (they're already filtered + sorted descending by age). The `anchor` field is `"started"` (Linear startedAt) or `"created"` (GitHub fallback) — render as a parenthetical to clarify which timestamp drives the count.
- **UNPROJECTED section (NTH-506): omit entirely if no such issues exist.** When the briefing scope is project-bound (e.g. running `/pm` inside a repo with a configured `linear_project_name`), also surface issues in the SAME team where `project_name == null`. These typically come from Linear's GitHub integration auto-mirroring GH 

Related in General