Frameworks

Build a GitHub agent with the eve extension

Mount @github-tools/eve-extension under agent/extensions/ to add all 42 GitHub tools to an eve agent — the recommended way to wire GitHub into eve, with durable approval and Vercel Connect support.

eve is Vercel's filesystem-first agent framework: an agent is a folder with instructions, a model config, and tools. @github-tools/eve-extension packages all 42 GitHub tools as a mountable eve extension — a single pnpm add and a one-line mount under agent/extensions/, no CLI setup, and no direct SDK import in agent/tools/.

This is the recommended way to add GitHub tools to an eve agent. The lower-level direct import, @github-tools/sdk/eve, is deprecated in its favor — it keeps working, but new agents should mount the extension instead.

Add GitHub tools to an eve agent via the extension

The whole agent

Three files. That's the entire thing:

You are a GitHub assistant. Use the GitHub tools to inspect repos, PRs, and issues.
Ask before merging or closing anything destructive.

Run it:

Terminal
npx eve dev

You now have a GitHub agent that can read repos, review PRs, triage issues, and manage CI — with every write operation gated behind durable approval by default. The full example lives in examples/eve-extension-agent/ (or pnpm dev:eve-extension-agent from the monorepo root).

Install

pnpm
pnpm add @github-tools/eve-extension

eve is a required peer dependency (which itself requires ai v7):

pnpm
pnpm add eve

You still need GITHUB_TOKEN (or a Vercel Connect connector, below). See Installation.

Mount it

Drop a file under agent/extensions/ — the filename becomes the tool namespace:

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

export default githubExtension({
  connector: 'github/my-connector', // or token: process.env.GITHUB_TOKEN
  preset: 'code-review',
  requireApproval: {
    addPullRequestComment: ({ toolInput }) => toolInput?.owner !== 'vercel-labs',
  },
})

Tools are exposed to the model as <namespace>__<toolName>, where <namespace> comes from the mount file's name — agent/extensions/github.ts yields github__listPullRequests, github__createIssue, and so on.

code-review is used above (rather than maintainer) because it pairs cleanly with a Connect connector — maintainer and repo-explorer include gist tools, and GitHub only grants gist access to user access tokens, never the installation tokens Connect mints, so gist calls 403 over Connect (see Tokens & Auth). The requireApproval predicate above is a real gate, not a no-op: write tools already require approval by always() by default, so { mergePullRequest: true } would change nothing — a predicate is what actually narrows or loosens the default.

Pick exact tools

preset scopes to one of five predefined groups. To hand-pick tools instead — standalone, or layered on top of a preset — use include and exclude:

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

export default githubExtension({
  include: ['getRepository', 'listPullRequests', 'mergePullRequest'],
})

include adds to preset — the effective set is the union of both, so you can pull in a tool a preset is missing without switching to a bigger preset:

agent/extensions/github.ts
export default githubExtension({
  preset: 'code-review', // read-only PR review tools
  include: ['createIssue'], // + one write tool code-review doesn't include
})

exclude removes tool names from whatever preset + include resolved to — useful for dropping a couple of tools you don't want exposed from a larger preset:

agent/extensions/github.ts
export default githubExtension({
  preset: 'maintainer', // all 42 tools
  exclude: ['createRepository', 'deleteGist'], // minus these two
})

Config schema

FieldTypeNotes
tokenstring?Falls back to GITHUB_TOKEN when omitted and connector is not set
connectorstring | (() => string | Promise<string>)Vercel Connect connector name, or a resolver to pick one dynamically (e.g. per environment/tenant); takes priority over token
connectrecord?Passed through to getToken when connector is set
presetpreset name or arraycode-review, issue-triage, ci-ops, repo-explorer, maintainer — see Presets
includestring[]?Tool names to add on top of preset (union), or the full set standalone — see Pick exact tools
excludestring[]?Tool names to remove from the resolved preset + include set
requireApprovalboolean | recordGlobal or per-tool; per-tool values may be 'once', 'always', 'never', or predicate functions
overridesrecordPer-tool description / approval / toModelOutput / outputSchema
author / committer / coAuthorscommit identityAttribution for commit-creating tools — see Commit Attribution

Durable approval, done right

Approval pauses the session durably until a human responds, and policies are expressive:

ValueMaps toBehavior
true / 'always'always()Require approval on every call
false / 'never'never()Skip approval
'once'once()Approve once per session, then auto-allow
predicatecustom ApprovalInput-dependent gate (toolInput, session context)

Default (no requireApproval): all write tools → always(). Unlisted write tools keep the always() fail-safe default. Read tools never require approval. Details: Control write safety.

Vercel Connect

Skip GITHUB_TOKEN entirely and mint the token from a Connect connector — pass connector directly in the mount config, no separate connectGithubTools import needed:

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

export default githubExtension({
  connector: 'github/my-connector',
  preset: 'code-review',
})

Unlike the deprecated direct import, no build.externalDependencies workaround is needed in agent/agent.ts — the extension is pre-built via eve extension build and loaded through eve's extension mechanism rather than inlined from a workspace-linked source import.

@vercel/connect is an optional peer dependency of the extension — install it only when using connector. connector also accepts a () => string | Promise<string> resolver for picking a connector per environment or tenant — see dynamic connector selection. See Vercel Connect for the connector setup checklist and multi-tenant scoping.

Idempotency

eve replays completed steps but re-runs steps interrupted mid-execution:

ToolIdempotency
createOrUpdateFileNatural when content + sha unchanged
closeIssueNatural when already closed
createBranchNatural when branch exists at same SHA
addIssueComment, createIssue, mergePullRequest, …Not idempotent

Gate non-idempotent writes behind always() or once() where replay safety matters.

Migrating from the direct import

If you have an existing agent using @github-tools/sdk/eve directly in agent/tools/, move to the extension in three steps:

  1. pnpm add @github-tools/eve-extension and remove the now-unused direct eve/ai/zod install if nothing else in the agent needs them.
  2. Delete agent/tools/github.ts and create agent/extensions/github.ts exporting githubExtension({ ...same options... }) instead of createGithubTools({ ...same options... }). Options (preset, include, exclude, requireApproval, overrides, author/committer/coAuthors, token) are unchanged.
  3. If you used connectGithubTools from @github-tools/sdk/connect/eve, drop it — pass connector directly to githubExtension instead.
  4. If you cherry-picked single-tool factories (e.g. listPullRequests() exported alone from its own file), replace each agent/tools/*.ts file with an include: [...] list in the single agent/extensions/github.ts mount — see Pick exact tools.

One behavior change to be aware of: tool names gain the <namespace>__ prefix described above, so update any code that references tool names by their bare string (requireApproval and include keys stay bare — only the exposed model-facing tool name gets the prefix).

eve extension vs direct import vs AI SDK vs Workflow SDK

eve extensioneve (direct import)AI SDKWorkflow SDK
Import@github-tools/eve-extension@github-tools/sdk/eve@github-tools/sdk@github-tools/sdk/workflow
Mount pointagent/extensions/agent/tools/anywhereworkflow function
StatusRecommendedDeprecatedActiveActive
Tool registrationgithubExtension() mountdefineDynamic in agent/tools/createGithubTools() objectcreateGithubTools() in workflow
Tool naming<namespace>__<toolName>bare tool namebare tool namebare tool name
Approvalalways / once / predicatesalways / once / predicatesboolean needsApprovalboolean needsApproval (durable pause)
Durabilityeve session (filesystem-first)eve session (filesystem-first)in-process"use workflow" steps

External references