Step 1 of 7: Launch your first agent
By the end you will be able to:
- Explain what the three building blocks do: the Agents SDK runs the agent, Workers AI supplies the model, AI Gateway watches and controls every model call
- Describe how a Worker, a hostname and a gateway fit together in your own team account
- Take an agent from a zip file to a live URL, and follow one request through your logs
Checking your assignment… If it cannot load, ask a host and continue with the guide.
The account id and hostname below are placeholders. They appear here once a host assigns you to a team.
- Account
shown here once your team is assigned- Account id
TEAM_ACCOUNT_ID- Demo hostname
TEAM_HOSTNAME- Worker
agent- AI Gateway
agent-gateway
Use the Cloudflare account on your team card (also on the Workspace page). No account yet? Ask a host: you can read on, but you can't deploy until it is ready.
Why it matters
- A URL you can open beats a perfect agent nobody has seen.
- Every later step changes this agent. A live, working starter first means each step is a small change to something that already runs.
- It shows you how the pieces fit together, once. Agents SDK, Workers AI and AI Gateway are all in play before you write any code.
The concepts
Your agent is three Cloudflare products working together. This is the path one chat message takes. Below, each product gets a short reason you need it, then you see how the starter wires them up.
- 1YouThe chat page in a browser, or curl
POST /api/chat - 2Your WorkerAgents SDK: the agent, its tools and its memory
agent - 3AI GatewayLogs and controls every model call
agent-gateway - 4Workers AIThe model that does the thinking
@cf/google/gemma-4-26b-a4b-it
Agents SDK: the agent itself
The Agents SDK is Cloudflare's TypeScript library for building agents. You write a class that extends Agent (the starter's ChatAgent does), and Cloudflare runs each instance as a Durable Object: a small, named server-side object that keeps its own state.
Why you need it. A model on its own answers one message and forgets it. It has no memory, cannot wait for anything, cannot do anything in the world and cannot ask a person first. Those are exactly the things that turn a model into an agent, and without the SDK each one is yours to build and host: a server, a database, a WebSocket layer, a scheduler, an approval flow. The Agents SDK gives you all of them as one class, so your time goes into what the agent does for your users instead of the plumbing around it.
What it gives you:
- Every agent is its own small server. One instance per name (a user, a case, a team), created on first use and found again by name, running on Cloudflare with nothing for you to provision or scale.
- It remembers.
this.stateand a built-in SQLite database (this.sql) are saved on every change, so what the agent knows survives restarts, redeploys and idle time. Step 3 uses this. - It works when nobody is typing.
this.schedule()runs code after a delay, at a date or on a cron, and an idle agent hibernates and wakes on the next request or schedule. - It talks to people in real time. WebSockets and streaming HTTP are built in, and state can sync straight to the browser, which is how the starter chat streams answers as they are written.
- Tools are plain functions. The model decides when to call one, and your code runs it inside your Worker with your bindings. Step 2 adds one.
- A person can stay in control. Human-in-the-loop is a first-class pattern: an action can wait for an Approve click before it runs. Step 5 adds one.
- It plugs into the rest of the platform. The same class can start Workflows for long tasks, act as an MCP server, or react to email. Step 4 picks one.
Docs: Agents overview · Agent class API
Workers AI: the model
Workers AI runs AI models on Cloudflare's GPUs and hands them to your Worker through one binding, env.AI.
Why you need it. An agent needs a model to read the request and decide what to do. Normally that means choosing a vendor, opening an account, agreeing a price and keeping an API key safe, before you have written a line of agent code. Workers AI removes all of it: the model is a binding on your Worker, in the account you already have, with no key to store or leak. That is why you can have a working agent in minutes.
Which model, and why. The starter uses @cf/google/gemma-4-26b-a4b-it, a small, fast model that can call tools and read images. It is set as MODEL in src/server.ts. We start small on purpose: the first replies come back quickly, and the tools, memory and approvals in Steps 2 to 6 do not need a large model. Larger models, such as @cf/moonshotai/kimi-k2.7-code, reason better and answer more slowly. Nothing else in the starter depends on the choice, so you can change MODEL whenever you want to try a bigger one.
What it gives you:
- No GPUs and no API keys.
env.AI.run(model, input)is the whole call. There is nothing to provision and no secret to store or leak. - A catalogue of open models. Text, embeddings, image and speech models, all listed in the model catalogue. Switching model is changing the one
MODELstring insrc/server.ts. - Serverless, pay per use. No GPU to rent or keep warm. Usage is metered in Neurons (a unit of GPU compute) and there is a free daily allocation.
- Runs on the same network as your Worker. The model and your code sit on Cloudflare's network, so a request does not leave for a separate AI vendor.
- Works with the AI SDK. The starter calls it through
workers-ai-providerand the AI SDK, so tools, streaming and structured output work the same way they would with any other model.
One thing to know: Workers AI has no local simulator, so npm run dev calls the real model on Cloudflare.
Docs: Workers AI · Models
AI Gateway: the control point
AI Gateway sits between your Worker and the model. Your code passes a gateway id with each call ({ gateway: { id } }), and every request goes through that gateway on its way to the model and back.
Why you need it. As soon as a real person talks to your agent you need answers to four questions: what was it asked, what did it say, what did that cost, and how do I stop it going wrong? Without a gateway, the record lives in your own code, which you have to write and then trust, and there are no brakes. The gateway sits outside your code, so the record and the controls stay in one place even when the agent changes. That is why Step 6 builds on it, and why every call goes through it from the start.
What it gives you:
- One place every model call passes through. You change how calls are handled in the gateway, not in your code.
- Logs and analytics. Each request is recorded with its status, latency, tokens and an estimate of its cost, so you can see what your agent actually sent and received.
- Caching and rate limits. Identical requests can be answered from cache, and request rates can be capped, which keeps latency and cost down.
- Spend limits, retries and fallbacks. Set a budget that blocks requests once it is used up, retry failed calls, or fall back to another model when one fails.
- Guardrails and DLP. Screen prompts and answers for unsafe content or sensitive data such as card numbers. Step 6 turns these on.
- Provider-neutral. It works with 20+ model providers, so the same gateway can front a different model later without rewriting your agent.
Your team has its own gateway, agent-gateway, so its logs show only your requests. You will see your first one at the end of this step.
Docs: AI Gateway · Guardrails · DLP
Your team account
Your team has its own Cloudflare account, and a host only invites you to it. It starts empty: you create everything in it yourself. Your first npm run deploy creates the Worker and its hostname, and you create the AI Gateway in the dashboard (part 3). Only two values differ between teams:
| What | Name | Same for every team? |
|---|---|---|
Worker (name in wrangler.jsonc) | agent | yes |
AI Gateway (AI_GATEWAY_ID) | agent-gateway | yes |
Account id (account_id) | on your team card | no |
Demo hostname (the routes entry) | agent.<your zone>, on your team card | no |
Build it
Commands below can be copied and pasted as they are, once you replace anything in <...> (each one is marked where it appears). Each command shows the system you picked below (the same choice is on the Workspace page).
This step assumes Step 0 is done: npx wrangler whoami lists your team account (the name and id are on your team card). If it does not, finish Step 0 first.
Prefer to let your coding agent do the typing? Copy this prompt into your agent, with your two team values filled in. It does everything except part 3, creating the AI Gateway, which is a dashboard click only you can do.
I am doing Step 1 of Build with Cloudflare Stockholm. If you have the build-stockholm MCP server, call get_step with step 1 and follow it.
1. Unpack the starter zip I downloaded (2026.11.0.zip, probably in my Downloads folder) into a new folder called stockholm-agent, and work inside it.
2. In wrangler.jsonc change ONLY two values and keep the commas: "account_id" to <ACCOUNT ID FROM MY TEAM CARD>, and the pattern in "routes" to <DEMO HOSTNAME FROM MY TEAM CARD>.
3. Run npm install, then npm run check:team, and show me the output.
4. Stop and tell me to create the AI Gateway agent-gateway in the dashboard (AI > AI Gateway > Create custom gateway, Gateway ID agent-gateway). Wait until I say it exists. Do not try to create it yourself.
5. Then run npm run deploy, wait until my hostname answers, and send POST /api/chat with {"message":"hello"} to it. Show me the reply.
Do not change anything else in wrangler.jsonc, and do not create or delete resources I did not ask for.
When it works, give me one good prompt to try in the chat page and say what I should see.Paste it into your coding agent: the terminal, the IDE panel or the desktop app all work.
1. Download, unpack and explore the starter
Download the starter (2026.11.0.zip)
Starter version 2026.11.0. You are already signed in, so the download just works. Do not run npm create cloudflare: that fetches the stock starter and loses the event additions.
The starter is Cloudflare's agents-starter: a working chat agent on the Agents SDK that calls Workers AI, with no API key needed. The event adds a few things on top.
Unpack it
The zip has no top-level folder, so these commands unpack it into one called stockholm-agent and move you inside (adjust the path if your browser saved it somewhere other than Downloads):
mkdir stockholm-agent && unzip ~/Downloads/2026.11.0.zip -d stockholm-agent && cd stockholm-agent && ls
You should see: package.json, wrangler.jsonc and a src folder.
The starter at a glance
Click a box or an arrow to see what it does.
The same map comes back in later steps with the part you are changing lit up. Four things were added for the event:
POST /api/chat: a plain JSON endpoint that every shield in Step 6 tests your agent through. It is the same agent as the chat page (same tools, notes and schedules); each call is a one-off question with no chat history.AI_GATEWAY_IDinwrangler.jsonc: model calls go through your own AI Gateway (agent-gateway), already filled in./mcp: a small MCP server with oneask_agenttool, the server that Step 6's Secure MCP shield protects. It makes its own single model call; it does not run the chat agent's tools or memory.workers_devandpreview_urlsare off, and your hostname is a Custom Domain on your own zone. Switching theworkers.devaddress off does not make the agent private: your demo hostname is public too, so use synthetic data only.
src/server.ts is the file you change in steps 2 to 5.
Take a tour with your coding agent
Open the stockholm-agent folder in your coding agent (set up in Step 0) and paste this. It only reads; it changes nothing.
You are inside a Cloudflare Agents SDK starter project. Do not change any files. Read package.json, wrangler.jsonc, src/server.ts, src/mcp.ts and src/app.tsx. If you are unsure about the Agents SDK, check the live docs at https://developers.cloudflare.com/agents/ first. Then give me a short tour, in plain language, for a developer who has never used the Agents SDK: 1. The big picture in five lines: what ChatAgent is, how a chat message becomes a model call, and where Workers AI and AI Gateway come in (look for AI_GATEWAY_ID). 2. Where the agent keeps state and memory today, and how the Agents SDK features (setState, this.sql, this.schedule) would be used to add more. 3. How tools are defined in tools(), which ones exist, and exactly where I would add a new one. 4. What POST /api/chat does and how it differs from the chat page and from /mcp. 5. The three places I should read first, with file and line numbers, and one thing in this project that would surprise a newcomer. Keep it under 400 words.
Paste it into your coding agent: the terminal, the IDE panel or the desktop app all work.
No coding agent? Spend five minutes in src/server.ts instead: read ChatAgent, tools() and the /api/chat route.
2. Point the starter at your team account
Open wrangler.jsonc. Only two values are yours, and both are on your team card at the top of this page: your account id and your demo hostname. Edit these two lines in place; do not replace the whole file, or you lose the Durable Object and binding settings.
- "account_id": "TEAM_ACCOUNT_ID",
+ "account_id": "<the account id from your team card>",
...
- "routes": [{ "pattern": "TEAM_HOSTNAME", "custom_domain": true }],
+ "routes": [{ "pattern": "<the demo hostname from your team card>", "custom_domain": true }],
Do this before you run anything. The model runs on Cloudflare (Workers AI has no local simulator), so even npm run dev uses whichever account account_id names. Then check it:
npm run check:team
You should see: Team check OK: account 1a2b3c..., demo hostname ... with your own values. The check only reads your files and terminal: it does not need anything to exist in your account yet. npm run dev and npm run deploy run it first and stop if a value is still a placeholder (TEAM_ACCOUNT_ID, TEAM_HOSTNAME), if the account is the old shared event account, or if a CLOUDFLARE_ACCOUNT_ID in your terminal is a different account. It only warns about an old CLOUDFLARE_API_TOKEN; that token overrides your login, so remove it. The clear-old-settings commands are in Step 0. It is a safety net, not a lock: Cloudflare permissions decide where you can really deploy.
3. Create your AI Gateway agent-gateway
Your account starts with no gateway, and the starter sends every model call through one named agent-gateway. If it does not exist, the chat answers with an error (code 2001, shown by curl as gateway_not_configured). Create it now, once, in the dashboard (a gateway cannot be created with wrangler: its login has no AI Gateway permission):
- Open the AI Gateway page and choose your team account if asked. The account name at the top left must be the one on your team card.
- Choose Create custom gateway. Do not use the default gateway the dashboard offers: Cloudflare names it
default, and the starter looks for another name. - Gateway ID:
agent-gateway, exactly, lowercase. This is the id the starter sends with every call (AI_GATEWAY_ID), so do not add a suffix or change it: the starter andnpm run check:teamexpect this one. - Workers AI Billing: leave the default (Standard billing), if the dashboard asks.
- Select Create. Leave the other settings as they are for now; Step 6 changes some of them. Log collection is on by default, which is what Part 7 below needs.
You should see: agent-gateway in the gateway list. If Create custom gateway is missing or refused, tell a host: your invitation should give you the Administrator role in this account, and yours may be missing it.
4. Run it locally
npm install
npx wrangler --version
npm run dev
The first line downloads the starter's packages. It should end with found 0 vulnerabilities; a line saying that some packages are looking for funding is only a notice, not a problem. The second prints the Wrangler version the starter ships with (4.146.0 in this release). npm run dev starts the starter on your laptop. Open http://localhost:5173 in a browser and say hello. It needs the wrangler login from Step 0, because the model runs on Cloudflare, and it needs the gateway from part 3. Stop it with Ctrl+C when the chat answers.
5. Deploy
npm run deploy
What this does: it runs the team check, builds the chat page, creates the Worker agent in your team account (there is nothing to update yet) and creates the Custom Domain from routes: Cloudflare adds the DNS record and issues the certificate in your zone. You should see Uploaded agent and a Current Version ID. The first deploy in a new account can take a little longer than later ones.
There is no workers.dev link: it is off on purpose. Depending on the Wrangler version the output may say No targets deployed, or list your hostname as a custom domain; either is fine as long as your hostname answers in part 6. If Wrangler stops with a message about a DNS record that conflicts with your hostname, read the Stuck? entry below before answering it.
6. Wait for your hostname, set your demo URL and talk to it
A brand-new hostname is not instant. Cloudflare creates the DNS record and the certificate after the deploy, so for the first minutes your laptop may say the host does not exist, or fail the secure connection. That is normal. Check it (replace the host with the one on your team card):
curl -sS -o /dev/null -w "%{http_code}\n" https://<your demo hostname>/
You should see: 200. Run it again every 30 seconds or so. Most of the time it answers within a few minutes; the Cloudflare docs give no exact time for the certificate, so if it is still failing after about ten minutes, see Stuck? below.
Then set your demo URL once per terminal, using the hostname from your team card. Every curl and PowerShell example in the later steps reuses it, so open a new terminal later and you set it again:
export DEMO_URL=https://<your demo hostname>
Open your demo URL in a browser and chat. Then call the JSON endpoint the way the shields will later:
curl -s -X POST "$DEMO_URL/api/chat" \
-H 'content-type: application/json' \
-d '{"message":"hello"}'
You should see: a reply from the agent, as {"reply":"..."} (PowerShell shows it as a reply field). If you see gateway_not_configured instead, go back to part 3.
7. Find your request in the AI Gateway log
In your team account's Cloudflare dashboard, open AI Gateway > agent-gateway > Logs. Your messages are there, each with its model, status and token counts. That log is how you will see what your agent does for the rest of the day.
Check it worked
npm run check:teamprintsTeam check OK.agent-gatewayexists in your team account's AI Gateway page.- The chat page loads on your demo hostname and answers.
- The
curl(orInvoke-RestMethod) call returns a reply. - In the dashboard, AI Gateway >
agent-gateway> Logs shows your request.
Stuck?
npm installhangs or errors. A corporate laptop may block the npm registry. Try a phone hotspot, or ask a host.npm installreports vulnerabilities, or Wrangler is older than 4.146.0. You have an older copy of the starter. Download it again from part 1 (this page links version2026.11.0) and unpack it into a fresh folder. In a pinch,npm audit fixclears the warnings in your current folder.- Replies are slow. The starter uses a small, fast model (
@cf/google/gemma-4-26b-a4b-it), so a slow reply is usually the first call after a deploy or a busy moment. Wait a few seconds and ask again;npx wrangler tailshows what the Worker is doing. If you changedMODELto a larger model, that is the cause: switch it back. npm run devsays you must log in. Runnpx wrangler loginin an interactive terminal with the email your team's invitation went to.npm run check:teamstops with an error. Read the message: it names the value to fix. A placeholder is still inwrangler.jsonc, the account is the old shared event account, or an oldCLOUDFLARE_ACCOUNT_IDorCLOUDFLARE_API_TOKENis set in your terminal, a.envfile or a.dev.varsfile. Use the clear-old-settings commands in Step 0.wrangler whoamidoes not list your team account, or a command says you cannot reach it. You have not accepted your team account invitation yet: check your inbox, or open Get ready to see where a host has got to. Then re-runnpx wrangler loginwith the same email. Still missing? Tell a host.- You deployed under a different name. Set
"name": "agent"and deploy again. A different name creates a second, separate Worker; delete the extra one withnpx wrangler delete --name <that name>. - The chat is silent, or answers with a gateway error (
gateway_not_configured, oragent errorwith an older starter and2001: Please configure AI Gatewayinnpx wrangler tail). The gateway does not exist in your team account yet, or its name is not exactlyagent-gateway. Create it as in part 3 (it takes a minute) and ask again; no redeploy is needed. The browser chat page does not show this error, it just stays silent: the cause is innpx wrangler tail, and thecurlcall in part 6 names it. To keep going without it, setAI_GATEWAY_IDto""and redeploy: the starter then calls Workers AI directly, but Step 6 needs the gateway later. npm run deployfails with an authentication or permission error (code10000), or says it could not find the zone. "Could not find zone for …" means theaccount_idand the hostname do not belong together: both must come from your team card, andnpx wrangler whoamimust list that account. A permission error on the hostname or the Worker means your role in this account is not Administrator, so it cannot create Workers or Custom Domains: tell a host, who checks your invitation. Do not work around it with aworkers.devlink.- Wrangler says a DNS record for your hostname conflicts. Something already has that name in your zone (for example a record added by hand, or a half-finished earlier try). If you are sure the record is not needed, answer yes and Wrangler points the name at your Worker. A CNAME on the name cannot be replaced that way: delete it in the dashboard under your zone's DNS records, then deploy again. If you did not create it, ask a host first.
- A deploy was interrupted, or the hostname was only half created. Run
npm run deployagain. It is safe to repeat: it brings the Worker and the Custom Domain to the state inwrangler.jsonc. - Your demo hostname shows nothing, "could not resolve host" or a certificate error right after deploying. The DNS record and certificate are created after the deploy: wait and retry the check in part 6. Your laptop remembers a failed lookup for a while: use a phone hotspot, or
curl --resolve <your demo hostname>:443:<an IP from nslookup against 1.1.1.1>, or wait about five minutes. Still failing after about ten minutes? Check that theroutespattern is exactly the hostname on your team card with nothing else around it, that the deploy printed no route error, and that the Custom Domain appears in the dashboard under Workers & Pages >agent> Settings > Domains & Routes. Then tell a host. Never usebuild-stockholm.events-cloudflare.com. That is the event site, not your account;npm run check:teamrefuses it. $DEMO_URLis empty, or a URL starts withhttps:///. You opened a new terminal since part 6. Set it again.curlfails on Windows. In PowerShellcurlis not the real curl; use theInvoke-RestMethodline.- Windows and
unzip. Use the PowerShell line in part 1, or right-click the zip and Extract All.
Go further
- Point your coding agent at live docs so it does not write from memory: paste
Fetch https://developers.cloudflare.com/agent-setup/prompt.mdinto Claude Code, Cursor, Copilot, OpenCode or Codex. The event's own MCP server ishttps://build-stockholm.events-cloudflare.com/mcp; Get set up has the details. - Watch your Worker live:
npx wrangler tail. - Use synthetic data for this workshop. Your demo URL and chat may be publicly reachable; do not upload real customer, employee or proprietary data.
Finished step 1?
Checking your team…
Back: Step 0: Get set up. Next: Step 2: First tool.
Need help? Raise a hand for a host, or ask the Mentor dock (it escalates to a host when unsure). Remote: remote help channel to be confirmed by the event owner.