Summarize PRs in Slack
Reviewers open every PR already knowing what changed, why, and where to start reading.
- ongithub pr.opened
- slackpost heads-up in #engineering
- agentsummarize the diff
- slackreply in thread
Review latency is mostly orientation cost: before anyone comments, someone has to work out what a PR is actually doing. This job pays that cost once, at open time. The moment a pull request opens, it posts a heads-up in the team channel, has an agent read the diff, and threads a summary under the heads-up — what changed, why it matters, and what reviewers should look at first.
How it works
- Trigger — a pull request opens in the target repo; PRs from bots are filtered out before the job runs.
- Heads-up — a deterministic tool call posts one line to the engineering channel: who opened what. Fixed channel, fixed format, no agent involved.
- Summary —
generateTextruns with the GitHub skill scoped to the repo, so the agent can read the diff, the changed files, and recent commits. - Thread reply — the summary posts as a threaded reply under the heads-up, keeping the channel to one line per PR.
Requirements
- A Terse project (
terse init) with the GitHub and Slack integrations connected (terse integrate connect github, thenslack). terse generaterun after connecting, soRepos.*andSlackChannel.*exist as typed constants insrc/terse.generated.ts.- A repo to watch and a channel to post to — the only two decisions this job needs.
The job
import { createJob, generateText, type GithubPROpenedTrigger } from "terse-sdk";
import {
Triggers,
Skills,
Repos,
SlackChannel,
toolbox,
} from "../terse.generated";
createJob({
name: "Summarize PR and notify Slack",
triggers: [Triggers.github.onPROpened({ repo: Repos.MyOrg.MyRepo })],
filter: async (event: GithubPROpenedTrigger) => {
return !event.sender.login.includes("[bot]");
},
onTrigger: async (event: GithubPROpenedTrigger) => {
// Deterministic: fixed channel, fixed opener — use toolbox, no agent needed
const message = await toolbox.slack.sendMessage({
channelId: SlackChannel.Engineering.channelId,
message: `New PR from ${event.sender.login}: ${event.pullRequest.title}`,
thread_ts: "",
blocks: "",
});
// Agentic: only the summary needs judgment
const summary = await generateText({
prompt:
`Summarize the changes in this PR. ` +
`Focus on what changed, why it matters, and what reviewers should look at first. ` +
`Keep it concise. Context: ${event.formatForAgentRunner()}`,
skills: [Skills.github({ repos: [Repos.MyOrg.MyRepo] })],
});
// Deterministic: post the result back in thread
await toolbox.slack.sendMessage({
channelId: SlackChannel.Engineering.channelId,
message: summary,
thread_ts: message.message_ts,
blocks: "",
});
},
});Repos.MyOrg.MyRepo and SlackChannel.Engineering aren't strings you look up
— they're typed constants generated from your connected workspace by
terse generate, so a renamed channel is a compile error, not a silent
misfire.
Make it yours
- Scope by path. Only summarize PRs that touch
src/or a critical directory — add the check to thefilter. - Route by team. Map
CODEOWNERSentries to different channels and send each summary where its reviewers actually live. - Add risk flags. Extend the prompt to call out migrations, dependency bumps, and auth-adjacent changes explicitly.
- Cover follow-up pushes. Add
Triggers.github.onPRSynchronized()to re-summarize when new commits land on an open PR.
For coding agents
This page is a build template. To implement it in a Terse project:
- Satisfy the Requirements section above (init, connect, generate).
- Create
src/jobs/pr-summaries-in-slack.tswith the job above and addimport "./jobs/pr-summaries-in-slack"tosrc/terse.jobs.ts. - The constants (
Repos.*,SlackChannel.*) and trigger/skill factories must come from the user's ownsrc/terse.generated.ts— verify every name there and substitute the user's real repo and channel. Never invent names. - Ask the user which repo and channel to target, test with
terse test run "Summarize PR and notify Slack"against a pinned sample event, then deploy withterse deployafter they confirm.

Apollo
PostHog