Log in to get this Skill or upvote it.

AI Bot Daily Performance & Predictive CSAT Digest

Note from the creator

Why I built it

“This skill allows us to track performance, containment, and sentiment around our Bot. It also helps to measure up with the changes our GenAI Managers are making within the Bot.”
avatarsrichards

What it does

This skill produces a recurring daily performance summary for an AI chat or voice bot. It reads yesterday's conversations from your Rippit workspace, identifies the bot's tickets by tag, excludes human handoffs, and computes ticket volume, resolution rate, predictive CSAT, top contact themes, and any optional flags you configure — separately for each channel you cover. The result is composed into a scannable digest and delivered by the method you pick (Slack DM, Slack channel, email, or Teams). On the first run it inspects your data, confirms tables, columns and tags with you, and runs a dry-run validation before any live send. If a run fails, it always sends a short fallback alert instead of finishing silently.

How it works

  1. 1

    Reads yesterday's tickets

    Queries your Rippit conversation table for the previous day's bot tickets per channel, excluding any escalated to a human.

  2. 2

    Scores each channel

    Aggregates volume, resolution, predictive CSAT, optional flags and top themes for every channel you cover.

  3. 3

    Delivers the digest

    Composes a scannable summary and sends it via your chosen channel, or a fallback alert if the run fails.

How It Looks

See the Slack post this Skill builds, before you download it.

# pond-support👥 14
Rippitapp9:02 AM
📊 Ribbit Assistant Daily Summary — Jun 11 (US/Eastern)

📊 Ribbit Assistant Daily Summary — Jun 11, US/Eastern Source: Rippit — pond_tickets | Window: Jun 11 04:00–Jun 12 04:00 UTC (yesterday, EDT)

💬 Chat

  • Tickets: 142
  • Resolved (of 128 scored): 101 / 79%
  • Predictive CSAT: 😊 88 satisfied | 😞 19 dissatisfied (unscored/neutral: 21)
  • Churn risk flag: 6
  • Top themes: 1) Lily pad refunds — 34 2) Fly delivery delay — 27 3) Tadpole onboarding — 19

📞 Voice

  • Tickets: 38
  • Resolved (of 35 scored): 24 / 69%
  • Predictive CSAT: 😊 21 satisfied | 😞 9 dissatisfied (unscored/neutral: 5)
  • Churn risk flag: 3
  • Top themes: 1) Pond membership billing — 11 2) Fly delivery delay — 8 3) Lily pad refunds — 6
⚠️ Notable Signals — 9 dissatisfied chat tickets clustered on fly-delivery-delay; Bullrush Bank appears in 3 churn-risk-flagged voice tickets.
“a1f7c3e2-88bd-4c19-9f0a-6d2e1b4a7c90 | chat | CSAT: dissatisfied | churn risk: yes "Third time asking where my flies are — just cancel my pond membership."”— Croak & Co.

Note: rates reflect only enriched/scored tickets (satisfied = positive sentiment). Data via Rippit · Lilypad

🐸 3👀 2
Message #pond-support

Illustrative preview, generated from the generic version of this Skill. The layout is real; the pond-side data is made up.

Analytics & InsightsAutomation#csat#analytics#reporting#automation#daily-digest#bot-performance

The Skill

Skill contents

---
name: ai-bot-daily-summary
description: "Generate a daily performance and predictive CSAT summary for an AI chat/voice bot (any company, any bot name), split by channel and delivered via Slack DM, Slack channel post, email, or Teams, using Rippit as the data source. Use whenever someone wants a recurring daily digest of their AI bot's ticket volume, resolution rate, predictive CSAT, and top contact themes. On first run it inspects the connected Rippit workspace, confirms the ticket table, tag scheme, CSAT signal, columns, recipient and delivery method, and runs a dry-run validation before any live send."
---
You are generating a daily performance and predictive CSAT summary for an AI bot, delivered via whichever channel is configured (Slack DM by default). This skill is a reusable template — point it at your own bot, company, delivery channel, and Rippit workspace.

## First run — make it yours

**Look first.** Before asking anything, call `list_data_sources` to see what's connected, then `describe_table` on the most likely ticket/conversation table. Note which columns could satisfy each parameter below: a tag or channel field, a timestamp, a sentiment/CSAT column, a resolution column, a contact-reason column, and any flag columns. If the connected data is missing something the skill fundamentally needs (no tags to identify the bot, no CSAT signal at all), say so plainly and ask how to proceed rather than running the interview into a dead end.

**Then ask, with a recommendation.** Ask one question at a time, leading with what you found and proposing a default. Substitute the real source, table and column names you discovered — never ship literal placeholders. Questions:
- `{{BOT_NAME}}` — What's the name of the AI bot this digest covers? It appears in headers and messages.
- `{{COMPANY_NAME}}` — What company name should appear in the footer credit line?
- `{{RECIPIENT_EMAIL_OR_HANDLE}}` — Who should receive the daily digest?
- `{{DELIVERY_METHOD}}` — How should I deliver it: slack_dm (default), slack_channel, email, or teams?
- `{{REPORT_TIMEZONE}}` — Which timezone defines 'yesterday' for the report window?
- `{{CHANNELS}}` — Which channels should I report on separately?
- `{{TABLE_ID_OR_NAME}}` — Which table holds the bot's ticket/conversation records? (Propose the closest match found.)
- `{{CHAT_TAGS}}` — Which tag(s) identify this bot's chat tickets?
- `{{VOICE_TAGS}}` — Which tag(s) identify voice tickets? Skip if no voice channel.
- `{{HANDOFF_TAG_PATTERN}}` — Any tag substring marking human escalations to exclude? Leave blank if not applicable.
- `{{CSAT_SIGNAL_TYPE}}` — How is CSAT scored: sentiment_label, numeric_scale, thumbs, or percentage?
- `{{SENTIMENT_COLUMN}}` — Which column derives predictive CSAT?
- `{{RESOLUTION_COLUMN}}` — Which column indicates resolution?
- `{{CONTACT_REASON_COLUMN}}` — Which column drives the top-theme breakdown?
- `{{OPTIONAL_FLAG_COLUMNS}}` — Which optional flag columns to report (tech/product-issue flag, churn risk, compliance, escalation risk)? Add one per flag present in the schema.

After the interview, restate the filled-in bindings for confirmation, then run. On later runs, reuse them unless the user asks to change them.

**First-run validation (before the first real send, skip on every run after):** Once bindings are set, run Steps 0-4 once in dry-run mode: fetch counts and examples but instead of sending, show a short validation summary — which table/columns Step 0 resolved and whether they match; total tickets per channel for one recent day (sanity check); whether the chat/voice tag union looks complete and non-overlapping, or whether any sampled tickets fell into neither/both buckets; the CSAT bucketing applied with a few example raw values and how each was classified; any optional flags found and their yes-counts; 2-3 example tickets pulled end to end as they'd appear in the real report. Ask the user to eyeball this before proceeding. Only move to live scheduled sends once they confirm — a first run straight to production risks silently misreporting on tags or a CSAT scale nobody checked.

## Step 0: Discover the schema (first run, or if a query starts failing)
Call `list_data_sources` to find the right ticket/conversation table for this workspace, then `describe_table` on it to get real column IDs for sentiment, resolution, and contact reason. Do NOT assume column IDs from another workspace apply — every workspace has its own. Cache the resolved table/column IDs for this run and future runs.

## Step 1: Resolve the recipient for `{{DELIVERY_METHOD}}`
- `slack_dm` (default): use `slack_search_users` to find `{{RECIPIENT_EMAIL_OR_HANDLE}}` and get their Slack user ID. Keep it — also used for the failure alert in Step 7.
- `slack_channel`: use `slack_search_channels` to confirm `{{RECIPIENT_EMAIL_OR_HANDLE}}` resolves to a real channel; keep the channel ID.
- `email`: confirm you have a valid send-email tool available and `{{RECIPIENT_EMAIL_OR_HANDLE}}` is a full email address.
- `teams`: use whatever Teams-equivalent lookup tool is connected to resolve `{{RECIPIENT_EMAIL_OR_HANDLE}}` to a user or channel ID.

If the required tool for the configured delivery method isn't connected, say so and ask which tool to use instead of guessing.

## Step 2: Determine the date window
The report covers YESTERDAY in `{{REPORT_TIMEZONE}}`. Rippit timestamps are stored in UTC, so convert yesterday's full local-time day into UTC bounds, accounting for the local zone's current DST offset — e.g. US/Eastern is UTC-4 (EDT) roughly mid-March through early November, and UTC-5 (EST) the rest of the year. Confirm the current offset for `{{REPORT_TIMEZONE}}` rather than assuming — DST rules vary by country, and some zones don't observe it. Use the resulting exact UTC bounds on the table's date field for ALL queries below.

## Step 3: Identify this bot's tickets — watch for multiple tags per channel + exclude human handoffs
Do not assume a single tag captures a channel. Check whether the chat and voice tag sets are each a single tag or a small family of tags (union them with `or_filters`/`ANY` if so), and confirm with `describe_column` or a sample `read_table` that the union is complete and non-overlapping before trusting it.

**Exclude human handoffs** if `{{HANDOFF_TAG_PATTERN}}` is set: add a `NONE` (substring, case-insensitive) filter on tags for that pattern to every chat and voice query, so escalated tickets don't inflate the bot's numbers.

Run every metric SEPARATELY per channel listed in `{{CHANNELS}}`. For EACH channel, run `aggregate_table` on `{{TABLE_ID_OR_NAME}}`:
- Total ticket count
- Predictive CSAT distribution — derived from `{{SENTIMENT_COLUMN}}`, bucketed according to `{{CSAT_SIGNAL_TYPE}}`:
  - `sentiment_label`: `positive` → satisfied, `negative` → dissatisfied; `neutral`, `unknown`, blank → unscored.
  - `numeric_scale`: pick a split appropriate to the scale (e.g. on 1-5, 4-5 → satisfied, 1-2 → dissatisfied, 3 → unscored) — confirm exact cutoffs with the user.
  - `thumbs`: up → satisfied, down → dissatisfied; no vote → unscored.
  - `percentage`: treat as already a satisfaction rate — report the average directly and skip the satisfied/dissatisfied split.
  - Report only scored buckets as satisfied/dissatisfied, with everything else combined as unscored.
- Resolution distribution from `{{RESOLUTION_COLUMN}}` (yes/no/blank)
- Any configured optional flags (`{{OPTIONAL_FLAG_COLUMNS}}`) — report the yes-count per channel for each flag present.
- Top 3-5 themes by volume from `{{CONTACT_REASON_COLUMN}}`

Then `read_table` for 4-6 example tickets across all channels (mix of dissatisfied/flagged and at least 1 satisfied). Capture the FULL ticket/external ID (never truncate a UUID), channel, predictive CSAT, any flag values, contact reason, and a verbatim representative quote if the schema has one.

## Step 4: Account for enrichment lag
Some tickets may not yet be scored if enrichment trails ingestion. Always report the enriched-record denominator explicitly (e.g. "of 171 scored") rather than implying the rate covers all tickets. Don't conflate this table's "resolved" field with a bot vendor's own "containment" metric if computed differently — label them separately if both are referenced.

## Step 5: Compose the summary (Slack markdown)
---
*📊 {{BOT_NAME}} Daily Summary — [Yesterday's Date, {{REPORT_TIMEZONE}}]*
*Source: Rippit — {{TABLE_ID_OR_NAME}} | Window: [date_from]–[date_to] UTC (yesterday, {{REPORT_TIMEZONE}})*

*[repeat this block once per channel in {{CHANNELS}}, e.g. 💬 Chat / 📞 Voice]*
• Tickets: [N]
• Resolved (of [scored] scored): [yes N / X%]
• Predictive CSAT: 😊 [N] satisfied | 😞 [N] dissatisfied  (unscored/neutral: [N])  — or, if `{{CSAT_SIGNAL_TYPE}}` is `percentage`, report "[X]% average satisfaction" instead of the split
• [Optional flag, if configured]: [N]
• Top themes: 1) [theme] — [N]  2) [theme] — [N]  3) [theme] — [N]

*⚠️ Notable Signals* (only if optional flags are configured)
• [brief cross-channel description of notable flagged patterns]

*🎫 Ticket Examples*
• *[FULL ticket ID — never truncated]* | [channel] | CSAT: [satisfied/dissatisfied/unscored] | [flag: yes/no if applicable]
  > "[verbatim quote, if available]"
_(4-6 examples spanning all channels; include at least 1 satisfied)_

_Note: rates reflect only enriched/scored tickets; unscored counts shown. State the actual CSAT mapping used (e.g. "satisfied = positive sentiment" or "satisfied = 4-5 on a 5pt scale")._
_Data via Rippit · {{COMPANY_NAME}}_
---

For `email` delivery, the same content works as HTML or plaintext — keep section headers as bold/heading text since Slack markdown won't render in most email clients. Keep it scannable. If a channel has 0 tickets, say so and continue with the others.

## Step 6: Send via `{{DELIVERY_METHOD}}`
- `slack_dm`: `slack_send_message` to the recipient's user ID.
- `slack_channel`: `slack_send_message` to the resolved channel ID.
- `email`: send via whatever email tool is connected, to `{{RECIPIENT_EMAIL_OR_HANDLE}}`.
- `teams`: send via whatever Teams-equivalent tool is connected.

If the send fails, log it and retry at most once.

## Step 7: Failure fallback — ALWAYS send something
Never finish silently. Send a short alert via the same `{{DELIVERY_METHOD}}` instead of skipping if ANY of these occur:
- The Rippit MCP connection is unreachable or any call errors out.
- `list_data_sources` does not return the configured table, or `describe_table` fails.
- ALL channels return ZERO tickets for the window (genuinely no data — distinct from a single empty channel among several).

Fallback message:
---
*⚠️ {{BOT_NAME}} Daily Summary — could not run for [Yesterday's Date]*
The scheduled summary did not complete this morning.
• Reason: [one-line cause]
• Next step: [e.g. "reconnect the Rippit connector, then reply here and I'll re-run it on demand"]
_Automated alert · {{COMPANY_NAME}}_
---

Notes:
- If Step 1 (recipient lookup) fails, there is no way to deliver anything — just log the error.
- Send the fallback only once per run; do not retry more than once.
- One channel empty but others have data → send the normal summary, noting the empty channel(s). Only ALL empty → fallback.
- If a workspace has channels beyond chat/voice (e.g. email, SMS), extend `{{CHANNELS}}` and repeat the Step 3/5 pattern per channel — the logic is channel-agnostic.

Built something clever?
Share it.

Publish a Skill, climb the leaderboard, and get Rippit rewards

+ Submit a Skill