Generate a weekly Salesforce pipeline report using a Claude Code skill

low complexityCost: Usage-based
Compatible agents

This skill works with any agent that supports the Claude Code skills standard, including Claude Code, Claude Cowork, OpenAI Codex, and Google Antigravity.

Prerequisites

Prerequisites
  • Claude Code or another AI coding agent installed
  • Salesforce instance with API access enabled
  • Slack app with chat:write permission added to the target channel
Environment Variables
# Your Salesforce instance URL (e.g. https://yourorg.my.salesforce.com)
SALESFORCE_INSTANCE_URL=your_value_here
# Salesforce OAuth access token or session token with Opportunity read permissions
SALESFORCE_ACCESS_TOKEN=your_value_here
# Slack bot token (xoxb-...) with chat:write permission for posting the report
SLACK_BOT_TOKEN=your_value_here
# Target Slack channel ID (starts with C) for the pipeline report
SLACK_CHANNEL_ID=your_value_here

Why a Claude Code skill?

Pipeline reporting is inherently ad-hoc. Leadership asks "where do we stand?" at different times for different reasons. An Claude Code skill turns pipeline analysis into a conversation:

  • "Post the weekly pipeline report to Slack"
  • "Break down pipeline by rep — who has the most value in Negotiation?"
  • "How does this week compare to last week?"
  • "Show me deals closing this month over $50K"

The agent reads API reference files, builds the right SOQL queries for your request, calculates metrics, and posts a formatted Slack message — all without you editing code. Unlike the Flow or n8n approaches, you can ask follow-up questions and get different views of the same data.

How it works

The skill has three parts:

  1. SKILL.md — instructions telling the agent the reporting workflow and which SOQL patterns to use
  2. references/ — API documentation for Salesforce SOQL aggregate queries and Slack chat.postMessage with Block Kit
  3. templates/ — the default report format showing which metrics to include and how to format the Slack message

When you invoke the skill, the agent reads these files, writes a script that runs the SOQL queries, calculates metrics, and posts to Slack.

What is a Claude Code skill?

An Claude Code skill is a directory of reference files and instructions that teach an AI coding agent how to complete a specific task. Unlike traditional automation that runs the same code every time, a skill lets the agent adapt — it can modify SOQL queries, add metrics, change the time window, and explain the data, all based on your natural-language request. The agent generates and runs code on the fly using the API patterns in the reference files.

Step 1: Create the skill directory

mkdir -p .claude/skills/sf-pipeline-report/{templates,references}

Step 2: Write the SKILL.md file

Create .claude/skills/sf-pipeline-report/SKILL.md:

---
name: sf-pipeline-report
description: Generate a Salesforce pipeline report and post it to Slack. Queries open Opportunities, calculates key metrics, and formats a Block Kit message.
disable-model-invocation: true
allowed-tools: Bash, Read
---
 
## Workflow
 
1. Read `references/salesforce-soql.md` for SOQL aggregate query patterns
2. Read `references/slack-api.md` for posting Block Kit messages
3. Read `templates/report-format.md` for the default report structure
4. Query Salesforce for pipeline by stage (open Opportunities grouped by StageName)
5. Query Salesforce for deals closed this week (IsWon = true, CloseDate = THIS_WEEK)
6. Query Salesforce for new deals this week (CreatedDate = THIS_WEEK)
7. Calculate metrics: total pipeline, deal count, average deal size, closed-won, new deals
8. Format a Slack Block Kit message with headline metrics and stage breakdown
9. POST the message to the configured Slack channel
10. Print a summary of the report
 
## Rules
 
- Use SOQL aggregate functions (GROUP BY, COUNT, SUM) to minimize API calls
- Handle null Amount fields — exclude with Amount != null in SOQL
- Format dollar amounts with commas and no decimal places
- If the user asks for additional metrics (per-rep, per-month, velocity), adapt the SOQL queries accordingly
- Use environment variables: SALESFORCE_INSTANCE_URL, SALESFORCE_ACCESS_TOKEN, SLACK_BOT_TOKEN, SLACK_CHANNEL_ID

Step 3: Add reference and template files

Create references/salesforce-soql.md:

# Salesforce SOQL Aggregate Query Reference
 
## Query with aggregation
 
```
GET {SALESFORCE_INSTANCE_URL}/services/data/v59.0/query?q={SOQL}
Authorization: Bearer {SALESFORCE_ACCESS_TOKEN}
```
 
### Pipeline by stage
 
```sql
SELECT StageName, COUNT(Id) deal_count, SUM(Amount) total_amount
FROM Opportunity
WHERE IsClosed = false AND Amount != null
GROUP BY StageName
ORDER BY SUM(Amount) DESC
```
 
Response:
```json
{
  "totalSize": 5,
  "records": [
    {
      "StageName": "Negotiation",
      "deal_count": 12,
      "total_amount": 1250000
    },
    {
      "StageName": "Proposal",
      "deal_count": 18,
      "total_amount": 890000
    }
  ]
}
```
 
### Closed-won this week
 
```sql
SELECT COUNT(Id) closed_count, SUM(Amount) closed_amount
FROM Opportunity
WHERE CloseDate = THIS_WEEK AND IsWon = true
```
 
### New deals this week
 
```sql
SELECT COUNT(Id) new_count, SUM(Amount) new_amount
FROM Opportunity
WHERE CreatedDate = THIS_WEEK
```
 
### Pipeline by rep
 
```sql
SELECT Owner.Name, COUNT(Id) deal_count, SUM(Amount) total_amount
FROM Opportunity
WHERE IsClosed = false AND Amount != null
GROUP BY Owner.Name
ORDER BY SUM(Amount) DESC
```
 
Notes:
- SOQL date literals: THIS_WEEK, THIS_MONTH, THIS_FISCAL_QUARTER, LAST_N_DAYS:7
- SOQL strings must be URL-encoded when passed as query params
- Aggregate queries count against the 15,000 daily API call limit
- NULL Amount values are excluded from SUM — always filter with Amount != null

Create references/slack-api.md:

# Slack API Reference
 
## Post a message with Block Kit
 
```
POST https://slack.com/api/chat.postMessage
Authorization: Bearer {SLACK_BOT_TOKEN}
Content-Type: application/json
```
 
Request body:
```json
{
  "channel": "{SLACK_CHANNEL_ID}",
  "text": "Weekly Pipeline Report — fallback text for notifications",
  "blocks": [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": "Weekly Pipeline Report"
      }
    },
    {
      "type": "section",
      "fields": [
        { "type": "mrkdwn", "text": "*Total Pipeline*\n$3,100,000" },
        { "type": "mrkdwn", "text": "*Open Deals*\n63" }
      ]
    },
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "*By Stage*\n• *Negotiation*: 12 deals — $1,250,000\n• *Proposal*: 18 deals — $890,000"
      }
    }
  ]
}
```
 
Notes:
- `text` is the fallback shown in notifications; `blocks` render in the Slack client
- The bot must have `chat:write` scope and be added to the target channel
- Section fields are displayed in a 2-column grid (max 10 fields per section)
- Use `*bold*` and `_italic_` for mrkdwn formatting

Create templates/report-format.md:

# Default Pipeline Report Format
 
## Headline metrics (section with fields)
 
| Metric | SOQL source | Format |
|--------|-------------|--------|
| Total Pipeline | SUM(Amount) from open Opportunities | $X,XXX,XXX |
| Open Deals | COUNT(Id) from open Opportunities | number |
| Avg Deal Size | Total Pipeline / Open Deals | $XX,XXX |
| Closed This Week | COUNT + SUM where IsWon = true, CloseDate = THIS_WEEK | count — $amount |
| New This Week | COUNT + SUM where CreatedDate = THIS_WEEK | count — $amount |
 
## Stage breakdown (section with mrkdwn text)
 
List each stage on a new line:
```
• *StageName*: deal_count deals — $total_amount
```
 
Sorted by total_amount descending.
 
## Optional additions (when the user asks)
 
- **Per-rep breakdown**: GROUP BY Owner.Name, format as a second section
- **Week-over-week delta**: compare to LAST_WEEK values, show +/- percentage
- **Deals closing this month**: WHERE CloseDate = THIS_MONTH AND IsClosed = false
- **Stale deals**: WHERE LastActivityDate < LAST_N_DAYS:14 AND IsClosed = false

Step 4: Test the skill

# In Claude Code
/sf-pipeline-report

Start with the default report:

"Post the weekly pipeline report to Slack"

The agent will run the SOQL queries, calculate metrics, and post the report.

Step 5: Schedule it (optional)

Option A: Cron + CLI

# Run every Monday at 8 AM
0 8 * * 1 cd /path/to/project && claude -p "Run /sf-pipeline-report — post the weekly pipeline report to Slack." --allowedTools 'Bash,Read' 2>&1 >> /var/log/sf-pipeline.log

Option B: GitHub Actions

name: Salesforce Weekly Pipeline Report
on:
  schedule:
    - cron: '0 13 * * 1'  # 8 AM ET Monday = 1 PM UTC
  workflow_dispatch: {}
jobs:
  report:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: anthropics/claude-code-action@v1
        with:
          prompt: "Run /sf-pipeline-report — post the weekly pipeline report to Slack."
          allowed_tools: "Bash,Read"
        env:
          SALESFORCE_INSTANCE_URL: ${{ secrets.SALESFORCE_INSTANCE_URL }}
          SALESFORCE_ACCESS_TOKEN: ${{ secrets.SALESFORCE_ACCESS_TOKEN }}
          SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
          SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}

Option C: Cowork Scheduled Tasks

Claude Desktop's Cowork supports built-in scheduled tasks. Open a Cowork session, type /schedule, and configure the cadence — hourly, daily, weekly, or weekdays only. Each scheduled run has full access to your connected tools, plugins, and MCP servers.

Scheduled tasks only run while your computer is awake and Claude Desktop is open. If a run is missed, Cowork executes it automatically when the app reopens. For always-on scheduling, use GitHub Actions (Option B) instead. Available on all paid plans (Pro, Max, Team, Enterprise).

Troubleshooting

When to use this approach

  • You want pipeline reports on demand — run it before a board meeting or sales standup
  • You need ad-hoc analysis like "pipeline by rep" or "deals closing this month" without building new queries
  • You want to combine pipeline data with other Salesforce objects in a single report
  • You don't want to maintain Salesforce Flows or Connected Apps for n8n

When to switch to a dedicated tool

  • You need the report to run automatically every week with zero human involvement (use n8n or Salesforce Flow)
  • Multiple team members need to modify the report format through a visual interface
  • You want built-in error alerting if the report fails to deliver

Common questions

Can I get a per-rep pipeline breakdown?

Yes. Tell the agent: "Include a breakdown by rep." It will add a SOQL query with GROUP BY Owner.Name and format the results as a second section in the Slack message.

How many Salesforce API calls does a report use?

The default report uses 3 API calls (pipeline by stage, closed this week, new this week). Adding per-rep or per-month breakdowns adds 1 call each. Salesforce Enterprise allows 15,000 API calls per 24-hour period.

Can I send the report to multiple Slack channels?

Yes. Tell the agent: "Post to #sales-leadership and #exec-team." It will make two Slack API calls with different channel IDs. Alternatively, post to one channel and use Slack's channel forwarding.

What's the difference between this and the Salesforce Reports API?

The Reports API executes saved Salesforce reports and returns structured data. This skill writes SOQL queries directly, which gives more flexibility for custom aggregations. If you already have a perfect report in Salesforce, tell the agent to use the Reports API instead.

Cost

  • Salesforce: API usage included in your plan (15,000 calls/day on Enterprise). The report uses 3 calls.
  • Slack: Free tier supports bot messaging.
  • Claude Code: Usage-based pricing per conversation.
  • GitHub Actions: Free tier covers weekly scheduled runs.

Looking to scale your AI operations?

We build and optimize automation systems for mid-market businesses. Let's discuss the right approach for your team.