camelRun by camelAI

Durable AI agents that outlive any server

camelRun is a hosted runtime for durable AI agents: if a server goes away mid-run, another picks the run up, and no tool call is sent twice.camelRun is a hosted runtime for durable AI agents. You write the tools; it runs the agent loop and keeps each agent's history, files and unfinished work. If a server goes away mid-run, another one picks the run up, and no tool call is sent twice.

Agentops
camelRun servers

Server 3 unplugged mid-refund. Server 1 resumed the run, and refund 1042 was sent once.

When camelRun deploys

Agents keep working while we deploy

When one of our servers leaves for a deploy, each agent's run finishes the step it is in. Then another server picks it up and calls the model again.

Your event stream reconnects and reads on from its last event, with no gap and no repeat.

Read about events
GET /v1/agents/client_…/events
SSE
Server 1 finishes the step
id: 1727520000000412data: {"type":"event","requestId":"8c1…","event":{"type":"tool_execution_end","toolCallId":"…","toolName":"refund",…}}message_start, message_end (the tool result)id: 1727520000000415data: {"type":"event","requestId":"8c1…","event":{"type":"turn_end",…}}
Server 1 leaves
event: reconnectretry: 0data: {"type":"reconnect","reason":"drain","retryMs":0}
Reconnects to server 2
Last-Event-ID: 1727520000000415event: readydata: {"version":5,"agentId":"client_…","watch":true}
Server 2 picks it up
id: 1727520000000416data: {"type":"event","requestId":"","event":{"type":"turn_resumed","handoff":"retire",…}}
id: 1727520000000417data: {"type":"event","requestId":"8c1…","event":{"type":"turn_opened",…}}

Through crashes

Tool calls are never sent twice, even through a crash

If a server is lost mid-run, another one picks the run up from what was recorded. A tool call whose answer was lost is never sent again: the model is told its outcome is unknown, so it can check before trying again.

Every tool call carries context.idempotencyKey, the same on every attempt. Pass it to anything with side effects, and checking or retrying stays safe.

refund.ts
import { schema, tool } from "@camelai/run";

const refund = tool({
  description: "Refund an order in full",
  input: schema.Object({ orderId: schema.String() }),
  timeoutMs: 60_000,
  execute: async ({ orderId }, context) => {
    context.progress("Contacting the payment provider");
    return payments.refund(orderId, { idempotencyKey: context.idempotencyKey, signal: context.signal });
  },
});
How idempotency works

When your app restarts

Stateful AI agents that keep going when your app restarts

The same key reaches the same agent from any process, so the run lives in camelRun, not in yours. Each tool call goes to whichever of your processes is serving the agent's tools.

On a deploy

Close on SIGTERM in the process that serves the tools. It finishes the calls it has, then exits.

worker.ts
process.once("SIGTERM", () => void agents.close().then(() => process.exit(0)));
On startup

After a crash, upsert the agent and run it with the same idempotencyKey. You get the run that was already going, or its result if it ended. There's no workflow code: the key is the checkpoint.

worker.ts
// On startup (and after a crash): serve the tools, then collect the job's run.
const agent = await agents.upsert("ops", { model, instructions, tools: { refund } });
const run = await agent.run(`Refund order ${job.orderId}`, { idempotencyKey: job.id });
Deploying your tools

Sleep and wake

Long-running AI agents that sleep between runs

Between runs an agent sleeps and costs only storage. A message, a schedule, a channel or a webhook wakes it on whichever server has room, and it picks up where it was.

People in the loop
Agentops
In a run

$0.01 per agent-hour

Asleep

Storage only, $0.10 per GB-month

FAQ

Questions about durable AI agents

Read the concepts
  • What makes an AI agent durable?

    A durable AI agent keeps its state outside the process that runs it. In camelRun, each agent's history, files, configuration and pending work live in the runtime. It carries on through deploys and crashes mid-run, sleeps when there is nothing to do, and resumes from any process that knows its key.

  • Do I have to write my agent as a workflow to make it durable?

    No. camelRun runs the agent loop itself and records every step, so there are no steps, activities or checkpoints to write. Upsert the agent by its key, give it tools, and run it. Pass context.idempotencyKey to anything with side effects, and a retry stays safe.

  • What happens to a running agent during a deploy?

    Nothing you need to handle. The server that is leaving lets the model call or tool calls in flight finish, then hands the agent to another server at that boundary, with nothing lost. Watchers get a reconnect frame, connect again with their last event id, and the ids keep rising from there.

  • What happens if a server crashes mid-run?

    The run continues on another server under the same request id. An answer the model already finished stands. A tool call that was cut off is marked "outcome unknown" instead of being sent again, and the model is called once more to decide what to do, since your tool may still have finished it.

  • Does a durable agent keep its state between sessions?

    Yes. The same key is the same agent, from any process, until you delete it. Its history keeps every message, and when a long history outgrows the model's context window, older messages are summarized for the model. Its files stay in its workspace.

  • How is a durable agent billed while it is idle?

    Only storage, at $0.10 per GB-month. Agent time, $0.01 per agent-hour, is charged only while an agent is in a run, and no agent time is billed while a run waits on a person. Tokens are $0 on your own provider keys.

  • What if my own app restarts in the middle of a run?

    The run keeps going without it. When your process comes back and upserts the agent, it serves the run's next tool calls, even for runs an earlier process started. Calling run() again with the same idempotencyKey hands you that run instead of starting a new one, and the result always arrives.

  • Do I need my own database or queue to make agents durable?

    No. The agent's key does the job of a session store: its history, files and unfinished work are kept in camelRun, and nothing is stored on your side. If you'd rather run it yourself, the runtime is open source and self-hosts as one container and Postgres.

Keep reading

More on durable agents

Start your first durable agent

Sign in with GitHub or Google, create an API key, and run the quickstart. Or paste one line into your coding agent and it sets camelRun up for you.

quickstart.mts
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();
npx tsx quickstart.mts
Set up with your coding agent

Read https://run.camelai.com/SKILL.md and set up camelRun in this project. Ask me what the agent should do.

Paste into Claude Code, Codex, Cursor or any coding agent. It asks what your agent should do, then builds it.