[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CP1WS0J5FF0D45Q76FGJJ7":3,"skill-same:01M6CP1WS0J5FF0D45Q76FGJJ7":219},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":25,"publishedAt":45,"linkOnly":46,"markdownContent":47,"markdownBody":48,"frontMatter":49,"refName":172,"commitSha":173,"skillDirectory":174,"forksCount":13,"repositoryHtmlUrl":175,"repositoryHomepageUrl":6,"ownerHtmlUrl":176,"ownerBlogUrl":177,"ownerDescription":6,"updatedAt":178,"install":179,"resources":192},"01M6CP1WS0J5FF0D45Q76FGJJ7","slack",null,"Slack operations via the Web API — messages, channels, threads, reactions, and approvals.","ncmlabs\u002Fforge","ncmlabs","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F126867372?v=4","01M6CP1F8M06XXPC3FR9KDQTX5","01M6CP1FCVBY4DQZ1N5A2GCM9K",0,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fncmlabs\u002Fforge\u002Fblob\u002Fdevelopment\u002Fskills\u002Fslack\u002FSKILL.md",[17,22],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000005","邮件与沟通","SCENARIO","使用场景",{"categoryNo":23,"categoryName":24,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000010","后端与接口",[5,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44],"message","bot","info","ok","operations","read","command","timestamp","curl","history","text","pin","Bash","api","messages","https","update","delete","web","2026-11-10 10:12:30",false,"---\nname: slack\ndescription: Slack operations via the Web API — messages, channels, threads, reactions, and approvals.\ntimeout: 120\nallowed-tools:\n  - Bash(curl:*)\ncapabilities:\n  - name: send_message\n    inputs: [Text, Text]\n    output: Text\n    params: [channel, text]\n    executor:\n      kind: command\n      argv: [curl, -s, -X, POST, \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage\", -H, \"Authorization: Bearer {env:SLACK_BOT_TOKEN}\", --data-urlencode, \"channel={channel}\", --data-urlencode, \"text={text}\"]\n      result:\n        success_path: ok\n        error_path: error\n        json_path: ts\n  - name: send_rich_message\n    inputs: [Text, Text]\n    output: Text\n  - name: reply_thread\n    inputs: [Text, Text, Text]\n    output: Text\n    params: [channel, thread_ts, text]\n    executor:\n      kind: command\n      argv: [curl, -s, -X, POST, \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage\", -H, \"Authorization: Bearer {env:SLACK_BOT_TOKEN}\", --data-urlencode, \"channel={channel}\", --data-urlencode, \"thread_ts={thread_ts}\", --data-urlencode, \"text={text}\"]\n      result:\n        success_path: ok\n        error_path: error\n        json_path: ts\n  - name: add_reaction\n    inputs: [Text, Text, Text]\n    output: Text\n    params: [channel, timestamp, emoji]\n    executor:\n      kind: command\n      argv: [curl, -s, -X, POST, \"https:\u002F\u002Fslack.com\u002Fapi\u002Freactions.add\", -H, \"Authorization: Bearer {env:SLACK_BOT_TOKEN}\", --data-urlencode, \"channel={channel}\", --data-urlencode, \"timestamp={timestamp}\", --data-urlencode, \"name={emoji}\"]\n      result:\n        success_path: ok\n        error_path: error\n  - name: list_channels\n    inputs: [Text]\n    output: Text\n  - name: read_history\n    inputs: [Text, Text, Text]\n    output: Text\n    params: [channel, oldest, limit]\n    executor:\n      kind: command\n      argv: [curl, -s, -G, \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.history\", -H, \"Authorization: Bearer {env:SLACK_BOT_TOKEN}\", --data-urlencode, \"channel={channel}\", --data-urlencode, \"oldest={oldest}\", --data-urlencode, \"limit={limit}\"]\n      result:\n        success_path: ok\n        error_path: error\n        json_path: messages\n  - name: read_thread\n    inputs: [Text, Text]\n    output: Text\n    params: [channel, thread_ts]\n    executor:\n      kind: command\n      argv: [curl, -s, -G, \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.replies\", -H, \"Authorization: Bearer {env:SLACK_BOT_TOKEN}\", --data-urlencode, \"channel={channel}\", --data-urlencode, \"ts={thread_ts}\"]\n      result:\n        success_path: ok\n        error_path: error\n        json_path: messages\n  - name: detect_mentions\n    inputs: [Text, Text]\n    output: Text\n  - name: send_approval\n    inputs: [Text, Text, Text, Text]\n    output: Text\n    params: [channel, text, callback_url, request_id]\n    executor:\n      kind: command\n      argv:\n        - curl\n        - -s\n        - -X\n        - POST\n        - \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage\"\n        - -H\n        - \"Authorization: Bearer {env:SLACK_BOT_TOKEN}\"\n        - --data-urlencode\n        - \"channel={channel}\"\n        - --data-urlencode\n        - \"text={slack_approval_fallback:text:request_id}\"\n        - --data-urlencode\n        - \"blocks={slack_approval_blocks:text:request_id}\"\n      result:\n        success_path: ok\n        error_path: error\n        json_path: ts\n  - name: edit_message\n    inputs: [Text, Text, Text]\n    output: Text\n    params: [channel, timestamp, text]\n    executor:\n      kind: command\n      argv: [curl, -s, -X, POST, \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.update\", -H, \"Authorization: Bearer {env:SLACK_BOT_TOKEN}\", --data-urlencode, \"channel={channel}\", --data-urlencode, \"ts={timestamp}\", --data-urlencode, \"text={text}\"]\n      result:\n        success_path: ok\n        error_path: error\n  - name: delete_message\n    inputs: [Text, Text]\n    output: Text\n    params: [channel, timestamp]\n    executor:\n      kind: command\n      argv: [curl, -s, -X, POST, \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.delete\", -H, \"Authorization: Bearer {env:SLACK_BOT_TOKEN}\", --data-urlencode, \"channel={channel}\", --data-urlencode, \"ts={timestamp}\"]\n      result:\n        success_path: ok\n        error_path: error\n  - name: pin_message\n    inputs: [Text, Text]\n    output: Text\n    params: [channel, timestamp]\n    executor:\n      kind: command\n      argv: [curl, -s, -X, POST, \"https:\u002F\u002Fslack.com\u002Fapi\u002Fpins.add\", -H, \"Authorization: Bearer {env:SLACK_BOT_TOKEN}\", --data-urlencode, \"channel={channel}\", --data-urlencode, \"timestamp={timestamp}\"]\n      result:\n        success_path: ok\n        error_path: error\n  - name: member_info\n    inputs: [Text]\n    output: Text\n    params: [user_id]\n    executor:\n      kind: command\n      argv: [curl, -s, -G, \"https:\u002F\u002Fslack.com\u002Fapi\u002Fusers.info\", -H, \"Authorization: Bearer {env:SLACK_BOT_TOKEN}\", --data-urlencode, \"user={user_id}\"]\n      result:\n        success_path: ok\n        error_path: error\n        json_path: user\n---\n\n# Slack Skill\n\nUse this skill to interact with Slack workspaces via the Web API and `curl`.\nOnly run commands that start with `curl` targeting `https:\u002F\u002Fslack.com\u002Fapi\u002F`. Do not run arbitrary shell commands.\n\n## Prerequisites\n\nThe `SLACK_BOT_TOKEN` environment variable must be set to a valid bot token (`xoxb-...`).\n\nBefore any operation, verify the token:\n\n```bash\ncurl -s \"https:\u002F\u002Fslack.com\u002Fapi\u002Fauth.test\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\"\n```\n\nIf the response contains `\"ok\": false`, return `\"ERROR: Slack auth failed. Check SLACK_BOT_TOKEN.\"` and stop.\n\n### Required Bot Token Scopes\n\n| Scope | Used by |\n|---|---|\n| `chat:write` | send_message, send_rich_message, reply_thread, edit_message, delete_message |\n| `channels:history` | read_history, read_thread, detect_mentions (public channels) |\n| `groups:history` | read_history, read_thread, detect_mentions (private channels) |\n| `im:history` | read_history (DMs) |\n| `mpim:history` | read_history (group DMs) |\n| `channels:read` | list_channels (public) |\n| `groups:read` | list_channels (private) |\n| `im:read` | list_channels (DMs) |\n| `mpim:read` | list_channels (group DMs) |\n| `reactions:write` | add_reaction |\n| `pins:write` | pin_message |\n| `users:read` | member_info |\n\n### Bot Token Setup\n\n1. Go to https:\u002F\u002Fapi.slack.com\u002Fapps and click **Create New App** → **From scratch**\n2. Under **OAuth & Permissions**, add the scopes listed above to **Bot Token Scopes**\n3. Click **Install to Workspace** and authorize\n4. Copy the **Bot User OAuth Token** (`xoxb-...`) and set it as `SLACK_BOT_TOKEN`\n5. Invite the bot to channels it needs to access: `\u002Finvite @YourBotName`\n\n## Capabilities\n\n### `send_message(channel, text)`\n\nSend a plain-text message to a channel or DM.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"text\": \"Hello from FORGE\"\n  }'\n```\n\nReturn the `ts` (message timestamp) from the response on success. This `ts` is the message ID used by other capabilities.\n\n### `send_rich_message(channel, blocks_json)`\n\nSend a message with Block Kit layout blocks for rich formatting.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"text\": \"Fallback text for notifications\",\n    \"blocks\": [\n      {\n        \"type\": \"header\",\n        \"text\": {\"type\": \"plain_text\", \"text\": \"Deploy Report\"}\n      },\n      {\n        \"type\": \"section\",\n        \"text\": {\"type\": \"mrkdwn\", \"text\": \"*Status:* All checks passed\\n*Branch:* `main`\\n*Commit:* `abc1234`\"}\n      },\n      {\n        \"type\": \"divider\"\n      },\n      {\n        \"type\": \"section\",\n        \"text\": {\"type\": \"mrkdwn\", \"text\": \"View the full report:\"},\n        \"accessory\": {\n          \"type\": \"button\",\n          \"text\": {\"type\": \"plain_text\", \"text\": \"Open Dashboard\"},\n          \"url\": \"https:\u002F\u002Fexample.com\u002Fdashboard\"\n        }\n      }\n    ]\n  }'\n```\n\nAlways include a `text` field as fallback for notifications and accessibility. The `blocks` array accepts any valid Block Kit layout block — see https:\u002F\u002Fapi.slack.com\u002Freference\u002Fblock-kit\u002Fblocks.\n\nReturn the `ts` on success.\n\n### `reply_thread(channel, thread_ts, text)`\n\nReply to a message in a thread. The `thread_ts` is the `ts` of the parent message.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"thread_ts\": \"1712023032.123400\",\n    \"text\": \"Thread reply from FORGE\"\n  }'\n```\n\nTo also broadcast the reply to the channel, add `\"reply_broadcast\": true`. Use sparingly — only when everyone needs visibility.\n\nReturn the `ts` on success.\n\n### `add_reaction(channel, timestamp, emoji)`\n\nAdd an emoji reaction to a message. Use the emoji name without colons.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Freactions.add\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"timestamp\": \"1712023032.123400\",\n    \"name\": \"white_check_mark\"\n  }'\n```\n\nCommon emoji names: `white_check_mark`, `eyes`, `thumbsup`, `thumbsdown`, `rocket`, `warning`, `x`.\n\nReturn confirmation on success.\n\n### `list_channels(filter)`\n\nList channels the bot has access to. The `filter` parameter sets the channel types to include.\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.list\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"types=public_channel,private_channel\" \\\n  --data-urlencode \"exclude_archived=true\" \\\n  --data-urlencode \"limit=200\"\n```\n\nValid types: `public_channel`, `private_channel`, `mpim` (group DMs), `im` (DMs).\n\nThe response includes a `channels` array with `id`, `name`, `purpose`, `topic`, and `num_members`.\n\nFor pagination, if `response_metadata.next_cursor` is non-empty, pass it as `cursor` in the next request:\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.list\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"types=public_channel\" \\\n  --data-urlencode \"cursor=dXNlcjpVMDYxTkZUVDI=\" \\\n  --data-urlencode \"limit=200\"\n```\n\nReturn the JSON array of channels.\n\n### `read_history(channel, oldest, limit)`\n\nRead messages from a channel. Use `oldest` (Unix timestamp) for incremental polling — only messages after that timestamp are returned.\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.history\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"channel=C0123456789\" \\\n  --data-urlencode \"oldest=1712023032.000000\" \\\n  --data-urlencode \"limit=50\"\n```\n\nOmit `oldest` to get the most recent messages. The response `messages` array is in reverse chronological order (newest first). Each message has `ts`, `user`, `text`, and optionally `thread_ts` (if it is a thread parent or reply).\n\nFor pagination, check `has_more` and use `response_metadata.next_cursor`.\n\nReturn the JSON messages array.\n\n### `read_thread(channel, thread_ts)`\n\nRead all replies in a thread. The `thread_ts` is the parent message timestamp.\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.replies\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"channel=C0123456789\" \\\n  --data-urlencode \"ts=1712023032.123400\"\n```\n\nThe first message in the response is the thread parent. Subsequent messages are replies in chronological order.\n\nReturn the JSON messages array.\n\n### `detect_mentions(channel, oldest)`\n\nRead channel history and filter for messages that @mention the bot. This is a composite operation.\n\nStep 1 — Get the bot user ID:\n\n```bash\ncurl -s \"https:\u002F\u002Fslack.com\u002Fapi\u002Fauth.test\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" | jq -r '.user_id'\n```\n\nStep 2 — Read history and filter for mentions:\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.history\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"channel=C0123456789\" \\\n  --data-urlencode \"oldest=1712023032.000000\" \\\n  --data-urlencode \"limit=100\" \\\n  | jq '[.messages[] | select(.text | contains(\"\u003C@BOT_USER_ID>\"))]'\n```\n\nReplace `BOT_USER_ID` with the value from Step 1. Store the latest `ts` from the results to use as `oldest` in the next poll cycle.\n\nReturn the filtered messages array.\n\n### `send_approval(channel, text, callback_url, request_id)`\n\nSend a message with interactive Approve\u002FReject buttons. The `request_id` is encoded in each button's `value` field as `\"approved:{request_id}\"` or `\"rejected:{request_id}\"` so the receiving webhook can correlate responses to the original approval request.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"text\": \"Approval required: Deploy v2.1.0 to production\",\n    \"blocks\": [\n      {\n        \"type\": \"section\",\n        \"text\": {\"type\": \"mrkdwn\", \"text\": \"*Approval Required*\\nDeploy v2.1.0 to production\"}\n      },\n      {\n        \"type\": \"actions\",\n        \"block_id\": \"approval_actions\",\n        \"elements\": [\n          {\n            \"type\": \"button\",\n            \"text\": {\"type\": \"plain_text\", \"text\": \"Approve\"},\n            \"style\": \"primary\",\n            \"action_id\": \"approve\",\n            \"value\": \"approved:REQUEST_ID\"\n          },\n          {\n            \"type\": \"button\",\n            \"text\": {\"type\": \"plain_text\", \"text\": \"Reject\"},\n            \"style\": \"danger\",\n            \"action_id\": \"reject\",\n            \"value\": \"rejected:REQUEST_ID\"\n          }\n        ]\n      }\n    ]\n  }'\n```\n\nReplace `REQUEST_ID` with the `request_id` parameter value.\n\nTo receive button clicks, configure an **Interactivity Request URL** in your Slack app settings (https:\u002F\u002Fapi.slack.com\u002Fapps → your app → **Interactivity & Shortcuts** → set the Request URL to your `callback_url`). The FORGE server exposes `POST \u002Fwebhook\u002Fapproval` as the dedicated endpoint for this purpose.\n\nWhen a user clicks a button, Slack POSTs a form-encoded payload to the callback URL. The FORGE `\u002Fwebhook\u002Fapproval` endpoint parses the `actions[0].value` field to extract the decision and `request_id`, then publishes an `ApprovalResponse` event to the event bus with fields: `request_id` (Text), `approved` (Bool), `comment` (Text with approver info).\n\nReturn the `ts` on success.\n\n### `edit_message(channel, timestamp, text)`\n\nUpdate an existing message. The bot can only edit messages it posted.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.update\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"ts\": \"1712023032.123400\",\n    \"text\": \"Updated message text\"\n  }'\n```\n\nReturn confirmation on success.\n\n### `delete_message(channel, timestamp)`\n\nDelete a message. The bot can only delete messages it posted (unless it has `chat:write.public` scope).\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.delete\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"ts\": \"1712023032.123400\"\n  }'\n```\n\nReturn confirmation on success.\n\n### `pin_message(channel, timestamp)`\n\nPin a message to a channel.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fpins.add\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"timestamp\": \"1712023032.123400\"\n  }'\n```\n\nReturn confirmation on success.\n\n### `member_info(user_id)`\n\nGet profile information for a Slack user.\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fusers.info\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"user=U0123456789\"\n```\n\nThe response `user` object includes `real_name`, `display_name`, `email` (if `users:read.email` scope is added), `title`, `status_text`, and `tz`.\n\nReturn the user profile JSON.\n\n## Rate Limit Guidance\n\nSlack uses tiered rate limits. The relevant tiers for this skill:\n\n| Tier | Limit | Methods |\n|---|---|---|\n| Tier 2 | ~20 req\u002Fmin | `chat.postMessage`, `chat.update`, `chat.delete`, `reactions.add`, `pins.add` |\n| Tier 3 | ~50 req\u002Fmin | `conversations.history`, `conversations.list`, `conversations.replies` |\n| Tier 4 | ~100 req\u002Fmin | `users.info`, `auth.test` |\n\nWhen rate-limited, the API returns HTTP 429 with a `Retry-After` header (seconds to wait). Respect it:\n\n```bash\n# Check for rate limiting in response headers\ncurl -s -D - -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.history\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"channel=C0123456789\" \\\n  --data-urlencode \"limit=50\" \\\n  | head -20\n```\n\nIf you see `HTTP\u002F2 429`, wait the number of seconds in `Retry-After` before retrying.\n\nFor bulk operations (reading many channels), add 1-second delays between requests to stay well under limits.\n\n## Error Handling\n\n### Authentication failures\n\nIf any request returns `\"error\": \"not_authed\"` or `\"error\": \"invalid_auth\"`:\n\nReturn `\"ERROR: Slack auth failed. Verify SLACK_BOT_TOKEN is set and valid.\"` — do not retry.\n\n### Missing scopes\n\nIf a request returns `\"error\": \"missing_scope\"` with a `\"needed\"` field:\n\nReturn `\"ERROR: Missing Slack scope '\u003Cneeded>'. Add it at https:\u002F\u002Fapi.slack.com\u002Fapps under OAuth & Permissions.\"` — do not retry.\n\n### Channel not found\n\nIf a request returns `\"error\": \"channel_not_found\"`:\n\nReturn `\"ERROR: Channel not found. Verify the channel ID and that the bot is a member.\"` — do not guess alternatives.\n\n### Bot not in channel\n\nIf a request returns `\"error\": \"not_in_channel\"`:\n\nReturn `\"ERROR: Bot is not in this channel. Invite it with \u002Finvite @BotName in Slack.\"` — do not retry.\n\n### Rate limited\n\nIf a request returns HTTP 429 or `\"error\": \"ratelimited\"`:\n\nReturn `\"ERROR: Rate limited. Retry after \u003CRetry-After> seconds.\"` — wait before retrying.\n\n### Message not found\n\nIf `chat.update` or `chat.delete` returns `\"error\": \"message_not_found\"`:\n\nReturn `\"ERROR: Message not found. Verify the channel and timestamp.\"` — do not retry.\n\n## Safety Rules\n\n- Only run `curl` commands targeting `https:\u002F\u002Fslack.com\u002Fapi\u002F*`. No other URLs.\n- Never log, echo, or print `$SLACK_BOT_TOKEN` in output.\n- Do not run arbitrary shell commands beyond `curl` and `jq` for parsing.\n- Return the curl command that was run alongside the result for auditability (with the token replaced by `$SLACK_BOT_TOKEN`).\n- Do not delete messages you did not post unless explicitly instructed.\n- Do not store or cache message content outside the current session.\n\n## Session Adapter Mapping\n\n| FORGE session field | curl mapping |\n|---|---|\n| `channel` | `\"channel\"` in JSON body or `channel` query param |\n| `token` | `Authorization: Bearer $SLACK_BOT_TOKEN` header |\n| `output_mode = json` | All Slack API responses are JSON by default |\n| `timeout` | Managed by FORGE skill executor |\n\n## AgentResult Mapping\n\n| Slack API response | AgentResult field |\n|---|---|\n| `ts` (message timestamp) | `output` |\n| JSON array (messages, channels) | `output` (structured) |\n| `\"ok\": false` with `\"error\"` | `output` (prefixed with `ERROR:`) |\n| curl command executed | `metadata.command` |\n","# Slack Skill\n\nUse this skill to interact with Slack workspaces via the Web API and `curl`.\nOnly run commands that start with `curl` targeting `https:\u002F\u002Fslack.com\u002Fapi\u002F`. Do not run arbitrary shell commands.\n\n## Prerequisites\n\nThe `SLACK_BOT_TOKEN` environment variable must be set to a valid bot token (`xoxb-...`).\n\nBefore any operation, verify the token:\n\n```bash\ncurl -s \"https:\u002F\u002Fslack.com\u002Fapi\u002Fauth.test\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\"\n```\n\nIf the response contains `\"ok\": false`, return `\"ERROR: Slack auth failed. Check SLACK_BOT_TOKEN.\"` and stop.\n\n### Required Bot Token Scopes\n\n| Scope | Used by |\n|---|---|\n| `chat:write` | send_message, send_rich_message, reply_thread, edit_message, delete_message |\n| `channels:history` | read_history, read_thread, detect_mentions (public channels) |\n| `groups:history` | read_history, read_thread, detect_mentions (private channels) |\n| `im:history` | read_history (DMs) |\n| `mpim:history` | read_history (group DMs) |\n| `channels:read` | list_channels (public) |\n| `groups:read` | list_channels (private) |\n| `im:read` | list_channels (DMs) |\n| `mpim:read` | list_channels (group DMs) |\n| `reactions:write` | add_reaction |\n| `pins:write` | pin_message |\n| `users:read` | member_info |\n\n### Bot Token Setup\n\n1. Go to https:\u002F\u002Fapi.slack.com\u002Fapps and click **Create New App** → **From scratch**\n2. Under **OAuth & Permissions**, add the scopes listed above to **Bot Token Scopes**\n3. Click **Install to Workspace** and authorize\n4. Copy the **Bot User OAuth Token** (`xoxb-...`) and set it as `SLACK_BOT_TOKEN`\n5. Invite the bot to channels it needs to access: `\u002Finvite @YourBotName`\n\n## Capabilities\n\n### `send_message(channel, text)`\n\nSend a plain-text message to a channel or DM.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"text\": \"Hello from FORGE\"\n  }'\n```\n\nReturn the `ts` (message timestamp) from the response on success. This `ts` is the message ID used by other capabilities.\n\n### `send_rich_message(channel, blocks_json)`\n\nSend a message with Block Kit layout blocks for rich formatting.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"text\": \"Fallback text for notifications\",\n    \"blocks\": [\n      {\n        \"type\": \"header\",\n        \"text\": {\"type\": \"plain_text\", \"text\": \"Deploy Report\"}\n      },\n      {\n        \"type\": \"section\",\n        \"text\": {\"type\": \"mrkdwn\", \"text\": \"*Status:* All checks passed\\n*Branch:* `main`\\n*Commit:* `abc1234`\"}\n      },\n      {\n        \"type\": \"divider\"\n      },\n      {\n        \"type\": \"section\",\n        \"text\": {\"type\": \"mrkdwn\", \"text\": \"View the full report:\"},\n        \"accessory\": {\n          \"type\": \"button\",\n          \"text\": {\"type\": \"plain_text\", \"text\": \"Open Dashboard\"},\n          \"url\": \"https:\u002F\u002Fexample.com\u002Fdashboard\"\n        }\n      }\n    ]\n  }'\n```\n\nAlways include a `text` field as fallback for notifications and accessibility. The `blocks` array accepts any valid Block Kit layout block — see https:\u002F\u002Fapi.slack.com\u002Freference\u002Fblock-kit\u002Fblocks.\n\nReturn the `ts` on success.\n\n### `reply_thread(channel, thread_ts, text)`\n\nReply to a message in a thread. The `thread_ts` is the `ts` of the parent message.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"thread_ts\": \"1712023032.123400\",\n    \"text\": \"Thread reply from FORGE\"\n  }'\n```\n\nTo also broadcast the reply to the channel, add `\"reply_broadcast\": true`. Use sparingly — only when everyone needs visibility.\n\nReturn the `ts` on success.\n\n### `add_reaction(channel, timestamp, emoji)`\n\nAdd an emoji reaction to a message. Use the emoji name without colons.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Freactions.add\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"timestamp\": \"1712023032.123400\",\n    \"name\": \"white_check_mark\"\n  }'\n```\n\nCommon emoji names: `white_check_mark`, `eyes`, `thumbsup`, `thumbsdown`, `rocket`, `warning`, `x`.\n\nReturn confirmation on success.\n\n### `list_channels(filter)`\n\nList channels the bot has access to. The `filter` parameter sets the channel types to include.\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.list\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"types=public_channel,private_channel\" \\\n  --data-urlencode \"exclude_archived=true\" \\\n  --data-urlencode \"limit=200\"\n```\n\nValid types: `public_channel`, `private_channel`, `mpim` (group DMs), `im` (DMs).\n\nThe response includes a `channels` array with `id`, `name`, `purpose`, `topic`, and `num_members`.\n\nFor pagination, if `response_metadata.next_cursor` is non-empty, pass it as `cursor` in the next request:\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.list\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"types=public_channel\" \\\n  --data-urlencode \"cursor=dXNlcjpVMDYxTkZUVDI=\" \\\n  --data-urlencode \"limit=200\"\n```\n\nReturn the JSON array of channels.\n\n### `read_history(channel, oldest, limit)`\n\nRead messages from a channel. Use `oldest` (Unix timestamp) for incremental polling — only messages after that timestamp are returned.\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.history\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"channel=C0123456789\" \\\n  --data-urlencode \"oldest=1712023032.000000\" \\\n  --data-urlencode \"limit=50\"\n```\n\nOmit `oldest` to get the most recent messages. The response `messages` array is in reverse chronological order (newest first). Each message has `ts`, `user`, `text`, and optionally `thread_ts` (if it is a thread parent or reply).\n\nFor pagination, check `has_more` and use `response_metadata.next_cursor`.\n\nReturn the JSON messages array.\n\n### `read_thread(channel, thread_ts)`\n\nRead all replies in a thread. The `thread_ts` is the parent message timestamp.\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.replies\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"channel=C0123456789\" \\\n  --data-urlencode \"ts=1712023032.123400\"\n```\n\nThe first message in the response is the thread parent. Subsequent messages are replies in chronological order.\n\nReturn the JSON messages array.\n\n### `detect_mentions(channel, oldest)`\n\nRead channel history and filter for messages that @mention the bot. This is a composite operation.\n\nStep 1 — Get the bot user ID:\n\n```bash\ncurl -s \"https:\u002F\u002Fslack.com\u002Fapi\u002Fauth.test\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" | jq -r '.user_id'\n```\n\nStep 2 — Read history and filter for mentions:\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.history\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"channel=C0123456789\" \\\n  --data-urlencode \"oldest=1712023032.000000\" \\\n  --data-urlencode \"limit=100\" \\\n  | jq '[.messages[] | select(.text | contains(\"\u003C@BOT_USER_ID>\"))]'\n```\n\nReplace `BOT_USER_ID` with the value from Step 1. Store the latest `ts` from the results to use as `oldest` in the next poll cycle.\n\nReturn the filtered messages array.\n\n### `send_approval(channel, text, callback_url, request_id)`\n\nSend a message with interactive Approve\u002FReject buttons. The `request_id` is encoded in each button's `value` field as `\"approved:{request_id}\"` or `\"rejected:{request_id}\"` so the receiving webhook can correlate responses to the original approval request.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"text\": \"Approval required: Deploy v2.1.0 to production\",\n    \"blocks\": [\n      {\n        \"type\": \"section\",\n        \"text\": {\"type\": \"mrkdwn\", \"text\": \"*Approval Required*\\nDeploy v2.1.0 to production\"}\n      },\n      {\n        \"type\": \"actions\",\n        \"block_id\": \"approval_actions\",\n        \"elements\": [\n          {\n            \"type\": \"button\",\n            \"text\": {\"type\": \"plain_text\", \"text\": \"Approve\"},\n            \"style\": \"primary\",\n            \"action_id\": \"approve\",\n            \"value\": \"approved:REQUEST_ID\"\n          },\n          {\n            \"type\": \"button\",\n            \"text\": {\"type\": \"plain_text\", \"text\": \"Reject\"},\n            \"style\": \"danger\",\n            \"action_id\": \"reject\",\n            \"value\": \"rejected:REQUEST_ID\"\n          }\n        ]\n      }\n    ]\n  }'\n```\n\nReplace `REQUEST_ID` with the `request_id` parameter value.\n\nTo receive button clicks, configure an **Interactivity Request URL** in your Slack app settings (https:\u002F\u002Fapi.slack.com\u002Fapps → your app → **Interactivity & Shortcuts** → set the Request URL to your `callback_url`). The FORGE server exposes `POST \u002Fwebhook\u002Fapproval` as the dedicated endpoint for this purpose.\n\nWhen a user clicks a button, Slack POSTs a form-encoded payload to the callback URL. The FORGE `\u002Fwebhook\u002Fapproval` endpoint parses the `actions[0].value` field to extract the decision and `request_id`, then publishes an `ApprovalResponse` event to the event bus with fields: `request_id` (Text), `approved` (Bool), `comment` (Text with approver info).\n\nReturn the `ts` on success.\n\n### `edit_message(channel, timestamp, text)`\n\nUpdate an existing message. The bot can only edit messages it posted.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.update\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"ts\": \"1712023032.123400\",\n    \"text\": \"Updated message text\"\n  }'\n```\n\nReturn confirmation on success.\n\n### `delete_message(channel, timestamp)`\n\nDelete a message. The bot can only delete messages it posted (unless it has `chat:write.public` scope).\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.delete\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"ts\": \"1712023032.123400\"\n  }'\n```\n\nReturn confirmation on success.\n\n### `pin_message(channel, timestamp)`\n\nPin a message to a channel.\n\n```bash\ncurl -s -X POST \"https:\u002F\u002Fslack.com\u002Fapi\u002Fpins.add\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"channel\": \"C0123456789\",\n    \"timestamp\": \"1712023032.123400\"\n  }'\n```\n\nReturn confirmation on success.\n\n### `member_info(user_id)`\n\nGet profile information for a Slack user.\n\n```bash\ncurl -s -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fusers.info\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"user=U0123456789\"\n```\n\nThe response `user` object includes `real_name`, `display_name`, `email` (if `users:read.email` scope is added), `title`, `status_text`, and `tz`.\n\nReturn the user profile JSON.\n\n## Rate Limit Guidance\n\nSlack uses tiered rate limits. The relevant tiers for this skill:\n\n| Tier | Limit | Methods |\n|---|---|---|\n| Tier 2 | ~20 req\u002Fmin | `chat.postMessage`, `chat.update`, `chat.delete`, `reactions.add`, `pins.add` |\n| Tier 3 | ~50 req\u002Fmin | `conversations.history`, `conversations.list`, `conversations.replies` |\n| Tier 4 | ~100 req\u002Fmin | `users.info`, `auth.test` |\n\nWhen rate-limited, the API returns HTTP 429 with a `Retry-After` header (seconds to wait). Respect it:\n\n```bash\n# Check for rate limiting in response headers\ncurl -s -D - -G \"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.history\" \\\n  -H \"Authorization: Bearer $SLACK_BOT_TOKEN\" \\\n  --data-urlencode \"channel=C0123456789\" \\\n  --data-urlencode \"limit=50\" \\\n  | head -20\n```\n\nIf you see `HTTP\u002F2 429`, wait the number of seconds in `Retry-After` before retrying.\n\nFor bulk operations (reading many channels), add 1-second delays between requests to stay well under limits.\n\n## Error Handling\n\n### Authentication failures\n\nIf any request returns `\"error\": \"not_authed\"` or `\"error\": \"invalid_auth\"`:\n\nReturn `\"ERROR: Slack auth failed. Verify SLACK_BOT_TOKEN is set and valid.\"` — do not retry.\n\n### Missing scopes\n\nIf a request returns `\"error\": \"missing_scope\"` with a `\"needed\"` field:\n\nReturn `\"ERROR: Missing Slack scope '\u003Cneeded>'. Add it at https:\u002F\u002Fapi.slack.com\u002Fapps under OAuth & Permissions.\"` — do not retry.\n\n### Channel not found\n\nIf a request returns `\"error\": \"channel_not_found\"`:\n\nReturn `\"ERROR: Channel not found. Verify the channel ID and that the bot is a member.\"` — do not guess alternatives.\n\n### Bot not in channel\n\nIf a request returns `\"error\": \"not_in_channel\"`:\n\nReturn `\"ERROR: Bot is not in this channel. Invite it with \u002Finvite @BotName in Slack.\"` — do not retry.\n\n### Rate limited\n\nIf a request returns HTTP 429 or `\"error\": \"ratelimited\"`:\n\nReturn `\"ERROR: Rate limited. Retry after \u003CRetry-After> seconds.\"` — wait before retrying.\n\n### Message not found\n\nIf `chat.update` or `chat.delete` returns `\"error\": \"message_not_found\"`:\n\nReturn `\"ERROR: Message not found. Verify the channel and timestamp.\"` — do not retry.\n\n## Safety Rules\n\n- Only run `curl` commands targeting `https:\u002F\u002Fslack.com\u002Fapi\u002F*`. No other URLs.\n- Never log, echo, or print `$SLACK_BOT_TOKEN` in output.\n- Do not run arbitrary shell commands beyond `curl` and `jq` for parsing.\n- Return the curl command that was run alongside the result for auditability (with the token replaced by `$SLACK_BOT_TOKEN`).\n- Do not delete messages you did not post unless explicitly instructed.\n- Do not store or cache message content outside the current session.\n\n## Session Adapter Mapping\n\n| FORGE session field | curl mapping |\n|---|---|\n| `channel` | `\"channel\"` in JSON body or `channel` query param |\n| `token` | `Authorization: Bearer $SLACK_BOT_TOKEN` header |\n| `output_mode = json` | All Slack API responses are JSON by default |\n| `timeout` | Managed by FORGE skill executor |\n\n## AgentResult Mapping\n\n| Slack API response | AgentResult field |\n|---|---|\n| `ts` (message timestamp) | `output` |\n| JSON array (messages, channels) | `output` (structured) |\n| `\"ok\": false` with `\"error\"` | `output` (prefixed with `ERROR:`) |\n| curl command executed | `metadata.command` |\n",{"name":5,"timeout":50,"description":7,"capabilities":51,"allowed-tools":170},120,[52,72,75,84,95,98,111,120,123,134,143,151,159],{"name":53,"inputs":54,"output":55,"params":56,"executor":58},"send_message",[55,55],"Text",[57,36],"channel",{"argv":59,"kind":32,"result":69},[34,60,61,62,63,64,65,66,67,66,68],"-s","-X","POST","https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.postMessage","-H","Authorization: Bearer {env:SLACK_BOT_TOKEN}","--data-urlencode","channel={channel}","text={text}",{"json_path":70,"error_path":71,"success_path":29},"ts","error",{"name":73,"inputs":74,"output":55},"send_rich_message",[55,55],{"name":76,"inputs":77,"output":55,"params":78,"executor":80},"reply_thread",[55,55,55],[57,79,36],"thread_ts",{"argv":81,"kind":32,"result":83},[34,60,61,62,63,64,65,66,67,66,82,66,68],"thread_ts={thread_ts}",{"json_path":70,"error_path":71,"success_path":29},{"name":85,"inputs":86,"output":55,"params":87,"executor":89},"add_reaction",[55,55,55],[57,33,88],"emoji",{"argv":90,"kind":32,"result":94},[34,60,61,62,91,64,65,66,67,66,92,66,93],"https:\u002F\u002Fslack.com\u002Fapi\u002Freactions.add","timestamp={timestamp}","name={emoji}",{"error_path":71,"success_path":29},{"name":96,"inputs":97,"output":55},"list_channels",[55],{"name":99,"inputs":100,"output":55,"params":101,"executor":104},"read_history",[55,55,55],[57,102,103],"oldest","limit",{"argv":105,"kind":32,"result":110},[34,60,106,107,64,65,66,67,66,108,66,109],"-G","https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.history","oldest={oldest}","limit={limit}",{"json_path":40,"error_path":71,"success_path":29},{"name":112,"inputs":113,"output":55,"params":114,"executor":115},"read_thread",[55,55],[57,79],{"argv":116,"kind":32,"result":119},[34,60,106,117,64,65,66,67,66,118],"https:\u002F\u002Fslack.com\u002Fapi\u002Fconversations.replies","ts={thread_ts}",{"json_path":40,"error_path":71,"success_path":29},{"name":121,"inputs":122,"output":55},"detect_mentions",[55,55],{"name":124,"inputs":125,"output":55,"params":126,"executor":129},"send_approval",[55,55,55,55],[57,36,127,128],"callback_url","request_id",{"argv":130,"kind":32,"result":133},[34,60,61,62,63,64,65,66,67,66,131,66,132],"text={slack_approval_fallback:text:request_id}","blocks={slack_approval_blocks:text:request_id}",{"json_path":70,"error_path":71,"success_path":29},{"name":135,"inputs":136,"output":55,"params":137,"executor":138},"edit_message",[55,55,55],[57,33,36],{"argv":139,"kind":32,"result":142},[34,60,61,62,140,64,65,66,67,66,141,66,68],"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.update","ts={timestamp}",{"error_path":71,"success_path":29},{"name":144,"inputs":145,"output":55,"params":146,"executor":147},"delete_message",[55,55],[57,33],{"argv":148,"kind":32,"result":150},[34,60,61,62,149,64,65,66,67,66,141],"https:\u002F\u002Fslack.com\u002Fapi\u002Fchat.delete",{"error_path":71,"success_path":29},{"name":152,"inputs":153,"output":55,"params":154,"executor":155},"pin_message",[55,55],[57,33],{"argv":156,"kind":32,"result":158},[34,60,61,62,157,64,65,66,67,66,92],"https:\u002F\u002Fslack.com\u002Fapi\u002Fpins.add",{"error_path":71,"success_path":29},{"name":160,"inputs":161,"output":55,"params":162,"executor":164},"member_info",[55],[163],"user_id",{"argv":165,"kind":32,"result":168},[34,60,106,166,64,65,66,167],"https:\u002F\u002Fslack.com\u002Fapi\u002Fusers.info","user={user_id}",{"json_path":169,"error_path":71,"success_path":29},"user",[171],"Bash(curl:*)","development","357dd4b767160fd37a6f66eed6488d9fae43be60","skills\u002Fslack","https:\u002F\u002Fgithub.com\u002Fncmlabs\u002Fforge","https:\u002F\u002Fgithub.com\u002Fncmlabs","ncmlabs.com","2026-10-16 01:25:57",{"source":8,"skillName":5,"commands":180,"prompt":190,"zipAvailable":191},[181,184,187],{"tool":182,"command":183},"npx","npx skills add ncmlabs\u002Fforge --skill slack",{"tool":185,"command":186},"bunx","bunx skills add ncmlabs\u002Fforge --skill slack",{"tool":188,"command":189},"pnpm","pnpm dlx skills add ncmlabs\u002Fforge --skill slack","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fncmlabs\u002Fforge\u002Fblob\u002Fdevelopment\u002Fskills\u002Fslack\u002FSKILL.md",true,[193,199,203,207,211,215],{"path":194,"resourceType":195,"resourceTypeDesc":196,"sizeBytes":197,"sourceHtmlUrl":198},"agents\u002Fopenai.yaml","REFERENCE","参考文档",216,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FLVTD-LLC\u002Fskills\u002Fskills\u002Fbook-reader-conversations\u002Fagents\u002Fopenai.yaml",{"path":200,"resourceType":195,"resourceTypeDesc":196,"sizeBytes":201,"sourceHtmlUrl":202},"references\u002Fcore\u002Fchecklist.md",1972,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FLVTD-LLC\u002Fskills\u002Fskills\u002Fbook-reader-conversations\u002Freferences\u002Fcore\u002Fchecklist.md",{"path":204,"resourceType":195,"resourceTypeDesc":196,"sizeBytes":205,"sourceHtmlUrl":206},"references\u002Fcore\u002Fexamples.md",3280,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FLVTD-LLC\u002Fskills\u002Fskills\u002Fbook-reader-conversations\u002Freferences\u002Fcore\u002Fexamples.md",{"path":208,"resourceType":195,"resourceTypeDesc":196,"sizeBytes":209,"sourceHtmlUrl":210},"references\u002Fcore\u002Fknowledge.md",3859,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FLVTD-LLC\u002Fskills\u002Fskills\u002Fbook-reader-conversations\u002Freferences\u002Fcore\u002Fknowledge.md",{"path":212,"resourceType":195,"resourceTypeDesc":196,"sizeBytes":213,"sourceHtmlUrl":214},"references\u002Fcore\u002Frules.md",3192,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FLVTD-LLC\u002Fskills\u002Fskills\u002Fbook-reader-conversations\u002Freferences\u002Fcore\u002Frules.md",{"path":216,"resourceType":195,"resourceTypeDesc":196,"sizeBytes":217,"sourceHtmlUrl":218},"workflows\u002Frun-reader-conversations.md",2464,"https:\u002F\u002Fgithub.com\u002Fhashgraph-online\u002Fawesome-codex-plugins\u002Fblob\u002Fmain\u002Fplugins\u002FLVTD-LLC\u002Fskills\u002Fskills\u002Fbook-reader-conversations\u002Fworkflows\u002Frun-reader-conversations.md",[220,229,242,270,283,304],{"skillNo":221,"name":222,"nameZh":6,"description":223,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":224,"categories":225,"keywords":226,"publishedAt":45},"01M6CP25SKSYXW6F6VW5QHCHR1","greeter","Greet a person by name.","https:\u002F\u002Fgithub.com\u002Fncmlabs\u002Fforge\u002Fblob\u002Fdevelopment\u002Ftests\u002Ffixtures\u002Fskill-project\u002Fskills\u002Fgreeter\u002FSKILL.md",[],[222,227,36,228],"greet","hello",{"skillNo":230,"name":231,"nameZh":6,"description":232,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":233,"categories":234,"keywords":235,"publishedAt":45},"01M6CP23Y84FG8XFP7Q6SM0JM3","git_analysis","Deep agentic analysis of git repository health and trends","https:\u002F\u002Fgithub.com\u002Fncmlabs\u002Fforge\u002Fblob\u002Fdevelopment\u002Ftests\u002Ffixtures\u002Fsentinel\u002Fskills\u002Fgit-analysis\u002FSKILL.md",[],[236,237,238,239,240,241,38],"git","analysis","git analysis","health","agentic","repository",{"skillNo":243,"name":244,"nameZh":6,"description":245,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":246,"categories":247,"keywords":256,"publishedAt":45},"01M6CP2116VHMB054AAZ88CXPY","write-forge","Writing, checking or running FORGE `.forge` programs — the authoring loop, the CLI's JSON envelope and exit codes, and the syntax and checker mistakes that break agents. Use when a task asks for a FORGE program or `.forge` file, names FORGE tasks\u002Fflows\u002Fagents\u002Fpools\u002Fwardens, or when the project has a forge.project.toml.","https:\u002F\u002Fgithub.com\u002Fncmlabs\u002Fforge\u002Fblob\u002Fdevelopment\u002Fskills\u002Fwrite-forge\u002FSKILL.md",[248,251],{"categoryNo":249,"categoryName":250,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":252,"categoryName":253,"taxonomyType":254,"taxonomyTypeDesc":255},"01JBSEEDCAT000000000000036","内容创作者","PROFESSION","适用职业",[257,258,259,260,261,262,263,264,265,266,267,268,269],"forge","write","write forge","writing","cli","tasks","file","loop","json","syntax","use","exit","task",{"skillNo":271,"name":272,"nameZh":6,"description":273,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":274,"categories":275,"keywords":276,"publishedAt":45},"01M6CP1T778FD17PC9Z3GQMFX2","ollama","Use Ollama local inference for text generation, classification, and analysis via local GPU models.","https:\u002F\u002Fgithub.com\u002Fncmlabs\u002Fforge\u002Fblob\u002Fdevelopment\u002Fskills\u002Follama\u002FSKILL.md",[],[272,277,278,237,279,38,280,36,267,281,282],"generate","gpu","classification","analyze","models","inference",{"skillNo":284,"name":285,"nameZh":6,"description":286,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":287,"categories":288,"keywords":289,"publishedAt":45},"01M6CP1PZ9TSC71W7CD89NJVT7","github","GitHub operations via the gh CLI — issues, PRs, branches, and CI checks.","https:\u002F\u002Fgithub.com\u002Fncmlabs\u002Fforge\u002Fblob\u002Fdevelopment\u002Fskills\u002Fgithub\u002FSKILL.md",[],[285,290,291,261,292,293,294,295,296,297,298,299,36,38,39,300,301,302,303,43],"branches","pr","create","squash","diff","view","check","repo","branch","gh","ci","csv","issues","state",{"skillNo":305,"name":306,"nameZh":6,"description":307,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":308,"categories":309,"keywords":316,"publishedAt":45},"01M6CP1KXD4CY5EQ117Q2CQKY4","codex","Use Codex CLI as a bounded coding agent for repo exploration, implementation, review, and session resume.","https:\u002F\u002Fgithub.com\u002Fncmlabs\u002Fforge\u002Fblob\u002Fdevelopment\u002Fskills\u002Fcodex\u002FSKILL.md",[310,313],{"categoryNo":311,"categoryName":312,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":314,"categoryName":315,"taxonomyType":254,"taxonomyTypeDesc":255},"01JBSEEDCAT000000000000038","人力资源",[306,317,318,319,320,267,321,297,36,322,38,323,324,325,261,326],"coding","exploration","implementation","resume","session","explore","codex cli","implement","coding agent","review"]