---
title: "Tools"
description: "Give the model GitHub operations it can call, from reading an issue to merging a pull request."
canonical_url: "https://github-tools.com/tools"
---
# Tools

> Give the model GitHub operations it can call, from reading an issue to merging a pull request.

## Overview

A GitHub tool is one GitHub API operation an AI model can call, such as reading an issue or merging a pull request. The SDK has 97 of them: 49 read and 48 write. Each tool describes every input it takes, so the model knows what to pass, and returns only the fields the model needs instead of GitHub's whole response.

<shaped-output>



</shaped-output>

You create the tools in one call and hand them to the model like any other AI SDK tools. Most agents only need the tools for one job, which a [preset](https://github-tools.com/presets) picks for you. Every write tool asks for [approval](https://github-tools.com/approval) before it runs.

## Configure

Create the tools with `createGithubTools()` and pass them wherever the AI SDK takes `tools`: `generateText`, `streamText` or a `ToolLoopAgent`.

```ts [summarize.ts]
import { createGithubTools } from '@github-tools/sdk'
import { generateText } from 'ai'

const { text } = await generateText({
  model: 'anthropic/claude-opus-5.5',
  tools: createGithubTools({ preset: 'issue-triage' }),
  prompt: 'Summarize issue 42 on vercel/ai.',
})
```

[The tool catalog](https://github-tools.com/reference/tools) lists all 97 tools.

### Options

Every option is optional.

<table>
<thead>
  <tr>
    <th>
      Option
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      What it does
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        token
      </code>
    </td>
    
    <td>
      <code>
        GITHUB_TOKEN
      </code>
    </td>
    
    <td>
      A token string, or an async function that returns one. See <a href="https://github-tools.com/auth">
        Auth
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        preset
      </code>
    </td>
    
    <td>
      All 97 tools
    </td>
    
    <td>
      One preset or an array of presets. See <a href="https://github-tools.com/presets">
        Presets
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        requireApproval
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Which writes ask first: <code>
        true
      </code>
      
      , <code>
        false
      </code>
      
      , <code>
        'auto'
      </code>
      
       or per tool. See <a href="https://github-tools.com/approval">
        Approval
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        evaluation
      </code>
    </td>
    
    <td>
      Jev, <code>
        maxRisk: 1
      </code>
      
      , <code>
        minIntent: 0.6
      </code>
    </td>
    
    <td>
      The decision model behind <code>
        'auto'
      </code>
      
      . See <a href="https://github-tools.com/approval#let-a-model-decide">
        Approval
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        context
      </code>
    </td>
    
    <td>
      None
    </td>
    
    <td>
      A default <code>
        owner
      </code>
      
      , <code>
        repo
      </code>
      
      , pull request, issue or ref. See <a href="https://github-tools.com/context">
        Context
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        overrides
      </code>
    </td>
    
    <td>
      None
    </td>
    
    <td>
      A per-tool description, title or <code>
        needsApproval
      </code>
      
      . See <a href="#overrides">
        Overrides
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        author
      </code>
      
      , <code>
        committer
      </code>
    </td>
    
    <td>
      The token's owner
    </td>
    
    <td>
      Who the commits are from. See <a href="https://github-tools.com/commits">
        Commits
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        coAuthors
      </code>
    </td>
    
    <td>
      None
    </td>
    
    <td>
      <code>
        Co-authored-by
      </code>
      
       trailers on every commit. See <a href="https://github-tools.com/commits">
        Commits
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        guardrails
      </code>
    </td>
    
    <td>
      Block credentials
    </td>
    
    <td>
      The repositories and branches any call may act on, whoever approves it. See <a href="https://github-tools.com/approval#guardrails">
        Guardrails
      </a>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        dryRun
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Shadow mode: reads run, writes report what they would have done. See <a href="https://github-tools.com/approval#shadow-mode">
        Shadow mode
      </a>
    </td>
  </tr>
</tbody>
</table>

`createGithubAgent()` takes the same options plus `model`, `instructions` and `additionalInstructions`, and also accepts `preset: 'auto'`. The [AI SDK integration](https://github-tools.com/integrations/ai-sdk) covers it, and the [API reference](https://github-tools.com/reference/api) has every signature.

## Call a tool from your code

Each tool has an `execute` function, so a script or a test can call it without a model. The result is the shaped object the model would read:

```ts [issue.ts]
import { createGithubTools } from '@github-tools/sdk'

const tools = createGithubTools({ preset: 'repo-explorer' })

const issue = await tools.getIssue.execute!(
  { owner: 'vercel', repo: 'ai', issueNumber: 42 },
  { toolCallId: 'example', messages: [] },
)
// { number, title, body, state, url, author, assignees, labels, comments, createdAt, updatedAt, closedAt, rateLimit }
```

## Pick single tools

When you want a hand-picked set instead of a preset, import the tools one by one. Each tool is exported as a factory. Read factories take a token, and write factories also take `{ needsApproval }`, which defaults to `true`:

```ts [review-tools.ts]
import { addPullRequestComment, getPullRequest, listPullRequestFiles } from '@github-tools/sdk'

const token = process.env.GITHUB_TOKEN!

const tools = {
  getPullRequest: getPullRequest(token),
  listPullRequestFiles: listPullRequestFiles(token),
  addPullRequestComment: addPullRequestComment(token, { needsApproval: true }),
}
```

A factory returns the bare tool, without the extras `createGithubTools()` adds. The FAQ lists [what you give up](#what-do-single-tool-factories-leave-out).

## Overrides

Overrides change how one tool is presented to the model or approved, without changing what it does. Use them to reword a description for your domain, or to stop one write from asking. Key them by tool name:

```ts [overrides.ts]
import { createGithubTools } from '@github-tools/sdk'

const tools = createGithubTools({
  overrides: {
    listIssues: { description: 'List bugs for the current sprint' },
    deleteGist: { needsApproval: false },
  },
})
```

<table>
<thead>
  <tr>
    <th>
      Property
    </th>
    
    <th>
      What it changes
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        description
      </code>
    </td>
    
    <td>
      What the model reads to decide when to call the tool
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        title
      </code>
    </td>
    
    <td>
      The human-readable name
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        needsApproval
      </code>
    </td>
    
    <td>
      A boolean or a function of the input. Wins over <code>
        requireApproval
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        strict
      </code>
    </td>
    
    <td>
      Strict input generation, where the provider supports it
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        providerOptions
      </code>
    </td>
    
    <td>
      Provider-specific tool settings
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        toModelOutput
      </code>
    </td>
    
    <td>
      How the result is turned into what the model reads
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        onInputStart
      </code>
      
      , <code>
        onInputDelta
      </code>
      
      , <code>
        onInputAvailable
      </code>
    </td>
    
    <td>
      Callbacks while the model streams the input
    </td>
  </tr>
</tbody>
</table>

The type is exported as `ToolOverrides`.

## Page through long lists

List tools return one page at a time, so a repository with thousands of issues doesn't arrive in one result:

```ts
{ items, hasMore, page, perPage, nextPage? }
```

When `hasMore` is true, the model calls the tool again with `page: nextPage`. Passing `maxPages` (up to 20) fetches that many pages in one call and returns them together.

<table>
<thead>
  <tr>
    <th>
      Tools
    </th>
    
    <th>
      Default page size
    </th>
    
    <th>
      Largest <code>
        perPage
      </code>
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Most lists
    </td>
    
    <td>
      30
    </td>
    
    <td>
      100
    </td>
  </tr>
  
  <tr>
    <td>
      Search tools
    </td>
    
    <td>
      10
    </td>
    
    <td>
      30
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        listDiscussions
      </code>
      
      , <code>
        listNotifications
      </code>
    </td>
    
    <td>
      20
    </td>
    
    <td>
      
    </td>
  </tr>
</tbody>
</table>

## Output size

Results are trimmed by default so one call can't fill the model's context. Most trims have an input that asks for more:

- Long issue, pull request, discussion and release bodies are cut to about 500 characters. Pass `detail: 'full'` for the whole text.
- Diff patches are left out of `listPullRequestFiles`, `getCommit` and `compareCommits`. Pass `includePatch: true`, and `filenames` on `listPullRequestFiles`, for the diffs you need.
- `getFileContent` takes `startLine`, `endLine` or `maxLines`. The model sees at most 20,000 characters of a file, 4,000 of each patch and 200 entries of a tree.
- `getWorkflowJobLogs` returns the last 200 lines without timestamps. Raise `maxLines` up to 2,000.

[Context tools](https://github-tools.com/context#context-tools) go further by answering a whole question, such as "why did CI fail", in one call.

## Check the rate limit

GitHub limits how many requests a token can make. Every result that is an object carries a `rateLimit` field from the last GitHub response: `remaining`, `limit`, `reset`, and `resource` and `retryAfter` when GitHub sends them. `resource` is `core`, `search` or `graphql`.

`createGithubTools()` removes `rateLimit` from what the model reads, and your code still gets it, for example in `onStepFinish` or a UI tool part:

```ts [rate-limit.ts]
import type { GithubRateLimit } from '@github-tools/sdk'

const remaining = (result as { rateLimit?: GithubRateLimit }).rateLimit?.remaining
```

When the limit runs out, calls fail with [`RATE_LIMITED`](https://github-tools.com/errors), and the message includes the reset time.

## Send fewer tool definitions

The model reads every tool definition on every request, whether it calls the tool or not. A [preset](https://github-tools.com/presets) lists only the tools one job needs, and `preset: 'auto'` lets a decision model [pick them per conversation](https://github-tools.com/presets#let-the-agent-pick-tools).

## FAQ

<accordion>
<accordion-item label="Why is tools.mergePullRequest a type error?">

`tools.mergePullRequest` is a type error when the preset doesn't include `mergePullRequest`, because the return type of `createGithubTools()` follows the preset. `issue-triage` doesn't include it, so the property doesn't exist on its tool set.

</accordion-item>

<accordion-item label="What do single tool factories leave out?">

Single tool factories leave out `context`, `overrides`, `requireApproval: 'auto'` and the removal of `rateLimit` from what the model sees. Those only apply through `createGithubTools()`.

</accordion-item>

<accordion-item label="How do I set commit attribution on a single tool?">

The commit tools (`createOrUpdateFile`, `editFiles`, `mergePullRequest`, `enablePullRequestAutoMerge`) take `author`, `committer` and `coAuthors` in the same object as `needsApproval`. See [Commits](https://github-tools.com/commits).

</accordion-item>

<accordion-item label="Can an override change what a tool does?">

No, an override can't replace a tool's `execute`, `inputSchema` or `outputSchema`.

</accordion-item>

<accordion-item label="Do all list tools page the same way?">

No, a few list tools keep their own shape. `listWorkflows`, `listWorkflowRuns`, `listWorkflowJobs` and `listCheckRuns` keep their own keys (`workflows`, `runs`, `jobs`, `checkRuns`) and add the paging fields next to them. `listDiscussions` and `listPullRequestReviewThreads` page with a cursor: pass the returned `endCursor` as `after`. `listDependabotAlerts` returns `nextCursor` for the same purpose.

</accordion-item>

<accordion-item label="Can I use a per-step tool selector?">

Yes, per-step selectors such as [toolpick](https://github.com/pontusab/toolpick) work, because `createGithubTools()` returns a plain AI SDK `ToolSet`.

</accordion-item>
</accordion>


## Sitemap

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