Overview#
Deputy connects my task manager to a coding agent. It watches the tickets assigned to me in ClickUp or Jira and decides which ones an agent can safely do. Then it carries those tickets all the way to a merged pull request.
Along the way it triages, plans, implements, reviews, opens the PR and fixes CI. A person still decides at every point that needs judgement.
It ships with ClickUp, Jira and Claude Code. To add another task manager or agent, you implement one small interface.
I built it because of the problem I wrote about in When Agents Write the Code, Review Becomes the Bottleneck. Writing code is no longer the hard part. The hard part is everything around it: choosing what's safe to automate, bringing people in at the right moments, and only sending reviewers work that's worth their time.
How it works#
Deputy runs every 15 minutes. Each run moves every ticket one step forward, then exits. It never sits waiting for CI or a person. If the laptop closes or a run crashes, only one step is lost, never the whole ticket.
Every ticket follows the flow below. ◆ marks a step that waits for a person.
Where a ticket can branch#
- Triage reads only the ticket text and picks one of four paths:
- Unclear: Deputy posts its questions on the ticket. Once someone answers, triage runs again.
- Unsafe: the ticket is marked human-only. Deputy never touches it.
- Large scope: the ticket goes to planning first.
- Small and clear: the ticket skips planning and goes straight to the queue.
- Plan: an analyst reads the repository and posts a plan on the ticket. If I approve it, the ticket is queued. If I reject it, the ticket is triaged again.
- Queue: a ticket starts only when its repo is free (one agent per repo) and every ticket it depends on is closed.
- Review: a separate reviewer checks the pushed branch. It can send the work back for changes, up to a set number of rounds. Only approved work becomes a pull request.
- Pull request: if CI fails, Deputy pushes a fix and waits for the next result. When the PR merges, the ticket is done.
- Blocked: any step can end here. Deputy hands the ticket to a person and explains why in a comment.
A crashed run doesn't block straight away. It retries the same step on the next run first.
The flow lives in a table in graph.py, not in if statements spread through the code. An illegal move raises an error instead of corrupting state. The diagram in Deputy's docs is generated from that same table, so the docs can't drift from the behaviour.
Key Features#
- Triage sees only the ticket: It runs in an empty folder with no tools, so it judges the ticket's words and nothing else.
- Plans need sign-off: For larger tickets, a read-only analyst studies the real code and posts a plan. Nothing is built until a person approves it.
- Review before the PR: An independent reviewer checks every branch before a PR exists. Human reviewers see fewer PRs, and better ones.
- Repo brain: Each repo has a markdown notes file of lessons from past runs, such as which env var the tests need. Deputy writes to it only after an approved review. It has a size cap, and anyone can edit it by hand.
- Many workspaces and repos: ClickUp and Jira can run side by side, each with its own GitHub account. A Jira ticket that spans a backend and a frontend goes to both repos. It counts as done only when every PR has merged.
- Real spending limits: On a subscription, the dollar cost the CLI reports isn't the real limit. The usage quota is. So Deputy caps daily tokens as well as dollars, and checks both before every agent run.
- Read-only dashboard: A local web page shows what's stuck, what's running, what it cost and what merged. It opens the database read-only, so it can watch the runner but never change anything.
Technologies Used#
- Python: The runner, state machine, providers and CLI (
run,status,doctor,graph,serve). - SQLite: Local state on each machine. The ticket's AI State field is the only state shared between machines.
- Claude Code (headless): The agent for triage, planning, implementation and review.
- git worktrees + GitHub CLI: One isolated worktree per task, and every PR operation.
- ClickUp & Jira APIs: Ticket intake, comments, dependencies and status.
- React + Vite: The dashboard frontend, served by the runner.
- systemd / cron: Scheduling, on a laptop or a VPS.
Challenges and Learnings#
The hardest bugs weren't in the agent. They were in the plumbing around it, where a small leak quietly turns into wrong behaviour.
Isolation means more than removing tools. Triage should judge a ticket from its text alone. But starting the agent inside a repo loads that repo's CLAUDE.md, settings, skills and git state before the prompt is even read. Without tools, the agent couldn't act on the repo, but it could still see it. When I asked triage which project it was in, it recited the runner's own CLAUDE.md. The fix was to run triage from a fixed, empty folder with everything switched off. Now it reports no project context. As a bonus, a triage call dropped from about 31k input tokens to about 370.
Stopping a run must stop everything it started. Killing only the agent process left its shell commands, MCP servers and subagents running. They kept holding the worktree and kept spending quota. Now each agent leads its own process group, and a timeout kills the whole group. Output streams to a per-run log as it's produced, so even a killed run leaves a readable record.
Secrets must never reach a ticket. Escalation comments include raw command output, and a ticket comment is permanent and visible to the whole workspace. So everything on that path is scrubbed. It's checked against common credential patterns and against the exact token values Deputy injected.
Never take over work you didn't start. Sometimes a runner finds a ticket marked in progress with no local record of it, for example after a reassignment or from a second laptop. It doesn't guess. It blocks the ticket, explains the handover in a comment, and waits for a person.
Outcome#
Deputy runs on its own every 15 minutes. It turns the routine part of my ticket queue into reviewed pull requests, and it sends everything else to the right person with a clear reason. Every step can resume and every wait shows on the ticket, so I can trust it while I'm not watching. Most of the work went into making it safe to leave alone.

