Inspiration

I planned my own wedding, and the part nobody warns you about is that the planning is the easy part. The coordination is what eats you alive. At my wedding, the flowers arrived while the venue crew was still stacking chairs. Nobody had told the florist that the loading slot had moved. I had told the venue. I thought I had told everyone.

That is the thing about coordinating vendors, you become the single source of truth for information that exists only in your head. Every change fans out to three people, and if you forget one, that omission shows up on the one day you cannot redo.

Planners live this at scale. The work is not hard. It is relentless. That felt like exactly the kind of problem an agent should own, so I built the coordinator I wish I had.


What it does

Backchannel runs the entire vendor loop from inside Slack:

  • Listen. Planner sends a voice note or message: "confirm the florist for 2pm on August 15, then loop in Marco at the venue"
  • Understand. Reads the event channel through the Slack MCP Server: vendor contacts, timelines, constraints.
  • Draft. Writes the vendor email and posts it as an approval card. Nothing sends without a click.
  • Send. On approval, a real email goes out and the thread is tracked.
  • Watch. Polls the inbox, matches each reply to its exact outbound via email reply headers. A /backchannel-refresh slash command forces an immediate check if the planner does not want to wait for the next poll cycle.
  • Classify. Labels the reply confirmed, conflict, ambiguous, or unrelated.
  • Resolve. On conflict, cross checks workspace constraints, asks the planner one question, then coordinates the new terms with the other affected vendor.
  • Report. Posts a summary card when everything is confirmed, and writes each decision back to the event channel with a parseable tag so the team and future queries see current facts.

It also respects sequencing: once that's locked, loop in Marco means Marco waits until the florist confirms.


How I built it

  • Agent core: Bolt for Python in Socket Mode, reasoning through the Claude Agent SDK with three custom tools: draft vendor email, post coordination summary, add emoji reaction.
  • Workspace grounding: Slack MCP Server, queried in real time at decision time with a user token.
  • Voice: OpenAI Whisper on audio pulled through the Slack files API.
  • Email: One Gmail account, aiosmtplib out on 465, aioimaplib in on 993, replies matched by message id headers.
  • Classification: Claude Haiku with a strict JSON contract, keeping per reply cost low.
  • State management: JSON files with atomic writes, plus an adaptive poller that slows down as an outbound ages.

Challenges I ran into

  • Slack CLI vs Windows. PowerShell parses the CLI's quoted Python path as a literal string, so hooks never ran. I pivoted to Socket Mode directly with manually provisioned tokens.
  • Whisper rejected Slack audio. The files are MP4 containers mislabeled as m4a. Forcing the extension fixed it.
  • The reply loop that would not stop. The same vendor email kept reclassifying. Fixed with three layers: a UID watermark, terminal state checks, and in process deduplication.

Accomplishments that we're proud of

  • The demo is real infrastructure end to end. A voice note reached the florist's actual inbox, the florist proposed a different time, Backchannel caught the conflict, checked the venue's window from the workspace, asked me one question, coordinated the new time with the venue, and fired the summary only after both vendors confirmed. No mocked emails. No simulated replies.
  • My favorite unscripted moment: the agent noticed the ceremony start time was missing from the workspace and asked instead of guessing. That is exactly the judgment I wanted it to have.
  • And the trust design held everywhere: every outbound gated by approval, every email signed as an assistant acting on behalf of the agency, every decision written back where the team can see it.
  • I learned a thing or two about content/video creation too!

What I learned

  • Slack Block Kit makes human-in-the-loop workflows feel natural.
  • Slack MCP + LLM reasoning made the agent workspace-native. Instead of scraping data or maintaining a separate knowledge base, the agent queries Slack in real time and treats the workspace as the source of truth.
  • Before this project, I had never built a Slack app. Learning Slack Bolt, Block Kit, MCP, and event-driven workflows showed how quickly collaborative AI experiences can be built directly inside Slack.
  • Voice note length. Long voice notes came back partially transcribed, so I kept demo notes short and documented Slack's own server side transcription as the production fix.
  • Email threading through reply headers is dramatically more reliable than any content matching approach.
  • Human in the loop approval is not friction, it is the thing that makes an outbound capable agent trustworthy enough to demo with confidence.
  • Agents might need explicit rules for sequential intent.

What's next for Backchannel

Post MVP

  • Build a reusable event knowledge base for each event to avoid collecting information over and over again.
  • 24 hour nudges: quiet vendors get a follow up drafted and queued for approval automatically.
  • Multi event routing: the agent infers which event a request belongs to from context, not an env variable.
  • Better voice handling. Move to Slack's own server side transcription so voice note length stops being a constraint and have the agent detect an incomplete instruction rather than acting on a partial one. A dropped clause should trigger a clarifying question in the thread, not a confidently wrong email.

Production hardening

  • Polling → Gmail push via Pub/Sub: reply latency drops from minutes to seconds.
  • Gmail app password → agency domain with SPF, DKIM, and DMARC: avoids emails going to spam folder.
  • JSON state → Postgres: durability and multi instance scale.
  • Whisper → Slack server side transcription: removes the audio truncation cap.

Further out

  • Slack Connect as a priority channel: when vendors are Slack native, the same loop runs over shared channels with thread timestamps instead of email headers.

Built With

  • agents
  • ai
  • automation
  • bolt
  • claude
  • devpost
  • event-planning
  • hackathon
  • imap
  • llm
  • mcp
  • productivity
  • python
  • slack
  • slack-agent
  • smtp
  • whisper
Share this project:

Updates

Submission history