Turn GitHub Issues into a work queue your agents drain

GitHub Issues is where your team files work. It is not a dispatcher: no atomic claim, so two agents grab the same ticket; no lease, so a dead agent’s work just strands; no dependency-aware pull, so a blocked ticket still surfaces. Connect the repo to Retasc and every issue syncs in as a claimable queue item your agents pull from, then closes back on GitHub when the work ships.

Updated July 2026 · 7 min read

Why a queue, not just the issues list

GitHub Issues is a filing cabinet, and a good one: it is where humans report, discuss, and triage. It was never built for how a fleet of agents picks work up. Three gaps show up the moment more than one agent is pulling. There is no atomic claim, so two agents that read the list in the same second both start #142. There is no lease, so when an agent dies mid-issue the work just stops, with no signal and no handoff. And nothing walks the dependency graph, so a ticket blocked on another still lands in front of whoever asks next. Assigning the issue does not fix this: an assignee is a label, not a lock, and it is still a person deciding who does what.

Pulling inverts that. Keep GitHub Issues as the reporting surface your team already lives in, connect the repo, and each issue arrives in Retasc as a claimable, leased, dependency-aware queue item. Agents pull from the queue, the server hands each one a different issue, and the ticket resolves back on GitHub when the work is done.

Claiman assignee is a label · a claim is an atomic lock, one agent
Leaseno handoff when an agent dies · a 30-min lease auto-reclaims
Dispatcha flat list · blocked work is never handed out

Connect a repo from the Dash

Connecting is a Dash action, and an owner does it once per repo. It takes a raw GitHub token, so it is deliberately kept off the agent tools and out of any model context; a human wires it in the Dash. You give it two things, and an optional third: the project that synced issues land in, the repo in owner/name form, and, if you want the loop to close, a GitHub token with issues:write. Leave the token blank for a one-way feed; more on that below.

Retasc mints the rest server-side: an unguessable webhook URL of the form https://<deployment>.convex.site/webhooks/github/<intakeId>, and a signing secret shown to you exactly once. Copy the secret then, because it is never shown again. Lose it and you’ll disconnect and reconnect for a fresh one.

The last step is on GitHub, and the Dash walks you through it: in the repo, open Settings, then Webhooks, then Add webhook. Paste the Payload URL, set Content type to application/json, paste the Secret, choose "Let me select individual events" and check Issues, and Save. GitHub sends a ping the instant you save, and a healthy connector answers it.

Youproject + repo (owner/name) + optional token (issues:write)
Retascwebhook URL + signing secret · secret shown once
GitHubWebhooks → event: Issues · content type application/json

How a ticket becomes a queue item

When an issue event arrives and its signature checks out, Retasc normalizes the payload into a native queue item. The title and body come across, encrypted at rest under your org’s own key like anything else you put in Retasc, and the issue lands as todo work at default priority with a support label, so intake is one filter away from native work. A GitHub milestone with a due date maps to the issue’s dueAt, so a deadline you set on GitHub feeds Retasc’s deadline-aware dispatch. Every synced issue keeps a link back to its source.

Redeliveries are safe. Retasc dedupes on GitHub’s delivery id, so a webhook GitHub retries is a no-op, and it upserts on the source id (github:owner/repo#n), so an edit upstream updates the same queue item instead of spawning a duplicate. One asymmetry is deliberate: syncing in never changes an issue’s Retasc status. Intake refreshes content; your agents own the lifecycle. That is what keeps the inbound sync and the outbound close from chasing each other in a loop.

POST /webhooks/github/<intakeId> · X-Hub-Signature-256 verified
RTSC-61from acme/api#142 · milestone → dueAtlabelsupport
RTSC-61branch rtsc-61/flaky-retryclaimed
RTSC-61closes acme/api#142 as completeddone

Closing the loop back on GitHub

Give the connector a token and the loop closes itself. When an agent marks a synced issue done in Retasc, Retasc sends a PATCH to the GitHub API and closes the source issue as completed. Mark it canceled instead and the GitHub issue closes as not planned. The person who filed the ticket sees it resolve where they filed it, with no one switching tabs to keep GitHub in sync.

Two edges are worth stating plainly. The close is best-effort: it is scheduled after the Retasc transition has already committed, so a GitHub outage or a stale token cannot roll back the work. It just means the source issue stays open and the failure is logged for you to see. And it fires only on a real transition into done or canceled. A close on the GitHub side does nothing to the Retasc issue, by design, because once an issue syncs in the queue owns its lifecycle.

One-way or two-way, and what is guarded

The token is the only difference between the two modes. No token is a clean one-way feed: issues stream in, agents work them, nothing is written back, which is the safe default for a repo you only want to drain. Add a token with issues:write and the same connector starts closing issues at the source. Start one-way and add the token later by reconnecting; nothing else changes.

Whichever shape you run, the wiring is built to point at a company repo. Every delivery is verified with an HMAC-SHA256 signature over the raw body before a byte is parsed, and an unknown or revoked connector answers the same flat 401 as a bad signature, so the webhook path cannot be probed. Connectors are scoped to your org throughout. The signing secret and the GitHub token live server-side and are never returned over the API or the agent tools; a connector read tells you whether a token is present, never what it is. Revoking a connector in the Dash stops the sync immediately and leaves the issues it already synced in place.

Gotchas

A few edges worth knowing before you wire a busy repo.

Scopethe GitHub issues event only in v1 · pull requests come later
GitHub closeignored · the queue owns lifecycle once an issue syncs in
Content typemust be application/json or the delivery fails to parse
Labelsonly a support label · GitHub labels, assignees, author not copied
Secretnever shown twice · reconnect to rotate the URL and secret

None of these are dead ends, and most are the queue being deliberate about who owns what. The one to plan around is the first: intake is issues today, so a pull-request workflow still runs through your agents the usual way, over the queue they already pull.

Questions that come up

Can AI agents work my GitHub Issues automatically?

Yes. Connect the repo from the Retasc Dash and each GitHub issue syncs in as a claimable queue item. Your agents pull from that queue over MCP, claim one atomically, work it on its own branch, and the issue closes back on GitHub when the work ships. GitHub Issues stays your team’s reporting surface; Retasc is the dispatcher the agents pull from.

Does closing a Retasc issue close the GitHub issue?

Yes, if the connector has a GitHub token with issues:write. Marking the synced issue done closes the source issue as completed; canceled closes it as not planned. Without a token the sync is one-way and nothing is written back. The close is best-effort: it runs after the Retasc transition has committed, so a GitHub outage never rolls back the work, it just leaves the source issue open and logs the failure.

Is the GitHub sync one-way or two-way?

Both, and the token decides. With no token it is one-way: issues stream in, agents work them, nothing is written back. Add a token with issues:write and the same connector closes issues at the source when the work is done. You can start one-way and add the token later by reconnecting.

How is the GitHub webhook secured?

Every delivery is verified with an HMAC-SHA256 signature over the raw request body, keyed by a secret Retasc generates and stores server-side. An unknown or revoked connector returns the same 401 as a bad signature, so the webhook URL cannot be enumerated. Connectors are scoped to your org, and the signing secret and GitHub token are never returned over the API or the agent tools.

Connecting a repo takes a few minutes in the Dash, and signup seeds the first $10 of usage. Moving a backlog over from somewhere else? The Linear import lands issues the same way, and the parallel agents guide covers the fleet that drains them.