Copy everything below this line and paste it into Claude Code on your work machine.
I want to build a Slack triage agent using Goose (https://block.github.io/goose/) with Claude Code as the provider. This is Phase 1 of a larger multi-agent system inspired by Paul Shortland's architecture (Temporal + Agent SDK + 3-tier recall). For now we're keeping it simple.
Create a project at ~/Projects/slack-triage-agent/ with this structure:
slack-triage-agent/
├── recipes/
│ ├── slack-triage.yaml
│ └── simulate-triage.yaml
├── context/
│ ├── team.md
│ ├── projects.md
│ └── triage-rules.md
├── logs/
│ └── (triage logs land here, one per day)
└── prompts/
└── (for custom Goose prompt templates later)
- Install Goose CLI:
brew install block-goose-cli - Verify:
goose --version - I have an Anthropic API key ready
- I have Claude Code CLI installed already
A Goose recipe that:
- Uses
claude-codeas the provider (settings.goose_provider: "claude-code") - Takes parameters:
channels(required, comma-separated channel names),logs_dir(optional, default./logs),date(optional, defaulttoday),lookback_hours(optional, default24) - ALL parameters must be referenced in the instructions via
{{ param_name }}Jinja2 syntax or Goose will error saying "Unnecessary parameter definitions"
The instructions should tell the agent to:
Step 1 — Load memory: Read all triage log files from {{ logs_dir }}/ from the past 7 days. Use them to recognize recurring issues, track open items from previous days, apply learned patterns, and reference specific previous triages.
Step 2 — Load context: Read all files in the context/ directory for org structure, project info, and triage rules.
Step 3 — Fetch messages: Fetch the last {{ lookback_hours }} hours of messages from channels: {{ channels }}. Use Slack MCP tools.
Step 4 — Classify each thread by priority:
- URGENT: Production impact, outages, security incidents, customer-facing with no workaround. Action needed within 1 hour.
- ACTION_NEEDED: Direct questions with no response after 2+ hours, requests with deadlines, blocking PRs. Action needed within 24 hours.
- FYI: Announcements, resolved issues, automated reports, general discussion.
- NOISE: Social chatter, bot noise, already-resolved, duplicates.
- When in doubt, classify UP (FYI → ACTION_NEEDED, ACTION_NEEDED → URGENT).
Step 5 — Draft responses for URGENT and ACTION_NEEDED items (brief summary + suggested action + who it's relevant to).
Step 6 — Write daily log to {{ logs_dir }}/{{ date }}-triage.md with this structure:
# Triage Log — [DATE]
## Summary
- X messages triaged across Y channels
- N URGENT, N ACTION_NEEDED, N FYI, N NOISE
## URGENT
### #channel-name: Brief title
- **First reported**: time by @who
- **Context**: what happened
- **Suggested action**: what to do
- **Pattern note**: any connection to previous issues
## ACTION_NEEDED
(same format)
## FYI
(brief list)
## Open Items Carried Forward
(items from previous days still unresolved)
## Patterns & Learnings
(new observations from today's triage — the agent teaches its future self)
(build on patterns noted in previous days, don't repeat them)The "Patterns & Learnings" section is critical — this is the agent's memory. Each run reads its own previous logs and accumulates observations.
A simulation recipe for testing triage rules against historical Slack messages (Paul's key technique — replay 30 days of history to refine rules before going live).
- Provider:
claude-code - Parameters:
input_file(required, path to historical messages),output_file(optional, default./logs/simulation-results.md) - Instructions: Read the input file, classify each message/thread using the same rules as the triage recipe, draft responses for URGENT/ACTION_NEEDED, write results to output file, and end with a self-assessment: which classifications are least confident and why, what additional context would help, what patterns emerge.
- Also read context files from
context/directory.
Create with placeholder sections (commented out examples) for:
- Org structure (my name, role, team)
- Key people (names, roles, what to escalate to them)
- Channels to watch (which channels, what traffic they get)
Create with placeholder sections for:
- Current priorities (active projects/initiatives)
- Known issues (things the agent should recognize as existing/known)
Create with:
- Priority definitions (URGENT, ACTION_NEEDED, FYI, NOISE) with concrete examples
- Escalation rules section (starts mostly empty — gets refined through simulation)
- Note that this file is a living document refined through simulation
After creating everything, run:
cd ~/Projects/slack-triage-agent
goose run --recipe recipes/slack-triage.yaml --explain
goose run --recipe recipes/simulate-triage.yaml --explainBoth should parse without errors. The first should show channels as a required parameter. The second should show input_file as required.
This is Phase 1 of a 3-tier memory system:
- Tier 1 (now): Short-term recall via daily log files loaded into context. 7-10 days fit easily in Opus 4.6's 1M context.
- Tier 2 (later): Long-term recall via ChromaDB + SQLite for semantic search over months of history, exposed as an MCP server.
- Tier 3 (now): Curated recall via the context/ files — hand-maintained org knowledge.
Future phases will add: safety-wrapped CLI MCP servers, dynamic prompt assembly, Temporal for durable execution, and running in Kubernetes via CronJob with the official Goose Docker image (ghcr.io/block/goose:latest).
# Export some Slack messages to a markdown file, then:
goose run --recipe recipes/simulate-triage.yaml \
--provider claude-code \
--params input_file=./sample-slack-messages.mdgoose schedule add --schedule-id morning-triage \
--cron "0 0 9 * * *" \
--recipe-source ./recipes/slack-triage.yaml