Tips · Oct 5, 2026 · 15 min read
How to Build an AI Agent: 3 Ways, From Scratch to Hosted

TL;DR: How to build an AI agent comes down to one decision: how much of it you own. Every agent has a harness (the loop that calls the model and runs tools), an environment (where it runs and keeps state) and a purpose (the system prompt and tools that tell it who it is and what its job is). You can build all three yourself; adopt a harness such as the Claude Agent SDK, Codex or Pi and bring your own container; or use a hosted runtime such as camelRun, Claude Managed Agents, the OpenAI Agents API or AgentCore harness, and write only the prompt and tools. Coding agents that need a shell fit the second way; agents that live inside your product and act through your app's APIs fit the third.
What an AI agent is made of
An AI agent is a model that decides its next step, calls a tool to take it, reads the result, and repeats until the task is done. Under the branding, every agent has three parts:
- The harness is the loop. It sends the conversation to the model, runs the tool calls the model asks for, feeds the results back, keeps the context inside the model's window, retries failed provider calls, and decides when to stop.
- The environment is where the harness runs and where state lives: a process or container, a sandbox for any code the model writes, and storage for history and files that must survive a restart.
- The purpose is the system prompt (who the agent is, what its job is and how it behaves) and the tools (what it can actually do: your APIs, MCP servers, a database, web search). Together they give the agent its understanding of who it is and what it's there to do. The harness and environment could run any agent; the purpose is what makes this one yours.
+---------------------------------------------------------+
| Purpose system prompt + tools |
+---------------------------------------------------------+
| Harness the loop: model calls, tool calls, context |
+---------------------------------------------------------+
| Environment compute, code sandbox, durable state |
+---------------------------------------------------------+
The three ways to build an AI agent differ only in which layers you own:
| Purpose | Harness | Environment | |
|---|---|---|---|
| Way 1: build it yourself | You | You | You |
| Way 2: adopt a harness | You | Off the shelf | You |
| Way 3: hosted runtime | You | Provider | Provider |
The model vendors draw the same lines. Anthropic offers the Messages API, the Claude Agent SDK and Claude Managed Agents; OpenAI's guide to building agents splits the Responses API, the Agents SDK and the Agents API the same way. For exact definitions of each layer, see Agent Harness vs Framework vs Runtime vs Sandbox.
Components of an AI agent
Zoom in and a production AI agent architecture has up to eight components. Most agents need most of them; the three ways differ in who writes each one.
| Component | What it does |
|---|---|
| Harness (the loop) | Calls the model, runs the tools it asks for, returns results, compacts long context, retries, stops |
| Model | Chooses the next step. Your harness or runtime limits which models you can use |
| Tools | What the agent can do: functions, HTTP APIs, MCP servers, OpenAPI specs, built-ins like web search. Authorization belongs here, not in the prompt |
| Memory and state | Conversation history, files and pending work that must survive deploys and crashes |
| Environment | Compute for the loop, plus a sandbox for model-written code (a Linux container or microVM, or a lighter language sandbox) |
| Triggers and channels | What wakes the agent: a user message, a schedule, a webhook, a Slack thread, a GitHub pull request |
| Human approvals | Pausing before a risky tool call and resuming when someone answers, possibly days later |
| Observability | A record of every model call and tool call, with cost and errors, so you can debug and evaluate |
Way 1: Build an AI agent from scratch
In way 1 you call a model API directly and write everything else. The loop itself is short. This TypeScript sketch is illustrative, not production code; callModel() stands in for your provider's chat API with tool calling.
// Illustrative sketch. callModel() is a stand-in for your provider's API.
const tools = {
get_order: async ({ id }) => db.orders.find(id),
refund_order: async ({ id }) => payments.refund(id),
};
async function runTurn(history, userText) {
history.push({ role: "user", content: userText });
for (let step = 0; step < 25; step++) {
const reply = await callModel({ system: SYSTEM_PROMPT, messages: history, tools: TOOL_SCHEMAS });
history.push(reply.message);
if (reply.toolCalls.length === 0) return reply.text; // the model answered
for (const call of reply.toolCalls) {
const result = await tools[call.name](call.args); // your code runs the tool
history.push({ role: "tool", toolCallId: call.id, content: JSON.stringify(result) });
}
}
throw new Error("Step limit reached");
}
That is a working agent, and it's where the real work starts. The sketch leaves out most of the components above:
- State that survives restarts.
historylives in memory, so a deploy or crash mid-turn loses it unless you persist after every step. - Context management. Long conversations outgrow the context window and need truncation or compaction.
- Failures. Rate limits, provider overloads, tool timeouts, malformed arguments, runaway loops.
- Side effects. If the process dies after
refund_orderruns but before its result is saved, a naive retry refunds twice. Risky tools need idempotency keys and often a human approval. - Waiting. An approval or a scheduled follow-up can take days, so the loop has to suspend to storage and resume later.
- Everything around it: a sandbox if the model writes code, streaming to your UI, per-user isolation, spend limits and tracing.
We know the length of that list first-hand. The camelAI team has built agent infrastructure five times in three years, and moving camelCode's agents onto camelRun let us delete about 72,000 lines of code (why we built camelRun). Durable AI Agents covers the state and side-effect problems in depth.
Frameworks help with the loop, not the hosting. Libraries such as LangGraph, Pydantic AI, Mastra, the Vercel AI SDK and the OpenAI Agents SDK give you a tested loop, tool schemas and streaming, and several add persistence. Anthropic's client SDKs include a beta tool runner. You still deploy and operate the result. To build an AI agent without a framework, start from the sketch above; a framework covers part of the list above it, but not the hosting.
- What you write: the loop, tools, persistence, context management, error handling, and the service it runs in.
- What you operate: the process and its scaling, a database for history, a queue for long tasks, any sandbox.
- Trade-offs: total control and no platform fees beyond tokens and your own infrastructure, in exchange for owning every failure mode.
- Who it's for: teams whose loop is the product (a new agent design, research, unusual control flow), and anyone learning how agents work.
- Rough time to first agent: an afternoon for a working loop; weeks to production.
Way 2: Adopt a harness and bring your own container
A harness is a ready-made loop with built-in tools, context management and compaction. Many come from coding agents, and each of these can run without its interactive UI:
| Harness | License | Models | Run it headless |
|---|---|---|---|
| Claude Code / Claude Agent SDK | Anthropic Commercial Terms | Claude only | claude -p, or the Python and TypeScript SDKs |
| Codex | Apache-2.0 | OpenAI by default; local models via --oss | codex exec --json |
| Pi | MIT | Many providers | pi -p, or pi --mode rpc |
| OpenCode | MIT | Many providers | opencode serve (HTTP API, OpenAPI spec at /doc) |
| Goose | Apache-2.0 | Many providers | goose run -t "…" or --recipe |
| OpenHands | MIT | Many providers | openhands --headless -t "…" (auto-approves every action) |
The catch: harnesses expect a computer. Anthropic's hosting guide for the Agent SDK explains that the SDK runs a claude subprocess that owns a shell, a working directory and session files on local disk. One session is one subprocess, and the guide suggests 1 GiB of RAM, 5 GiB of disk and 1 CPU per agent as a starting point. Those session files don't survive a container restart unless you add a session store. So way 2 leaves you two jobs: give every agent a box, and keep what's in it.
Running a harness headless looks like this (starting points, not a tested deployment). --bare authenticates with ANTHROPIC_API_KEY; Anthropic doesn't let third-party products offer claude.ai login without its approval, so plan on API keys.
claude --bare -p "Find and fix the failing test" --allowedTools "Read,Edit,Bash" --output-format json
codex exec --json --sandbox workspace-write "Find and fix the failing test"
Where to run it, from simplest to most managed
- Docker on a VM. A container per agent or per tenant on one machine. Simple and inexpensive to start; you own scheduling, disks, tenant isolation, egress rules and recovery when the VM dies.
- Serverless containers such as Google Cloud Run, AWS Fargate or Azure Container Apps. Scaling and patching are handled. They suit short, request-shaped jobs; long sessions need state stored outside the container.
- Sandbox providers. Isolated machines built for agents and created by API, usually with snapshots or pause and resume (table below).
- Kubernetes. For platform teams that want sandboxes in their own cluster. The agent-sandbox project (Apache-2.0) manages stateful, single-instance sandboxes isolated by gVisor or Kata Containers, with warm pools and pause/resume.
| Sandbox provider | What stands out | How it bills |
|---|---|---|
| E2B | Linux VMs on demand; pausing keeps filesystem and memory; sessions up to 1 h (Hobby) or 24 h (Pro) | Per vCPU-second and GiB-second while running |
| Modal Sandboxes | gVisor or a VM runtime; volumes and filesystem snapshots; up to 24 h per sandbox | Per core-second (1 core = 2 vCPU) and GiB-second |
| Vercel Sandbox | MicroVMs; persistent sandboxes and snapshots; 24 h sessions on Pro | Active CPU (I/O wait not billed), provisioned memory, per-creation fee |
| Cloudflare Containers | Runs alongside Workers and Durable Objects | CPU on active usage, memory and disk per second; Workers Paid ($5/month) |
| Fly.io Sprites | A persistent Linux computer with checkpoints; sleeps when idle | CPU-hours and GB-hours while awake, plus storage |
| Northflank | Deploys into your own AWS, GCP or Azure account | Per vCPU-hour and GB-hour |
| Daytona | Stateful sandboxes with snapshots; its open-source repository is now archived | See vendor |
Pricing verified October 2026. Pricing and limits change often; check each vendor's pricing page before deciding.
The billing unit matters more than the list price. Agents spend much of their time waiting on the model, and some providers don't bill CPU while it waits: Vercel's Active CPU excludes I/O wait, Cloudflare bills CPU on active usage, and Sprites stop billing compute while asleep. Compute is rarely the largest line anyway: Anthropic's hosting guide puts a minimally provisioned container at roughly $0.05 an hour and says token cost typically dominates container cost by an order of magnitude or more.
The harder problem is keeping each agent's machine and files around between sessions. We tried Modal, Cloudflare Containers and Sprites before building our own persistent container service.
What you still build: a queue and a router that send each session to the right container, session persistence, authentication in front of the agent, per-tenant isolation and egress control, secrets kept out of the sandbox, observability and cost limits. How to Run Claude Code Headless in Docker covers the CLI path, and How to Host the Claude Agent SDK in Production covers the SDK.
- What you write: configuration, a system prompt (often appended to the harness's own), tools as MCP servers or plugins, and the service around the harness.
- What you operate: containers or sandboxes, session storage, and routing.
- Trade-offs: a mature loop with strong file and shell tools from the start. In return you run a computer per agent, inherit the harness's assumptions (a shell, a filesystem, sometimes one model vendor), and own persistence and isolation.
- Who it's for: coding and file-heavy agents that run builds, tests and arbitrary CLIs; CI jobs; internal automation.
- Rough time to first agent: under an hour for a headless run on your laptop; weeks for a multi-user service.
Way 3: Use a hosted runtime and write only the prompt and tools
A hosted runtime runs the harness and the environment for you. You define the agent's model, instructions and tools; the runtime runs the loop, stores history and files, sandboxes model-written code, and wakes the agent when there's work. The main options:
| Models | Where model-written code runs | State | Open source / self-host | Platform pricing basis | |
|---|---|---|---|---|---|
| camelRun | Anthropic, OpenAI, OpenRouter, Amazon Bedrock, or an OpenAI- or Anthropic-compatible server; switch models and keep history | JavaScript sandbox; your tools run in your code | History and files kept until you delete the agent | Runtime AGPL-3.0, SDKs MIT; self-host with Docker and Postgres | $0.01 per agent-hour of active run time; sleeping agents cost only storage ($0.10 per GB-month) |
| Claude Managed Agents (beta) | Claude 4.5 and later | Anthropic cloud sandbox (bash, files, web) or a self-hosted sandbox | Stored server-side | Hosted by Anthropic; sandbox can be self-hosted | $0.08 per session-hour while running |
| OpenAI Agents API (beta since Sep 10, 2026) | OpenAI models | OpenAI-hosted Linux sandbox (1, 4 or 16 GB) or your own | Durable sessions; a hosted sandbox can be deleted an hour after activity and keep-alives cease; /workspace/outputs kept | Codex harness is Apache-2.0; the API is OpenAI-hosted | Container rates for hosted sandboxes: $0.03 / $0.12 / $0.48 per 20-minute session (1 / 4 / 16 GB); eligible sessions billed by the minute with a 5-minute minimum |
| AgentCore harness (GA Jun 17, 2026) | Bedrock, OpenAI, Gemini, any LiteLLM provider | MicroVM per session with a filesystem and shell | Memory and files persist across sessions | Built on open-source Strands Agents; runs on AWS | No harness charge; AgentCore Runtime per vCPU-hour and GB-hour, plus other services used |
Pricing verified October 2026 on the camelRun, Claude, OpenAI and AgentCore pricing pages. Pricing and limits change often; check each vendor's pricing page before deciding. Model tokens are extra on all four. Each row bills a different unit (an active agent-hour, a running session-hour, a 20-minute container session, a vCPU-hour), so compare them on your own workload rather than side by side.
Here is the smallest camelRun agent, from the README:
import { Agents } from "@camelai/run";
const agents = new Agents(); // CAMELAI_API_KEY
const agent = await agents.upsert("support-triage", { instructions: "Be concise." });
console.log((await agent.run("Which tickets look urgent?")).text);
await agents.close();
upsert takes your own key, so support-triage (or user-123, or a ticket id) is the same agent, with its history, from any process until you delete it. A tool is an ordinary function that runs in your process, with your credentials. This is the TypeScript example from the quickstart:
import { Agents, schema, tool } from "@camelai/run";
const agents = new Agents(); // reads CAMELAI_API_KEY
// A tool is an ordinary function: it runs here, in your process.
const weather = tool({
description: "Today's weather in a city",
input: schema.Object({ city: schema.String() }),
execute: ({ city }) => ({ city, forecast: "sunny", highC: 24 }),
});
// The same key is the same agent, with its history, every time you run this.
const agent = await agents.upsert("quickstart", {
instructions: "You are a concise assistant.",
tools: { weather },
});
const run = await agent.run("Should I bring an umbrella in Lisbon today?");
console.log(run.text);
await agents.close();
The rest of the components table is camelRun's job: the loop, durable history, a sandbox where model-written JavaScript can call the agent's tools, schedules, channels (Slack, Discord, Telegram, GitHub and generic webhooks) and human approvals, which wait 7 days by default (up to 30) while the sleeping agent isn't billed for run time. Tools like weather are served over a connection the SDK opens out to camelRun, so you don't expose an endpoint; multi-instance or serverless backends can serve tools over HTTP instead. Durable history doesn't make side effects exactly-once: camelRun never re-sends a tool call whose result was lost, tells the model the outcome is unknown, and gives every call an idempotency key for your code to use.
Know the limit before you choose it. camelRun's code sandbox runs JavaScript only: no shell, no Python, no package installs, no network. Your own tools run in your code, so those limits don't apply to them, and a Python SDK for defining tools isn't Python code execution. An agent that needs to run a test suite or an arbitrary CLI belongs in way 2, or on Claude Managed Agents, the OpenAI Agents API or AgentCore harness, which give the model a Linux environment.
Which hosted runtime fits:
- camelRun when agents live inside your product (one per customer, ticket, thread or pull request), their tools are your app's APIs, and you want model choice or open source you can self-host. It runs thousands of agents at once. See Multi-Tenant AI Agents.
- Claude Managed Agents when you're standardized on Claude and want Anthropic to run the agent with a full Linux sandbox. See camelRun vs Claude Managed Agents and Claude Managed Agents alternatives.
- OpenAI Agents API when you use OpenAI models and want the Codex harness with hosted sandboxes or computer use. See camelRun vs OpenAI Agents API.
- AgentCore harness when you're an AWS shop that needs IAM, VPC and AWS-native governance. See camelRun vs AWS Bedrock AgentCore.
Cloudflare Agents, Letta, LangSmith Deployment and others are covered in AI Agent Runtimes and Hosting Platforms Compared.
- What you write: a system prompt and tools.
- What you operate: your app and wherever your tools run (and, if you self-host camelRun, the runtime).
- Trade-offs: the shortest path to a durable agent, at the cost of control over the harness and dependence on the provider's limits, maturity and model support. Two of the four are in beta, and two are tied to one model vendor.
- Who it's for: product teams putting agents in front of customers, and teams that don't want to run agent infrastructure.
- Rough time to first agent: minutes; camelRun's quickstart is written as a five-minute path.
How to build an AI agent: which way fits
| Way 1: build it yourself | Way 2: harness + your container | Way 3: hosted runtime | |
|---|---|---|---|
| You write | Loop, tools, state, hosting | Config, prompt, tools, the service around it | Prompt and tools |
| You operate | Everything | Containers or sandboxes, session storage, routing | Your app and tool endpoints |
| Model choice | Any | Set by the harness (Claude Agent SDK: Claude; Codex, Pi, OpenCode: configurable) | Set by the runtime (camelRun, AgentCore harness: any; Claude Managed Agents: Claude; Agents API: OpenAI) |
| Code execution | Whatever you build | Full Linux | Linux sandbox (Claude Managed Agents, Agents API, AgentCore) or JavaScript only (camelRun) |
| Best for | New loop designs, research, learning | Coding agents, CI, file-heavy work | Agents inside a product, one per user or thread |
| Rough time to first agent | An afternoon; weeks to production | An hour locally; weeks as a service | Minutes |
The time estimates are rough planning guides, not benchmarks; scope moves them more than the approach does.
- Choose way 1 when the loop itself is what you're building or studying, or you need control flow no harness offers.
- Choose way 2 when the agent needs a real computer: running builds and tests, installing packages, using arbitrary CLIs. If you'd rather not run the containers, Claude Managed Agents, the OpenAI Agents API and AgentCore harness give you a managed Linux sandbox.
- Choose way 3 when agents are part of your product, their tools are your app's APIs, and most of them sit idle waiting for a message, a schedule or a person. That's the case camelRun is built for.
- Mix them when needs split. A hosted-runtime agent can call a tool that starts a short sandbox job when it occasionally needs Linux, and a way-2 coding agent can call your app through an MCP server.
FAQ
How much does it cost to run an AI agent? Model tokens are usually the largest line; Anthropic's hosting guide says they typically outweigh container costs by an order of magnitude or more. Platform charges come in different units: per active agent-hour (camelRun, billed on your own model keys too), per running session-hour (Claude Managed Agents), per container session (OpenAI's hosted sandboxes), or per vCPU-hour and GB-hour (AgentCore Runtime and most sandboxes). Estimate from your workload: how long agents actually run versus wait, and how many are awake at once.
Can I switch approaches later? Yes, if your tools are portable. Tools written as plain functions, HTTP endpoints or MCP servers move between all three ways, and so does a system prompt. State is harder: history, files and session formats differ between harnesses and runtimes, so check export options before you commit. camelRun, for example, exports an account's agents, their full histories and their files as a zip.
How do I stop an agent from doing something destructive? Treat the model's tool calls as untrusted input. Check authorization inside each tool against the end user's identity, not in the prompt; require human approval for irreversible actions; and key side effects by an idempotency key so a retry can't repeat them. A runtime can hand your tool that key, but your code still has to use it.
Try camelRun
If your agents belong inside your product, camelRun runs the loop, history, sandboxed JavaScript and wake-ups while your tools stay in your code. It works with any model, costs $0.01 per agent-hour of active run time plus model usage, and is open source if you'd rather host it yourself. The quickstart gets a first agent running with a tool in your own process.
Related: Agent Harness vs Framework vs Runtime vs Sandbox · AI Agent Runtimes and Hosting Platforms Compared · How to Run Claude Code Headless in Docker · camelRun vs Claude Managed Agents