Customer Success
100 lines

Plan overview

Customer Slack Signals

Read the internal and shared external Slack channels for an account, extract every meaningful signal with a permalink, and produce a health verdict with action items.

Best for

Customer success · Account management · Support

Runs with

Slack · Signal extraction · Action items

At a glance

04

Outputs

01

Capabilities

03

Teams

Core outputs

Signal log with permalinks

Executive verdict

Top themes

Action items

Capability requirements

MCP

What it solves

The real state of an account lives in scattered Slack threads across two channels, and no one has a repeatable way to read the relationship.

Turns noisy Slack chatter into a structured account health read.

Preserves a linkable source for every signal it surfaces.

Assigns owners and channels to each follow-up automatically.

Workflow

1

Fetch recent history from the internal and external account channels.

2

Extract signals — requests, escalations, sentiment — each with a permalink.

3

Summarize relationship health and derive owned action items.

Implementation

Review the underlying FML plan — the sessions, tools, and typed schemas that define this workflow — and see exactly how it is instructed for repeatable execution.

FML Plan

customer-chatter.fml

100 lines

Copy
parameter("internalChannelId", type=string) # Slack channel ID for the internal side channel
parameter("externalChannelId", type=string) # Slack channel ID for the shared external customer channel

require mcp Slack

transformer("slimSlackMessages") {
    onFunctionOutput = "conversations_history"
    jmesPath = "messages[*].{text: text, user: user, ts: ts, thread_ts: thread_ts}"
}

components {
    schema("signal") {
        author?: string # Slack user who posted (display name or handle)
        relevance?: string # Why this signal matters (e.g. feature request, escalation, blocker)
        timestamp?: string # ISO datetime
        permalink: string # Constructed Slack permalink to the message
        summary: string # 1-sentence summary of the message or thread
        full_message: string # The exact, verbatim full text of the original Slack message
        channel: string # internal | external
    }
    schema("action_item") {
        due?: string # Stated due date, or empty if none mentioned
        permalink?: string # Slack permalink to the source message, if directly applicable
        item: string # Concise description of the follow-up
        owner: string # Who owns it — Barndoor name, customer name, or 'Unknown'
        source_channel?: string # internal | external
    }
}

session("fetch-signals") {
    call("conversations_history") -> internal_messages {
        channel = "{{ .params.internalChannelId }}"
        limit = 100
    }
    call("conversations_history") -> external_messages {
        channel = "{{ .params.externalChannelId }}"
        limit = 100
    }
    - You have two batches of Slack messages:
        1. INTERNAL channel ({{ .params.internalChannelId }})  side discussion:
           {{ .vars.internal_messages }}
        2. EXTERNAL channel ({{ .params.externalChannelId }})  shared channel:
           {{ .vars.external_messages }}

      Extract signals from each batch separately. A signal is any message or
      thread that carries one of:
        - a feature request, bug report, or complaint
        - a positive or negative sentiment expression
        - an escalation or blocker
        - an explicit action item or commitment from either side
        - a planned meeting, demo, or follow-up

      Map each signal to the `signal` schema and tag it with `channel`:
        - "internal" for items from the internal channel
        - "external" for items from the external channel
      Include the exact, verbatim text of the original message in the `full_message` field.
      Use the message's `ts` (Slack timestamp) converted to ISO for `timestamp`.

      Construct the `permalink` for each signal using the archives URL format:
      https://barndoorai.slack.com/archives/{CHANNEL_ID}/p{TS_WITHOUT_DOT}
      (Use {{ .params.internalChannelId }} or {{ .params.externalChannelId }} as the CHANNEL_ID depending on the source. Remove the decimal point from the `ts` value to create the `p...` suffix).
      If the message is a thread reply  i.e. it has a `thread_ts` that differs from its own `ts`  append the thread context so the link opens the thread panel:
      https://barndoorai.slack.com/archives/{CHANNEL_ID}/p{TS_WITHOUT_DOT}?thread_ts={THREAD_TS}&cid={CHANNEL_ID}
      (Use the raw `thread_ts` value, with the decimal point kept, for the thread_ts query param.)

      Discard pure status pings, bot messages, emoji-only reactions, and routine
      "+1"/"thanks" replies that carry no information.
      
    schema $signal[]
}

session("build-summary", after="fetch-signals") {
    context true
    - Using the signals extracted above, produce three outputs:

      `exec_summary` (1-2 sentences, CS-level):
      Plain-English verdict on the health of the relationship based on the Slack chatter.
      Name the most important theme and indicate whether the relationship is
      trending positive, neutral, or at risk. Reference specific signals where
      possible (e.g. "The customer raised a P1 on auth flow Tuesday and is awaiting
      a fix; otherwise traffic is steady").

      `top_themes` (3-5 short strings):
      Recurring topics across both channels. Each theme should reference how
      many messages touched it and which channel(s) carried it. Examples:
        - "OAuth re-auth pain — 4 messages in external, 2 internal follow-ups"
        - "Upcoming QBR scheduled for next week"

      `action_items`:
      Specific follow-ups derived from the chatter. For each, include the
      owner (Barndoor name, customer-side name, or 'Unknown'), the source
      channel, a stated due date if one was mentioned in Slack, and optionally the
      `permalink` to the source signal it originated from (omit if this is an aggregated item).
      
    schema {
        exec_summary: string # 1-2 sentence CS-level verdict on customer health from Slack chatter
        top_themes: string[] # Short recurring-theme description with rough volume + channel
        action_items: $action_item[]
    }
}