---
name: project-report
description: Post a daily project report as a GitHub Discussion summarizing wins, issues, risks, and low-hanging fruit from the last 24h of commits and new issues in dburkart/vibix. On first invocation, schedules itself to run every 24h via CronCreate (auto-expires after 7 days). Use when the user invokes `/project-report` or asks for a daily/recurring project status post.
---

# project-report

Produces a human-readable daily status report for `dburkart/vibix` and posts it as a
GitHub Discussion in the **Announcements** category. On first invocation it also
installs a CronCreate job so the skill re-fires every 24 hours. CronCreate auto-
expires after 7 days, which gives the user the requested 7-day cap for free —
no counter file, no manual teardown.

## Cycle

### 1. Ensure the daily schedule exists

Call `CronList`. If no existing job has a prompt equal to `/project-report`, create
one:

```
CronCreate(
  cron: "<MM> <HH> * * *",        // pick an off-minute; see below
  prompt: "/project-report",
  recurring: true,
  durable: false,                  // session-scoped is fine; matches auto-expiry
)
```

Pick `MM` and `HH` to fire roughly 24h after *now*, and avoid minute 0 / 30 —
e.g. if it's 14:07 local, `"13 14 * * *"` is good. Tell the user once (at install
time) that the cron auto-expires after 7 days per the runtime's rule; that IS the
7-day cap.

If a job already exists, skip creation — this invocation is either manual or a
scheduled fire, and we do not want duplicates.

### 2. Gather inputs (last 24 hours)

Use `gh` — all queries scoped to `dburkart/vibix`.

```sh
SINCE=$(date -u -v-24H +%Y-%m-%dT%H:%M:%SZ)   # macOS date

# Commits on main in the last 24h
gh api "repos/dburkart/vibix/commits?since=$SINCE&sha=main" \
  --jq '.[] | {sha: .sha[0:7], msg: .commit.message, author: .commit.author.name, url: .html_url}'

# Issues opened in last 24h (gh issue list excludes PRs by default)
gh issue list --repo dburkart/vibix --state all \
  --search "created:>=$SINCE" \
  --json number,title,labels,url,createdAt,body,author \
  --limit 100
```

If both lists are empty, still post a "quiet day" report — the cadence is the point.

### 3. Analyze

Synthesize into the four sections below. Do **not** paste commit titles verbatim —
pull out *themes*. Group related commits. Read issue bodies, not just titles, when
judging severity.

1. **Wins** — merged RFCs, landed features, new subsystems, significant test
   coverage, perf improvements. Reference PR/commit URLs inline.
2. **Issues uncovered** — new bugs or regressions filed in the last 24h (filter on
   the `bug` label and issue body tone). Call out anything labeled `priority:P0`
   or `priority:P1` explicitly.
3. **Risks** — forward-looking concerns derived from the day's activity:
   accumulating tech debt, design decisions that constrain future work, open P0s
   aging without movement, review bottlenecks, test-coverage gaps, RFC drift.
   This section requires judgment, not recitation.
4. **Low-hanging fruit** — concrete, small, high-visibility work items that would
   unlock visible progress for someone *using* vibix (booting it, running a
   program, seeing output on the console, interacting with the shell). Each item:
   1–3 sentences, ends with `Fileable via /file-issue if you want it tracked.`
   **Do not file these automatically** — surfacing them is the job.

### 4. Compose the discussion body

```markdown
# Project Report — <YYYY-MM-DD>

_Covers commits on `main` and issues opened from <SINCE> to <NOW> UTC._

## 1. Wins
- …

## 2. Issues uncovered
- …  *(or "None filed in this window.")*

## 3. Risks
- …

## 4. Low-hanging fruit
- **<short title>** — <1-3 sentences>. Fileable via `/file-issue` if you want it tracked.
- …

---
<small>Generated by the `project-report` skill.</small>
```

Discussion title: `Project Report — <YYYY-MM-DD>`.

### 5. Post the discussion

`gh` has no first-class `discussion create` subcommand — use GraphQL:

```sh
REPO_ID=$(gh api graphql -f query='{ repository(owner:"dburkart",name:"vibix"){ id } }' \
  --jq '.data.repository.id')

# Announcements category ID — stable; fetched once:
CAT_ID="DIC_kwDOSASln84C6tE-"

gh api graphql \
  -f query='mutation($r:ID!,$c:ID!,$t:String!,$b:String!){
    createDiscussion(input:{repositoryId:$r,categoryId:$c,title:$t,body:$b}){
      discussion{ url number }
    }
  }' \
  -f r="$REPO_ID" -f c="$CAT_ID" -f t="$TITLE" -F b=@body.md
```

(Use `-F b=@body.md` — a file ref — rather than `-f b="$BODY"`, so newlines and
backticks in the body survive shell quoting.)

Report the new discussion URL back to the user at the end of the run.

### 6. Idempotency guard

Before posting, search existing discussions for today's title to avoid double-
posts if the user invokes `/project-report` manually on a day the cron already
fired:

```sh
gh api graphql -f query='query($q:String!){
  search(query:$q, type:DISCUSSION, first:5){
    nodes{ ... on Discussion { title url createdAt } }
  }
}' -f q='repo:dburkart/vibix "Project Report — <YYYY-MM-DD>" in:title'
```

If today's report already exists, skip posting and report the existing URL instead.

## Never

- File issues automatically from the low-hanging-fruit section — surface only.
- Post more than one report per UTC day (see idempotency guard).
- Fabricate activity on a quiet day — say "Quiet day" and move on.
- Manually extend past 7 days — CronCreate's 7-day auto-expiry IS the cap. If the
  user wants another week, they re-invoke `/project-report` after expiry.
- Create a second `/project-report` cron when one already exists (check CronList).
