← gitpulse
New Feature·Pushed May 1, 2026·M

Git history now generates editorial stories via LLM

The gitpulse GitHub Action now reads local commit history, asks an LLM to write a journalistic story for each commit, and outputs Story JSON. Works with any OpenAI-compatible endpoint.

Gitpulse now turns commit history into editorial content automatically. The action walks the git log on the default branch, sends each commit's metadata to an OpenAI-compatible LLM, and writes structured Story JSON to the site content directory. The pipeline processes commits from the last 30 days by default (configurable via [[code]]GITPULSE_BOOTSTRAP_DAYS[[/code]]), calling out to the LLM for a headline, standfirst, and body text. Each story includes the SHA, author, commit URL, and classification—all marked as direct-push for this initial version. The GitHub Actions workflow now accepts provider-neutral inputs: [[code]]ai-model[[/code]], [[code]]ai-base-url[[/code]], and [[code]]ai-temperature[[/code]]. Switching from OpenAI to Groq, OpenRouter, or MiniMax requires only updating the base URL. The same [[code]]OPENAI_API_KEY[[/code]] secret works across all OpenAI-compatible providers. Currently every commit gets classified as direct-push. Pull request classification via GraphQL associatedPullRequests is planned for Phase 2.1. In the [[code]]@gitpulse/action[[/code]] package.
Technical description
This PR introduces Phase 2 of the gitpulse GitHub Action: a complete pipeline that transforms raw git commits into editorial stories using a large language model. **The Pipeline** The orchestration lives in [[code ref=6]]main[[/code]]. It loads configuration, determines the default branch via [[code ref=3]]walkCommits[[/code]], calculates a date cutoff (N days ago), then iterates each commit—calling the LLM and writing the result. The git layer uses git log with a custom format string and ASCII record/field separators. Each commit record is parsed and augmented with diff stats (files changed, insertions, deletions) parsed from [[code]]git show --shortstat[[/code]]. No external Git library is used—only [[code]]execSync[[/code]]. The LLM layer wraps LangChain's [[code ref=4]]createSummarizer[[/code]] with structured output via a zod schema. The schema enforces constraints: headlines 8-120 characters, no trailing period, no emoji; body 80-1200 characters of plain prose. The system prompt specifies a "beat reporter" voice—dry, precise, no marketing speak. Trivial commits (typo fixes, dependency bumps) are acknowledged plainly rather than dramatized. Stories are rendered by [[code ref=5]]buildStoryFromCommit[[/code]] into a [[code ref=1]]Story[[/code]] object and written as pretty-printed JSON to [[code]]site/src/content/stories/{commit-sha}.json[[/code]]. **Configuration** [[code ref=2]]loadConfig[[/code]] reads environment variables with sensible defaults: - [[code]]OPENAI_API_KEY[[/code]] (required) - [[code]]AI_MODEL[[/code]] defaults to gpt-4o-mini - [[code]]AI_BASE_URL[[/code]] is optional—empty means use OpenAI directly; setting it redirects to any OpenAI-compatible endpoint - [[code]]AI_TEMPERATURE[[/code]] defaults to 0.7 - [[code]]GITPULSE_BOOTSTRAP_DAYS[[/code]] defaults to 30 - [[code]]GITPULSE_LIMIT[[/code]] for testing small batches The workflow file was updated to use provider-neutral input names matching the env vars (ai-model, ai-base-url, ai-temperature). **Scope Limitations** All commits are currently classified as [[code]]"direct-push"[[/code]]. The PR classification via GitHub's GraphQL associatedPullRequests is explicitly deferred to Phase 2.1. ````mermaid graph LR A[git log] --> B[walkCommits] B --> C[for each commit] C --> D[createSummarizer] D --> E[LLM with zod schema] E --> F[Story JSON] F --> G[site/src/content/stories/] ```` **Files at a Glance** - [[code]]action/src/types.ts[[/code]] — [[code ref=1]]Story[[/code]], [[code]]CommitRecord[[/code]], [[code]]AISummary[[/code]] interfaces - [[code]]action/src/config.ts[[/code]] — [[code ref=2]]loadConfig[[/code]] with env-driven runtime configuration - [[code]]action/src/git.ts[[/code]] — [[code ref=3]]walkCommits[[/code]] using git log format strings and diff stat parsing - [[code]]action/src/llm.ts[[/code]] — [[code ref=4]]createSummarizer[[/code]] with LangChain ChatOpenAI and zod structured output - [[code]]action/src/render.ts[[/code]] — [[code ref=5]]buildStoryFromCommit[[/code]] and [[code]]writeStory[[/code] - [[code]]action/src/index.ts[[/code]] — [[code ref=6]]main[[/code]] orchestration entry point - [[code]].github/workflows/analyze.yml[[/code]] — provider-neutral workflow inputs (ai-model, ai-base-url, ai-temperature) - [[code]]action/package.json[[/code]] — added [[code]]analyze[[/code]] script - [[code]]action/tsconfig.json[[/code]] — added [[code]]noEmit[[/code]] and [[code]]allowImportingTsExtensions[[/code]] for tsx support

Categories

  • New Feature (75%)Core purpose: adds a new local-git-to-LLM-to-story pipeline that generates editorial content from commit history
  • Configuration (25%)Workflow inputs renamed to provider-neutral names; new environment-driven config layer added