#15

Start a story when the bot is @-mentioned

OpenTooTallNatewants to merge intofrom

Today /storytime is the only way to start a story. This adds a second entry point: mentioning the bot in a channel starts one.

@Storytime Bot
@Storytime Bot -t Pirates -t Space
@Storytime Bot --video --style claymation

Approach

A mention arrives as an app_mention event on the existing /api/slack/webhook endpoint, which already handles the Events API. Unlike a slash command it carries no trigger_id, so the configuration modal cannot be opened from one. The mention therefore starts the story directly: the bot's own mention is stripped out of the text and the remainder is parsed with parseStorytimeArgs, the same flags the slash command accepts, with the usual defaults for anything left out. Other words in the message land in arg's positional bucket and are ignored, so @Storytime Bot let's write something starts a story with the defaults.

Only the bot's own mention is removed, identified from authorizations[0].user_id, so -t "a tale for <@U999>" keeps the other user intact. Without authorizations, every user mention is dropped instead.

Existing behavior is untouched: the slash command still opens the modal, the modal still starts the story on submit, and thread replies still resume the story hook.

Guards

  • Mentions inside a thread do not start a story. Replies in a story thread already continue that story through the message event; starting here would spawn a second story in the channel while the first is still running. Only top-level mentions (no thread_ts, or thread_ts === ts) start one.
  • Redelivered events are ignored. Slack retries when it doesn't see a 200 within three seconds, which a cold start can hit even though the handler ran. A mention carrying x-slack-retry-num is skipped rather than starting a duplicate story.
  • Mentions posted by a bot are ignored, the same way thread messages from bots already are.
  • Gateway transcripts stay off, matching the slash command, whose modal leaves the field out — without this, @Storytime Bot --transcripts would be the one way to turn them on from Slack, contradicting the README.

The story starts inside waitUntil so Slack gets its acknowledgement immediately. Invalid flags and start failures are reported to the mentioning user with an ephemeral message, matching the slash command and modal paths.

Slack app configuration

Mention handling needs the app_mentions:read scope and the app_mention event subscription on the same Request URL the message.channels subscription already uses. Existing installations must add both and reinstall; until they do, nothing changes for them. Both are documented in the README, along with the new section describing the mention flow.

Tests

pnpm test: 159 passing, up from 135. New app/api/slack/webhook.test.ts covers the mention path end to end through the route — defaults, flags, surrounding chatter, each guard above, and the error paths — plus the thread-reply hook resume, which had no coverage before. New lib/slack-mention.test.ts covers mention stripping, including labeled mentions, other users, and channel links. pnpm build, pnpm lint, and tsc --noEmit are clean.

Not covered

Starting a story inside a thread. storytime() posts to a channel and has no thread parameter, so that would be a larger change.

🤖 Generated with Claude Code

Activity

3
vercel[bot]1mo ago

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated
storytime-slackbot ReadyPreview, v0Oct 10, 2026 12:14am UTC
copilot-pull-request-reviewer[bot]reviewed1mo ago
copilot-pull-request-reviewer[bot]1mo ago

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.