---
title: "Triage issues"
description: "Build an eve agent that asks for updates on inactive issues, labels them stale, and closes the unanswered ones once you approve."
canonical_url: "https://github-tools.com/guides/triage-issues"
---
# Triage issues

> Build an eve agent that asks for updates on inactive issues, labels them stale, and closes the unanswered ones once you approve.

To triage stale issues with an AI agent, mount the `issue-triage` preset in an eve agent, tell it what counts as stale, and let comments and labels run while each close waits for your approval. This guide builds that agent with the [eve extension](https://github-tools.com/integrations/eve) in three files.

## What you'll build

Ask the agent to sweep a repository and it finds open issues with no activity in 30 days, comments to ask the author whether they still apply, and labels them `stale`. On the next sweep, it proposes closing the `stale` issues that got no answer, and each `closeIssue` call waits for you.

<stale-sweep>



</stale-sweep>

## Before you start

- An eve project, or an empty folder for one. eve needs `ai` 7.
- A GitHub connector named `github/my-connector` in [Vercel Connect](https://github-tools.com/auth#create-a-github-connector), with its token pulled locally. A `GITHUB_TOKEN` with Issues (write) works instead, as shown below.

## 1. Install the packages

<code-group>

```bash [pnpm]
pnpm add @github-tools/eve-extension @vercel/connect eve ai zod
```

```bash [npm]
npm install @github-tools/eve-extension @vercel/connect eve ai zod
```

```bash [yarn]
yarn add @github-tools/eve-extension @vercel/connect eve ai zod
```

```bash [bun]
bun add @github-tools/eve-extension @vercel/connect eve ai zod
```

</code-group>

The agent is three files:

```text
agent/
├── agent.ts               # defineAgent({ model: 'anthropic/claude-opus-5.5' })
├── instructions.md        # the sweep
└── extensions/
    └── github.ts          # the GitHub tools
```

## 2. Mount the triage tools

The extension mounts the `issue-triage` [preset](https://github-tools.com/presets) and lets the two reversible writes run without asking:

```ts [agent/extensions/github.ts]
import githubExtension from '@github-tools/eve-extension'

export default githubExtension({
  connector: 'github/my-connector',
  preset: 'issue-triage',
  requireApproval: {
    addIssueComment: false,
    addLabels: false,
  },
})
```

`closeIssue` isn't listed, so it keeps the default and asks every time. To use a personal token instead of a connector, replace `connector` with `token: process.env.GITHUB_TOKEN`.

eve names the tools after the file: the model sees `github__searchIssues`, `github__closeIssue` and so on.

## 3. Describe the sweep

The instructions say what stale means and what to do with each issue:

```md [agent/instructions.md]
You maintain this repository's issue tracker. Your only job is sweeping stale issues.

When asked to sweep a repository:
- Find open issues with no activity in the last 30 days with searchIssues,
  using `repo:<owner>/<repo> is:issue is:open updated:<YYYY-MM-DD` for the date 30 days ago.
- For each one without the `stale` label: post one comment asking the author whether
  it still applies, then add the `stale` label.
- For each one that already has the `stale` label and no comment from the author since:
  close it with a short, polite explanation.
- Never touch an issue that changed in the last 30 days.
- End with a short summary: commented, closed, skipped.
```

`searchIssues` takes GitHub's search syntax, so one call finds every inactive issue instead of paging through the whole list.

## Run it

```bash [Terminal]
npx eve dev
```

Ask "sweep stale issues on my-org/my-repo". The agent comments on and labels the inactive issues without stopping, then returns an approval request for each `closeIssue` call. Approve the ones you agree with.

## FAQ

<accordion>
<accordion-item label="Can the sweep run on a schedule?">

Yes, with an [eve schedule](https://eve.dev/docs/schedules) under `agent/schedules/`. A markdown schedule has no channel, so a write that asks for approval fails the session instead of waiting. Have the scheduled prompt only comment and label, and run the closing sweep from a chat where someone can approve.

</accordion-item>

<accordion-item label="Why do comments and labels run without asking?">

Both are cheap to undo, and the instructions limit them to inactive issues. `closeIssue` changes what people see in the tracker, so it keeps asking.

</accordion-item>

<accordion-item label="Can a model approve the closes instead of me?">

Not with `requireApproval: 'auto'` alone: it covers 14 low-risk tools, such as labels and comments, and `closeIssue` isn't one of them. Setting `closeIssue: 'auto'` in the per-tool form hands that write to the decision model too. See [Approval](https://github-tools.com/approval#let-a-model-decide).

</accordion-item>

<accordion-item label="How do I triage new issues instead of stale ones?">

Keep the extension and change `instructions.md`: for example, read each issue opened today with `getIssueContext`, pick a label from the repository's labels, and comment with a next step. The [chat bot guide](https://github-tools.com/guides/chat-bot) does this when someone mentions the bot.

</accordion-item>
</accordion>


## Sitemap

See the full [sitemap](https://github-tools.com/sitemap.md) for all pages.
