Cantelop
Cantelop is the platform for running cloud agents. It is built on opinionated infrastructure that supports any harness.
To get started, see the quick start guide. To dive deeper into the capabilities of the platform, check the README of the SDK.
This post goes into the design philosophy, defined by the following principles:
- Minimal setup
- Any agent harness
- A Session is an actor
- Opinionated infrastructure
- Performance on the critical path
Background#
Actor model is a natural fit for agentic applications. It provides a simple abstraction for managing stateful, long-running, non-deterministic workloads.
Cloudflare's Durable Objects and Elixir embody the actor model.
Durable Objects in particular are widely used for agentic applications. However, the developer experience is desired to be better. Building complete agentic systems requires combining them with Cloudflare Workers and sandboxes while coordinating state across these components. This often means redesigning the agent harness around Cloudflare's infrastructure.
Infrastructure needs to be paired with clean abstractions that make it intuitive to use. Vercel and Next.js are great examples of how an opinionated, integrated developer experience can make complex infrastructure approachable.
Cantelop takes a lot of inspiration from Cloudflare on the actor model as well as the developer experience of Vercel and Next.js, combining them with an opinionated sandbox architecture into a single platform.
Minimal setup#
The SDK provides two surfaces: the Edge API and the Session runtime.
The Edge API is the application's public HTTP layer. It receives and validates requests, selects a workspace, opens a session, and dispatches application-defined messages.
export default defineApi<SessionMessage>(({ app, router }) => {
router.route("POST", "/chat", async ({ request }) => {
const input = await request.json();
const workspace = await app.workspaces.open({ slug: "default" });
const session = app.sessions.open({
workspaceId: workspace.id,
keepAliveSeconds: 300,
});
const message = await session.dispatch({
type: "prompt",
prompt: input.prompt,
});
return Response.json(
{ sessionId: session.id, message },
{ status: 202 },
);
});
});
The Session runtime defines the agent behavior that runs inside the Linux sandbox. Each active Session receives a dedicated SDK-managed process that is never shared with another Session.
export default defineSessionBehaviour<SessionMessage, SessionEvent>(
async ({ message, session, env, output, signal }) => {
const response = await agentHarness.run(message.payload.prompt, {
sessionId: session.id,
env,
signal,
});
await output.send({ type: "done", response });
},
);
Any agent harness#
Cantelop is unopinionated about how the agent itself is built. It does not prescribe a model provider, agent framework, tools, skills, or message protocol.
In practice, an existing locally developed harness can be wrapped in a Session behavior without being redesigned around Cantelop.
The Session runtime provides the surrounding execution environment: an isolated
Linux machine, environment variables and secrets, cancellation signals, an
output stream, and a durable workspace mounted at /workspace.
Short-lived sandboxes should not dictate the harness architecture. Data that
must survive reactivation belongs in /workspace. The rest is ephemeral.
The platform has been tested with Claude, the OpenAI Agents SDK, and Pi, but its generic integration boundary can support any harness.
A Session is an actor#
Every Session is a stable, addressable actor with its own identity and mailbox. Requests using the same Session ID are routed to the same logical actor.
Mailbox handlers run one at a time in acceptance order, while different Sessions can run concurrently.
The application defines the Session's message protocol:
type SessionMessage =
| { type: "prompt"; prompt: string }
| { type: "steer"; prompt: string }
| { type: "cancel" };
Long-running work can run as a managed activity, allowing the mailbox to remain responsive to messages such as steering and cancellation. Prompts received while an activity is running can be queued by the application:
export default defineSessionBehaviour<SessionMessage, SessionEvent>(
(context) => {
const command = context.message.payload;
if (command.type === "cancel") {
// implement cancel behavior
return;
}
if (command.type === "steer") {
// implement steering behavior
return;
}
startPrompt(context, command.prompt);
},
);
Opinionated infrastructure#
A Session is a durable logical identity that runs in a dedicated sandbox. Once its work completes and the configured keep-alive period expires, the sandbox is released.
When a message arrives for an idle Session, Cantelop can allocate a new sandbox behind the same Session ID.
Developers can use keepAliveSeconds to keep the sandbox running between
messages, preserving its in-memory and ephemeral state.
Every sandbox mounts a durable workspace at /workspace. Files written there
survive sandbox termination and become available to the next activation. Other
filesystem state, including temporary files, home directories, and caches, is
ephemeral.
Multiple Sessions can share the same workspace, including Sessions running concurrently in different sandboxes. The shared filesystem is provided over NFS.
keep-alive expires
Sandbox A ends
Performance on the critical path#
Although Cantelop coordinates several infrastructure components, it should feel like a single, cohesive runtime. From the compute availability perspective, developers should not have to consider whether a Session already has a warm sandbox or needs to activate a new one.
Sandbox startup is one of the benchmarks we watch most closely. The complete activation path takes around 250 ms.