Update GitHub issues in batches

flurryport:github-update-issuesdeliveryv2first-partysha256:cd009f69f903Needs: read/write agent token

Update, close and reopen GitHub issues in batches, with the PAT held server-side.

How Update GitHub issues in batches carries work out, and where the credential resolvesINTENTYour agentitemsCAPTUREYour endpointsignature checkedstored encryptedreceipt writtenTRANSFORMReshapedeclared by the recipepinned at installDELIVERapi.github.comPOST /graphql$secrets.GITHUB_PATARRIVESGitHubthe work landssigned receipt backThe credential is never in the conversation: it resolves at the target, server-side, at delivery.
How Update GitHub issues in batches carries work out, and where the credential resolvesINTENTYour agentitemsCAPTUREYour endpointsignature checkedstored encryptedreceipt writtenTRANSFORMReshapedeclared by the recipepinned at installDELIVERapi.github.comPOST /graphql$secrets.GITHUB_PATARRIVESGitHubthe work landssigned receipt backThe credential is never in theconversation: it resolves at the target,server-side, at delivery.

Let your AI groom a GitHub backlog through a pipe whose fine-grained PAT it never touches. Send a list of issues and what should change on each, and every edit applies in one call: retitle, rewrite a body, close, reopen, relabel, reassign. The pipe updates existing issues and never creates one, which keeps every fire repeatable: sending the same batch twice leaves the same result, so a fire whose receipt you could not read is safe to send again. Edits go out as aliased GraphQL mutations in a single request, so a batch of twenty is one call and one receipt rather than twenty of each. Changing anything needs a PAT scoped Issues (Read and write), which is a wider grant than the read rung asks for and the reason the two are separate installs rather than one. This recipe needs github-search-issues in practice, because it addresses issues by node id and search is where node ids come from.

The credential never enters the model context: it lives in the FlurryPORT secret store, deliveries are signed server-side, and every send returns a receipt your agent can quote.

What this is

Your AI grooms a GitHub backlog through a pipe whose fine-grained PAT it never touches. Send a list of issues and what should change on each, and every edit applies in one call.
Retitle, rewrite a body, close, reopen, relabel, reassign. Twenty issues in one fire is normal.

Setup in two steps

  1. GitHub side. Settings, Developer settings, Fine-grained tokens: generate a token for ONLY the repositories this pipe should be able to change, with Issues (Read and write) and Metadata (Read). That token is the entire blast radius of the pipe, so scope it on purpose.
  2. FlurryPORT side. Your AI requests secret setup and FlurryPORT emails you a secure page. Paste the token there and the pipe goes live.

How to drive it

Issues are addressed by node id, and node ids come from search and read GitHub issues. Search for what you want to change, carry the id values over, and send the edits:
items: [
  { "id": "I_kwDOAn8...", "state": "CLOSED" },
  { "id": "I_kwDOAn8...", "body": "Reproduced on 0.4.1." }
]

The two pipes are designed to work as a pair: one to see, one to act.

Reading the receipt honestly

This is the part worth knowing before you trust a batch.
HTTP 200 does not mean every entry applied. GitHub applies the entries in order and reports each one separately. A bad entry comes back empty with a row in the errors array naming it, while the others apply normally. A run whose first entry failed still changed everything after it.
So check the per-entry results and the errors array, not the status code.
On plans without full response bodies the receipt is capped at 4096 bytes and long batches get cut off. The writes still happened; only your view of them was truncated. Check ResponseBodyTruncated, and keep batches at twenty or fewer so the receipt stays readable.

Why this pipe never creates issues

Updating is repeatable. Send the same batch twice and you get the same end state, which is what makes an unreadable receipt recoverable: just send it again.
Creating is not repeatable, and mixing the two would poison that guarantee. Filing lives in create a GitHub issue so the repeatable path and the non-repeatable one stay in different pipes.

Credential custody

The PAT is stored encrypted, added at delivery, and scrubbed from stored responses. Because this pipe can change your backlog, consider turning on endpoint signing so possession of the capture URL is not by itself the authority to edit issues.

Install with your agent

npx flurryport mcp

Point your agent at the FlurryPORT MCP server (npx flurryport mcp) and ask it for the flurryport:github-update-issues recipe. Works from AI clients that can run a local process: desktop apps and terminal agents. Web-only chat clients cannot reach a local MCP server; open a desktop client instead.

Tools your agent gains

flry_github_update_issues
Update one or many GitHub issues in a single call. Input: items[], each with id (an issue node id from flry_github_search_issues) plus any of title, body, state (OPEN or CLOSED), labelIds, assigneeIds. Results arrive on the replay execution: read them with get_replay_execution and check BOTH the per-entry results and the errors array, because a partial failure still returns HTTP 200. Updates only, never creates, so a retry cannot duplicate anything.

Setup walkthrough

  1. GITHUB_PAT: GitHub Settings, Developer settings, Fine-grained tokens: generate one for ONLY the repositories this pipe should be able to change, with Issues (Read and write) plus Metadata (Read). This is the whole blast radius of the pipe, so scope it deliberately. Paste it in the FlurryPORT secret page. The same token serves github-search-issues and github-create-issue if you install those too.

Intent schema

{
  "type": "object",
  "required": [
    "items"
  ],
  "properties": {
    "items": {
      "type": "array",
      "description": "One entry per issue to change. Every entry needs id; everything else is the change you want applied.",
      "items": {
        "type": "object",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The issue node id, as returned in the id field of a github-search-issues result. NOT the issue number people quote."
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "description": "OPEN or CLOSED. Closing and reopening are both just a state change."
          },
          "labelIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Label NODE IDs, not label names, and the list REPLACES the issue's labels rather than adding to them."
          },
          "assigneeIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User node ids. Replaces the assignee set."
          }
        }
      }
    }
  }
}

Transformation

{ "body": { "query": "mutation(" & $join([$map($body.items, function($v,$i){ "$in" & $i & ":UpdateIssueInput!" })], ",") & "){" & $join([$map($body.items, function($v,$i){ " m" & $i & ":updateIssue(input:$in" & $i & "){issue{number title state url updatedAt}}" })], "") & " }", "variables": $merge([$map($body.items, function($v,$i){ {("in" & $i): $v} })]) } }

Delivery target

POST https://api.github.com/graphql

Placeholders like $secrets.NAME resolve server-side at delivery, never in the agent.

Gotchas

Where this fits

Related recipes

flurryport:github-create-issuedelivery

Let your AI file GitHub issues with a fine-grained PAT it never touches.

flurryport:github-search-issuesdelivery

Search GitHub issues and read whole threads back, without your AI ever holding the PAT.

flurryport:azure-devops-managedelivery

Create and update Azure DevOps work items in one batched pipe: priority, state, tags, and sprint included.

flurryport:azure-devops-querydelivery

Query Azure DevOps work items with WIQL and read the matching ids back, without your AI ever holding the PAT.

flurryport:azure-devops-readdelivery

Read fields for a batch of Azure DevOps work items by id: title, state, tags, priority, iteration.

flurryport:azure-devops-workitemdelivery

Let your AI file Azure DevOps work items (bugs, tasks) the model never holds credentials for.