Skip to content

Cloud

Loom + FAST: Wiring an Enterprise Agent Control Plane to a Customer-Facing App on AgentCore

AWS quietly shipped two open-source answers to two different agent problems. I deployed both, wired them together, then tried to break the architecture. Here is what holds, what doesn't, and the pattern for letting customers 'create agents' without losing governance.

 ·  9 MIN READ


Alexandre Agius

Alexandre Agius

AWS SOLUTIONS ARCHITECT

SHARE

Two open-source projects landed in the AWS agent ecosystem recently, and they answer two questions that teams keep conflating:

  • Loom answers “how does my platform team operate a fleet of agents?” — an enterprise control plane for Amazon Bedrock AgentCore: agent lifecycle, IAM and credential management, MCP/A2A server governance with approval workflows, HITL policies, cost tracking, admin analytics.
  • FAST (Fullstack Solution Template for AgentCore) answers “how does my product team ship a customer-facing agent app this week?” — a fork-and-customize template: React frontend on Amplify Hosting, a customer Cognito pool, an AgentCore runtime, all deployed with a couple of CDK commands. The samples gallery shows what people build on it.

I spent a day deploying both, wiring them together, and then red-teaming the result. The integration is cleaner than I expected — and the places where it breaks are instructive.

TL;DR

  • FAST completes Loom; neither replaces the other — one control plane governs the fleet, one FAST fork per product ships the customer experience.
  • The entire integration contract is a JWT authorizer: deploy the agent from Loom, bound to the customer identity pool.
  • When customers want to "create agents": give them logical agents through a BFF — governance by catalog, isolation by key design, metering by chokepoint.
  • Keep infrastructure creation in the control plane; never expose its API to customer identities.

The one-line integration contract

Loom is a control plane: its UI is for platform operators, behind its own identity pool, and you would never put customers in front of it. FAST is a data plane: its frontend calls the AgentCore runtime directly from the browser with the customer’s JWT. No backend-for-frontend in the baseline.

So how do you make a FAST app talk to a Loom-governed agent? One governance act:

Deploy the agent from Loom with a JWT authorizer bound to the customer identity pool — discovery URL pointing at the customer pool, allowed clients pinned to the customer app’s client ID.

In AgentCore terms, that’s this configuration on the runtime — set from the control plane, never touched by the product team:

{
  "authorizerConfiguration": {
    "customJWTAuthorizer": {
      "discoveryUrl": "https://cognito-idp.<region>.amazonaws.com/<customer-pool-id>/.well-known/openid-configuration",
      "allowedClients": ["<customer-app-client-id>"]
    }
  }
}

Two-box diagram: Loom, the control plane for platform operators, deploys and governs an AgentCore runtime; FAST, the customer-facing app, invokes the same runtime with the customer's JWT. The runtime's JWT authorizer is the single contract between them.

That’s the entire contract. The platform team decides, in the control plane, which identity population may invoke which runtime. The customer app never holds AWS credentials; AgentCore validates the customer’s JWT at the door.

Two small customizations were needed in the FAST fork (both upstreamable):

  1. The frontend deploy script assumes you want FAST’s own bundled runtime — an env-var override lets it point at any runtime ARN instead.
  2. FAST’s SSE parser expects {"data": "..."} chunk objects; Loom’s Strands agent streams bare JSON strings. One extra case in the parser handles both.

With that, a customer signs into the FAST app, chats, and the tokens stream from a runtime the platform team fully governs — model, prompt, tools, approval policies, all changeable in Loom with zero frontend redeploys. Keep the internal (SigV4) and customer-facing (JWT) variants as two runtimes with the same brain: each can be revoked independently, and your admin tooling keeps working when you rebind the customer one.

Then I challenged it: “the customer wants to create an agent”

This is where architectures like this usually fall over, so let’s push. Your product grows, and now customers want to create their own agents. How does that work against an enterprise governance layer?

First, interrogate the premise. “Create an agent” hides two very different things:

Logical agent Physical agent
What it is A name, a prompt, a model choice, a tool selection — configuration A new AgentCore runtime — container, IAM role, authorizer — infrastructure
Who needs it ~Every tenant The rare tenant with isolation/compliance requirements
Creation cost A database row Minutes, account quotas, IAM sprawl

Almost every “create your own agent” product you know sells the first and never provisions the second per customer. That distinction decides the whole design, because there are only three ways to wire customer-driven creation, and two of them hurt:

Anti-pattern

1. Expose the control plane's API to customer identities

Dead on arrival. In Loom's case, agent:write lives in the same backend as security:write (IAM roles, credential providers, secrets). Bridging customer tokens into it turns every authorization bug into a tenant-to-platform escalation. A control plane has no tenancy model because it was never supposed to.

Anti-pattern

2. Use the control plane as a provisioning broker

The product backend calls it M2M. Tempting, and still wrong: no idempotency contract, no per-tenant quotas, shared execution roles — meaning every tenant's agent runs with the same IAM identity, and cross-tenant data access is one bug away. You'd rebuild half the product to make it multi-tenant. That's not integration, that's a fork.

Recommended

3. Logical agents on a shared, governed runtime

Tenant "agents" are rows in the product's database. One multi-tenant runtime — deployed and governed by the control plane — interprets the tenant's config per request.

Option 3 is the recommendation, and I prototyped it to make sure it isn’t just slideware.

The Tier-1 pattern, verified

The prototype: a TenantAgent DynamoDB table (partition key = the tenant’s identity from the verified JWT), and a small backend-for-frontend that is the only path to the runtime:

Flow diagram: the customer browser sends the prompt and JWT to a backend-for-frontend, which validates the JWT and extracts the tenant, loads the tenant's agent configuration, and enforces the allowed-model catalog. The BFF then invokes the shared AgentCore runtime with SigV4 — the runtime is invocable only by the BFF's IAM role — and a per-tenant usage record is written on every call.

Everything worth claiming, I tested with real requests:

  • Self-service creation — a customer created a “CostBot” persona (FinOps instructions, Haiku-class model) as a POST /agents call. A database row; zero infrastructure.
  • Governance by catalog — creating an agent on a non-approved model returns 403 with the allowed list. The enterprise constrains the building blocks (model catalog, approved tool registry); customers compose freely inside the box. No human approval gate per agent — that would kill self-service.
  • Structural tenant isolation — tenant B listing agents gets []; tenant B invoking tenant A’s agent gets 404. Not because of a check someone remembered to write, but because the partition key comes from the verified token, not from the request body.
  • Metering — every call writes tokens/duration per tenant. This is the piece the “browser calls the runtime directly” pattern can never give you, and it’s why the BFF stops being optional the moment you productize: per-tenant billing needs a chokepoint you own.

One finding I didn’t expect: the control-plane system prompt and the tenant’s persona instructions layer surprisingly well. When my test persona tried to make cost the only decision lens, the platform prompt pushed back — cost-focused answer, but reliability and security not subordinated. Guardrails outranking customization, observable in the output.

And for the tenant that genuinely needs a dedicated runtime? Product-owned provisioning inside IAM permission boundaries, mandatory tenant tags, and auto-registration into the AWS Agent Registry — so the control plane stays the fleet observatory even for runtimes it didn’t create. The registry, not the control plane’s API, is the meeting point.

The security lesson I earned

Prototype shortcut: I exposed the BFF on a public endpoint with JWT validation in the Lambda code. Within hours, automated security tooling flagged the function as world-accessible and stripped the public-access policy. It was right, and my enterprise policy agrees: authentication belongs at the edge, not in your handler. The compliant shape is API Gateway with a Cognito authorizer (the request never reaches your code unauthenticated), WAF in front, or a VPC-internal ALB if the callers are private. “Auth in code behind a public URL” is a pattern scanners exist to kill — let them.

Verdict

FAST completes Loom; neither replaces the other. One installation of the control plane governs the fleet; one FAST fork per product ships the customer experience; a JWT authorizer is the contract between them. When customers want to “create agents,” give them logical agents through a BFF and keep infrastructure creation in the control plane — governance by catalog, isolation by key design, metering by chokepoint.

The nicest property of the whole architecture: the day the platform team swaps the model, tightens a guardrail, or revokes a tool, every customer conversation picks it up on the next request — and no product team redeploys anything.

Go build

Everything in this post is open source — fork, deploy, break it yourself:

  • Loom — the control plane (FastAPI + React, three-phase deployment from local SQLite to ECS Fargate)
  • FAST — the customer-app template (CDK or Terraform, deploys in minutes)
  • FAST samples gallery — what others have built on it

And a question for you, because I know several of you are building agent platforms right now: how are you handling customer-created agents — logical configs, dedicated runtimes, or something else entirely? The comments are open below; I read all of them.

ABOUT THE AUTHOR

Alexandre Agius

Alexandre Agius

AWS Solutions Architect

Passionate about AI & Security. Building scalable cloud solutions and helping organizations leverage AWS services to innovate faster. Specialized in Generative AI, serverless architectures, and security best practices.

ONE LETTER A MONTH · NO TRACKER · UNSUBSCRIBE ANYTIME

CONTINUE READING

Related dispatches

Comments

Sign in to leave a comment