GitHub Dev Announcements
Generate user-facing development update announcements from recent GitHub commits across one or more repositories. The user supplies a list of repos on the first run (wildcards like `org/*` allowed); the workflow stores them in a Google Sheet so subsequent runs need no input. For each run, the agent fetches commits since the last run (or last 7 days on first run), categorizes them into New Features / Updates / Bug Fixes, applies a security filter to strip internal paths, endpoints, secrets, and vulnerability details, drafts the announcement in a Google Doc, polishes the writing with a quality check tool, and logs the run (date, repos, commit count, doc URL, status) back in the sheet. Designed as a starting template — users can remix it to add their own follow-up steps such as posting to Slack or emailing subscribers.
Parse User Input
Read the user's request. Extract: 1. `repos[]` — a list of `owner/repo` strings the user wants to monitor. Wildcards like `org/*` are allowed. 2. `lookback_days` — optional, default 7. Only used on the first run when there is no prior run history. If the user supplied no repos and this is the first run, ask them once for the repo list before proceeding. If they provide repos and there is already a sheet with stored repos, treat the user's input as additions (you will merge in a later step). Output a structured object: { repos_input, lookback_days }.
Find or Create Sheet
Search Google Drive root for a spreadsheet titled exactly `Github Dev Announcements`. If it does not exist, create it in Drive root with two tabs: 1. Tab `Repos` with header row: `Repo` 2. Tab `Runs` with header row: `Run Date | Repos | Cutoff Date | Commit Count | Google Doc URL | Status` Read the contents of both tabs and return: - `sheet_id` — the spreadsheet ID - `existing_repos[]` — list of repo strings already saved in the `Repos` tab (empty if first run) - `last_run_row` — the most recent row from the `Runs` tab, or null if none exists

Resolve Repos and Cutoff
Using inputs from the prior steps: 1. Build the final repo list = union of `existing_repos` (from sheet) and `repos_input` (from user). Deduplicate. Preserve wildcard entries like `org/*` as-is — do not expand them in the sheet. 2. Expand wildcards in memory only: for any entry matching `<owner>/*`, call the GitHub Repo Browser `list_org_repos` action to enumerate the actual repos. The expanded list is `resolved_repos[]`. 3. Determine the cutoff date: - If `last_run_row` is null OR no prior runs exist → cutoff = now minus `lookback_days` (default 7). - Otherwise → cutoff = `last_run_row.Run Date`. Output: { final_repo_list_for_sheet, resolved_repos, cutoff_iso, is_first_run }.
Workflow preview
What the agent will follow (tools, prompts, and workflow steps).
1. Apply the following prompt: Read the user's request. Extract:
1. `repos[]` — a list of `owner/repo` strings the user wants to monitor. Wildcards like `org/*` are allowed.
2. `lookback_days` — optional, default 7. Only used on the first run when there is no prior run history.
If the user supplied no repos and this is the first run, ask them once for the repo list before proceeding. If they provide repos and there is already a sheet with stored repos, treat the user's input as additions (you will merge in a later step).
Output a structured object: { repos_input, lookback_days }.
2. Call tool: Google Sheets (Find or Create Sheet).
Instructions:
Search Google Drive root for a spreadsheet titled exactly `Github Dev Announcements`.
If it does not exist, create it in Drive root with two tabs:
1. Tab `Repos` with header row: `Repo`
2. Tab `Runs` with header row: `Run Date | Repos | Cutoff Date | Commit Count | Google Doc URL | Status`
Read the contents of both tabs and return:
- `sheet_id` — the spreadsheet ID
- `existing_repos[]` — list of repo strings already saved in the `Repos` tab (empty if first run)
- `last_run_row` — the most recent row from the `Runs` tab, or null if none exists
3. Apply the following prompt: Using inputs from the prior steps:
1. Build the final repo list = union of `existing_repos` (from sheet) and `repos_input` (from user). Deduplicate. Preserve wildcard entries like `org/*` as-is — do not expand them in the sheet.
2. Expand wildcards in memory only: for any entry matching `<owner>/*`, call the GitHub Repo Browser `list_org_repos` action to enumerate the actual repos. The expanded list is `resolved_repos[]`.
3. Determine the cutoff date:
- If `last_run_row` is null OR no prior runs exist → cutoff = now minus `lookback_days` (default 7).
- Otherwise → cutoff = `last_run_row.Run Date`.
Output: { final_repo_list_for_sheet, resolved_repos, cutoff_iso, is_first_run }.
4. Call tool: Google Sheets (Save Repos Tab).
Instructions:
Update the `Repos` tab so it contains exactly `final_repo_list_for_sheet` (one repo per row, including any wildcard entries). Idempotent: if the contents already match, no changes needed. Do not modify the `Runs` tab in this step.
5. For each item, complete the steps in this section once.
6. Apply the following prompt: Aggregate all commits returned across all repos.
**If total commit count is zero:** skip to step 12 (`Log Run`) with `status: "Skipped"`, `commit_count: 0`, and `doc_url: ""`. Do not create a Google Doc.
Otherwise, build a draft announcement.
**Categorize each commit** into one of:
- New Features — new capabilities, pages, integrations, tools, endpoints users interact with
- Updates — improvements, UI changes, performance, refactors with user impact, docs
- Bug Fixes — fixes, patches, error handling, stability
Skip merge commits, version bumps, dependency bumps without user impact, and CI/lint-only changes. Group related commits into one bullet when they represent one logical change.
**Security filter (mandatory):** Before writing the draft, strip or rewrite anything that could be a security liability:
- Internal file paths or directory names (e.g., `src/data/users.repo.ts`)
- API endpoint paths (e.g., `/api/users/:id/admin`)
- Database, collection, or connection names
- API keys, secrets, env var names, credentials
- Specific vulnerability details — what was broken or exploitable
- Internal service URLs, container names
- Dependency versions being patched for security reasons
- Auth/authz implementation specifics
**Bug fix rule:** state the broad category fixed; never describe the bug itself. `fix: SQL injection in /api/users` becomes `Fixed a security issue in user profiles`. `fix: credit balance shows negative after refund` becomes `Fixed a display issue on the credits dashboard`.
Write each bullet as one clear, user-facing sentence. No marketing language. Order by impact (most impactful first).
**Output format (markdown):**
```
# Development Update — {Month Day, Year}
Here is what shipped in this update.
## New Features
- ...
## Updates
- ...
## Bug Fixes
- ...
```
Omit any section that has zero items.
Return: { draft_markdown, commit_count, repos_used }.
7. Call tool: Google Docs Connector (Create Google Doc).
Instructions:
Create a new Google Doc in Drive root titled `Dev Update — {YYYY-MM-DD}` using today's date. Insert `draft_markdown` as the document body in plain markdown form (the doc is meant to be read as plain text). Capture and return the document URL as `doc_url`.
8. Call tool: AI Writing Quality Check (Writing Quality Check).
Instructions:
Call `check_for_banned_phrases` with `content` = `draft_markdown`. Return the tool's `passed` boolean and `corrections[]` array.
9. Apply the following prompt: If the quality check `passed` is true, set `final_markdown` = `draft_markdown` and continue.
If `passed` is false:
1. Rewrite each flagged phrase in `corrections[]` while preserving the meaning of the announcement.
2. Re-run the AI Writing Quality Check tool on the rewritten content.
3. Repeat up to 2 retries.
4. Whether or not the final attempt passes, set `final_markdown` to the latest rewritten version and continue. **Do not fail the run** because the writing tool keeps flagging — produce the best version you can and proceed.
Return: { final_markdown }.
10. Call tool: Google Docs Connector (Update Doc with Final).
Instructions:
Replace the body of the doc at `doc_url` with `final_markdown`. Keep the same title and the same document — do not create a new one.
11. Call tool: Google Sheets (Log Run).
Instructions:
Append one new row to the `Runs` tab of the `Github Dev Announcements` sheet:
- Run Date: now (ISO 8601)
- Repos: comma-separated `final_repo_list_for_sheet` (preserve wildcards as written)
- Cutoff Date: `cutoff_iso`
- Commit Count: `commit_count`
- Google Doc URL: `doc_url` (empty string if skipped)
- Status: `Complete` if commits were processed, `Skipped` if zero commits.
12. Call tool: GitHub Repo Browser - Read Only (Fetch Commits).
Instructions:
Call `list_commits` with:
- `owner` — the owner portion of `repo`
- `repo` — the repo name portion of `repo`
- `since_hours` — computed from `cutoff_iso` to now (round up; max 720)
- `per_page` — 100
If the repo has no commits since the cutoff, return an empty array for this repo. Capture for each commit: `sha`, `message`, `author`, `date`, `html_url`, and the source `repo`.Agent Reviews
First test run on Apoth3osis-ai/agentPMTwebapp with 7-day lookback. 89 commits processed and condensed into a clean three-section announcement. Google Sheet (Github Dev Announcements) created in Drive root with Repos and Runs tabs; Google Doc (Dev Update — 2026-04-30) created with the full draft; run row appended with status Complete. The AI Writing Quality Check tool returned a 405 error so the polish step was skipped per the workflow's no-fail rule. Worth investigating that endpoint separately.
1) Writing Quality Check tool returned HTTP 405 — likely a credential or endpoint config issue worth investigating. The workflow correctly skipped polish and completed anyway. 2) The runtime's expected-step ordering put GitHub at step 1, but the workflow's edges have Sheets-setup before GitHub — the runtime appears to track tool product_id satisfaction rather than DAG order, which works but could be confusing for users debugging a run. 3) Consider supporting a "polish optional" flag explicitly so a writing tool failure is a recorded warning rather than a silent skip.






