Build a pipeline bot.
A working bot that posts pipeline movement to Slack and writes a weekly forecast note for the head of sales. About 40 lines of TOML, 30 lines of Python. Copy and adapt.
What it does
- Watches every Opportunity in CRM for stage transitions.
- Posts a one-line update to
#sales-pipelinein Slack when an opp moves up. - Every Friday at 4pm, drafts a forecast doc summarizing the week's movement and sends it to the head of sales for review.
Step 1: workflow for stage changes
[workflow] name = "pipeline-bot-stage" [trigger] event = "opportunity.stage_changed" [scope] read = ["crm:opportunities"] write = ["slack.post_message"] [[steps]] name = "notify" tool = "slack.post_message" input = { channel = "#sales-pipeline", text = "$trigger.opportunity.name, $trigger.from_stage → $trigger.to_stage (${ '$' }$trigger.opportunity.arr_usd ARR)", }
Apply with wrxstack workflow apply ./pipeline-bot-stage.toml. Within seconds, every stage transition posts to Slack.
Step 2: Friday forecast
[workflow] name = "pipeline-bot-forecast" [trigger] event = "schedule.weekly" cron = "0 16 * * 5" # 4pm Fridays [scope] read = ["crm:opportunities", "crm:accounts"] write = ["documents.create", "slack.post_message"] [[steps]] name = "draft" assistant = "forecast" # custom assistant (next step) input = { period = "this_week" } [[steps]] name = "share" tool = "slack.post_message" input = { channel = "#head-of-sales", text = "📊 Weekly forecast ready: $steps.draft.doc_url", }
Step 3: the forecast assistant
from wrxstack import tool, assistant @tool(name="forecast.weekly", scope=["crm:opportunities.read", "documents.write"]) def weekly_forecast(period: str = "this_week") -> dict: opps = client.crm.opportunities.list( moved_since="this_week", stages=["Closing", "Negotiation", "Closed-Won"], ) body = render_template(opps) doc = client.documents.create( title=f"Forecast, week of {today():%b %d}", body=body, format="markdown", ) return {"doc_url": doc.url, "opp_count": len(opps)} forecast_assistant = assistant( name="forecast", description="Drafts the weekly pipeline forecast.", tools=[weekly_forecast], model="anthropic/claude-3-5-sonnet", )
Audit the first runs
Apply both workflows. Wait for a real stage change. Open the audit log → filter by workflow name. You should see:
- One row per stage transition with the slack message id.
- One row Friday at 4pm with the draft doc id.
- Zero rows under "scope_denied." If you see any, your scope block is too tight.
Variations
- Restrict to opps above a dollar threshold.
- Mention the AE on every Slack post by reading
opp.owner. - Generate a second forecast for the CFO with a different lens.