deploy/agentcore/http template of the hoop repository creates the VPC, the Sidecar and the harness. Start with the quick start, then run it against your API.
Bedrock Agents Classic has been closed to new customers since July 30, 2026, and AWS recommends a move to AgentCore: the harness, or your own agent on Runtime. See Bedrock Agents Classic maintenance mode. This setup does not cover a Bedrock Agents Classic agent. It applies once the agent runs on AgentCore.
Why the agent cannot skip the Sidecar
Four controls are the VPC’s. One stack holds them, andscripts/ci/check-agentcore-egress.py in the hoop repository fails CI if one goes away:
- No route out. The agent subnets’ route table has no NAT gateway and no internet gateway.
- One security group. The agent’s security group reaches the VPC endpoints and the S3 gateway on 443, and the Sidecar’s listener on 8080. Nothing else. The endpoints serve ECR, Bedrock Runtime and CloudWatch Logs only.
- A scoped S3 endpoint. The S3 gateway endpoint allows only
s3:GetObjecton the bucket where ECR keeps image layers. AWS’s default policy would let the agent write to any bucket, an outside one included. - A DNS Firewall. A Route 53 Resolver DNS Firewall answers AWS names,
hoop.internaland the Sidecar’s own hosts, andNXDOMAINfor the rest. Without it, the VPC resolver answers any public name, so a DNS query can carry data out.
Get the template
Both setups below use$T, so run them in the shell that sets it:
Quick start
The Launch Stack link creates the stack in us-east-1 withUpstreamUrl set to demo. The Sidecar then serves hoop’s demo API, a set of invented users with emails, phones and cards, from inside its task. You need no API of your own.
You need:
- An AWS account where you can create IAM roles, with access to the Bedrock model
us.anthropic.claude-haiku-5-5in us-east-1. - A Sidecar token. The Sidecar runs logged in, in the demo too: sign in to use.hoop.dev, open Sidecars, choose Connect an existing Sidecar, and copy the token. A free use.hoop.dev organization holds one Sidecar.
- For steps 2 to 4:
git, the AWS CLI v2 signed in to that account,jq,python3,curl7.75 or later, and$Tfrom Get the template.
1
Launch the stack
Launch StackThe link fills the stack name
hoop-agentcore-quickstart, UpstreamUrl demo and the harness hoop_agentcore_quickstart. Paste your token into HoopSidecarToken, accept that the stack creates IAM resources, and choose Create stack. Wait for CREATE_COMPLETE, about 8 minutes.2
Ask the agent
session asks the demo one: list the users, then delete user 1. It prints each command the agent ran, its output and the answer. The users come back with [REDACTED:EMAIL_ADDRESS], [REDACTED:PHONE_NUMBER] and [REDACTED:CREDIT_CARD], and the DELETE gets 403 and this agent may only read from the API.3
Read the audit trail
agentcore and the session id that session printed:4
Delete the stack
DELETE_FAILED, see Clean up.Run it against your API
For a harness, follow steps 1 to 3. For your own Runtime agent, follow steps 1 and 2 withAGENT=none, then Bring your own Runtime agent.
Requirements
- An AWS account and a Region where AgentCore runs. In us-east-1 the defaults work. Elsewhere, set
AGENT_AZ_IDSto two zone ids that AgentCore supports there. - Access to the Bedrock model in
ModelId, by defaultus.anthropic.claude-haiku-5-5. - The AWS CLI v2,
jq,python3andcurl7.75 or later. Docker with buildx for the Runtime agent. - A Sidecar token or a license. Copy the token at use.hoop.dev, as in the quick start. A machine that already logged in prints it with
hoop sidecar status --token. Without a token or a license, CloudFormation refuses the stack: the Sidecar would wait for a person to approve a login code. hoophq/hoopsidecar1.272.0 or later.template.yamlpins 1.272.0 by digest. Older releases report the template’s install source asother.
1
Keep the secrets outside the clone
Authorization: Bearer:2
Create the stack
For a harness, edit its instructions first.
SystemPrompt in template.yaml names the headers to send and uses /users/1 as an example.Replace https://api.example.com with your API: a scheme and a host, an optional port, and no path.create looks up the Region’s S3 prefix list, deploys template.yaml as the stack hoop-agentcore-http, and prints its outputs. It takes about 8 minutes. Set STACK to choose another name: each stack names its harness after it, so two stacks can share a Region.The Sidecar reaches your API from the service subnet, through an internet gateway. These are the parts of its config, SIDECAR_YAML in the task definition of template.yaml, that decide what the agent can do:SIDECAR_YAML
listenis plain HTTP inside the VPC. See Limits for why.caller_tokenadmits a request only when itsX-Hoop-Tokenheader holds the caller token. The stack generates the token in Secrets Manager and gives it to the Sidecar and the harness. Audit rows name the principalagentcore. See Caller token.upstreamis yourUPSTREAM_URL. Withhttps, the hop to the API uses TLS and verifies the API’s certificate. The listener forwards theAuthorizationheader unchanged.guardrailsrefuses every method butGET,HEADandOPTIONS.otheris any method that HTTP does not define, such asMOVE.maskredacts emails, phone numbers and card numbers in responses, and no other value.http.headersrecords the agent’sX-AgentCore-Session-Idon each audit row.HOOP_SIDECAR_INSTALL_SOURCE, in the same task definition, names this template in the Sidecar’s usage analytics. AddHOOP_SIDECAR_ANALYTICS=offthere to send no analytics.
SIDECAR_YAML and run create again. The stack registers a new task revision, and ECS replaces the running Sidecar.AGENT=none creates the network and the Sidecar without a harness.3
Ask the harness
Bring your own Runtime agent
A stack with or without a harness serves your own agent in a container. Run the example first, from~/hoop-agentcore. Replace api.example.com with your API’s host:
runtime create builds runtime-example/ for linux/arm64, pushes it to the stack’s AgentRepositoryUri, and creates a Runtime agent on the agent subnets. It writes the agent’s ARN to ./.agentcore-ids-<STACK>. runtime session prints each request the agent sent and its result.
For your own agent, set these in the agent:
On every request to the Sidecar, send:
X-Hoop-Token: <caller token>. Put the token in this header only, never in a URL or a body. The Sidecar refuses a request that carries it anywhere else.X-AgentCore-Session-Id: <session id>. AgentCore gives your container the session id in theX-Amzn-Bedrock-AgentCore-Runtime-Session-Idheader of each/invocationsrequest. Copy it.Authorizationwith your API’s own token, if the API takes one. The listener forwards it unchanged.
runtime-example/agent.py sends these headers in code, so the tokens never enter the model’s context.
Verify
To check the last rows from the harness, ask it in a session framed as a test. Asked plainly to skip the Sidecar or the token, the model refuses. Replace
api.example.com with your API’s host:
SidecarLogGroup, which keeps it for 90 days. To read it:
agentcore and the session id the agent sent. The DELETE rows name rule read-only. A request without the token is the anonymous row with rule identity, and carries no session id.
Postgres through the Sidecar
Thepostgres template gives the agent psql against one Postgres database, through a Sidecar postgres listener. The listener refuses the writes that its SQL classifier finds, masks emails in results and records each statement with the session id. It keeps every network control above, and differs from the REST setup:
- An image with
psql. The harness has no internet to installpsql, so it runs the officialpostgresimage for linux/arm64 from ECR Public, through an ECR pull through cache rule in the stack. - The session id travels in
PGOPTIONS. The agent sends-c agentcore.session.id=<id>, and each audit row names it. - The login’s grants stop what the listener misses. The listener passes the client’s login through to the database, so the agent holds the password. Some statements that write pass the classifier as reads. The demo login has SELECT on one table and nothing more.
- A demo database. The stack runs Postgres on Fargate, and the database admits the Sidecar’s security group only. The README shows how to point the listener at your RDS instance over VPC peering.
COPY ... TO STDOUT returning rows unmasked and a refused write closing the connection.
Kubernetes through the Sidecar
Thekubernetes template gives the agent kubectl against one EKS cluster with a private API endpoint, through a Sidecar http listener in front of the API server. The Sidecar refuses DELETE, masks Secret values in kubectl’s JSON and records each request with the session id. It keeps every network control above, and differs from the REST setup:
- No caller token. kubectl cannot send
X-Hoop-Token, so the listener admits any caller that the security groups let in. The API server’s token check is the gate, and rows name the principalanonymous. - An image with kubectl.
setup.shbuilds it for linux/arm64 with Docker and pushes it to the stack’s ECR repository. - HTTPS to the listener. kubectl runs in the agent’s container, so it can trust the listener’s self-signed certificate.
setup.shmakes the certificate. - VPC peering to the cluster. The peering route is in the Sidecar’s route table only, and the cluster’s security group admits the Sidecar, not the agents.
- The session id travels as an impersonation extra. kubectl sends it in
Impersonate-Extra-Hoop-Session, which needs one ClusterRole foruserextras/hoop-session.
kubectl apply failing on the masked annotation.
Limits
AgentCore’s, and this stack’s:- The agent holds the tokens. The harness and the Runtime agent keep the caller token and the API token in environment variables, and
GetHarnessandGetAgentRuntimereturn them. Moving the API token into the Sidecar is planned. - A token that the agent prints lands in CloudWatch. The harness logs each tool result.
- Each VPC endpoint is an AWS API that the agent’s shell can call with the execution role: Bedrock models, ECR pulls and an ECR authorization token, and CloudWatch Logs writes under
/aws/bedrock-agentcore/runtimes/. The role holds no more than a session needs, so add nothing to it. Each endpoint’s policy admits this account’s principals only. AWS APIs without an endpoint, STS and Secrets Manager among them, time out. - Keep
InvokeHarnessfor people you trust with the agent. Its caller can add a browser, code interpreter or gateway tool to a session. Such a tool needs a permission on the execution role and the AgentCore endpoint, and this stack grants neither. - Bedrock models only. The model call leaves through the
bedrock-runtimeendpoint. An OpenAI or other LiteLLM model needs a path out: point itsapiBaseat a Sidecar listener to that provider. A LiteLLM OpenAI model worked this way in our tests. This stack has no such listener. - The listener is plain HTTP inside the VPC. The harness loop runs outside the agent’s container and trusts no private CA, and a public certificate needs a domain that you own. The security groups admit only the agents.
- The agent can resolve the Sidecar’s hosts. The DNS Firewall covers the whole VPC, so its allow list names the API’s host, Docker Hub,
use.hoop.devandapi.segment.iofor the Sidecar. The agent resolves these names and has no route to them. - A missing endpoint hangs a session. Without the Bedrock Runtime or ECR endpoint, a session sends no byte for minutes and ends with no error.
- Memory is off. The harness sets
Memory: Disabled, because AgentCore memory was not tested in VPC mode. - A new VPC. The stack does not attach to an existing VPC.
- Idle cost: about $0.095 per hour, $68 per 30 days, in us-east-1. That is four interface endpoints in two zones ($0.080), the Sidecar’s 0.25 vCPU and 0.5 GB on Fargate ARM ($0.0099), and its public IPv4 address ($0.005). Add $0.40 per month for each secret, $0.50 per month for the
hoop.internalzone, $0.60 per million DNS Firewall queries, and each session’s Runtime and model charges.
- The session id is a label. The agent writes the header, so it can write any value. It correlates rows. It does not prove who asked.
- One token for every agent. Each row names
agentcore, not a person. Per-user rows need a per-user token. - The rule reads the request method only. An API that accepts
X-HTTP-Method-Override,X-HTTP-MethodorX-Method-Overrideruns the method that the header names, even on aGET. Turn overrides off at the API. - A request is held until it is whole. The Sidecar judges a request after its body arrives, and forwards none of it before. A request over 8 MiB is refused.
- Masking applies to responses. A JSON or text response under
brorzstdis refused, not forwarded unmasked. A JSON or text response too large to mask is refused too: over 8 MiB as sent, or over 16 MiB once inflated. See Masking. - Scope. The template covers JSON REST APIs over HTTP/1.1 and HTTP/2.
Clean up
From~/hoop-agentcore:
delete removes the Runtime agent, then the stack. Delete the API token secret only after the stack is gone: the stack reads the secret to delete the harness. Then remove ~/hoop-agentcore and the Sidecar at use.hoop.dev (Sidecars).
- AgentCore can hold the subnets for hours. It releases its network interfaces in the agent subnets late, 8 h 20 min after the agents were gone in our tests. Until then the stack cannot delete the subnets and ends in
DELETE_FAILED. Rundeleteagain later. - A failed create can leave a namespace. If the create fails while Cloud Map makes the
hoop.internalnamespace, the rollback can leave it behind. Find it withaws servicediscovery list-namespacesand delete it.
Free and Enterprise
Free tier: one Data Masking rule and one Guardrail per Sidecar are free, forever. Running more than one rule per feature, or managing rules centrally across Sidecars, requires Enterprise.
-
The template fits the free tier. It uses one guardrail rule,
read-only, and one masking rule,pii, however many agents and sessions call it. One rule can carry more than one check:read-onlynames seven methods, andpiithree entities. -
The license comes from use.hoop.dev. With
HoopSidecarToken, the Sidecar takes your use.hoop.dev organization’s license on each heartbeat, and ignoresHoopLicense. A free organization holds one Sidecar. An Enterprise license with the guardrails and data-masking features lifts the one-rule caps. Your organization can hold it, or you pass it inHoopLicenseinstead ofHoopSidecarToken: withsetup.sh, setLICENSE_FILEinstead ofSIDECAR_TOKEN_FILE. See Licensing. -
The Sidecar logs its rule limits when it starts. With
Gfrom Verify:An Enterprise license prints"guardrail_rules":"unlimited","mask_rules":"unlimited". - Approvals and central management: the Control Plane adds approvals, shared rule sets and one view of many Sidecars. It also needs an Enterprise license.
Next
OpenAI Agents API
The same setup for an agent in an OpenAI hosted sandbox.
Claude Managed Agents
The same setup for an agent on Anthropic’s cloud sandbox.
HTTP
What the http listener inspects, masks and refuses.
Guardrail Rules
operation, http_resource, http_status and http_header rules.