A small CLI that posts a URL to a Slack channel as the user, waits for the link
to be unfurled by an app (e.g. the GitHub app), and rewrites the post as a
compact Slack link — target = the original URL, display text = the unfurl's
fallback. The bulky unfurl attachment is removed.
From the project directory, no install needed:
export SLACK_USER_TOKEN=xoxp-...
export SLACK_CHANNEL=C0123ABC # or pass --channel before the subcommand
uv run github-pr-link post https://github.com/org/repo/pull/42uv run syncs the project's venv and runs the entry point. On success, the
tool is silent. Add --debug to dump the polled message JSON to stdout:
uv run github-pr-link post --debug https://github.com/org/repo/pull/42Before posting, the channel's last 100 messages are scanned for the same PR
URL. If one is found, the tool exits with already posted: <ts> and does
not post a duplicate. post requires a channel ID (C0123ABC), same as
show and delete.
Find a post by PR URL and react to it with :white_check_mark::
uv run github-pr-link approve https://github.com/org/repo/pull/42Searches the last 100 messages in the channel, using the same substring match
as show.
To find an existing post in the channel (by substring match against message text) and print it together with all its thread replies:
uv run github-pr-link show https://github.com/org/repo/pull/42Output is plain text — <ts> <user> <text> per line, replies indented two
spaces. Slack <url|label> markup is left raw. Searches the last 100 messages
in the channel; older posts are reported as no post found matching: <link>.
Omit the link to print every thread whose parent message has been deleted
(Slack tombstone placeholders), separated by blank lines:
uv run github-pr-link showNote: show requires a channel ID (e.g. C0123ABC), not a name. Slack's
conversations.history only accepts IDs. Set SLACK_CHANNEL=C0123ABC or
pass --channel C0123ABC before the subcommand.
Find a post the same way as show and delete the parent message and all
thread replies:
uv run github-pr-link delete https://github.com/org/repo/pull/42A user token can only delete messages you posted; others' messages are
skipped with a skipped <ts>: cant_delete_message line on stderr.
Successfully deleted messages print deleted <ts> on stdout. Same channel
ID requirement as show.
Omit the link to scan the last 100 messages for threads whose parent has
already been deleted (Slack tombstone placeholders) and attempt to delete
each remaining reply:
uv run github-pr-link deleteFailure modes (all exit non-zero, message on stderr):
no unfurl after 10s— nothing unfurled within the poll window.error: unfurl link does not match posted URL …— the unfurl came from an app butapp_unfurl_urldoesn't match what was posted.error: unfurl has no fallback text— the unfurl attachment has nofallbackfield to use as the link display text.error: chat.postMessage failed …/error: chat.update failed …— Slack API errors.
uv tool install .
# or
pipx install .Puts a github-pr-link binary on your $PATH, callable from anywhere.
This tool uses a user token (xoxp-…) and only targets public channels. The
following scopes must be granted to the Slack app whose token you are using:
chat:write— to post the message and later edit itchannels:history— to re-read the message and detect the unfurlreactions:write— to approve an existing post
| Env var | Required | Purpose |
|---|---|---|
SLACK_USER_TOKEN |
yes | The user token (xoxp-…). |
SLACK_CHANNEL |
optional | Default channel. Overridden by --channel when present. |
uv sync --extra dev
uv run pytest
uv run ruff check