跳到正文
cccskills
免费在 GitHub 公开

slack-expert

Expert-level Slack platform development using Bolt SDK — build Slack apps with slash commands, interactive components (buttons, modals, shortcuts), home tabs, event subscriptions, workflows, Socket Mode, and Block Kit. Use for building Slack bots, workflow automation, and rich interactive Slack experiences.

中文简介正在准备中。当前显示原文说明。

集成工具Slack
查看安装方法

包含的文件(10)

  • SKILL.md11.7 KB
  • commands/slack-expert.md112 B
  • hooks/post-execute.cjs177 B
  • hooks/pre-execute.cjs283 B
  • references/research-requirements.md287 B
  • rules/slack-expert.md283 B
  • schemas/input.schema.json486 B
  • schemas/output.schema.json256 B
  • scripts/main.cjs999 B
  • templates/implementation-template.md186 B

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Slack Expert Skill

Overview

Full-platform Slack development using the Bolt SDK. Covers interactive app development beyond basic messaging — slash commands, modals, shortcuts, home tabs, event subscriptions, workflow steps, and multi-workspace OAuth.

Related skill: slack-notifications — use that skill for simple one-way messaging/alerts. Use slack-expert when building interactive Slack apps or bots.

Requirements

VariablePurposeRequired
SLACK_BOT_TOKENBot OAuth token (xoxb-...)Yes (single workspace)
SLACK_SIGNING_SECRETRequest signature verificationYes
SLACK_APP_TOKENSocket Mode app-level token (xapp-...)Socket Mode only
SLACK_CLIENT_IDOAuth client IDMulti-workspace only
SLACK_CLIENT_SECRETOAuth client secretMulti-workspace only
SLACK_STATE_SECRETOAuth state tokenMulti-workspace only

Quick Start — Bolt App (Node.js)

const { App } = require('@slack/bolt');

const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  // For Socket Mode, add:
  socketMode: true,
  appToken: process.env.SLACK_APP_TOKEN,
});

// Slash command
app.command('/hello', async ({ command, ack, respond }) => {
  await ack();
  await respond(`Hello <@${command.user_id}>!`);
});

// Button click
app.action('approve_button', async ({ body, ack, client }) => {
  await ack();
  await client.views.open({
    trigger_id: body.trigger_id,
    view: confirmationModal,
  });
});

// Event subscription
app.event('app_mention', async ({ event, say }) => {
  await say({ text: `Hello <@${event.user}>!`, thread_ts: event.ts });
});

(async () => {
  await app.start(process.env.PORT || 3000);
  console.log('Bolt app running');
})();

Core Concepts

Listeners

// Message listener with regex
app.message(/deploy/, async ({ message, say }) => {
  await say('Triggering deployment...');
});

// Slash command — MUST ack() within 3 seconds
app.command('/status', async ({ ack, respond, command }) => {
  await ack();
  // Long-running: defer actual work
  respond({ text: 'Checking status...', response_type: 'ephemeral' });
  const status = await fetchStatus(); // async work after ack
  await respond({ text: `Status: ${status}` });
});

// Shortcut (global or message)
app.shortcut('create_ticket', async ({ shortcut, ack, client }) => {
  await ack();
  await client.views.open({
    trigger_id: shortcut.trigger_id,
    view: ticketModal,
  });
});

Modals (Views)

const modal = {
  type: 'modal',
  callback_id: 'ticket_submission',
  title: { type: 'plain_text', text: 'Create Ticket' },
  submit: { type: 'plain_text', text: 'Submit' },
  close: { type: 'plain_text', text: 'Cancel' },
  blocks: [
    {
      type: 'input',
      block_id: 'title_block',
      element: {
        type: 'plain_text_input',
        action_id: 'title_input',
        placeholder: { type: 'plain_text', text: 'Ticket title' },
      },
      label: { type: 'plain_text', text: 'Title' },
    },
    {
      type: 'input',
      block_id: 'priority_block',
      element: {
        type: 'static_select',
        action_id: 'priority_select',
        options: [
          { text: { type: 'plain_text', text: 'High' }, value: 'high' },
          { text: { type: 'plain_text', text: 'Medium' }, value: 'medium' },
          { text: { type: 'plain_text', text: 'Low' }, value: 'low' },
        ],
      },
      label: { type: 'plain_text', text: 'Priority' },
    },
  ],
};

// Handle modal submission
app.view('ticket_submission', async ({ ack, view, client, body }) => {
  await ack();
  const title = view.state.values.title_block.title_input.value;
  const priority = view.state.values.priority_block.priority_select.selected_option.value;
  await createTicket({ title, priority, userId: body.user.id });
});

Block Kit — Rich Messages

const richMessage = {
  blocks: [
    {
      type: 'header',
      text: { type: 'plain_text', text: 'Deployment Ready' },
    },
    {
      type: 'section',
      fields: [
        { type: 'mrkdwn', text: '*Service:*\napi-gateway' },
        { type: 'mrkdwn', text: '*Version:*\nv1.2.3' },
        { type: 'mrkdwn', text: '*Environment:*\nProduction' },
        { type: 'mrkdwn', text: '*Requested by:*\n<@U1234567>' },
      ],
    },
    { type: 'divider' },
    {
      type: 'actions',
      block_id: 'deploy_actions',
      elements: [
        {
          type: 'button',
          text: { type: 'plain_text', text: 'Approve' },
          style: 'primary',
          action_id: 'approve_deploy',
          value: 'v1.2.3',
          confirm: {
            title: { type: 'plain_text', text: 'Confirm Deploy' },
            text: { type: 'mrkdwn', text: 'Deploy *v1.2.3* to production?' },
            confirm: { type: 'plain_text', text: 'Deploy' },
            deny: { type: 'plain_text', text: 'Cancel' },
          },
        },
        {
          type: 'button',
          text: { type: 'plain_text', text: 'Reject' },
          style: 'danger',
          action_id: 'reject_deploy',
          value: 'v1.2.3',
        },
      ],
    },
  ],
};

App Home Tab

// Publish home tab when user opens it
app.event('app_home_opened', async ({ event, client }) => {
  if (event.tab !== 'home') return;

  await client.views.publish({
    user_id: event.user,
    view: {
      type: 'home',
      blocks: [
        {
          type: 'header',
          text: { type: 'plain_text', text: 'My App Dashboard' },
        },
        {
          type: 'section',
          text: { type: 'mrkdwn', text: 'Welcome to your app home!' },
          accessory: {
            type: 'button',
            text: { type: 'plain_text', text: 'Refresh' },
            action_id: 'refresh_home',
          },
        },
      ],
    },
  });
});

Lazy Listeners (Long-Running Operations)

// Use lazy: for operations that take >3s
app.command(
  '/report',
  async ({ command, ack, respond, say }) => {
    await ack(); // Must ack in <3s
  },
  async ({ command, respond }) => {
    // lazy: runs asynchronously, can take minutes
    const report = await generateReport(command.text);
    await respond({ text: report, response_type: 'in_channel' });
  }
);

Socket Mode (Internal Tools)

// Socket Mode — no public URL required, ideal for internal tools
const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  socketMode: true,
  appToken: process.env.SLACK_APP_TOKEN, // xapp- token
});

OAuth (Multi-Workspace Apps)

const { App, ExpressReceiver } = require('@slack/bolt');
const { FileInstallationStore } = require('@slack/oauth');

const receiver = new ExpressReceiver({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  clientId: process.env.SLACK_CLIENT_ID,
  clientSecret: process.env.SLACK_CLIENT_SECRET,
  stateSecret: process.env.SLACK_STATE_SECRET,
  scopes: ['chat:write', 'channels:read', 'commands'],
  installationStore: new FileInstallationStore(),
});

const app = new App({ receiver });

Workflow Steps (Deprecated → Automations)

// Legacy workflow steps (still used in some workspaces)
const ws = new WorkflowStep('copy_review', {
  edit: async ({ ack, step, configure }) => {
    await ack();
    await configure({ blocks: editBlocks });
  },
  save: async ({ ack, step, view, update }) => {
    await ack();
    const { values } = view.state;
    await update({ inputs: {}, outputs: [] });
  },
  execute: async ({ step, complete, fail }) => {
    try {
      // do work
      await complete({ outputs: {} });
    } catch (err) {
      await fail({ error: { message: err.message } });
    }
  },
});
app.step(ws);

Scopes Reference

CapabilityRequired Scopes
Post messageschat:write
Read channelschannels:read, groups:read
Read messageschannels:history, groups:history
Slash commandscommands
React to messagesreactions:write
Upload filesfiles:write
Read user profilesusers:read, users:read.email
Home tabim:history
Bot mentionsapp_mentions:read
DMsim:write, mpim:write

Common Patterns

Approval Workflow

app.command('/approve-request', async ({ command, ack, client }) => {
  await ack();
  // Post approval request to manager channel
  await client.chat.postMessage({
    channel: '#approvals',
    text: `<@${command.user_id}> requests approval`,
    blocks: buildApprovalBlocks(command),
  });
});

app.action('approve_action', async ({ action, body, ack, client }) => {
  await ack();
  const requestId = action.value;
  await markApproved(requestId, body.user.id);
  // Update original message
  await client.chat.update({
    channel: body.channel.id,
    ts: body.message.ts,
    text: `Approved by <@${body.user.id}>`,
    blocks: buildApprovedBlocks(requestId),
  });
});

User Lookup

async function lookupUser(client, email) {
  const result = await client.users.lookupByEmail({ email });
  return result.user.id;
}

Error Handling

app.error(async error => {
  console.error('Global error handler', error);
  // Notify admin channel
  await app.client.chat.postMessage({
    channel: process.env.ADMIN_CHANNEL,
    text: `App error: ${error.message}`,
  });
});

Security

  • Always verify SLACK_SIGNING_SECRET to authenticate requests from Slack
  • Never log raw payloads (may contain user PII)
  • Use response_type: 'ephemeral' for sensitive command responses
  • Store tokens in encrypted secrets manager, not .env in production
  • Scope bot tokens to minimum required permissions
  • Rotate signing secrets if compromised — requires reinstalling the app

Debugging

# Enable Bolt debug logging
DEBUG=bolt:* node app.js

# Test with Slack CLI (requires Slack CLI installed)
slack run
slack triggers create --trigger-def "triggers/trigger.json"

# Replay events locally
slack events replay

Related

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Ensure accessibility in UI components including semantic HTML, ARIA attributes, keyboard navigation, and WCAG 2.2 AA compliance.

中文简介正在准备中。当前显示原文说明。

oimiragieo/agent-studio422026年7月14日 更新

Use when you want to improve response quality through meta-cognitive reasoning. Applies 15+ reasoning methods to reconsider and refine initial outputs.

中文简介正在准备中。当前显示原文说明。

oimiragieo/agent-studio422026年7月14日 更新

N-round opposing-stance debates for trade-off analysis. Assigns pro/con roles to agents, runs structured debate rounds with quality scoring, and produces a moderator synthesis with confidence-rated recommendation. Generalizable to architecture, technology, security, and design decisions.

中文简介正在准备中。当前显示原文说明。

oimiragieo/agent-studio422026年7月14日 更新

Force adversarial code review stance that eliminates confirmation bias — reviewer must find issues or re-analyze

中文简介正在准备中。当前显示原文说明。

oimiragieo/agent-studio422026年7月14日 更新

Creates specialized AI agents on-demand when no existing agent matches a request. Use when the Router cannot find a suitable agent for a task. Enables self-evolution by generating persistent agents.

中文简介正在准备中。当前显示原文说明。

oimiragieo/agent-studio422026年7月14日 更新

LLM-as-judge evaluation framework with 5-dimension rubric (accuracy, groundedness, coherence, completeness, helpfulness) for scoring AI-generated content quality with weighted composite scores and evidence citations

中文简介正在准备中。当前显示原文说明。

oimiragieo/agent-studio422026年7月14日 更新

查看 oimiragieo 的全部技能

报告此技能的问题