Back to list
rbarazi

slack-work-objects

by rbarazi

0🍴 0📅 Jan 13, 2026

SKILL.md


Slack Work Objects

Create trackable, interactive Work Objects in Slack that persist across conversations.

Problem Statement

Agents often create entities (reports, tasks, documents) that users need to track and interact with later. Work Objects provide persistent, unfurlable links with expandable details panels.

When to Use

  • Creating persistent entities users can reference across conversations
  • Building links that unfurl with rich previews
  • Providing expandable detail panels (flexpane) for entities
  • Keywords: work objects, link unfurling, flexpane, slack entities, persistent objects

Quick Start

# MCP tool returns Work Object as resource
WidgetTemplateService.hydrate_for_tool_result(
  template: :weatherCurrent,
  slack_template: :slackWeatherCurrent,
  data: {
    location: "Toronto",
    workObjectUrl: "https://app.example.com/work-objects/weather/toronto",
    externalRefId: "weather-current-toronto-ca"
  },
  text: "Current weather in Toronto"
)

What Are Work Objects?

  • Link Unfurling: Rich previews when URLs are shared
  • Flexpane Details: Expanded view when clicked
  • Cross-Conversation Tracking: Same entity recognized everywhere
  • Actions: Buttons for common operations

Architecture

MCP Tool Result → slack://work-objects/ resource
    ↓
Message posted with Work Object URLs
    ↓
Slack triggers link_shared event → App responds with chat.unfurl
    ↓
User clicks → entity_details_requested → App shows flexpane

Resource Format

{
  type: "resource",
  resource: {
    uri: "slack://work-objects/weather/uuid",
    mimeType: "application/vnd.slack.work-object+json",
    text: JSON.generate({
      event_type: "weather_report",
      entity: {
        url: "https://app.example.com/work-objects/...",
        external_ref: { id: "weather-current-toronto", type: "weather_current" },
        entity_type: "slack#/entities/item",
        entity_payload: { ... }
      }
    })
  }
}

Testing Strategy

RSpec.describe SlackWorkObjectFormatter do
  it "formats entity with required fields" do
    result = described_class.format_weather_flexpane(data, weather_type: :current)

    expect(result[:entity_type]).to eq("slack#/entities/item")
    expect(result[:entity_payload][:attributes]).to be_present
  end
end

RSpec.describe "link_shared webhook", type: :request do
  it "unfurls work object URLs" do
    post "/webhooks/slack", params: link_shared_event
    expect(slack_client).to have_received(:chat_unfurl)
  end
end

Common Pitfalls

  • Stable external_ref IDs: Use location-based, not timestamp-based
  • URL must match: url and app_unfurl_url must match unfurled URLs
  • Trigger expiry: Flexpane trigger_id expires after 3 seconds
  • UTF-8 handling: Use parameterize for special characters

Reference Files

Score

Total Score

50/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon