DEV Community

Cover image for AI can write code. But it still breaks APIs. We built a CLI to fix that!
Chilarai
Chilarai

Posted on

AI can write code. But it still breaks APIs. We built a CLI to fix that!

AI can write your code faster than ever.

However, when you ask it to integrate Stripe, Slack, or Google, it becomes unreliable. Auth breaks. Requests fail silently. Rate limits surprise you at 2 AM. Edge cases you never thought of appear in production.

This isn't an AI problem. It's an execution problem.


The Real Trouble With API Integrations

Every developer has been here: you find the endpoint, wire it up, and ship it, then spend the next week firefighting.

  • OAuth tokens expiring mid-session
  • Retries that hammer the API and trigger rate limits
  • Silent failures with no structured error to catch
  • A library upgrade that quietly changes a parameter name
  • Duplicate sends because retries weren't idempotent

The standard answer? Write more glue code. Handle it yourself.

And now, with AI agents writing our code? The glue code looks more polished, but it still breaks the same ways, just faster.

The root issue is that integrations are not just code; they're execution. And execution needs to be treated as a first-class concern.


Introducing Swytchcode CLI

Swytchcode CLI is an execution layer for API integrations.

Instead of writing custom integration logic every time, the CLI gives you a controlled, deterministic way to call APIs with retries, auth, error handling, and version-awareness built in.

Think of it as separating two things that we've always conflated:

  • Intent: what you want to do (send a welcome email)
  • Execution: how it actually happens (auth, retry, response mapping, error codes)

The CLI owns execution. You (or your AI agent) just declare intent.


See It in Action


Getting Started as a Developer

Installing is straightforward:

# mac/Linux
curl -fsSL https://cli.swytchcode.com/install.sh | sh

# windows
irm https://cli.swytchcode.com/install.ps1 | iex
Enter fullscreen mode Exit fullscreen mode

Now let's walk through integrating Resend (transactional email) from scratch.

Step 1: Initialize your node.js project

swytchcode init
Enter fullscreen mode Exit fullscreen mode

This creates a .swytchcode/tooling.json in your project, the file that defines your execution policies, trusted tools, and integration versions. Think of it like a tsconfig.json, but for integration behavior.

Step 2: Pull the integration spec

swytchcode get resend
Enter fullscreen mode Exit fullscreen mode

This fetches the Resend integration bundle that contains available methods, full parameter schemas, and endpoint definitions. No more reading through docs to figure out which fields are required or what the exact endpoint path is.

Step 3: Declare what you want to do

swytchcode add emails.email.create
Enter fullscreen mode Exit fullscreen mode

This adds emails.email.create to your tooling.json with its full input schema like from, to, subject, optional html, attachments, idempotency key, and all. The CLI knows how to wire it safely.

Not sure which canonical ID to use? swytchcode list shows everything available from your fetched integrations.

Step 4: Execute

For Node.js apps, swytchcode-runtime is a thin wrapper that calls swytchcode exec for you, and no shell scripting is required. Install it alongside your app:

npm install swytchcode-runtime dotenv
Enter fullscreen mode Exit fullscreen mode

Then call it directly in your code. Credentials are passed per call, never stored in your config files:

require('dotenv').config();
const { exec } = require('swytchcode-runtime');

const result = await exec('emails.email.create', {
  // `body` maps to the HTTP request body as defined by the integration spec
  body: {
    from: 'you@yourdomain.com',
    to: 'user@example.com',
    subject: 'Welcome!',
    html: '<h1>Welcome aboard!</h1>',
  },
  // your API key — passed as a request header, never stored in tooling.json
  Authorization: `Bearer ${process.env.RESEND_API_KEY}`,
});

console.log('Email sent, id:', result.id);
Enter fullscreen mode Exit fullscreen mode

The runtime calls swytchcode exec under the hood, and this is the only place that actually hits the Resend API. Everything before it is set up. The CLI handles:

  • Auth via your API key
  • Retry with backoff
  • Structured error parsing
  • Deterministic, repeatable output

No hidden magic. No surprise behavior. Full control.


Using Swytchcode CLI With Cursor or Claude Code

This is where it gets interesting.

IDE agents like Cursor and Claude Code are excellent at understanding your intent and generating code, but they still produce raw API calls that can fail in production. Swytchcode changes the contract: instead of generating HTTP request code, the agent calls the CLI.

Setting it up

In your project, add a CLAUDE.md (for Claude Code) or .cursorrules (for Cursor) that instructs the agent to use the CLI for integrations:

.cursorrules / CLAUDE.md:

API Integrations


Use `swytchcode` CLI for all third-party API calls. Do not write raw HTTP requests or use SDK clients directly.

To add a new integration action:
1. Run `swytchcode get <provider>` to fetch the spec
2. Run `swytchcode add <action>` to register the action
3. In application code, use `swytchcode-runtime` to execute: `const { exec } = require('swytchcode-runtime')`
Enter fullscreen mode Exit fullscreen mode

Never call external APIs directly in application code.

Now when you ask Cursor or Claude Code to "send a welcome email with Resend", instead of generating fragile SDK code, the agent runs:

swytchcode get resend
swytchcode add emails.email.create
Enter fullscreen mode Exit fullscreen mode

And your application calls:

const { exec } = require('swytchcode-runtime');

const result = await exec('emails.email.create', {
  body: { from: 'you@yourdomain.com', to: 'user@example.com', subject: 'Welcome!' },
  Authorization: `Bearer ${process.env.RESEND_API_KEY}`,
});
Enter fullscreen mode Exit fullscreen mode

What this looks like in practice

Say you're pair-programming with Claude Code and you type:

"Send a welcome email via Resend when a user signs up"

Without Swytchcode, the agent writes something like:

const resend = new Resend(process.env.RESEND_API_KEY);
await resend.emails.send({
  from: 'you@yourdomain.com',
  to: user.email,
  subject: 'Welcome!',
  html: '<h1>Welcome aboard!</h1>',
});
Enter fullscreen mode Exit fullscreen mode

Looks fine. But: no retry handling, no structured error classification, no idempotency, and no audit trail.

With Swytchcode, the agent instead runs:

swytchcode get resend
swytchcode add emails.email.create
Enter fullscreen mode Exit fullscreen mode

And application code becomes:

const { exec } = require('swytchcode-runtime');

const result = await exec('emails.email.create', {
  body: {
    from: 'you@yourdomain.com',
    to: user.email,
    subject: 'Welcome!',
    html: '<h1>Welcome aboard!</h1>',
  },
  Authorization: `Bearer ${process.env.RESEND_API_KEY}`,
});
Enter fullscreen mode Exit fullscreen mode

The execution is handled by the CLI. The agent's job is to declare intent—the CLI's job is to execute it safely.


How It Works Under the Hood

Two files drive everything:

tooling.json is your execution policy and trusted tool registry:

{
  "mode": "sandbox",
  "version": "1.0.11",
  "tools": {
    "emails.email.create": {
      "type": "method",
      "integration": "resend.resend@v1.5.0",
      "summary": "Send an email",
      "inputs": [
        { "name": "body", "type": "object", "required": false },
        { "name": "Idempotency-Key", "type": "string", "required": false }
      ]
    }
  },
  "integrations": {
    "resend.resend": { "version": "v1.5.0" }
  }
}
Enter fullscreen mode Exit fullscreen mode

wrekenfile.yaml is the integration spec fetched automatically by swytchcode get and stored in .swytchcode/integrations/. It defines method shapes, endpoints, and validation rules. manifest.json stores the resolved base URLs per environment (production vs. sandbox).

swytchcode exec reads all three locally and no registry calls at runtime, executes deterministically, and returns structured output you can rely on.


Why This Matters Now

We are entering an era where AI agents autonomously call APIs on your behalf. That's powerful and dangerous if the execution layer isn't sound.

Swytchcode gives you a safe boundary: AI declares intent, and the CLI executes. No malformed requests. No silent failures. No agents are going rogue because they guessed a parameter wrong.

For developers: less glue code, fewer late-night incidents.
For AI-assisted workflows: a reliable, auditable execution layer your agents can trust.


Try It

Integrations don't fail because of syntax. They fail because of execution.

If you're building anything that touches external APIs, give Swytchcode CLI a try and see how much glue code you can delete.

We're actively improving it and would love to hear what integrations you're working with. Drop a comment below or reach out directly.

Top comments (0)