July 12, 2026
Don’t Build the Integration, Build the Capability
A platform team’s job with AI isn’t to wire every agent into every system. It’s to make any team’s secure, agent-ready connection a…

By Evgeny Kharitonov
7 min read
A platform team's job with AI isn't to wire every agent into every system. It's to make any team's secure, agent-ready connection a same-day job. Here's the design work that gets you there.
Every department wants agents. Marketing wants one wired into their campaign tools so it can draft and schedule sends without leaving the conversation. IT wants one connected to their device-management system so fleet questions answer themselves. Support wants theirs sitting on top of the ticketing platform. Data wants the warehouse accessible as naturally as a chat. And everybody wants to search the company knowledge base without switching tools.
That's a lot of connectors — and if you build them one at a time, you're in trouble before you've shipped the third one. You've got a scatter of half-maintained services, no coherent identity model, and a platform team that's bottlenecked every time someone files a new "we want an agent" request. The problem isn't any single integration. The problem is that one-at-a-time is the wrong unit of work.
Here at Tailor Brands, we ran into this early. So instead of building integrations, we built a capability — an internal platform we call Loom, designed so that any team can have a new secure, agent-ready connector in roughly a day. This post is about the design decisions that made that possible.
The trap: one integration at a time
The mechanics of connecting an agent to a single system are, by now, a solved problem — there's a standard protocol for it (MCP), and the tutorials all walk the same happy path. The catch is the words single system: you stand up a connector for the marketing platform, another for the ticketing system, another for device management. When you do that at company scale you end up with something like:
- A new microservice per connector, each one owned (or forgotten) differently.
- Auth solved independently on each one — some use API keys in the environment, some roll their own token check, none of them share a policy.
- Observability bolted on differently if at all.
- The platform team as the person who does this work every time a new request comes in.
The goal isn't to build the integrations. It's to build the capability to produce integrations quickly and safely. That reframe changes the design completely.
Design decision 1 — one platform, many connectors
The first decision: instead of one service per connector, Loom hosts all of them inside a single platform service.
Here's why this works. When you actually sit down to build a connector, the unique work per connector is surprisingly small: talk to the upstream API, shape the results in a way that's useful to an LLM, expose the right operations. That part varies by connector. But everything around it — identity verification, request routing, graceful shutdown, structured logging, health endpoints — is identical across all of them. Built once in a shared chassis, maintained once.
The unique work per connector is small. The scaffolding is large. Build the scaffolding once.
The trade-off is obvious and worth naming honestly: connectors deploy together. If you want to ship an update to the marketing connector, you redeploy the platform, which also redeploys the ticketing and device-management ones. For an internal platform — where you control the pipeline and the workloads — this is actually fine. One deployment pipeline, one reliability surface, one place to find logs. For a product you sell to external customers where each connector might have different SLAs, you'd think twice. For us, it's strictly a feature.
Today Loom runs roughly seven connectors across departments: Marketing, IT, Support, Data, an org-wide knowledge base backed by vector search, a shared file store, and a connector for our internal deployment system — all built and hardened over a couple of months. That it didn't take a big team is the whole point of this post: most of each connector is scaffolding we only had to write once.
Design decision 2 — solve identity once, at the edge
The second decision is where to enforce authentication — and the answer is: not inside the connectors.
Every Loom connector sits behind a zero-trust access layer. Traffic arrives at the edge — a Cloudflare Access layer in front of the platform — which verifies the request against our company SSO (Okta) before it ever reaches the application. The edge authenticates; the application trusts. When a request makes it through, a signed identity assertion is forwarded downstream. The connector decodes it to know who's calling; it doesn't re-verify, because the only way a request reaches it is through the edge.
"A connector should assume it's already behind a locked door — don't build a second lock inside an already-locked room."
The consequences of this choice are significant:
- Access policy becomes a per-connector dial, not per-connector code. Who can reach the device-management connector versus the marketing connector is a configuration entry in the edge layer, not a logic branch in application code.
- Security review has one address. When you want to audit how agents are authenticated against your systems, there's one place to look.
- The OAuth machinery lives at the perimeter. Agent clients need to discover connectors and register against them dynamically — the protocol defines an OAuth discovery and dynamic client registration flow per resource. That flow belongs at the edge — it has to know about auth — not scattered inside six different application handlers.
That last point is exactly why the next decision matters.
Design decision 3 — a front door per connector
We started Loom with path-based routing under a single host: one hostname, paths like /marketing, /support, /device-management. It seemed simpler. It wasn't.
The problem is that access control, OAuth discovery, and request routing all want to operate at the level of a connector, not at the level of a path suffix. Cloudflare Access policies are scoped to hosts. OAuth discovery endpoints live at /.well-known under the resource root — and "the resource" has to be a host, not a path prefix, or the client registration flows break. The routing layer wants to match by host.
When every layer independently wants host-level boundaries, path-based routing is fighting the grain of the stack. We switched to a dedicated subdomain per connector — marketing-mcp.example.internal, support-mcp.example.internal, and so on. It looks like more pieces, but it's actually simpler: one clean addressing scheme that the edge, the OAuth flows, and the routing layer all agree on. That alignment keeps everything else simple.
Design decision 4 — design for scale-out from day one
Agents generate bursty, concurrent load. A single conversation can spawn multiple parallel tool calls; a shared deployment tool or knowledge base sees that load multiplied across every employee using it. The only scalable answer is to run many interchangeable replicas behind a load balancer.
That only works if each request is self-contained. Statelessness is the constraint — but a narrower one than it first sounds. The rule isn't no state; it's no state in the process. If a connector holds session context in memory, or caches user data on one pod, then every request has to land on that same pod and you've given up horizontal scale. Shared state is fine, as long as it lives somewhere every replica can reach: auth arrives in the forwarded assertion, call context rides in the request, and anything that genuinely needs to persist goes to a backing store. One of our connectors does exactly this — it keeps per-user credentials for a task-management tool in Postgres, which keeps the pods interchangeable and, as a bonus, opens the door to richer stateful features later. The pods stay disposable; the state just doesn't live inside them.
It's less elegant in the small. There are moments when stateful shortcuts feel natural — holding onto a cursor, caching an auth token per user. We push back on all of them. Statelessness is less elegant in the small; far more robust in the large. An extra round-trip or a lookup in a fast shared store is almost always the right call over process-local state you have to maintain.
The payoff — make the next connector cheap
Once the pattern stabilized — shared chassis, edge auth, subdomain boundary, stateless design — adding a new connector became mechanical. Describe what system you're connecting, what operations it exposes, and who should have access. Stand up the connector code (which is genuinely small once the scaffolding exists). Add an access policy entry at the edge. Add a routing entry for the new subdomain. That's it.
Mechanical work should be automated. Once the pattern repeated often enough to be confident it was stable, we wrapped the entire rollout in a single command: describe the connector and it scaffolds the connector code, wires the access policy, wires the routing entry, and opens everything for review as a single coherent change. What used to be a multi-repo, multi-step process scattered across a few different systems is now a guided conversation.
The effect on how the platform team relates to the rest of the company is real. The answer to "can we get an agent connected to X?" went from "let's scope a project" to "let's do it this week." The platform team becomes the on-ramp, not the gate. That's the outcome the design was aimed at from the beginning.
There's a second-order effect that's easy to miss: when adding a connector is cheap, connectors become disposable. Where a solid official or community connector already exists, we just use it. Where one doesn't — or where it exists but doesn't match how our teams actually work — we build our own, tuned to exactly what we need. And because the investment in any single connector is small, we're never precious about it: one that stops earning its keep gets thrown away and replaced, not maintained forever out of sunk cost. Being able to treat integrations as disposable — use, build, swap, or delete on demand — turns out to be a surprisingly powerful place to stand.
The automation didn't come first, though — and that honesty matters. We built it only after the pattern had repeated enough times that we were confident it was stable and worth encoding. Automating an uncertain pattern just makes it faster to make the same mistake in more places. Get the pattern right first; automate second.
What we'd carry forward
If you're building something similar, here's what the design history argues for:
- Build the capability, not the integrations. One shared chassis, maintained once.
- Push security to the edge. Auth solved in one layer, surfaced as policy, not code.
- Pick a boundary the whole stack agrees on. Subdomain-per-connector aligns routing, access control, and OAuth discovery — fighting that alignment is expensive.
- Design for many replicas early. Statelessness is a constraint, not a nice-to-have; retrofit is much harder than design.
- Automate the rollout only after the pattern is stable. Premature automation locks in early mistakes.
Small tip from my perspective: the departments asking for connectors don't think about your routing layer or your trust model. They care that it showed up the same week they asked, and that they can trust it with their data. The platform abstractions exist to make that reliability and speed possible — not to be visible.
Agents are only as valuable as the systems you safely connect them to. An agent that can reason beautifully but can't touch your CRM, your device management layer, or your company knowledge is a clever toy. A platform team's job isn't to build every flow — it's to make every flow possible.