playbooks
FIRE Bridge: Connect Tools Without Glue Code
Bridge pattern for connecting Claude Code to N8N, Make, Zapier, and custom APIs. One agent, every tool, no spaghetti.
FIRE Bridge: Connect Tools Without Glue Code
Claude Code is not an island. Every real workflow touches at least one tool it didn't build itself: a CRM, an automation platform, a webhook receiver, a legacy API. The FIRE Bridge is the pattern that connects them all without turning your codebase into a tangle of SDK imports and provider-specific boilerplate. One agent. Every tool. No spaghetti.
“Integration debt is the fastest way to turn a 2-week automation into a 6-month maintenance burden.”
Section 01: The Integration Problem
The default approach to connecting Claude Code with external tools is “add the SDK.” Add the N8N API client. Add the Make webhook library. Add the Zapier trigger library. Three tools means three SDKs, three auth flows, three error surfaces, and three upgrade paths that will all break on different weeks.
Without bridge
- One SDK per tool
- N hardcoded auth flows
- No shared retry logic
- Breaks change in isolation
Common failure modes
- Auth token expires mid-run
- Rate limit silently drops events
- Schema drift breaks payloads
- Dev env != prod env
With FIRE Bridge
- Single dispatch interface
- Adapters swap without refactor
- Shared envelope + error model
- Swap tools, not architecture
The problem is not the number of tools. It is the coupling. When each tool gets its own bespoke integration layer, changing one breaks three, and adding a fourth doubles the surface area.
Section 02: Bridge Pattern Explained
The FIRE Bridge is a thin adapter layer that sits between Claude Code and every external tool. Claude issues a single dispatch(event, payload) call. The bridge resolves which adapter handles that event and forwards it, translating the generic envelope into whatever format the target tool expects.
// Generic bridge call - same shape for every tool
await bridge.dispatch("lead.qualified", {
name: "Acme Corp",
score: 87,
owner: "walid@ayautomate.com",
})
// The bridge resolves: N8N webhook adapter
// Translates → POST https://n8n.ayautomate.com/webhook/leads
// Payload transformed to N8N-expected shape
// Retry + auth handled by adapter, not by callerThree rules make the bridge work:
- 01Event names are domain-driven, not tool-driven. lead.qualified, not zapier_trigger_lead.
- 02Adapters own all translation. The caller never knows the wire format.
- 03The bridge owns retries, auth refresh, and error normalization. Adapters delegate up.
Do This
Name events after what happened in your domain, not which tool you happen to send them to. That name will survive three tool migrations.
Section 03: 4 Bridge Styles
Not every external tool gets the same connection pattern. The four styles below cover 95% of real-world integrations. Pick the right one based on latency tolerance and control needs.
Webhook Bridge
N8N · Make · ZapierClaude posts a JSON envelope to a webhook URL. The receiving platform (N8N, Make, Zapier) triggers its own workflow. Fastest to set up, lowest operational overhead. Best for fire-and-forget events where you don't need a synchronous response.
// Webhook adapter
class WebhookAdapter implements BridgeAdapter {
async send(event: string, payload: unknown) {
const res = await fetch(this.url, {
method: "POST",
headers: { "Content-Type": "application/json",
"X-Bridge-Event": event,
"X-Bridge-Secret": this.secret },
body: JSON.stringify({ event, payload, ts: Date.now() }),
})
if (!res.ok) throw new BridgeError(event, res.status)
}
}Latency: <500 ms · Retry: exponential backoff · Auth: HMAC secret
Polling Bridge
Legacy APIs · Rate-limited endpointsClaude writes to a queue (Redis, Postgres, or a JSON file). A polling loop checks the queue on an interval and forwards items to the target. Use when the target does not accept inbound webhooks or imposes strict rate limits you want to batch against.
// Polling bridge - queue-side (Claude writes)
await db.bridgeQueue.create({
data: { event: "invoice.sent", payload: JSON.stringify(data) }
})
// Polling loop (cron, every 60 s)
const pending = await db.bridgeQueue.findMany({
where: { status: "pending" }, take: 10, orderBy: { createdAt: "asc" }
})
for (const item of pending) {
await targetAdapter.send(item.event, JSON.parse(item.payload))
await db.bridgeQueue.update({ where: { id: item.id },
data: { status: "done" } })
}Latency: seconds-minutes · Retry: requeue on failure · Auth: adapter-level
MCP Bridge
Native Claude CodeRegister an MCP server that exposes your integration surface as tools. Claude calls the tools natively. No custom dispatch layer needed. Best for interactive, bidirectional workflows where Claude needs to read state before writing it.
// mcp-bridge-server.ts - expose tools to Claude
server.tool("create_n8n_workflow", {
name: z.string(),
trigger: z.enum(["webhook", "cron", "manual"]),
nodes: z.array(z.unknown()),
}, async ({ name, trigger, nodes }) => {
const wf = await n8nClient.workflows.create({ name, trigger, nodes })
return { content: [{ type: "text", text: `Created: ${wf.id}` }] }
})
// Claude calls it like any other tool - no bridge code in Claude
// "Create an N8N workflow that fires on new Stripe payments"Latency: synchronous · Retry: MCP layer · Auth: MCP server handles it
CLI Shell-out Bridge
Custom APIs · Local toolsClaude invokes a local CLI binary that wraps the integration. Useful when the target has an excellent CLI but no SDK, or when you want a hard boundary between Claude's execution environment and the integration credentials.
# Claude calls Bash tool:
npx aybridge send lead.qualified --name "Acme Corp" --score 87 --owner "walid@ayautomate.com"
# aybridge CLI resolves the adapter, handles auth from keychain,
# prints structured JSON result to stdout for Claude to parse.
# Credentials never touch Claude's context window.Latency: subprocess overhead · Retry: caller script · Auth: system keychain
Section 04: 3 Worked Examples
Claude Code → N8N → Slack summary
After every deploy, Claude posts a deploy.succeeded event to the webhook bridge. N8N picks it up, formats a Slack message with diffs and metrics, and posts to #releases. Claude never imports the Slack SDK; N8N owns that integration.
- 1.PostToolUse hook fires after successful git push
- 2.Hook calls bridge.dispatch("deploy.succeeded", { sha, branch, diff_url })
- 3.Webhook adapter posts to N8N /webhook/deploys
- 4.N8N workflow formats Slack Block Kit message
- 5.Slack message appears in #releases within 2 s
Claude Code → Make → CRM enrichment
During a discovery call, Claude drafts a contact note and fires contact.note_added. Make receives it, looks up the contact in Attio, enriches the record with LinkedIn data, and creates a follow-up task. Claude wrote one line. Make did six.
// Triggered by Claude after drafting a note
await bridge.dispatch("contact.note_added", {
email: "cto@prospect.com",
note: draftedNote,
tags: ["discovery", "technical"],
})
// Make scenario:
// 1. Receive webhook 2. Lookup Attio contact
// 3. Enrich via LinkedIn 4. Update Attio record
// 5. Create follow-up task 6. Notify in SlackZapier → Claude Code → reply draft
Inbound direction: a new Gmail thread triggers a Zapier zap that posts to Claude's headless webhook endpoint. Claude reads the thread, generates a reply draft, and stores it back via bridge. The bridge MCP tool writes the draft to Gmail. Zapier started it; Claude finished it.
- 1.Zapier: new Gmail thread → POST /api/bridge/inbound
- 2.Claude Code (headless): receives event, reads thread context
- 3.Claude generates reply draft using existing knowledge base
- 4.bridge.dispatch("draft.ready", { threadId, draft }) via MCP tool
- 5.MCP server writes draft to Gmail via Google API
Section 05: Failure Modes
The bridge pattern does not eliminate failure. It centralizes it so you can actually debug it. These are the failure modes that will find you and what to do about each one.
Silent webhook drops
The target URL returns 200 but silently discards the payload because the schema changed. The bridge never knows.
Fix: Log every outbound event with its response body. Replay-test weekly against real endpoints.
Auth token expiry mid-run
OAuth tokens rotate. A 24-hour automation works fine for 23 hours, then fails on the 24th without warning.
Fix: Adapters should refresh tokens proactively, not reactively. Check expiry before every dispatch call.
Rate limit cascade
One busy period exhausts the Zapier task limit for the month. Everything else that depended on it stops.
Fix: Monitor task consumption per adapter. Set alerts at 70%. Have the polling bridge as fallback.
Payload schema drift
You rename a field in Claude's output. The N8N workflow that consumes it never got the memo.
Fix: Version your event envelopes: { event, version, payload }. Adapters handle version coercion explicitly.
Dev/prod environment mismatch
The webhook URL in development points to production N8N. A test run triggers a live Slack blast.
Fix: The bridge reads BRIDGE_ENV. dev routes to sandbox endpoints. prod routes to live. Never hardcode.
Circular triggers
Claude fires an event → N8N processes it → N8N posts back to Claude → Claude fires the same event again.
Fix: Every inbound event from an external platform carries a source tag. Claude ignores events it originated.
“The bridge owns the failure surface. If something breaks, it breaks in one place, with one log, and one fix. That is the point.”
Quick Reference: Which Style to Use
| Style | Use when | Avoid when |
|---|---|---|
| Webhook | Fire-and-forget, sub-second latency OK, target supports inbound POST | You need a synchronous response from the target |
| Polling | Target is rate-limited, legacy, or pull-only | You need real-time delivery; polling adds lag |
| MCP | Bidirectional, Claude needs to read before writing, interactive | Simple one-way events; overkill |
| CLI shell-out | Credentials must stay out of Claude's context, great CLI exists | High-frequency calls; subprocess overhead adds up |
Do This
Start with the webhook bridge. It covers 80% of use cases, takes 30 minutes to set up, and teaches you the adapter interface before you need the more complex styles.
Want this running in your stack?
AY Automate builds AI automation systems for production teams.