flake-update-20260505

Generate Quarterly Report

Step 1 — Determine Period

Parse the user’s request to extract the quarter and year. Convert to date range:

Input Start End
Q1 2026 2026-01-01 2026-03-31
Q2 2026 2026-04-01 2026-06-30
Q3 2026 2026-07-01 2026-09-30
Q4 2026 2026-10-01 2026-12-31
“last quarter” Calculate from current date

Step 2 — Collect Data (Parallel)

Run all data collection concurrently.

2a. daily-plan review (GitHub + Jira + Org + AI)

daily-plan review "<START>..<END>" --json --no-discussions --no-comments

This returns JSON with:

  • org_done — completed org-mode TODO items
  • ai_sessions — AI coding sessions
  • jira_completed — Jira issues resolved via resolutiondate JQL (keys: key, summary, status, priority, url)
  • github_merged — PRs authored and merged (keys: repo, number, title, url)
  • github_reviewed — PRs reviewed, excluding own PRs (keys: repo, number, title, author, url)
  • github_issues_created — Issues filed (keys: repo, number, title, url)
  • github_security_advisories — Security advisories where user is credited or author (keys: ghsa_id, cve_id, summary, severity, state, repo, url, credits, role). Filtered to only advisories where the user appears in credits or is the authorcollaborating_users is skipped (indicates team access, not active involvement). Comments on advisories are not accessible via the API (private fork).

daily-plan automatically splits queries by month and uses --limit 1000 to avoid GitHub Search API truncation. Results are scoped to the configured owners (tektoncd, openshift-pipelines).

daily-plan’s GitHub queries are scoped to the configured owners (tektoncd, openshift-pipelines). PRs in other orgs (NixOS/nixpkgs, containers/, chmouel/, github/advisory-database, etc.) are not included — add those orgs to daily-plan’s config if they should be tracked. Security advisories are filtered to only those where the user is in credits or is author — team-based collaborating_users access is excluded.

2b. GitLab (gitlab.cee.redhat.com)

The internal Red Hat GitLab instance requires REST API with a personal access token. The mcp__plugin_gitlab_gitlab__* MCP plugin targets gitlab.com only — do NOT use it for internal GitLab.

Load token:

export GITLAB_TOKEN=$(passage show gitlab/cee-redhat/token 2>/dev/null || echo "")

If empty, ask the user to provide it or skip GitLab. Generate tokens at: https://gitlab.cee.redhat.com/-/user_settings/personal_access_tokens (scope: read_api).

Resolve user ID:

curl -s "https://gitlab.cee.redhat.com/api/v4/users?username=vdemeest" \
  -H "PRIVATE-TOKEN: $GITLAB_TOKEN" | python3 -c "import json,sys; u=json.load(sys.stdin)[0]; print(u['id'], u['name'])"

MRs authored:

curl -s "https://gitlab.cee.redhat.com/api/v4/merge_requests?author_id=<ID>&state=merged&scope=all&order_by=updated_at&sort=desc&per_page=100&created_after=<START>&created_before=<END>" \
  -H "PRIVATE-TOKEN: $GITLAB_TOKEN"

MRs reviewed:

curl -s "https://gitlab.cee.redhat.com/api/v4/merge_requests?reviewer_id=<ID>&state=merged&scope=all&order_by=updated_at&sort=desc&per_page=100&created_after=<START>&created_before=<END>" \
  -H "PRIVATE-TOKEN: $GITLAB_TOKEN"

Note: author_username filter does NOT work on the global MR endpoint — always use author_id (numeric) + scope=all.

Extract from each MR: iid, title, references.full, merged_at, web_url. Group by namespace/project.

2c. Google Calendar — Meetings

Use GoogleWorkspace skill scripts to query calendar events for the quarter:

cd ~/.config/claude/skills/GoogleWorkspace/scripts && node workspace.js call calendar events.list '{
  "calendarId": "primary",
  "timeMin": "<START>T00:00:00Z",
  "timeMax": "<END>T23:59:59Z",
  "singleEvents": true,
  "orderBy": "startTime",
  "maxResults": 2500,
  "fields": "items(summary,start,end,status,attendees)"
}'

Filter to work meetings (exclude personal blocks like “Focus time”, “Home”, etc.). Count by meeting name to identify recurring series. Only count meetings with 2+ attendees.

2d. Gmail / mu — Meeting Notes

Use mu find (Maildir) to search for Gemini meeting notes in Q1:

mu find 'from:gemini-notes@google.com AND date:<START_YYYYMMDD>..<END_YYYYMMDD>' --fields 's' 2>/dev/null

Alternatively use GoogleWorkspace scripts:

cd ~/.config/claude/skills/GoogleWorkspace/scripts && node workspace.js gmail-search \
  "from:gemini-notes@google.com newer_than:120d"

If MCP tools are available instead (e.g. in Claude Desktop):

mcp__google-workspace__search_emails: from:gemini-notes@google.com to:vdemeest@redhat.com after:<START> before:<END>

2e. Google Drive — Documents

cd ~/.config/claude/skills/GoogleWorkspace/scripts && node workspace.js drive-search \
  "modifiedTime > '<START>T00:00:00' and modifiedTime < '<END>T23:59:59' and trashed=false"

2f. Slack

Use the Slack skill:

~/.config/claude/skills/Slack/tools/SlackRead.sh search "from:vdemeest <relevant_terms>" --after <START> --before <END>

Or via MCP if available:

mcp__slack__search_messages: from:vdemeest after:<START> before:<END>

Step 3 — Analyze & Categorize

Before generating HTML, analyze the raw data:

  1. Count totals for the stats strip (PRs merged, reviewed, GitLab MRs, issues filed, repos contributed to)
  2. Group GitHub PRs by repository, ordered by PR count descending
  3. Group GitHub issues by theme (security, infrastructure, features, governance, code modernization)
  4. Group GitLab MRs by release track (OSP 1.15, 1.20, 1.21, 1.22, cross-release)
  5. Identify Jira epics — filter jira_completed for Epics and Features only (exclude Stories, Tasks, Sub-tasks, Bugs for the main epic section; keep notable bugs separate)
  6. Identify key initiatives — look for patterns: security campaigns, governance work, community leadership, tooling, release management
  7. Extract meeting patterns from Gmail/Gemini notes — recurring meetings, frequency

Step 4 — Generate HTML

Use the template from reference/Template.html in this skill directory. The template is a complete, self-contained HTML file with all CSS inline.

Read the template:

read reference/Template.html

Fill in all data sections. Key rules:

Linking — every item must be clickable

Item type URL format
Jira keys <a href="https://issues.redhat.com/browse/<KEY>" target="_blank" class="key-badge">KEY</a>
GitHub PRs/issues Use the url field from gh search JSON output: <a href="<url>" target="_blank" class="pr-link">title</a>
GitLab MRs Use web_url from API: <a href="<web_url>" target="_blank" class="pr-link">!iid title</a>

Section summaries

Every data section must open with a <div class="section-summary"> containing 2–3 sentences synthesizing the section’s impact. Cover: total volume, standout items, and business/technical significance. Interpret — don’t just repeat the table.

Executive summary

3–5 sentences in third person, past tense, executive-readable prose. Cover:

  • Major outcomes (epics closed, features shipped, security work)
  • Breadth of contribution (repos, systems, teams)
  • Standout contributions (CVEs, governance, proposals → merged)
  • Quantified signal (“50+ PRs merged across 15 repos”)

Sections to include (omit any with zero results)

  1. Executive Summary (always)
  2. Jira — Epics & Features Closed
  3. GitHub — PRs Authored & Merged (grouped by repo, with group headers like “⚡ Tekton Core”, “🏛 Community”)
  4. GitHub — PRs Reviewed (grouped by repo)
  5. GitHub — Issues Filed (grouped by theme)
  6. GitHub — Security Advisories (credited/authored only)
  7. GitLab — MRs Reviewed (grouped by release track)
  8. Key Initiatives & Strategic Contributions (achievement grid)
  9. Meeting & Cross-Team Engagement (Google Calendar)
  10. Documents & Presentations (Google Drive)
  11. Communication Highlights (mu/Gmail — notable outbound threads)
  12. Areas of Focus (tag cloud)

Stats strip values

Count from the collected data:

  • Epics Closed (Jira epics/features with Done status)
  • GitHub PRs Merged (authored)
  • GitHub PRs Reviewed
  • Issues Filed
  • Security Advisories (credited/authored)
  • Jira Issues Closed
  • GitLab MRs Reviewed (if available)

Step 5 — Write Output

# Write the HTML report
write ~/desktop/downloads/q<N>-<YEAR>-achievements-vincent-demeester.html

Confirm to the user: file path, total counts, any data sources that were unavailable.

Common Mistakes

Mistake Fix
Including personal repos (vdemeester/*) Exclude — only include org repos (tektoncd, openshift-pipelines, etc.)
Plain text Jira keys, PR titles, MR titles Always hyperlink with <a> tags
Including Jira Stories/Tasks in the epics section Filter for issuetype in (Epic, Feature) only
Using MCP gitlab plugin for internal GitLab MCP targets gitlab.com — use REST API for gitlab.cee.redhat.com
author_username on global MR endpoint Use author_id (numeric) + scope=all
Missing section summaries Every card must have a section-summary div
Sections with zero results Omit entirely — no “No items found” text
Forgetting to load GITLAB_TOKEN Load from passage or ask user before GitLab queries

Graceful Degradation

If a data source is unavailable:

  1. GitLab token missing → Skip GitLab section, note in footer
  2. Google Workspace not configured → Skip Gmail/Drive sections
  3. Slack not configured → Skip Slack section
  4. daily-plan not found → Fall back to direct gh + Jira CLI queries
  5. Always note unavailable sources in the footer “Data sources” line