Introduction
You describe what your product can do. Cheela runs the model, decides when to call you, and makes a signed HTTPS request to your endpoint. Your handler runs on your own infrastructure, with your own credentials.
What Cheela does
A capability is one thing your product can do — look up an order, check stock, book a slot — described with a name, a schema, and a handler. You register capabilities with a Runtime and deploy the description to Cheela.
From then on, Cheela owns the loop. It sends your capabilities to a model as tools, reads what the model wants to call, calls it, feeds the result back, and repeats until the model has an answer. You get the transcript, the token counts, and a trace for every step.
import { Runtime } from "@cheela/runtime";
import { z } from "zod";
const runtime = new Runtime();
runtime.register(
{
name: "order-status",
description: "Looks up the status of one order by its id",
version: "1.0.0",
input: z.object({ orderId: z.string() }),
},
{
name: "lookup",
async handler(context, input) {
// Runs on your server, against your database.
return await db.orders.findById(input.orderId);
},
},
);
export default runtime;Where your code runs
On your servers. Cheela never receives your handler, your database credentials, or your source. What you deploy is the description of a capability: its name, version, description, and JSON Schema.
When the model calls a capability, Cheela makes an HTTPS request to the endpoint you registered. That request is signed:
HMAC-SHA256(runtimeSecret, "runtimeId.timestamp.nonce.sha256(body)")Your endpoint verifies it before running anything. createCheelaHandler from @cheela/runtime does the verification and the dispatch, so this is a two-line endpoint rather than a security exercise.
You do not pick a provider or a model, and cheela.config.ts has no field for either. Executions run on Cheela’s own OpenRouter credential so tokens can be metered and billed. A runtime choosing its own model would be choosing how much Cheela pays.
Two ways in
A deployed capability can be reached down two different paths, and they have different security properties.
| PATH | WHO CALLS IT | AUTH |
|---|---|---|
| POST /v1/runtime/execute | Your own app or chat widget. Sends messages; Cheela runs the full agent loop and decides which capabilities to call. | The runtime’s public key (ch_pk_…) |
| POST /v1/capabilities/:runtimeId/:capability | Somebody else’s agent, which found the address in your published manifest. No model, no loop — it already knows what it wants. | None. The manifest is public, so the addresses in it must be. |
The second path is what “AI-native” means in practice: a stranger’s agent can use your product without scraping your UI. It is opt-in — nothing is published until you run cheela manifest pull and serve the result.
The packages
Everything is Apache-2.0 and published under the @cheela scope. Most projects need two or three.
| PACKAGE | WHAT IT IS FOR |
|---|---|
| @cheela/sdk | Types and helpers for describing a capability. |
| @cheela/runtime | The Runtime class, plus the request handlers that verify Cheela's signature. |
| @cheela/cli | `cheela init`, `dev`, `deploy`, `status`, `manifest`. |
| @cheela/ui | React chat components — <CheelaProvider/> and <Chat/>. |
| @cheela/web-component | The same chat as <cheela-chat>, for pages with no build step. |
| @cheela/client | Framework-agnostic core: HTTP client, conversation state, events. |
| @cheela/protocol | Wire-format types shared by the API and every client. |
| @cheela/provider | Adapters for OpenAI, Anthropic, Gemini, OpenRouter. |
| @cheela/adp | Agent Discovery Specification manifest types and validation. |
Where to start
Pick the half you need. They are independent.
Prefer reading code? The examples directory has three working projects: a signed Next.js endpoint, a React chat page, and a static HTML embed.
- Node 22 or newer is required by every package.
- You will need an account to create a runtime and get an API key — the dashboard is where runtimes live.