butchr
Watches Jira tickets assigned to the account, detects active (In Progress/In Review) tickets, and notifies agents of ticket, comment, and link changes.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@butchrlist my active Jira tickets and their agent status"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
butchr
Agents support selectable Claude (default) and Codex providers. See provider configuration and deployment.
The software factory, rewritten. A single local daemon that:
Runs your resource-agent rules — each rule is a JQL query plus a brief and agent preferences, read from
BUTCHR_RULES_FILEor$XDG_CONFIG_HOME/butchr/rules.json(when the default file is absent, or itsrulesarray is empty, nothing is staffed — there are no built-in rules; aBUTCHR_RULES_FILEthat does not exist stops the daemon at startup). Seesrc/rules/rules.tsfor the schema. Rules may also nameresourceProvider: "github-issue"with a GitHub issue search query; those are staffed only whenGITHUB_TOKEN_FILEandBUTCHR_GITHUB_ORGSare set, in<workspace root>/github-issue/<rule>/<owner%2Frepo%23n>, and their agents work the issue with thegithub_get_issueandgithub_add_commenttools, which act only on the agent's own issue — a limit on the tools, not on a shell-capable agent that can readGITHUB_TOKEN_FILE(seesrc/rules/github-issue-type.tsandsrc/tools/github-issue.ts). Rules namingresourceProvider: "jira-idea"take JQL but staff only Jira Product Discovery ideas (issue typeIdeain aproduct_discoveryproject), in<workspace root>/jira-idea/<rule>/<IDEA>, with thejira_idea_get,jira_idea_github_issuesandjira_idea_add_commenttools. Ajira-idearule'sinwardConnectionRulesmay namegithub-issuerules: its agents then hear changes to GitHub issues those rules match that the idea links to through a Jira remote link (read-only). When both providers run,github_link_jira_ideaandjira_idea_link_github_issuelet an agent create that remote link on request, only between resources those same rules currently match (src/tools/idea-github-link.ts).jira-workrules never staff an idea however broad their JQL (seesrc/resources/jira-idea.tsanddocs/jira-idea.md). Rules namingresourceProvider: "zendesk-ticket"take Zendesk search syntax and are staffed only whenBUTCHR_ZENDESK_ACCEPT_SHELL_CREDENTIAL_RISK=agents-can-read-the-zendesk-token,ZENDESK_SUBDOMAINand an owner-onlyZENDESK_OAUTH_TOKEN_FILE(an OAuth token; email/API-token auth is refused) are set, in<workspace root>/zendesk-ticket/<rule>/<subdomain%23id>, withzendesk_get_ticketandzendesk_add_internal_note, whose only write is a private internal note. Agents run shell commands as the daemon's user and can read that token, so the tool limit is not a security boundary; Zendesk's account permissions are (seedocs/zendesk-ticket.md). The daemon refuses to start while agents from the old<workspace root>/<ISSUE>layout are still running (seesrc/daemon/legacy-preflight.ts).Runs one agent per (rule, matched ticket) — while a rule's query returns a ticket, a herdr agent works it via
@brooswit/drovr, in<workspace root>/jira-work/<rule>/<ISSUE>; when the query stops returning it, the agent is stopped. Two rules matching one ticket run two independent agents. A rule'schildRulemakes its agents hear changes to tickets that rule matches which alreadyImplementstheir ticket; itsinwardConnectionRulesdo the same over an existingRelateslink, one way only — the rules it lists do not hear it back unless they list it too (read-only; Butchr never creates links). Workspaces from before rules (<workspace root>/<ISSUE>) are left untouched and never adopted.Pushes updates to those agents — over MCP (
@brooswit/thatch): agents connect to the daemon identifying which issue they work on, and the daemon channels ticket/comment/link changes up the Implements chain to the right one.Shows a live view — a webapp listing the active agents; click one and butchr opens a terminal window running
herdr agent attachon it, so you drop straight into that agent's shell. No browser extension, no embedded terminal — terminals are real herdr terminals.
Change detection is @brooswit/sundry's watch over a Jira JQL feed. Blocking agent prompts are handled through herdr's own blocked detection + send_keys (herdr owns the terminal; butchr reads and answers).
Architecture
one Elysia process
├── /mcp agents connect here (thatch), identifying via x-issue (ticket) + x-butchr-agent (rule agent) headers
├── /agents,/health read-only live view
└── loops (landing incrementally)
├── rules every enabled rule's JQL → one desired agent per (rule, ticket)
├── reconcile desired rule agents ↔ herdr agents: spawn / stop
└── notify ticket/comment/link change → thatch channel → the agent for whatever that ticket implementssrc/: config · atlassian (Jira client) · daemon (the app + notify) · web (live view). More loops land as their own modules.
Related MCP server: Jira MCP Server
Install & run
On each machine:
npm i -g @brooswit/butchr # or pin a version
cp .env.example .env # fill in ATLASSIAN_SITE / EMAIL / TOKEN_FILE
butchr # reads .env / the environmentAs of 0.10.0, also set BUTCHR_ASSIGNEE_STORY and BUTCHR_ASSIGNEE_TASK (Atlassian accountIds) in .env before deploying — jira_create_issue assigns a Story/Task by role from these, and REFUSES to create one of that type if its role is unset and the caller passed no explicit assignee. Epics are unaffected.
Optionally set BUTCHR_CAPTURE_DIR to change where the session-limit watcher durably captures a pane's ANSI-stripped text when its own detection is inconclusive (the phrase is present but unrecognised, or recognised with no parseable reset time) — default .captures under the workspace root (BUTCHR_WORKSPACES, or ~/butchr-workspaces). Bounded to at most one capture per issue/trigger/pane incarnation and 50 files total (oldest evicted first); an operator turns a capture into a test fixture by deleting its # -prefixed header block.
herdr's own blocked classification is not the only blocked-detector: a pane herdr reports idle/done continuously for BUTCHR_IDLE_DIALOG_MINUTES (default 2) whose text parses as a dialog at the END of the pane is treated as blocked too — read, auto-answered if the shape is known, escalated to the pane's own ticket otherwise (an unrecognised idle-blocked dialog escalating, rather than freezing the agent silently, is the whole point — see src/agents/idle-dialog.ts). Every escalation additionally captures the full pane text to the same BUTCHR_CAPTURE_DIR, under an <ISSUE>-escalation-<timestamp>.txt name, and the Jira comment references that path (never the raw text) so the next unrecognised dialog can be fixtured from the escalation itself.
From source (development):
bun run startLabel-write permission. butchr writes agent:*/pr:* labels quietly (notifyUsers=false) so watchers aren't spammed on every status flip — but Jira Cloud only honours that for an account holding the Administrator project role (or global Administer Jira) on the board's project. Grant the daemon's Atlassian account that role on each project it labels tickets in. Without it, labels still sync — nothing is disabled — but every label change sends the ticket's watchers a Jira notification, and the daemon says so once at startup, e.g.:
[labels] KAN: account booswrit@gmail.com lacks ADMINISTER_PROJECTS — label writes will NOTIFY watchers. Remedy: grant booswrit@gmail.com the Administrator project role on KAN, or accept notifying label writes.No config knob is needed — the daemon detects this per project automatically. Current state as of 2026-08-28: brooswit is a site admin (has it everywhere); booswrit was granted the KAN Administrator role.
Development
bun run check # generate + typecheck + tests + coverage ≥90% (what CI runs)bun run check is the single verification command — run it in full, not step by step. It runs tsc under bun --bun rather than through a shebang-resolved node, so no particular node version is required. Before the gate runs, it prints a one-line preflight naming the runtimes actually in use (e.g. preflight: bun 1.4.0, node v12.22.9, tsc 5.6.3 (typecheck runs under bun)); paste that line along with the rest of the output when reporting a gate result.
Every src/ change needs a changelog.d/<TICKET>.md fragment (CI enforces it) — see changelog.d/README.md. The version is assigned at merge, not on a branch: do not bump package.json or add a dated CHANGELOG.md heading yourself.
Predecessor (300 releases of history) preserved at brooswit/butchr-legacy.
This server cannot be deployed
Maintenance
Related MCP Connectors
Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.
Agent-native collaboration network: orchestrate a team of long-running agents from any MCP client.
Read and write Mission Control state via MCP — projects, tasks, subtasks, templates, status updates.
Work management where AI agents are first-class members: tasks, projects, memory over hosted MCP
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn MCP server that enables interaction with Jira to fetch issues by key and perform JQL searches. It provides a foundation for integrating multiple work systems, with planned support for Slack and GitHub.338 npmMIT
- AlicenseNot gradedqualityDmaintenanceA comprehensive, production-ready MCP server for seamless Jira Cloud integration, enabling AI agents and custom applications to manage boards, issues, users, projects, and workflows via natural language commands.642 npm4MIT
- FlicenseNot gradedqualityDmaintenanceManages Atlassian Jira Cloud projects, issues, sprints, boards, worklogs, comments, and workflow transitions from MCP-compatible clients.-
- AlicenseAqualityFmaintenanceA local MCP server for Jira Cloud-driven development. Connects MCP clients to Jira for searching issues, reading tasks, parsing attachments, and mapping projects to local repos.1010 npmMIT