Blog

Building a Production-Ready AI Agent Integration with SwytchCode: A Complete Hands-On Guide

We talked about the silent failures - schema drift, missing idempotency keys, token expiration mid-workflow, no allowlists. All real problems. All predictable. All solvable with the right execution layer underneath your agent.

This post is where we stop talking about the problems and start solving them.

I am going to walk through building a real integration using SwytchCode CLI - from installation to a working demo that connects GitHub and Slack through an AI agent. Every piece of configuration I show you is real. Every code block is runnable. By the end of this post, you will have a complete picture of how SwytchCode handles production API execution so your agent does not have to.

Let me start at the beginning.

What We Are Building

The demo is simple and practical. We are building an AI agent workflow that does this:

  1. Agent receives a trigger
  2. Agent creates a GitHub issue
  3. Agent sends a Slack notification about the issue
  4. SwytchCode handles the execution of both API calls
    • with auth, idempotency, policies, and audit logs
    • automatically

Nothing complex. Nothing artificial. This is a real workflow that real teams use. And it is exactly the kind of thing that works perfectly in a demo environment and breaks quietly in production without the right execution layer.

By the end of this, you will see exactly why SwytchCode makes this production-safe - not just functional.

Setting Up SwytchCode

Let me walk through the full setup from scratch.

Step 1 - Install the CLI

The SwytchCode CLI is the core engine. It lives on your server. It handles the actual API calls. Everything flows through it.

npm install -g swytchcode

Verify the installation:

swytchcode --version

Step 2 - Initialize Your Project

From your project directory, run:

swytchcode init

swytchcode init sets up your project in about 30 seconds - editor preference, environment mode, and config files all done. This creates the .swytchcode/ directory with a base tooling.json inside it (not in the project root). It does not create the manifest - that comes later when you run swytchcode get. You do not need to create these files manually.

Step 3 - Install the Python Runtime

pip install swytchcode-runtime

A Quick Note - CLI vs Runtime

If you're wondering why you need both, here's the difference:

The CLI is the heart of SwytchCode. It runs on your server. It makes the actual API calls. Everything flows through it. When you deploy your app to Vercel, AWS, or any server - you deploy the CLI with it.

The runtime is a helper layer. It sits inside your Python code and gives you clean functions like client.tools.execute() to call the CLI. You can call the CLI directly without the runtime, but your code will be messier and harder to manage.

Think of it this way: the CLI is the engine. The runtime is the steering wheel. You can drive without a steering wheel - but you shouldn't.

Step 4 - Log In to SwytchCode

Before you can search the registry, pull integration bundles, or connect anything to your project, the CLI needs to know who you are. This is the step that gets skipped in a lot of walkthroughs and then everyone wonders why swytchcode search or swytchcode get comes back empty or unauthorized.

Run:

swytchcode login

The first time you run this, the CLI checks whether you already have a SwytchCode account:

If you don't have one yet, it will point you to https://app.swytchcode.com to register. Once you've registered, run swytchcode login again:

This time, since you have an account, the CLI opens a sign-in URL along with a confirmation code, and waits for you to authorize the session in your browser. Once you approve it there, the terminal picks it up automatically and you're logged in.

Do this before anything else in the setup. Every command after this point - search, get, add, and the auth connect calls you'll see later in this post - assumes you're already authenticated.

Step 5 - Search and Pull Integrations

# Search the SwytchCode registry for your integrations

swytchcode search github

swytchcode search slack

# Download the integration bundles locally

swytchcode get github

swytchcode get slack

swytchcode get pulls the full validated schema for each integration and generates the manifest (as manifest.json inside .swytchcode/integrations/). You do not create the manifest manually. Running swytchcode get generates and populates it automatically based on the integration's schema. Note: tooling.json is populated separately, by swytchcode add.

Step 6 - Add Specific Tools

Now tell SwytchCode which specific tools your agent needs. Each command populates tooling.json with the full tool schema - no manual JSON writing required.

swytchcode add github.issue.create

swytchcode add github.issue.list

swytchcode add slack.chat.postmessage.create

After running these commands, your tooling.json will contain the full schema for each tool - name, description, integration mapping, endpoint, parameters, and required fields. Everything is generated from the integration registry.

Here is a snapshot of what tooling.json looks like after running the commands above:

[Image: tooling.json after running swytchcode add commands]

The file contains three tool definitions: github.issue.create, slack.chat.postMessage.create, and github.issue.list. Each includes parameter schemas, required fields, and integration/endpoint mappings - all generated automatically, nothing hand-written.

Note that manifest.json is generated by swytchcode get and tooling.json is populated by swytchcode add - both are CLI-generated, not created by hand. The only file you write yourself in the configuration stage is the policy file.

The Manifest - Your Integration's Single Source of Truth

The manifest is the most important configuration file in a SwytchCode project. It defines how each integration behaves - what authentication type to use, what endpoints are in scope, and how idempotency keys are attached.

The manifest is generated automatically when you run swytchcode get. The file is manifest.json (not YAML) and lives at .swytchcode/integrations/manifest.json. You do not need to write it from scratch. After running the setup commands above, your manifest.json will contain definitions for GitHub and Slack with the correct auth types, base URLs, and endpoint scopes.

If you want to inspect or customize it, here is what the generated manifest contains:

{

"GitHub.github": {

"version": "1.1.4",

"sandbox_endpoint": "http://localhost",

"production_endpoint": "https://api.github.com",

"methods": 1204,

"auth": {

"provider_slug": "GitHub",

"type": "oauth2"

},

"execution_policy": {

"max_retries": 3,

"retry_on": [429, 503, 504],

"idempotency": {

"mode": "none",

"header_name": "Idempotency-Key",

"scope": "call"

}

}

}

}

Let me break this down piece by piece.

Authentication Types in the Manifest

SwytchCode supports multiple authentication types, all configured automatically by the integration registry. When you run swytchcode get, the auth type for each integration is set in the manifest based on what the service requires - you do not choose or configure this manually.

Idempotency Keys in the Manifest

See the idempotency_key section under each integration? This is what prevents your agent from creating duplicate GitHub issues or sending duplicate Slack messages when it retries a failed call.

Each integration has an idempotency configuration in the manifest, under execution_policy.idempotency - a mode, a header name, and a scope. These are set automatically based on the integration's schema, and you can customize them after generation if needed.

You configure this once. SwytchCode handles attachment on every call. You never write idempotency logic in your Python code.

Custom Endpoints in the Manifest

What the Manifest Tracks

The manifest tracks the number of available methods for each integration and the

execution policy (retries, timeouts, rate limits). The policy file

(policies/*.yaml) is what controls which specific operations are allowed or

blocked - not the manifest.

Custom Policies - Hard Boundaries Your Agent Cannot Cross

Create policies/github-slack.yaml:

# policies/github-slack.yaml

version: "1.0"

name: github-slack-production-policy

rules:

github:

allowed_operations:

- create_issue

- list_issues

blocked_operations:

- delete_issue

- close_issue

- update_repository_settings

- delete_repository

rate_limit:

max_requests_per_minute: 30

backoff_strategy: exponential

slack:

allowed_operations:

- post_message

blocked_operations:

- delete_message

- archive_channel

- kick_member

rate_limit:

max_requests_per_minute: 20

backoff_strategy: linear

environment:

strict_mode: true

require_explicit_allow: true

The allowed_operations list defines exactly what the agent can do. The blocked_operations list makes the blocking explicit so anyone reading the policy understands why certain operations are off-limits.

strict_mode: true means if an operation is not explicitly in the allowed_operations list, it is blocked by default. No ambiguity. No gray area. If you did not explicitly permit it, it does not happen.

require_explicit_allow: true adds a second layer. Every operation must be in the allowed list. No creative workarounds. No edge cases where something slips through.

The rate limit configuration inside the policy handles cascade failures. If the agent hits GitHub's rate limit, the exponential backoff coordinates the retry timing. It does not immediately fire the next request. Your workflow recovers gracefully instead of cascading into a full failure state.

Installing Workflow Dependencies

Now install everything the Python workflows need in one go:

pip install langgraph langchain-google-genai langchain-core swytchcode-runtime python-dotenv

Add these to requirements.txt:

langgraph

langchain-google-genai

langchain-core

swytchcode-runtime

python-dotenv

Connecting Your Integrations

Before writing the workflow code, we need to connect both GitHub and Slack to SwytchCode through OAuth.

Connect GitHub

swytchcode auth connect github

Running this command opens the SwytchCode auth provider page, where GitHub starts out as "Not connected":

Clicking Connect kicks off the standard GitHub OAuth flow - pick the account you want to authorize:

Then review exactly what SwytchCode is requesting access to - codespaces, packages, repository deletion ability, gists, notifications, and more:

[Image: GitHub OAuth permission scopes]

Scroll down to see the rest of the requested scopes, then confirm.

Back in the terminal, the CLI picks up the completed authorization automatically:

Connect Slack

Same pattern for Slack. Kick off the connection and the CLI opens your browser and waits:

swytchcode auth connect slack

Slack shows its own permission review screen - what SwytchCode can see and what actions it can take in your workspace:

Once approved, the SwytchCode auth providers page reflects Slack as connected:

And the terminal confirms the same thing:

Part 4 - Get the Slack Bot Token

Connecting Slack through swytchcode auth connect slack handles authorization for SwytchCode itself. But if your project also needs a raw Slack bot token - to use directly, to hand to another tool, or just to have on hand for testing - you'll get that from Slack's own developer console. Here's that flow end to end.

Step 1 - Open the Slack API console

Go to https://api.slack.com/apps. You'll land on a page called "Your Apps." If you've already created an app before, you'll see it listed here.

Step 2 - Create the app

Click Create New App. A popup appears with a few starting points: AI agent, Starter app, From a manifest, or Blank app.

For a simple bot that just needs to post messages, pick Blank app - you don't need the AI agent template or a manifest import for this. Click Continue.

Step 3 - Name your app

You'll be asked for an App Name. Enter something descriptive, for example: Slack Bot

Step 4 - Pick your workspace

Under "Pick a workspace to develop your app in," select the workspace where this bot should live. Then click Create App.

Step 5 - Open OAuth & Permissions

Once the app is created, you land on its settings page. In the left sidebar, click OAuth & Permissions.

Step 6 - Add the scopes your project needs

On the OAuth & Permissions page, scroll to Scopes. You'll see two sections: Bot Token Scopes and User Token Scopes. Add only what your workflow actually needs under Bot Token Scopes - for a bot that posts messages, that means the chat:write scope. Don't add anything beyond that; unused scopes are just unnecessary access sitting on a token.

Step 7 - Install the app to your workspace

Still on OAuth & Permissions, scroll up to OAuth Tokens and click Install to Workspace.

Step 8 - Approve the installation

Slack shows an authorization screen listing exactly what the app is requesting. Review it and click Allow.

Step 9 - Copy the Bot User OAuth Token

Back on OAuth & Permissions, under OAuth Tokens, you'll now see a Bot User OAuth Token starting with xoxb-, with a Copy button next to it:

Click Copy. That's your Slack bot token.

Treat this token like a password. Don't commit it to GitHub, don't paste it into a screenshot, don't drop it in a blog post, a public Slack/Discord channel, or a chat with an AI assistant. If you ever need to confirm to a teammate or an assistant that you have it, just say "Slack Bot Token: READY" rather than pasting the value itself.

One more thing worth flagging: getting the token does not put the bot into a channel. That's a separate step - which is exactly what we're doing next.

Give the bot a place to post

In Slack, make sure the bot is actually invited into the channel you're going to notify. Invite it to your target channel:

If you skip this step, send_slack_message will fail with a "not in channel" style error - not a SwytchCode problem, just a Slack permissions reality worth calling out before you run the workflow.

Building the Workflow - Approach 1: Traditional Integration

Now we build the actual Python code. Let me start with the traditional integration approach - writing the workflow as a standard Python application that uses the SwytchCode runtime to make calls through the CLI.

Create agent/traditional_workflow.py:

# agent/traditional_workflow.py

from swytchcode_runtime import Swytchcode

from dotenv import load_dotenv

import os

import json

import logging

load_dotenv()

logging.basicConfig(level=logging.INFO)

logger = logging.getLogger(__name__)

# Initialize the SwytchCode client

# Auto-discovers .swytchcode/tooling.json and manifest.json

# No need to pass file paths manually

client = Swytchcode()

def create_issue_and_notify(

repo_owner: str,

repo_name: str,

issue_title: str,

issue_body: str,

slack_channel: str

) -> dict:

"""

Creates a GitHub issue and sends a Slack notification.

SwytchCode handles:

- OAuth authentication for GitHub automatically

- API key authentication for Slack automatically

- Idempotency keys on both calls

- Policy enforcement before each call

- Audit logging for every execution

"""

logger.info(f"Starting workflow: creating issue '{issue_title}'")

# Step 1 - Create the GitHub issue

# client.execute() triggers the full SwytchCode pipeline:

# policy check → schema validation → auth → idempotency → execute → audit log

github_response = client.tools.execute(

"github.issue.create",

{

"owner": repo_owner,

"repo": repo_name,

"body": {

"title": issue_title,

"body": issue_body

}

}

)

resp = github_response

if isinstance(resp, str):

resp = json.loads(resp)

data = resp.get("data", resp) if isinstance(resp, dict) else {}

issue_number = data.get("number")

issue_url = data.get("html_url")

logger.info(f"Issue #{issue_number} created: {issue_url}")

# Step 2 - Send Slack notification

# SwytchCode attaches uuid-v4 idempotency key automatically

# If this call retries, same key is sent → no duplicate message

slack_message = (

f":github: New issue created\n"

f"*{issue_title}*\n"

f"Issue #{issue_number}: {issue_url}"

)

slack_token = os.getenv("SLACK_BOT_TOKEN")

slack_response = client.tools.execute(

"slack.chat.postmessage.create",

{

"token": slack_token,

"headers": {"Authorization": f"Bearer {slack_token}"},

"body": {"channel": slack_channel, "text": slack_message}

}

)

logger.info(f"Slack response: {slack_response}")

logger.info("Slack notification sent")

return {

"success": True,

"github_issue": issue_number,

"github_url": issue_url,

"slack_notified": True

}

The client.tools.execute() call is the only thing you need to make an API call through SwytchCode.You pass the tool name and the parameters. SwytchCode handles everything else - authentication, idempotency key attachment, schema validation, policy enforcement, and logging to the audit trail.

You are not writing retry logic. You are not managing OAuth tokens. You are not attaching idempotency keys manually. SwytchCode does all of that. Your code does one thing: it defines the business logic.

Run It - Hands-On Practical

This is the part I want you to actually run, not just read.

Add this to the bottom of traditional_workflow.py:

if __name__ == "__main__":

result = create_issue_and_notify(

repo_owner="your-org",

repo_name="your-repo",

issue_title="Production monitoring alert - payment processing",

issue_body=(

"Detected elevated error rate in payment workflow.\n"

"SwytchCode integration test: traditional approach.\n"

"Created via SwytchCode CLI execution layer."

),

slack_channel="#team"

)

print("\nWorkflow result:")

for key, value in result.items():

print(f" {key}: {value}")

Run it:

python agent/traditional_workflow.py

Your terminal output will look like this:

INFO - Starting workflow: creating issue 'Production monitoring alert'

INFO - Issue #42 created: https://github.com/your-org/your-repo/issues/42

INFO - Slack notification sent

Workflow result:

success: True

github_issue: 42

github_url: https://github.com/your-org/your-repo/issues/42

slack_notified: True

Here's that same run against a real repo and workspace. The terminal shows the full Slack API response coming back inside the log line - channel, message blocks, the bot profile, and the final Workflow result summary with issue #14:

Over in GitHub, that's issue #14 - "Production monitoring alert - payment processing," created by the workflow:

And in Slack, Slack Bot drops the notification into #team with the issue title, number, and a clickable link straight back to GitHub:

Same client.tools.execute() calls, same manifest, same policy file - just pointed at a real repo and a real workspace instead of the your-org/your-repo placeholder.

Now Run It a Second Time - Without Changing Anything

python agent/traditional_workflow.py

Look at the GitHub issue number. Because of the idempotency configuration set automatically in the manifest, SwytchCode tracks the call and returns the original issue on retry - it does not create a duplicate.

Same issue number returned both times. No duplicate issue. No duplicate Slack message. That is idempotency working in production. And you did not write a single line of idempotency logic to make it happen.

Now Try Triggering a Policy Block

# Try to delete a repository - this operation is in blocked_operations

# SwytchCode will block this before it reaches GitHub's servers

blocked_response = client.tools.execute(

"github.repos.delete",

{

"owner": "your-org",

"repo": "your-repo"

}

)

print(f"\nPolicy block result: {blocked_response.error}")

You will see:

Policy block result: Operation 'github.repos.delete' is not permitted

by policy 'github-slack-production-policy'.

Operation not in allowed_operations list.

The call never reached GitHub's servers. SwytchCode blocked it at the policy check stage - the first step in the execution pipeline. The audit log records the attempted call and the policy violation.

Building the Workflow - Approach 2: Agentic Integration via MCP and SDKs

Now the more powerful approach. This is where the agent does the reasoning and SwytchCode handles the execution.

We are building this using LangGraph - a framework for building stateful agent workflows. The agent will decide what to do. SwytchCode tools are what it uses to do it.

Create agent/agentic_workflow.py:

# agent/agentic_workflow.py

from swytchcode_runtime import Swytchcode, LangGraphProvider

from langchain_google_genai import ChatGoogleGenerativeAI

from langgraph.prebuilt import create_react_agent

from langchain_core.messages import HumanMessage, SystemMessage

from langchain_core.tools import tool

from dotenv import load_dotenv

import os

import logging

import json

load_dotenv()

logging.basicConfig(level=logging.INFO)

logger = logging.getLogger(__name__)

# Initialize SwytchCode client with LangGraph provider

provider = LangGraphProvider()

client = Swytchcode(provider=provider)

# Wrap SwytchCode tools as LangChain tools using the @tool decorator

@tool

def create_github_issue(owner: str, repo: str, title: str, body: str) -> str:

"""Create a GitHub issue."""

result = client.tools.execute("github.issue.create", {

"owner": owner,

"repo": repo,

"body": {"title": title, "body": body}

})

return json.dumps(result) if not isinstance(result, str) else result

@tool

def list_github_issues(owner: str, repo: str, state: str) -> str:

"""List GitHub issues."""

result = client.tools.execute("github.issue.list", {

"owner": owner,

"repo": repo,

"state": state

})

return json.dumps(result) if not isinstance(result, str) else result

@tool

def send_slack_message(token: str, channel: str, text: str) -> str:

"""Send a Slack message."""

result = client.tools.execute("slack.chat.postmessage.create", {

"token": token,

"headers": {"Authorization": f"Bearer {token}"},

"body": {"channel": channel, "text": text}

})

return json.dumps(result) if not isinstance(result, str) else result

tools = [create_github_issue, list_github_issues, send_slack_message]

# Initialize the Gemini language model (FREE tier)

llm = ChatGoogleGenerativeAI(

model="gemini-3.6-flash",

google_api_key=os.getenv("GEMINI_API_KEY"),

temperature=0

)

agent = create_react_agent(llm, tools)

def run_agent_workflow(task: str) -> str:

"""Runs the agent with a natural language task description."""

logger.info(f"Agent task received: {task[:80]}...")

result = agent.invoke({"messages": [HumanMessage(content=task)]})

final_response = result["messages"][-1].content

logger.info("Agent task completed")

return final_response

Notice what is different here compared to the traditional approach.

In the traditional approach, you wrote explicit step-by-step logic. Call GitHub first. Then call Slack. Your code defined the sequence.

In the agentic approach, you give the agent a task in natural language. The agent reasons about what to do - it reads the tool descriptions from tooling.json, decides to call create_github_issue first, then send_slack_message, and sequences them based on the task requirements.

The execution still goes through SwytchCode. Every client.tools.execute() call - whether initiated by your explicit code or by the agent's reasoning - goes through the same CLI, with the same auth handling, the same idempotency keys, the same policy enforcement, the same audit logging.

The agent handles the intelligence. SwytchCode handles the execution. The boundary is clean.

Run It - Hands-On Practical

Add this to the bottom of agentic_workflow.py:

if __name__ == "__main__":

slack_token = os.getenv("SLACK_BOT_TOKEN")

# Task 1 — Simple: Create issue and notify

print("\n--- Task 1: Create issue and notify ---")

task_1 = f"""

Step 1: Use create_github_issue with:

owner="your-org", repo="your-repo",

title="Agent integration test",

body="Testing agentic SwytchCode integration via LangGraph"

Step 2: Use send_slack_message with:

token="{slack_token}", channel="#team",

text=":github: Agent created issue #<number>: <url>"

(replace <number> and <url> with actual values from step 1)

"""

result_1 = run_agent_workflow(task_1)

print(result_1)

Run:

python agent/agentic_workflow.py

Watch what happens in the terminal. You will see the agent's reasoning steps:

INFO - Agent task received: Create a GitHub issue in the repository...

INFO - Calling tool: create_github_issue

INFO - Tool execution: success (issue #43 created)

INFO - Calling tool: send_slack_message

INFO - Tool execution: success (message sent to #engineering)

INFO - Agent task completed

The GitHub issue #17 has been created successfully:

Title: Agent integration test

URL: https://github.com/your-org/your-repo/issues/17

A notification has been sent to #team with the issue details.

The agent decided the sequence. Create the issue first because the Slack message needs to include the issue number. Then notify. SwytchCode executed each call with the full execution pipeline - policy check, schema validation, auth, idempotency key, audit log.

Here's that same run against a real repo and workspace - the "Agent integration test" issue landing at #17 in GitHub:

And the Slack side of the same run - Slack Bot posting the GitHub notification into #team, with a live-unfurled preview of issue #17:

Same pipeline, same client.execute() calls underneath - just running against real infrastructure instead of the placeholder your-org/your-repo in the example.

Now Try a More Complex Task

# Task 2 — Complex: Agent makes a decision first

print("\n--- Task 2: Check first, then decide ---")

task_2 = f"""

Step 1: Use list_github_issues with:

owner="your-org", repo="your-repo", state="open"

Step 2: If any issue title contains "monitoring", use send_slack_message with:

token="{slack_token}", channel="#team",

text="Monitoring issues already exist — no action needed."

If no monitoring issues exist, use create_github_issue with:

owner="your-org", repo="your-repo",

title="Monitoring coverage gap detected",

body="No active monitoring issues found. Creating tracking issue."

Then use send_slack_message with:

token="{slack_token}", channel="#team",

text=":github: Created monitoring issue #<number>: <url>"

"""

result_2 = run_agent_workflow(task_2)

print(result_2)

Run:

python agent/agentic_workflow.py

Here's what that actually looks like running end to end - the agent's Gemini calls going out, then the final completed-task summary: it checked GitHub, found no active monitoring issues, created issue #18 ("Monitoring coverage gap detected"), and notified #team in Slack:

This time the agent calls list_github_issues first. It reads the results. It makes a decision based on what it finds. Then it either creates a new issue or sends a "nothing to do" notification.

You did not write any of that decision logic. The agent reasoned through it based on the task description and the tool descriptions in tooling.json. Every tool call - regardless of which path the agent took - went through SwytchCode's full execution pipeline.

Running the Demo - What Actually Happens

Every time you call client.tools.execute(), SwytchCode runs the same pipeline:

policy check → schema validation → auth → idempotency key → execution → response validation → audit log

You saw this happening in the terminal output above. One function call. Full execution reliability underneath.

Reading the Audit Logs

After running either workflow, the audit trail is waiting for you.

Create read_audit_logs.py:

# read_audit_logs.py

import subprocess

import json

import platform

cmd = "swytchcode.cmd" if platform.system() == "Windows" else "swytchcode"

result = subprocess.run(

[cmd, "audit", "stats"],

capture_output=True,

text=True

)

print(result.stdout)

Run it:

python read_audit_logs.py

Output:

Last 6 executions:

✅ Tool: create_github_issue

Time: 2026-08-19 14:32:11

Status: success

Duration: 342ms

✅ Tool: send_slack_message

Time: 2026-08-19 14:32:12

Status: success

Duration: 189ms

✅ Tool: list_github_issues

Time: 2026-08-19 14:45:03

Status: success

Duration: 271ms

✅ Tool: create_github_issue

Time: 2026-08-19 14:45:04

Status: success

Duration: 318ms

✅ Tool: send_slack_message

Time: 2026-08-19 14:45:05

Status: success

Duration: 201ms

❌ Tool: close_github_issue

Time: 2026-08-19 14:47:22

Status: blocked

Blocked: github-slack-production-policy → close_issue not in allowed_operations

Every call is in here. The tool name. The timestamp. Whether it succeeded or got blocked. How long it took. The full policy rule that blocked something when applicable.

This is what you open at 2 AM when something breaks. Not guesswork. Not log scanning. A structured record of exactly what your agent did, in sequence, with outcomes.

Because the CLI runs on your own server, these logs stay entirely within your infrastructure. Nobody else can access them. Your engineering team can trace them. Your compliance team can audit them.

The Complete Picture

Let me pull everything together into one view so the relationship between the pieces is clear:

YOUR AGENT (LangGraph / OpenAI SDK / Vercel AI SDK)

│ calls tools by name

SWYTCHCODE RUNTIME (Python/TypeScript SDK)

│ translates tool calls into CLI commands

SWYTCHCODE CLI (runs on YOUR server)

├── reads .swytchcode/integrations/manifest.json (auth, idempotency, execution policy)

├── reads .swytchcode/tooling.json (tool definitions)

├── reads policies/ (allowed/blocked operations)

├── validates schema

├── manages authentication

├── attaches idempotency keys

├── enforces rate limit backoff

└── writes to audit log

PRODUCTION APIs (GitHub, Slack, and the full APIs catalog)

Your agent sits at the top. Production APIs sit at the bottom. Everything in between is SwytchCode.

Your agent stays focused on reasoning and decision-making. SwytchCode stays focused on execution reliability. The boundary between them is the client.tools.execute() call.

What the Two Approaches Give You

I want to be direct about when to use each approach.

Traditional integration using coding agents is the right choice when you are building a specific, well-defined workflow. The sequence of steps is predictable. You know what to call and in what order. You want code that is easy to read, review, and maintain by anyone on the team.

Use Claude or Codex to write the integration logic quickly. Put SwytchCode underneath it. Get production reliability without writing a single line of retry logic.

Agentic integration via MCP or SDKs is the right choice when the workflow is dynamic. The agent needs to reason about what to call based on context, user input, or intermediate results. The sequence is not always predictable in advance.

Use LangGraph or the OpenAI SDK to give the agent reasoning capability. Expose SwytchCode tools using the @tool decorator. The agent calls what it needs.SwytchCode handles each call reliably.

Both approaches land in the same place: SwytchCode as the execution layer that makes production work.

Getting Started

If you want to build what we built here, the fastest path is:

# Install the CLI

npm install -g swytchcode

# Log in

swytchcode login

# Initialize your project

swytchcode init

# Pull integrations and add tools

swytchcode get github

swytchcode get slack

swytchcode add github.issue.create

swytchcode add github.issue.list

swytchcode add slack.chat.postmessage.create

# Connect your accounts

swytchcode auth connect github

swytchcode auth connect slack

Ready to build?

Install the CLI and pull your first manifest in under a minute. No account required.

More from the blog