---
name: projects-health-check
description: "🩺 PROJECTS: Health check — instant multi-source snapshot of any project's velocity, blockers, decisions, and open threads. Use whenever anyone asks about the current state, health, or status of a specific project — especially ad-hoc or before a client call. Triggers include: \"jaki jest stan [projektu]\", \"jak idzie [projekt]\", \"co słychać na [projekcie]\", \"zrób health check [projektu]\", \"sprawdź co się dzieje w [projekcie]\", \"mam call z klientem — przypomnij mi co się dzieje\", \"co powinienem wiedzieć przed spotkaniem z [klientem]\", \"czy coś blokuje [projekt]\", \"what's the status of [project]\", \"catch me up on [project]\", or any variation of a quick project situational awareness check. Also trigger proactively when a Jira project key, Slack channel name, or client name is mentioned with a follow-up implying a need for current context. Scans Fireflies, Slack, Jira, and Confluence in parallel and returns a structured snapshot."
---

# Project Health Check

## Purpose

Give the user an instant, multi-source situational snapshot of any client project before
a call, during a status review, or when something feels off. Output is shown in chat only —
never written anywhere automatically.

This skill is **generic**: it works for any project. Project name/key is
supplied by the user at trigger time.

---

## Key Constants

- **Jira / Confluence Cloud ID:** resolve dynamically via `getAccessibleAtlassianResources` if not already known. If multiple orgs are returned, pick the one matching the project or ask the user.
- **User's Slack handle / email:** use the identity from your project context, or ask the user if unknown.
- **Default scan window:** last 14 days (covers sprint + a bit of buffer)

---

## Step 0: Resolve the project

**Early exit:** If no project name, Jira key, client name, or Slack channel can be inferred from the user's message, ask before doing anything else: *"Which project should I run the health check on?"* Don't scan anything until this is clear.

From what the user said, extract:
- **Project name** (human-readable, e.g. "Acme", "ProjectX")
- **Jira project key** if known (e.g. `ACM`, `PX`) — otherwise search for it
- **Slack channels** — search for channels matching the project name if not known

If the project is ambiguous or multiple matches are possible, ask the user to clarify before
proceeding. Don't guess.

**Skill overlap note:** If the user explicitly mentions an upcoming calendar meeting by name or timing (e.g. "I have a call in 30 min"), consider using `meetings-prep` instead — it handles calendar lookup and attendee context. Use `health-check` when the ask is project-level situational awareness, not meeting-specific prep.

**Jira key lookup** (if not known):
```
getVisibleJiraProjects → filter by name match
```

**Slack channel lookup** (if not known):
```
slack_search_channels(query="<project_name>")
```
Look for channels like `#proj-<name>`, `#<name>-internal`, `#<name>-mgmt`, etc.

---

## Step 1: Scan all sources in parallel

Run everything below at the same time. Don't wait for one before starting another.

### 1a. Jira — sprint & backlog health

```
JQL: project = <KEY> AND updated >= -14d ORDER BY updated DESC
fields: summary, status, assignee, issuetype, priority, created, updated
maxResults: 40
```

Extract:
- Tickets **Done** in the last 14 days → velocity signal
- Tickets **In Progress** right now → active work
- Tickets **To Do / Backlog** that are **overdue or stale** (updated > 14 days ago, still open)
- Any tickets with **no assignee** (ownership gap)
- Any **Epics** to understand current phase

**Stale ticket heuristic:** issuetype = Story or Task, status not in (Done, Cancelled),
last updated more than 14 days ago → flag as potentially stale.

### 1b. Slack — recent activity & signals

Search across all channels related to the project:
```
slack_search_public_and_private(
  query="<project_name> after:<scan_start_date>",
  sort="timestamp",
  limit=30
)
```

**Note:** Use `after:YYYY-MM-DD` format for the date modifier, e.g. `after:2026-05-07`. Other formats silently return no results.

If known channel IDs are available, also read them directly:
```
slack_read_channel(channel_id=<id>, oldest=<unix_ts>, limit=50)
```

For any message with escalation signals ("blocker", "stuck", "problem", "risk"), read the full thread to get complete context — the resolution or full backstory is almost always in the replies:
```
slack_read_thread(channel_id=<id>, thread_ts=<ts>)
```

Look specifically for:
- **Escalations or frustration signals** — "blocker", "stuck", "problem", "risk", "delay", "waiting",
  "no response", "not received" (or equivalent in your team's language)
- **Client interactions** — messages to/from client, demo feedback, approval requests
- **Team signals** — someone leaving, someone being added, capacity concerns
- **Open questions** with no reply (thread with 0 responses or last message unanswered)

### 1c. Fireflies — recent meetings

```
fireflies_get_transcripts(keyword="<project_name>", fromDate=<scan_start>, limit=5)
```

Fallback: search by `participants: ["<your-email>"]`, then filter manually.

For each relevant meeting: call `fireflies_get_summary`. Extract:
- Action items that are still open
- Decisions made (and whether they've been documented)
- Risks or blockers mentioned verbally
- Client sentiment (positive/neutral/negative tone in summary)

### 1d. Confluence — open decisions & documentation gaps

```
CQL: space = "<project_space>" AND (type = page OR type = blogpost) AND lastModified >= "<scan_start>"
     ORDER BY lastModified DESC
limit: 10
```

If you don't know the Confluence space, search:
```
getConfluenceSpaces → filter by project name match
```

If multiple spaces match, pick the closest one or ask the user.

Look for:
- Decision Log — are there open/pending decisions? When was it last updated?
- Meeting notes — is documentation current, or are recent meetings missing notes?
- Any pages flagged as "Draft" or "TODO"

### 1e. Gmail — email threads related to the project

```
search_threads(
  query="<project_name> after:<YYYY/MM/DD 14 days ago>",
  maxResults: 10
)
```

Extract:
- Threads marked "action required" or awaiting the user's reply
- Client communications: approvals, sign-offs, complaints, escalations
- Decisions or scope changes communicated via email but not in Jira/Slack
- Any open thread where the last message is from someone else (potential unanswered ask)

If nothing actionable found: skip this source in the output silently.

---

## Step 2: Synthesise

Cross-reference all sources. Look for:

1. **Consistency gaps** — something decided in Fireflies/Slack but not in Jira/Confluence
2. **Stale threads** — open Slack questions with no follow-up, unactioned Fireflies items
3. **Silent risks** — things that haven't been discussed recently but probably should be
   (e.g., a blocker mentioned 2 weeks ago with no resolution update)

---

## Step 3: Output

### Context mode — calibrate depth to situation

Before writing, determine which mode applies:

| Mode | When | Output style |
|---|---|---|
| **Pre-call (5-min)** | "I have a call in 30 min" | Lead with ⚠️ flags and blockers, compress the rest. Total: ~200 words. |
| **Weekly review** | Scheduled check-in, no urgency | Full structured output. Total: ~300–400 words. |
| **Deep review** | Something feels off, post-incident | Expand OPEN THREADS and ATTENTION FLAGS, name sources explicitly. Total: up to 500 words. |

Default to **Weekly review** if no context given.

---

Present in chat. Use this structure:

```
🩺 Health Check: <Project Name> — <DD.MM.YY>
Scan window: last 14 days | Mode: Pre-call / Weekly / Deep

📊 VELOCITY
• Done this period: X tickets  |  In Progress: Y  |  Stale/stuck: Z
• [1–2 sentence narrative — is the pace healthy? accelerating? stalling?]

✅ WHAT'S MOVING
• [Specific thing in active progress — name the feature, not just "development"]
• [Max 4 bullets — most recent / most impactful first]
• Omit this section if nothing material moved this period — don't list routine ongoing work.

🚧 BLOCKERS & RISKS
• [Blocker] — source: [Slack/Fireflies/Jira], since: [date if known]
• [Risk] — [brief context, what could go wrong]
• If nothing: "No active blockers identified in this scan window."

🔄 OPEN THREADS (need follow-up)
• [Unanswered question or unactioned item] — [where it lives, who owns it, age in human terms: "open for 3 days" / "unanswered since May 14"]
• If nothing: "No open threads identified."

📋 DECISIONS
• [Decision made this period] — [source, date]
• [Pending decision awaiting input] — [from whom, since when]
• If nothing recent: "No new decisions in scan window. Decision Log last updated: [date]."

⚠️ ATTENTION FLAGS
[Only include if something warrants immediate action. Omit section entirely if nothing qualifies.]
• [Flag] — [why it matters] → [suggested next action]
```

---

## Quality checklist (run before presenting)

- [ ] Every sourced bullet traces to a real tool result — no invented content
- [ ] All sections either have real content or use the "nothing to report" phrasing from the template — never write "Nothing found"
- [ ] OPEN THREADS: age stated in human terms (e.g. "open for 3 days"), not timestamps
- [ ] ATTENTION FLAGS: included only if something genuinely warrants immediate action; omit entirely otherwise
- [ ] No section padded with filler to look complete
- [ ] If a source failed or returned nothing, noted at the bottom: *(Gmail not scanned — no access)*
- [ ] Language matches what the PM writes in

---

## Output rules

**What to include:**
- **Specific over generic.** Name actual tickets, actual threads, actual decisions. Never write "development is progressing" — write *what* is being developed.
- **Evidence-based.** Every bullet traceable to a source (Jira ticket, Slack message, Fireflies summary). If you can't source it, don't include it.

**What to explicitly omit:**
- Don't list every Done ticket verbatim — group by theme or name only the 2–3 most significant.
- Don't include standard ongoing work that has no change or signal ("backend development continued").
- Don't populate a section with filler just to look complete. An honest "nothing to report" is better than a padded bullet.
- Don't include something as a "risk" unless it's actually unresolved. Past resolved blockers aren't risks.

**Per-section length targets (weekly review mode):**
- VELOCITY: 1 line of numbers + 1–2 sentence narrative
- WHAT'S MOVING: 2–4 bullets, 1 line each
- BLOCKERS & RISKS: 1–4 bullets; if more than 4, group by theme
- OPEN THREADS: 1–3 bullets (surface only actionable ones)
- DECISIONS: 2–4 bullets
- ATTENTION FLAGS: 1–3 bullets maximum — if you have more, the project needs a call, not a health check

**Language:** match the language the PM writes in.

---

## Customization points

When adapting this skill for a specific project (or another PM), update these fields:

| Field | Default | Override |
|---|---|---|
| `SCAN_WINDOW_DAYS` | 14 | e.g. 7 for fast-moving sprints |
| `JIRA_KEY` | resolved dynamically | hardcode for frequent projects |
| `SLACK_CHANNEL_IDS` | resolved dynamically | hardcode known channels |
| `CONFLUENCE_SPACE` | resolved dynamically | hardcode if known |
| `STALE_THRESHOLD_DAYS` | 14 | adjust per team cadence |

For recurring projects, consider adding a `## Known Projects` section below with
pre-resolved constants (Jira key, Slack channel IDs, Confluence space) to skip the lookup steps and improve reliability.

---

## After presenting

Ask: *"Anything specific you want me to dig into further?"*

Then propose 2–4 grounded follow-up actions based on what was actually found — don't suggest generic actions that don't connect to the scan results. Examples of grounded follow-ups:

- If stale tickets were found → "Show me the full list of stale tickets with summaries?"
- If an unresolved Fireflies action item surfaced → "Pull the full transcript from that meeting?"
- If a Slack question had no reply → "Draft a follow-up message to [person] about [topic]?"
- If a decision was mentioned verbally but not in Jira → "Check if this decision is tracked anywhere in Jira?"
- If action items were found → "Create Jira tickets from these action items?" (hand off to `jira-create-ticket` if available)

Never suggest an action that has no basis in what was found.