Slack Context Fetcher
Fetches Slack thread content when tickets reference Slack discussions. Uses the Pipeline API for state management.
Configuration
Uses the production API by default. No configuration needed for read operations.
Defaults (no setup required):
- API URL:
https://api-gateway-856475788601.us-central1.run.app - Read-only endpoints at
/public/*require no authentication
For write operations (state transitions), set:
export PIPELINE_API_KEY="..." # Get from GCP Secret Manager or ask admin
Required for Slack access:
SLACK_BOT_TOKEN="xoxb-..." # Slack bot token
Prerequisites
SLACK_BOT_TOKENenv var set (xoxb-... token)- Bot added to relevant channels
Workflow
1. Detect Slack References
Parse ticket description for Slack links:
Pattern: https://{workspace}.slack.com/archives/{channel_id}/p{timestamp}
Example: https://comfy-org.slack.com/archives/C07ABCD1234/p1234567890123456
Extract:
channel_id: C07ABCD1234thread_ts: 1234567890.123456 (insert decimal before last 6 digits)
2. Fetch Thread Content
CHANNEL="C07ABCD1234"
THREAD_TS="1234567890.123456"
curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
"https://slack.com/api/conversations.replies?channel=$CHANNEL&ts=$THREAD_TS" | \
jq '.messages[] | {user: .user, text: .text, ts: .ts}'
3. Resolve User Names
curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
"https://slack.com/api/users.info?user=$USER_ID" | \
jq -r '.user.real_name'
4. Format for Context
## Slack Thread Context
**Thread:** [Link](https://comfy-org.slack.com/archives/C07.../p1234...)
**Participants:** Alice, Bob, Charlie
**Messages:** 12
### Full Thread
**Alice** (2024-01-15 10:30):
> Original message about the issue...
**Bob** (2024-01-15 10:45):
> Response with context...
5. Save Artifacts and Update State
Save the Slack context to the local runs directory and update ticket metadata via API:
# Save local artifact
echo "$SLACK_CONTEXT" > "$RUN_DIR/slack-context.md"
import { PipelineClient } from '@pipeline/client'
const client = new PipelineClient({
apiUrl: process.env.PIPELINE_API_URL || 'https://api-gateway-856475788601.us-central1.run.app',
agentId: process.env.AGENT_ID,
})
// Verify ticket exists - fail loudly if ticket-intake wasn't run
const ticket = await client.getTicket(ticketId).catch(() => null)
if (!ticket) {
console.error('❌ No pipeline ticket found. Run ticket-intake first to register this ticket.')
// Stop here - ticket-intake must run before this skill
}
// Update ticket metadata with Slack thread info
await client.updateTicket(ticketId, {
metadata: {
...ticket.metadata,
slackThreads: [
...(ticket.metadata?.slackThreads || []),
{ url: threadUrl, fetched: new Date().toISOString(), messages: messageCount },
],
},
})
Integration with ticket-intake
During ticket-intake, if Slack URLs detected:
- Parse channel ID and thread timestamp
- Fetch thread content
- Save to
runs/{ticket-id}/slack-context.md(local artifact) - Update ticket metadata via Pipeline API
- Include in research context
Error Handling
| Error | Cause | Resolution |
|---|---|---|
channel_not_found | Invalid channel ID | Verify URL |
not_in_channel | Bot not added | Add bot to channel |
invalid_auth | Bad token | Check SLACK_BOT_TOKEN |
Output Artifacts
| Artifact | Location | Description |
|---|---|---|
| slack-context.md | runs/{ticket-id}/slack-context.md | Thread content (local file) |
| Ticket metadata | Pipeline API | Updated via API with refs |
