agentsclimarketplace

Post daily new issues

Skill warpdotdev/client-release-agent-oss/.warp/skills/post-daily-new-issues

Post the daily digest of new Sentry issues for the current stable release to an on-call Slack channel. Use when the user asks to run or post the daily stable Sentry digest for on-call.From its SKILL.md

Install
npx -y skills add warpdotdev/client-release-agent-oss --skill post-daily-new-issues

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

11.5 KB, ~3.1k tokens by cl100k_base, as published. Nobody here has run it

post-daily-new-issues

Post a daily digest of new Sentry issues for the current release on $DIGEST_CHANNEL (default stable) to an on-call Slack channel, tagging the on-call usergroup. The digest is scoped to a single calendar date so a scheduled agent can run this once per weekday without re-reporting issues that were already shared on a previous day.

Configuration

This skill reads environment-specific values from environment variables (see the repo README.md):

  • SLACK_BOT_TOKEN — Slack bot token with channels:read, chat:write, usergroups:read scopes.
  • SENTRY_AUTH_TOKEN — Sentry auth token with event:read and project:read scopes. Used to call the Sentry REST API directly.
  • SENTRY_ORG — Sentry org slug.
  • SENTRY_PROJECT — Sentry project slug (e.g. your release client project).
  • SENTRY_PROJECT_ID — numeric Sentry project ID (used to build release URLs).
  • RELEASE_SLACK_CHANNEL — Slack channel name (or ID) to post the digest in.
  • ONCALL_SLACK_GROUP — Slack usergroup handle for the on-call (e.g. oncall-primary).
  • RELEASE_VERSIONS_URL — optional public URL returning a JSON document with the current release version. Omit if you pass a version explicitly.
  • DIGEST_CHANNEL — channel whose release the digest reports on (default stable); also selects the version key read from RELEASE_VERSIONS_URL.

Step 0: Decide whether to run today (weekend skip)

This skill is intentionally a no-op on Saturday and Sunday. Compute the day of week in UTC:

DOW=$(date -u +%u)   # 1=Mon ... 7=Sun
  • If DOW is 6 (Sat) or 7 (Sun): print a short note (e.g. "Skipping: weekend") and exit without posting to Slack.
  • Otherwise continue.

If the caller passed an explicit target date (see Step 2), skip this step entirely and use what they provided.

Step 1: Find the current release version

If RELEASE_VERSIONS_URL is set, read the current version for $DIGEST_CHANNEL from it. The exact JSON path depends on your release metadata format; the channel key is selected by $DIGEST_CHANNEL, for example:

RELEASE_VERSION=$(curl -fsS "$RELEASE_VERSIONS_URL" | jq -r --arg ch "$DIGEST_CHANNEL" '.[$ch].version')

RELEASE_VERSION looks like v0.YYYY.MM.DD.HH.MM.stable_NN (a documented example template — adjust to match the version scheme your release pipeline emits). If RELEASE_VERSIONS_URL is unset, ask the user for the current release version. If the field is missing or curl fails, stop and surface the error — do not post a partial digest.

Step 2: Compute the target date window

The window is a half-open UTC interval [START_DATE, END_DATE) (i.e. firstSeen >= START_DATE AND firstSeen < END_DATE). Both are YYYY-MM-DD strings.

The default behavior depends on which weekday the agent is running:

  • Tue–Fri (DOW 2–5): report yesterday only.
    • START_DATE = yesterday (UTC), END_DATE = today (UTC).
  • Mon (DOW 1): report Saturday + Sunday + the previous Monday's overnight, because the agent did not run on the weekend.
    • START_DATE = 3 days ago (UTC, that Saturday), END_DATE = today (UTC, that Monday).

On macOS (BSD date):

TODAY=$(date -u +%Y-%m-%d)
if [ "$DOW" = "1" ]; then
  START_DATE=$(date -u -v-3d +%Y-%m-%d)   # Saturday
else
  START_DATE=$(date -u -v-1d +%Y-%m-%d)   # Yesterday
fi
END_DATE=$TODAY

On Linux (GNU date, e.g. inside a remote environment):

TODAY=$(date -u +%Y-%m-%d)
if [ "$DOW" = "1" ]; then
  START_DATE=$(date -u -d '3 days ago' +%Y-%m-%d)
else
  START_DATE=$(date -u -d 'yesterday' +%Y-%m-%d)
fi
END_DATE=$TODAY

Override: if the user explicitly asks for a different window (e.g. "post the digest for 2026-04-25"), use their dates instead and skip the weekend check.

Step 3: Fetch new issues from Sentry

Call the Sentry REST API directly with $SENTRY_AUTH_TOKEN. The query string must include both:

  1. firstRelease:<RELEASE_VERSION> — restricts to issues whose first-seen release matches the live release build (this matches Sentry's "New Issues" tab on the release page).
  2. firstSeen:>=START_DATE firstSeen:<END_DATE — narrows to the target window so already-reported issues from previous days are excluded. This is the noise-control mechanism; do not omit it.

Sort by frequency (sort=freq) and request limit=100 so the true total and the top 3 are both stable even if there's a long tail of one-event issues.

QUERY="firstRelease:${RELEASE_VERSION} firstSeen:>=${START_DATE} firstSeen:<${END_DATE}"

ISSUES_JSON=$(curl -fsS -G "https://sentry.io/api/0/projects/${SENTRY_ORG}/${SENTRY_PROJECT}/issues/" \
  -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
  --data-urlencode "query=$QUERY" \
  --data-urlencode "sort=freq" \
  --data-urlencode "limit=100")

The response is a JSON array. Each element has at least: shortId, title, count (event count, as a string), userCount, firstSeen, lastSeen, permalink. Parse it with jq.

If the array is empty, exit silently — do NOT post anything to Slack. Print a short note like "No new issues in window; skipping post" so the run log makes the no-op visible, then stop. The on-call channel should only get a message when there's something to act on; an empty digest just adds noise.

Step 4: Compute the total and pick the top 3

The message has two distinct numbers, and they must come from different slices of the response:

  • TOTAL_NEW_ISSUES — the full count of new issues in the window (used in the "N new issues since …" summary line). Compute this from the entire array, before any truncation.
  • Top 3 issues — the first 3 entries by event count, used to populate the bullet list. The list is intentionally short to keep the digest scannable; the on-call clicks through to Sentry for the long tail.

For each of the top 3, capture:

  • Short ID from .shortId
  • Title from .title — truncate to ~140 chars on a single line
  • Event count from .count (cast to int)
  • User count from .userCount
  • Issue URL: prefer .permalink if present, else build it as https://${SENTRY_ORG}.sentry.io/issues/<SHORT_ID>

If fewer than 3 issues exist, include all of them.

Example jq to compute both numbers in one pass:

TOTAL_NEW_ISSUES=$(printf '%s' "$ISSUES_JSON" | jq 'length')

BULLETS=$(printf '%s' "$ISSUES_JSON" | jq -r --arg org "$SENTRY_ORG" '
  [.[] | {
    short: .shortId,
    title: (.title | gsub("\n"; " ") | .[0:140]),
    events: (.count | tonumber),
    users: .userCount,
    url: (.permalink // ("https://" + $org + ".sentry.io/issues/" + .shortId))
  }]
  | sort_by(-.events)
  | .[0:3]
  | map("• <\(.url)|\(.short)> — \(.events) events, \(.users) users — \(.title)")
  | join("\n")
')

Step 5: Resolve Slack IDs

Resolve once per run. If the channel ID and subteam ID are stable in your environment you may cache them, but always validate they still match.

# Channel ID for $RELEASE_SLACK_CHANNEL
CHANNEL_ID=$(curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  "https://slack.com/api/conversations.list?types=public_channel,private_channel&limit=1000" | \
  jq -r --arg name "$RELEASE_SLACK_CHANNEL" '.channels[] | select(.name==$name) | .id')

# Subteam ID for the on-call usergroup
SUBTEAM_ID=$(curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  "https://slack.com/api/usergroups.list" | \
  jq -r --arg handle "$ONCALL_SLACK_GROUP" '.usergroups[] | select(.handle==$handle) | .id')

If either lookup is empty, surface the error and stop — do not guess IDs.

Step 6: Format and post the message

Use Slack Block Kit. The mention must be <!subteam^${SUBTEAM_ID}> so it actually pings the on-call group. Build a text fallback for notifications and search.

Build the Sentry release link first — every message must include it so the on-call can jump straight into the filtered "new issues" view:

RELEASE_URL="https://${SENTRY_ORG}.sentry.io/explore/releases/${RELEASE_VERSION}/?issuesType=new&project=${SENTRY_PROJECT_ID}"

The issuesType=new query param is what pre-selects the New Issues tab; do not omit it. project=${SENTRY_PROJECT_ID} is the numeric ID for your Sentry project.

Message structure:

  1. Header: <RELEASE_VERSION>: new Sentry issues for <date or range>
  2. Section with the subteam mention and a one-line summary that uses the true total, not the bullet count. Example: <!subteam^S012345> — ${TOTAL_NEW_ISSUES} new issues since <START_DATE> · <RELEASE_URL|View in Sentry> On a Monday run, phrase the window as since Saturday instead of a bare date.
  3. Section listing only the top 3 issues by event count, one per line, in this format:
• <ISSUE_URL|SHORT_ID> — <events> events, <users> users — <title>
  1. Section with a triage reminder, e.g.: _Please <${RELEASE_URL}|review the full New Issues tab in Sentry> and triage._ This is what tells the on-call the bullets are only a sample and that they need to click through.

Use Slack mrkdwn link syntax (<URL|text>) inside mrkdwn blocks. Keep titles on a single line; truncate with if needed.

If TOTAL_NEW_ISSUES is zero, do not reach this step — the skill exits in Step 3 without posting. There is no "all clear" message; silence is the all-clear signal.

Date display:

  • Tue–Fri: show START_DATE (e.g. 2026-04-28 (UTC)).
  • Mon: show the range, e.g. Sat 2026-04-25 – Mon 2026-04-27 (UTC).

Post as a top-level message (no thread_ts). Suppress link previews so the message stays compact — with several Sentry links per post, unfurls would dominate the channel:

curl -s -X POST \
  -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  -H "Content-Type: application/json" \
  --data "$(jq -n \
    --arg channel "$CHANNEL_ID" \
    --arg text "$TEXT_FALLBACK" \
    --argjson blocks "$BLOCKS_JSON" \
    '{channel: $channel, text: $text, blocks: $blocks, unfurl_links: false, unfurl_media: false}')" \
  "https://slack.com/api/chat.postMessage" | jq '{ok, ts, error}'

unfurl_links: false blocks regular URL previews; unfurl_media: false blocks image/video previews. Both are required — omitting either lets Slack render whichever class of preview it didn't see suppressed.

If ok is false, log the error field and stop. Common failures: not_in_channel (invite the bot), missing_scope, channel_not_found.

Step 7: Confirm

Fetch and print the permalink so a human (or downstream agent) can click into the post:

curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  "https://slack.com/api/chat.getPermalink?channel=$CHANNEL_ID&message_ts=<MESSAGE_TS>" | \
  jq -r '.permalink'

Notes

  • Why scope by firstSeen and not just firstRelease? Without the date filter, every daily run would re-post the same long-lived issues from earlier in the release's lifetime. Filtering by firstSeen on the target date is what makes the digest actionable and not noisy.
  • Why bundle the weekend on Monday instead of running on Sat/Sun? If the on-call rotation is staffed Mon–Fri, weekend posts would go unread. Bundling on Monday surfaces anything that broke over the weekend in a single message.
  • Manual reruns: if the user provides explicit START_DATE / END_DATE (e.g. for a backfill or to retry a missed day), use those and skip the weekday/weekend logic.
  • A reusable helper that fetches and normalizes issues is provided at scripts/fetch_new_issues.sh.

What ships with it: 1 file

2.8 KB alongside SKILL.md, 1 of them executable

scripts/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.