If you've tried giving an LLM direct access to GitHub, you've probably run into one of these problems:
- The model needs a personal access token somewhere in its prompt or environment. Anything that can trick the model into echoing text (prompt injection, a leaky tool call, a bad log line) can leak a credential with write access to your repos.
- You end up writing your own retry logic, rate-limit backoff, and input validation for every method you expose: create issue, list PRs, star repo, and so on. None of that is your actual product.
- There's no cheap way to say "this agent can create issues but can never delete a repository" without writing custom middleware yourself.
That last point matters most once you move past a demo. An AI agent that can technically call any GitHub endpoint is one bad tool call away from a very bad day.
Swytchcode solves this with a CLI (plus an MCP server and JS/Python SDKs) that sits between your agent and the GitHub API. Your agent calls a tool by a stable ID, like github.issues.create. Swytchcode validates the input, checks it against your project's policies, resolves the GitHub credential locally, and only then makes the request. The model never sees a token. See What is Swytchcode for the full concept.
This guide builds that setup from scratch for GitHub.
What we're building: RepoPilot
RepoPilot is the demo project for this tutorial: a GitHub AI agent with exactly three abilities.
- ⭐ Star a repository on request
- 🐛 Create an issue from a natural-language description
- 🔍 List open pull requests for a repo
Nothing more. Scoping the agent to precisely what it needs, instead of granting blanket API access, is the whole point of this walkthrough.
Full source for RepoPilot: <ADD_YOUR_REPO_LINK_HERE>. Swap in your repo link before publishing. It should contain the finished CLI setup plus the agent script from the last section.
Prerequisites
Before you start, make sure you have:
- Node.js 18+ (or Python 3.9+, both are supported)
- A GitHub account, plus a repo you're happy to test against. Star/issue actions are cheap and reversible, but use a sandbox repo if you're cautious.
- A free Swytchcode account. Sign-in is only for the CLI and registry; it's separate from your GitHub credentials, more on that below.
- An Anthropic or OpenAI API key, only if you want to wire this up to an actual LLM in the last section. The CLI steps work with zero API keys.
- 10 to 15 minutes
Step 1: Install the Swytchcode CLI
# macOS / Linux
curl -fsSL https://cli.swytchcode.com/install.sh | sh
# Windows (PowerShell)
irm https://cli.swytchcode.com/install.ps1 | iex
# or via npm, any OS
npm install -g swytchcode
Verify it's on your PATH:
swy --version
swy is the short alias for swytchcode. Every command below works with either name.
Step 2: Initialize your project
mkdir repopilot && cd repopilot
swy init
This creates a .swytchcode/ directory and a tooling.json file. Treat tooling.json as your agent's allow-list. It starts empty, and nothing is reachable by your agent until you explicitly add it in the next steps.
Step 3: Pull in the GitHub integration
swy search github
swy get github
search looks the integration up in the registry. There are 2000+ APIs available; browse them at swytchcode.com/apis. get downloads GitHub's method and workflow definitions to .swytchcode/integrations/. This step only fetches the bundle to disk. It doesn't grant your agent access to anything yet.
Step 4: Find the exact tools you need
You could scroll through GitHub's entire method list, or just ask for what you want:
swy exec github.user.starred.update --owner swytchcodehq --repo swytchcode-examples
Create an issue
swy exec github.issues.create \
--repo my-org/my-repo \
--title "Login page bug" \
--body "Steps to reproduce: ..."
List open pull requests
swy exec github.pull_requests.list --repo my-org/my-repo
Field names above match what swy info <canonical_id> returns for each method. Confirm against your own info output before scripting these, since exact fields can vary by integration version.
To preview a call without sending it, add --dry-run. It validates inputs without hitting the GitHub API:
swy exec github.issues.create --repo my-org/my-repo --title "test" --dry-run
See the CLI Reference for the full command surface.
Step 8: Add a policy guardrail
The three tools you just enabled aren't the real risk. The risk is whatever gets added later, by someone in a hurry, without thinking about blast radius.
Swytchcode's policy engine evaluates rules before every execution, independent of what your agent decides to do. Here's a rule that permanently blocks repo deletion for this project, regardless of what gets added to tooling.json later:
{
"id": "block-repo-delete",
"target": ["github.repo.delete"],
"when": { "field": "name", "operator": "exists" },
"action": {
"type": "POLICY_BLOCKED",
"message": "Repository deletion is disabled in this environment."
}
}
Add it with:
swy policy add
swy policy validate
Now, if a future teammate (or a confused agent) tries to enable and call github.repo.delete, the request is blocked before it reaches GitHub's API. You can review every blocked attempt later with swy audit policy. That's the difference between an agent that probably won't do anything destructive and one that structurally can't. For more patterns, see Policy Rules and Production Guardrails.
Step 9: Connect your GitHub AI agent to an LLM
Everything above works without any AI involved. Test it that way first. Once you trust the tools, handing them to a model takes a few lines. Here's a minimal example using Claude and the Swytchcode Runtime SDK:
npm install @swytchcode/runtime @anthropic-ai/sdk dotenv
import "dotenv/config";
import Anthropic from "@anthropic-ai/sdk";
import { Swytchcode, TOOL_USE_INSTRUCTIONS } from "@swytchcode/runtime";
import { AnthropicProvider } from "@swytchcode/runtime/providers/anthropic";
async function runAgent() {
const anthropic = new Anthropic();
const swx = new Swytchcode(new AnthropicProvider());
// Only the GitHub tools we enabled in Step 5 are visible here
const tools = await swx.tools.get({ toolkits: ["github"] });
const system = `You are RepoPilot, a GitHub assistant.\n\n${TOOL_USE_INSTRUCTIONS}`;
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: "Star the swytchcodehq/swytchcode-examples repo and then list open PRs on it." },
];
let response = await anthropic.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
system,
tools,
messages,
});
while (response.stop_reason === "tool_use") {
messages.push({ role: "assistant", content: response.content });
const toolResults = await swx.handleToolCalls(response);
messages.push({ role: "user", content: toolResults as Anthropic.ToolResultBlockParam[] });
response = await anthropic.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
system,
tools,
messages,
});
}
for (const block of response.content) {
if (block.type === "text") console.log(block.text);
}
}
runAgent();
Claude decides when to call github.user.starred.update or github.pull_requests.list based on the conversation. It can only call the three tools RepoPilot enabled in Step 5, and every call still passes the policy check from Step 8.
See the Anthropic SDK Quickstart for the Python version and the exact one-time setup commands. The same pattern works for OpenAI, LangGraph, CrewAI, and the Vercel AI SDK too, just swap the provider.
To connect this to Cursor, Claude Code, or another MCP-compatible editor instead of writing agent code by hand, use the MCP Quickstart. swy init --editor=cursor (or claude, windsurf, codex) registers the same three tools with your editor automatically. No separate SDK code required.
What you get with a Swytchcode GitHub AI agent
Here's how this compares to hand-rolling GitHub access for an agent:
| Raw API + token in prompt | RepoPilot (Swytchcode) | |
|---|---|---|
| Credential exposure | Token can appear in prompts and logs | Token never leaves local encrypted store |
| Permission scope | Whatever the token can do | Exactly the tools you add
|
| Blocking a dangerous action | Custom middleware you write and maintain | One JSON policy rule |
| Retries and rate limits | You build it | Handled by the execution engine |
| Auditability | You build it |
swy audit network / swy audit policy out of the box |
This pattern isn't GitHub-specific. The same get, add, auth connect, exec flow works for Stripe, Slack, Notion, and any of the 2000+ integrations Swytchcode supports. GitHub is just a good first integration to try, since every action it takes is visible and reversible.
FAQ: building AI agents for GitHub
Is it safe to give an AI agent access to GitHub?
Only if you scope it. A raw personal access token in an agent's environment gives it whatever that token can do, including deleting repos. Scoping access to a small set of enabled tools, plus a policy layer that blocks specific actions outright, is what makes it safe in practice.
How do I stop an AI agent from deleting a GitHub repo?
Don't rely on prompt instructions alone. Write a policy rule that blocks github.repo.delete (or any destructive method) at the execution layer, so the request never reaches the GitHub API regardless of what the model decides to do. See Step 8 above.
What is an MCP server, and do I need one for a GitHub AI agent?
MCP (Model Context Protocol) is a standard way for AI editors like Cursor or Claude Code to discover and call tools. You don't need it if you're calling tools from your own code with a runtime SDK. You do need it if you want an AI coding assistant to use the same GitHub tools directly in your editor.
Can I use this same setup for APIs other than GitHub?
Yes. The workflow (search, get, add, auth connect, exec, policy) is identical for any supported integration, including Stripe, Slack, and Notion.
Recap
-
swy initsets up an empty allow-list -
swy get githubdownloads the integration -
swy add method <id>enables exactly the tools you need -
swy auth connect githubstores a local, encrypted credential the model never sees -
swy exec <id>lets you test every tool by hand before an agent touches it -
swy policy addmakes destructive actions structurally impossible, not just unlikely - Hand the enabled tools to an LLM via the Runtime SDK or MCP
Built your own version of RepoPilot? Drop a link in the comments, or fork the repo above and send a PR.
Further reading:
- CLI Reference: every command and flag
- MCP Reference: connecting Cursor, Claude Code, Windsurf, and more
- Policy Rules: writing your own guardrails
- Managed Authentication: how credentials are stored and resolved
Building a GitHub AI agent of your own? Drop it in the comments.
Top comments (0)