← ALL POSTS

Tips · Oct 5, 2026 · 15 min read

How to Build an AI Agent: 3 Ways, From Scratch to Hosted

IR
Illiana Reed
CEO & Product, camelAI
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:

PurposeHarnessEnvironment
Way 1: build it yourselfYouYouYou
Way 2: adopt a harnessYouOff the shelfYou
Way 3: hosted runtimeYouProviderProvider

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.

ComponentWhat it does
Harness (the loop)Calls the model, runs the tools it asks for, returns results, compacts long context, retries, stops
ModelChooses the next step. Your harness or runtime limits which models you can use
ToolsWhat 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 stateConversation history, files and pending work that must survive deploys and crashes
EnvironmentCompute for the loop, plus a sandbox for model-written code (a Linux container or microVM, or a lighter language sandbox)
Triggers and channelsWhat wakes the agent: a user message, a schedule, a webhook, a Slack thread, a GitHub pull request
Human approvalsPausing before a risky tool call and resuming when someone answers, possibly days later
ObservabilityA 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. history lives 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_order runs 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:

HarnessLicenseModelsRun it headless
Claude Code / Claude Agent SDKAnthropic Commercial TermsClaude onlyclaude -p, or the Python and TypeScript SDKs
CodexApache-2.0OpenAI by default; local models via --osscodex exec --json
PiMITMany providerspi -p, or pi --mode rpc
OpenCodeMITMany providersopencode serve (HTTP API, OpenAPI spec at /doc)
GooseApache-2.0Many providersgoose run -t "…" or --recipe
OpenHandsMITMany providersopenhands --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

  1. 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.
  2. 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.
  3. Sandbox providers. Isolated machines built for agents and created by API, usually with snapshots or pause and resume (table below).
  4. 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 providerWhat stands outHow it bills
E2BLinux 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 SandboxesgVisor or a VM runtime; volumes and filesystem snapshots; up to 24 h per sandboxPer core-second (1 core = 2 vCPU) and GiB-second
Vercel SandboxMicroVMs; persistent sandboxes and snapshots; 24 h sessions on ProActive CPU (I/O wait not billed), provisioned memory, per-creation fee
Cloudflare ContainersRuns alongside Workers and Durable ObjectsCPU on active usage, memory and disk per second; Workers Paid ($5/month)
Fly.io SpritesA persistent Linux computer with checkpoints; sleeps when idleCPU-hours and GB-hours while awake, plus storage
NorthflankDeploys into your own AWS, GCP or Azure accountPer vCPU-hour and GB-hour
DaytonaStateful sandboxes with snapshots; its open-source repository is now archivedSee 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:

ModelsWhere model-written code runsStateOpen source / self-hostPlatform pricing basis
camelRunAnthropic, OpenAI, OpenRouter, Amazon Bedrock, or an OpenAI- or Anthropic-compatible server; switch models and keep historyJavaScript sandbox; your tools run in your codeHistory and files kept until you delete the agentRuntime 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 laterAnthropic cloud sandbox (bash, files, web) or a self-hosted sandboxStored server-sideHosted by Anthropic; sandbox can be self-hosted$0.08 per session-hour while running
OpenAI Agents API (beta since Sep 10, 2026)OpenAI modelsOpenAI-hosted Linux sandbox (1, 4 or 16 GB) or your ownDurable sessions; a hosted sandbox can be deleted an hour after activity and keep-alives cease; /workspace/outputs keptCodex harness is Apache-2.0; the API is OpenAI-hostedContainer 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 providerMicroVM per session with a filesystem and shellMemory and files persist across sessionsBuilt on open-source Strands Agents; runs on AWSNo 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:

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 yourselfWay 2: harness + your containerWay 3: hosted runtime
You writeLoop, tools, state, hostingConfig, prompt, tools, the service around itPrompt and tools
You operateEverythingContainers or sandboxes, session storage, routingYour app and tool endpoints
Model choiceAnySet 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 executionWhatever you buildFull LinuxLinux sandbox (Claude Managed Agents, Agents API, AgentCore) or JavaScript only (camelRun)
Best forNew loop designs, research, learningCoding agents, CI, file-heavy workAgents inside a product, one per user or thread
Rough time to first agentAn afternoon; weeks to productionAn hour locally; weeks as a serviceMinutes

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

FROM THE TEAM BEHIND CAMELAI

Try what we're building.