How do you assign GitHub issues to AI agents?
kanbots/issue-N-runId branch in a per-card git worktree, spawns claude -p against it, streams the run into the card, and finishes with a one-click Open draft PR.The literal click path
kanbots turns “assign this issue to an AI” into a drag. There is no separate dispatch screen, no “agent assignment wizard”, no API to call. You move the card; the agent starts. Everything else — the branch name, the worktree path, the stream parsing, the decision UI — falls out of that move.
Setup: connect the repo
The repo connection depends on which edition you’re running.
OSS desktop
- Install
gh(the GitHub CLI) and rungh auth loginonce. kanbots’sresolveGitHubToken()shells out togh auth tokenfirst. Alternatives:GITHUB_TOKENenv var, or a token in~/.kanbots/token. PATs needreposcope; fine-grained tokens needIssues,Contents, andPull requestsread/write. - Open kanbots, pick your folder. The first time you flip Settings → Workspace to GitHub mode, kanbots writes
{"mode":"github","owner":...,"repo":...}into.kanbots/config.jsonand runs the initial sync.
Cloud
- From Settings → Integrations → GitHub, click Connect GitHub. The KanBots GitHub App install page opens; the org admin picks the GH org and the repos to expose (granular, not all-or-nothing).
- The callback drops you back on
/o/<org>/settings/integrations?integration_installed=github. Per-installation tokens (1h TTL) are minted on demand from the App’s private key; no long-lived PAT in the database.
Initial sync: open issues land in Backlog
kanbots paginates GET /repos/{owner}/{repo}/issues?state=all&per_page=100and creates one card per issue. Labels are mapped to kanbots labels (auto-created if absent). Status comes from the status:* label on the issue if one exists; otherwise the card lands in the Inbox column waiting for triage. The card-to-issue link is stored in card_external_links with a unique (link_kind, external_id) constraint, so webhook redeliveries upsert the same card.
After the initial sync, GitHub webhooks (cloud) or a polling Octokit client (OSS) keep the board in sync as issues are opened, edited, labeled, or closed.
The dispatch: what a drag does
When you drag issue #142 to In progress, kanbots runs the following sequence:
- Column move → label edit. kanbots issues a
PATCH /repos/{owner}/{repo}/issues/142that removesstatus:backlogand addsstatus:in-progress. Drag-to-move is the GitHub edit. - Worktree. A fresh worktree is created at
.kanbots/worktrees/issue-142-<runId>/on a new branchkanbots/issue-142-<runId>, branched from the repo’s default branch. A.kanbots-identity.jsonfile is dropped at the worktree root so an orphaned run can be recovered later. - Pre-push hook. A
pre-pushhook is installed in the worktree that exits non-zero. The agent can rungit pushall it wants — it will fail. Pushes go through your hands (or through the GitHub App, in cloud) only. - Agent spawn. kanbots execs Claude Code:
For Codex, the adapter swaps inclaude -p \ --output-format stream-json --verbose \ --permission-mode bypassPermissions \ --append-system-prompt "<issue title + body>" \ --model <chosen model>codex execwith the equivalent flags. Both stream one JSON object per line. - Live thread. Every line is parsed by
stream-parser.tsintotext,tool_use,tool_result,decision,result, orrate_limit, persisted to theagent_eventstable, and broadcast to the run drawer. If you reload the desktop window, the thread replays from the table. - Agent state label. While the run is live, the issue gets an
agent:runninglabel. On a decision pause it becomesagent:blocked; on completion awaiting review,agent:review; on failure,agent:failed. Teammates on the GitHub issue see the state without opening kanbots.
Mid-run: decisions and replies
Claude or Codex can emit a decision stream event with a question and a list of options. The dispatcher marks the card awaiting_input, stops feeding stdin, and surfaces the prompt in the run drawer with numbered buttons. Click a button; the handler cards:resolvewrites the chosen value back into the agent’s stdin and the run continues. Close the window mid-decision and reopen later — the prompt is persisted on the card, not lost in memory.
The Reply box on the card takes slash commands too: /spec asks the agent to produce a spec for the issue; /review reviews its own diff; /split proposes child issues. The replies go through the same stream-parsing path, so the response shows up as new events in the thread.
Finishing: promote, PR, or discard
When the agent finishes (a result event with ok:true), the worktree stays on disk. You pick one of four actions:
- Open draft PR (GitHub mode). kanbots pushes the branch and opens a draft PR via Octokit (OSS) or the GitHub App
POST /repos/{owner}/{repo}/pulls(cloud). The PR body links back to the issue and lists the run’s commits. - Promote commit.Stage the tip of the worktree’s branch and cherry-pick onto your main checkout’s active branch. Worktree is removed.
- Reveal worktree. Opens the worktree path in your file manager so you can hand-edit before promoting.
- Discard. Stops the run if active, removes the worktree, deletes the branch.
Failure modes and fixes
“Branch not found on remote.”
The pre-push hook is in your worktree; if you bypass kanbots and manually run a git pushelsewhere, you might think the branch is on origin when it isn’t. Open draft PR fails with branch_not_found. Fix: use the kanbots promote-to-PR button; it pushes from your real checkout (cloud) or prompts you to push manually (OSS).
“Repo isn’t in the GitHub App’s selected list.”
On cloud, the GitHub App is installed with granular repo selection. If you forget to include the repo, PR creation fails with repo_not_in_installation. Fix: go to github.com/organizations/<org>/settings/installations, click the KanBots App, add the repo. The webhook fires and kanbots picks up the new repo within a few seconds.
“Decision timed out.”
Default decision timeout is 30 minutes. If the assignee is asleep when the agent pauses, the run can time out and fail. Fix: raise the timeout in Settings → Decisions (range 60s to 24h), or set a default_value on common decisions so the cloud auto-answers if no human responds in time. The agent sees the system answer the same way as a human one.
When this is the wrong fit
If your GitHub issues are bug reports without enough context to act on, an agent will spin and ask three decision questions before getting useful work done. Triage first: either flesh out the issue manually, or run a triage persona (see how triage autopilot works) that splits and clarifies before you dispatch a coding agent.
If your “issue” spans multiple repos or requires infrastructure changes outside the codebase, the worktree-per-issue model is not the right shape — kanbots agents only see the files inside their worktree.
Related reading
Same workflow from a kanban-board angle: what is an AI agent kanban board. The branch and worktree mechanics in isolation: how do you use git worktrees with Claude Code. Background, sleep-mode operation: run AI agents in the background on GitHub issues.
Try it on your own folder
Drop a folder, get a board, dispatch parallel agents. The desktop runs locally on macOS, Linux, and Windows.
Related questions
- What is the right AI coding agent setup for a team?A shared board, threaded runs, and bring-your-own-keys: why solo IDE agents do not generalize to teams and what the team-first pattern looks like.
- What is an AI agent kanban board?A kanban whose cards are running AI agents. How status columns map to agent lifecycle, what live updates look like, and why this beats issue trackers + a separate agent IDE.
- How do you build an AI agent task queue?Queue → in-progress → review → done, with cost caps, decision prompts, and per-slot parallelism. The plumbing of a real task queue for agents instead of a request/response chatbot.
- How do you orchestrate Claude Code across a team?Centralize Claude Code dispatch behind a shared board: who can start agents, who reviews, where decisions go, and how cost rolls up per project.