Jira bug ticket comes in → Claude reads your codebase → solution lands in Slack.
An autonomous agent that listens for Jira webhooks, explores your GitHub repository with AI-powered tool use, and posts a root cause analysis + proposed fix directly to a Slack channel — no human triage needed.
Jira (webhook)
│
▼
ticket-solver (Fastify)
│ validates label trigger
▼
Claude Opus 4.6
│ iteratively calls tools:
│ ├── get_file_tree → explore repo structure
│ ├── read_file → inspect relevant source files
│ └── search_code → find usages across the codebase
▼
Slack
└── root cause · affected files · proposed fix
The webhook is acknowledged immediately; the analysis runs in the background so Jira never times out.
| Layer | Tech |
|---|---|
| Server | Fastify |
| AI | Claude Opus 4.6 with adaptive thinking + tool use |
| GitHub | @octokit/rest |
| Slack | @slack/web-api |
| Language | TypeScript (ESM) |
git clone https://github.com/joaov56/ticket-solver
cd ticket-solver
npm installcp .env.example .envEdit .env:
# Jira
TRIGGER_LABEL=ai-solver # label that activates the agent
JIRA_WEBHOOK_SECRET= # optional HMAC secret for signature verification
JIRA_BASE_URL=https://your-org.atlassian.net
# Anthropic
ANTHROPIC_API_KEY=sk-ant-...
# GitHub — the repo the agent will read
GITHUB_TOKEN=ghp_...
GITHUB_REPO=owner/repo-name
GITHUB_BRANCH=main
# Slack
SLACK_BOT_TOKEN=xoxb-...
SLACK_CHANNEL=#bugs# development (hot reload)
npm run dev
# production
npm run build && npm startThe server starts on port 3000 (configurable via PORT).
- Go to Jira Settings → System → WebHooks → Create WebHook
- Set the URL to
https://your-server.com/webhook/jira - Trigger on: Issue Created and Issue Updated
- Add the label you configured in
TRIGGER_LABELto any bug ticket
From that point on, every ticket tagged with that label will be automatically analyzed.
The agent posts a structured message to your channel:
🤖 Bug Analysis: PROJ-123
──────────────────────────────
Ticket: PROJ-123 Priority: 🔴 High
Reporter: Jane Doe Labels: `ai-solver` `backend`
Summary: Payment service throws 500 on retry after timeout
🔍 Root Cause:
The retry logic in PaymentService re-uses the same expired HTTP client
instance instead of creating a new one after a timeout.
📁 Affected Files:
`src/services/payment.ts`, `src/utils/http-client.ts`
💡 Proposed Solution:
Reset the HTTP client instance on timeout in `handleRetry()`:
if (error instanceof TimeoutError) {
this.httpClient = new HttpClient(this.config);
}
Long analyses are posted as thread replies to keep the channel clean.
src/
├── index.ts # Fastify server entry point
├── config.ts # Environment variable validation
├── types/
│ └── index.ts # Jira webhook & BugTicket types
├── routes/
│ └── webhook.ts # POST /webhook/jira handler
└── services/
├── github.ts # Repo exploration (list, read, search)
├── claude.ts # Agentic loop with tool use
└── slack.ts # Slack message formatting & posting
MIT