Public
Remixed
An AI slackbot that can ingest data and generate html artifacts
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

Artifact Slackbot

An AI data analyst in your Slack. Drop a data file, ask a question, get back an interactive HTML report with charts — all in the thread.

A Val Town port of Anthropic's Slack data-analyst-bot cookbook, powered by Claude Managed Agents.

Features

  • Responds to @mentions in channels and to DMs, with full thread context across follow-ups
  • Reads CSV, Excel, Word, PowerPoint, PDF, JSON, TSV, Parquet, and more — and can produce reports in any of those same formats
  • Interactive HTML reports with embedded Plotly charts, hosted at a permanent Val Town URL and uploaded as a Slack thread attachment
  • Long-running session memory — pick up a Slack thread days later and the bot still remembers the conversation and the file you uploaded
  • One-click Slack app setup — no manual scope or event configuration
  • Easily extensible: swap the model, add skills, change the system prompt

Setup (~3 minutes)

  1. Click Remix to get your own copy of this val.
  2. Open your val's HTTP endpoint in a new tab (you'll see the URL in the header of your remixed val), then click Create Slack App. The app manifest — scopes, events, and webhook URL — is pre-filled, so just click Next → pick workspace → Create.
  3. Install to Workspace in the Slack app's Install App tab.
  4. Paste 3 secrets into your val's environment variables (the slots are already created — just fill the values):
    • SLACK_BOT_TOKEN — Slack app → OAuth & Permissions → Bot User OAuth Token (xoxb-…)
    • SLACK_SIGNING_SECRET — Slack app → Basic Information → Signing Secret
    • ANTHROPIC_API_KEY — from the Claude console (Managed Agents beta access required)

Usage

  • DM the bot — open a DM, attach a data file with a question. No @-mention needed; just send.
  • @mention in a channel — the bot replies in a thread on your message. Follow-ups in that thread don't need a new file or another @-mention — the same Anthropic session continues.

⚠️ Invite the bot to the channel first (/invite @Junior Analyst). Without channel membership, the bot receives the mention event but can't read attached files.

File formats

The bot accepts any file you drop in Slack and produces any format the Anthropic skills support — the same file types work in both directions (you can upload an Excel file or ask the bot to produce one; same for Word, PowerPoint, PDF, etc.).

Input — drop one of these in Slack

FormatExtensionHandled by
CSV.csvpandas.read_csv
TSV.tsvpandas.read_csv with separator
JSON.jsonpandas.read_json
Excel.xlsxxlsx skill + openpyxl
Word.docxdocx skill + python-docx
PowerPoint.pptxpptx skill + python-pptx
PDF.pdfpdf skill + pdfplumber (tables) / pypdf (text)
Plain text / Markdown.txt, .mddirect read
Code or log files.py, .log, .yaml, etc.direct read
Parquet.parquetpandas.read_parquet — installs pyarrow on first use (~5–10s)
Legacy Excel.xlspandas.read_excel — installs xlrd on first use

Not supported: images, audio, video.

Output — what comes back to the thread

Every file the agent writes to /mnt/session/outputs/ is uploaded as a Slack file attachment and stashed in Val Town blob storage with a hosted URL ({val}/reports/{uuid}) so recipients can open it in a browser, share the link externally, or preview HTML / Plotly charts natively.

FormatWhen you get it
report.htmlDefault for data-file analysis — interactive Plotly charts + narrative summary
.mdAsk for "a markdown summary" or "a brief"
.docxAsk for "a Word doc" — uses the docx skill
.xlsxAsk for "an Excel workbook" — uses the xlsx skill
.pptxAsk for "a slide deck" or "a 5-slide presentation" — uses the pptx skill
.pdfAsk for "a PDF report" — uses the pdf skill
.csv / .jsonAsk for "the cleaned dataset" or "raw data as CSV"

The bot can produce any of these from scratch without an input file too — e.g., @Junior Analyst build me a 5-slide deck on coffee brewing temperatures works without uploading anything.

Architecture

data-analyst-slackbot/
├── main.ts                      # HTTP entry point: setup page + /events + /process
├── setup.tsx                    # JSX setup page (Twind for styling)
├── prompt.md                    # System prompt for the agent
├── sales.csv                    # Bundled sample dataset for testing
├── README.md
└── lib/
    ├── flow.ts                  # Orchestrator: route inbound messages to new / existing sessions
    ├── session.ts               # Anthropic agent + environment, cached in blob
    ├── stream.ts                # Lossless-reconnect SSE consumer; posts progress + summary to Slack
    ├── outputs.ts               # Pull agent-generated files; upload to Slack with hosted URL
    ├── thread-sessions.ts       # Per-val SQLite map of thread_ts → session_id
    └── slack-utils.ts           # Slack web client, signature verification, file download

Slack POSTs events to /events. The handler verifies the signature, then dispatches the heavy work to /process as a separate HTTP request — Val Town kills detached promises after the response is sent, so the early-return pattern gives the real handler its own full execution lifecycle.

Customization

  • Edit the system promptprompt.md. Bump SIGNATURE in lib/session.ts to invalidate the cached agent so the next message rebuilds with the new prompt.
  • Add or remove Anthropic skills (xlsx, docx, pdf, pptx) → skills array in lib/session.ts.
  • Change the modelMODEL constant in lib/session.ts.
  • Add pip packages to the sandboxpip list in lib/session.ts.
  • Tune progress messages ("On it.", "Running analysis.") → lib/flow.ts and lib/stream.ts.
  • Change Slack scopes, events, or app metadata → the manifest object at the top of main.ts. Re-create the Slack app from the updated setup page.

Caveats

  • Long sessions can outlast a Val Town request. The lossless-reconnect pattern in lib/stream.ts handles SSE drops within a single /process call, but if /process itself dies (Val Town's request-lifetime cap), the Anthropic session continues on Anthropic's side and your thread goes silent. A future addition: a cron val that scans thread_sessions for running-but-orphaned sessions and re-attaches.
  • Hosted reports don't expire. Every report is stored in blob storage indefinitely under a UUID. Add a cleanup cron if you want them to expire after N days.
  • Cookbook is app_mention + DM only. Channel follow-ups still need an @-mention. Listening to message.channels would let follow-ups continue without re-mentioning, at the cost of every channel message hitting the bot.

Version pinning

Pinned imports to avoid breaking changes:

  • @anthropic-ai/sdk@0.96.0
  • @slack/web-api@7.14.1
  • hono@4.12.0

Credits

Based on Anthropic's Slack data-analyst-bot cookbook and the Val Town templates/ai-slackbot chassis (one-click Slack setup, /events/process early-return pattern).