Skip to content

jongalloway/newsletter-generator

Repository files navigation

newsletter-generator

Automated newsletter generator for GitHub Copilot CLI/SDK, VS Code Insiders, or DevTech MVP updates.

Note: This tool was built for generating internal team newsletters, but all source data comes from public release feeds and blog posts. You're welcome to fork and adapt it for your own newsletter needs.

What it does

This tool generates a curated weekly newsletter by:

  1. Fetching release notes, changelog entries, and blog posts from GitHub
  2. Filtering out low-value content (dependency bumps, CI changes, attributions, etc.)
  3. Summarizing using GitHub Copilot SDK to create concise, factual summaries
  4. Caching generated content to avoid regenerating unchanged sections

At startup, you'll choose:

  • Newsletter type - GitHub Copilot CLI/SDK, VS Code Insiders, or DevTech MVP
  • Copilot model - The model used for newsletter generation prompts
  • Cache behavior - Use cache, clear cache, or force refresh for the run

The console UI now includes:

  • Progress tasks for feed fetch and generation stages
  • Run Review confirmation before generation
  • Run Dashboard summary with source counts, cache stats, stage durations, and a release tree showing prereleases that were rolled up or skipped

The output is a markdown newsletter. Sections vary by newsletter type:

  • Copilot CLI/SDK — Welcome, News & Announcements, Project Updates
  • VS Code — Welcome, This Week in VS Code Stable, VS Code Insiders Highlights, News and Announcements (if applicable)
  • DevTech MVP — Welcome, Copilot CLI & SDK, VS Code, Visual Studio, Major Releases (auto-detected), Developer Blogs, Developer Videos

Information flow

flowchart LR
    subgraph Sources[Public data sources]
        FEEDS[Atom/RSS feeds\nGitHub · Microsoft · YouTube]
        VSCODE[VS Code Insiders\nrelease notes markdown]
    end

    subgraph Ingestion[Ingestion and normalization]
        ATOM[AtomFeedService]
        VS[VSCodeReleaseNotesService]
        FILTER[HTML stripping and\nlow-value filtering]
        PRE[Prerelease consolidation]
    end

    subgraph App[Generation pipeline]
        INPUT[Date range +\nnewsletter type + model]
        CACHE[CacheService\nsection cache]
        PROMPTS[NewsletterService\nprompts]
        COPILOT[GitHub Copilot SDK\nCopilotClient + CopilotSession]
        SECTIONS[Section content + title]
    end

    subgraph Output[Run results]
        DASH[Console progress +\nrun dashboard]
        FILE[output/newsletter-...md]
        LOGS["log/newsletter-{Date}.log"]
    end

    FEEDS --> ATOM
    VSCODE --> VS
    ATOM --> FILTER
    VS --> FILTER
    FILTER --> PRE
    INPUT --> CACHE
    PRE --> CACHE
    CACHE -->|cache hit| SECTIONS
    CACHE -->|cache miss| PROMPTS
    INPUT --> PROMPTS
    PROMPTS --> COPILOT
    COPILOT --> SECTIONS
    SECTIONS --> CACHE
    SECTIONS --> DASH
    PRE --> DASH
    SECTIONS --> FILE
    INPUT --> DASH
    DASH --> LOGS
Loading

Date logic

At startup, the tool asks how many days back to include (default: 7).

  • End date is always today
  • Start date is today minus the selected number of days

You can pass daysBack as a command argument to skip the prompt.

Usage

Basic usage

cd src/NewsletterGenerator
dotnet run

This generates a newsletter using the automatic date logic described above.

Commands

dotnet run -- generate
dotnet run -- list-models
dotnet run -- doctor
dotnet run -- clear-cache

generate is the default command, so dotnet run -- ...options... works without explicitly typing generate.

Tests

The repo includes an xUnit test project for feed parsing, cache behavior, prerelease consolidation, and VS Code release note parsing.

dotnet test

Generate options

Clear cache and regenerate everything:

dotnet run -- --clear-cache
dotnet run -- -c

Force refresh (ignore cache reads this run):

dotnet run -- --force-refresh
dotnet run -- -f

Custom date range (N days back from today):

dotnet run -- 7              # Last 7 days ending today
dotnet run -- 14             # Last 14 days ending today

Combine flags:

dotnet run -- --clear-cache 7

Choose newsletter type via CLI:

dotnet run -- --newsletter copilot
dotnet run -- --newsletter vscode
dotnet run -- --newsletter devtech

Choose model via CLI:

dotnet run -- --model gpt-5.3-codex
dotnet run -- --model gpt-4.1

Skip the pre-run confirmation prompt:

dotnet run -- --yes

Show full exception details:

dotnet run -- --debug

Enable infinite sessions for interactive revision loops:

dotnet run -- --infinite-sessions

Non-interactive mode

Use non-interactive mode for redirected output, scripts, or CI.

Required in --non-interactive mode:

  • --newsletter
  • --model
  • daysBack

Example:

dotnet run -- --non-interactive --newsletter copilot --model gpt-5.3-codex --force-refresh 7

Output

Generated newsletters are saved to:

output/newsletter-copilot-cli-sdk-YYYY-MM-DD.md
output/newsletter-vscode-YYYY-MM-DD.md
output/newsletter-devtech-mvp-YYYY-MM-DD.md

The filename uses the end date of the coverage period and includes the newsletter slug.

After each interactive generation run, the app prompts whether to start again from the beginning.

Caching

The tool caches:

  • Feed data (atom/RSS feeds)
  • Generated summaries for each section

Cache files are stored in src/NewsletterGenerator/.cache/ and use SHA256 hashing to detect changes in source data. The app resolves this location relative to the repository root, so it uses the same cache directory whether you run it from src/NewsletterGenerator or from the repo root. When source data changes, that section is regenerated. Use the clear-cache command or --clear-cache with generate to force regeneration of all content.

Configuration

The tool fetches from these sources:

Copilot CLI/SDK & shared sources:

VS Code Insiders:

DevTech MVP (includes the Copilot and VS Code sources above, plus):

Filtering rules and summarization prompts can be modified in:

  • Services/AtomFeedService.cs - Regex filters for release notes
  • Services/NewsletterService.cs - AI prompts and generation logic

GitHub Copilot SDK features used

This project uses the GitHub.Copilot.SDK NuGet package and exercises these SDK features:

Feature Where Why
Streaming All AI sessions (Streaming = true) Enables incremental response delivery; delta events are logged for diagnostics
ReasoningEffort profiles ResolveReasoningEffort(operationProfile), ReasoningEffort = reasoningEffort Uses low/medium/high profiles by operation so short summaries stay cheaper and larger sections get more headroom
SendAndWaitAsync session.SendAndWaitAsync(new MessageOptions { Prompt = prompt }), AssistantMessageEvent, AssistantMessageDeltaEvent, SessionIdleEvent, SessionErrorEvent Submits prompts and waits for the final assistant message while still streaming deltas and idle events
Session hooks OnErrorOccurred, OnSessionStart, OnSessionEnd SDK-level error retry and session lifecycle logging without manual plumbing
Deterministic session resume BuildSessionId(runContext, workflowStep, model), ResumeSessionAsync(...) Reuses the last matching session for repeat runs when a workflow step and run context are available
ClientName All AI sessions (ClientName = "newsletter-generator") Tags requests with a stable application identity, which is useful for diagnostics and example code
Permission policy / tool restrictions All AI sessions (AvailableTools = [], OnPermissionRequest = PermissionHandler.ApproveAll) Uses a least-privilege session policy because newsletter generation does not request tool access
Model fallback SetModelAsync(nextModel) Switches models in-session when the active model fails, instead of restarting from scratch
Usage metrics session.Rpc.Usage.GetMetricsAsync(), session.SessionId Captures prompt/output token usage for each operation and ties it to the session ID
PingAsync doctor command + startup status Lightweight connectivity check without creating a full session
ListModelsAsync Model selection, list-models command Enumerate available models for interactive selection
System messages SystemMessageMode.Replace on all sessions Full control over system prompt for editorial tone and output formatting
Infinite sessions (interactive revisions) InfiniteSessions = new InfiniteSessionConfig { Enabled = true }, --infinite-sessions Keeps multi-pass revision loops in a single long-running session
Event-driven responses AssistantMessageEvent, AssistantMessageDeltaEvent, SessionIdleEvent, SessionErrorEvent Collect final responses and streaming deltas via pattern matching
GetAuthStatusAsync Startup status table Display authentication state before generation

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors