Installation
Cheela is a set of small packages rather than one framework. Install the two or three that match what you are building.
Requirements
- Node 22 or newer. Every package declares
engines.node >= 22; the runtime usescrypto.randomUUIDandnode:crypto’s timing-safe comparison. - A package manager. The monorepo uses pnpm; npm and yarn work identically for consumers.
- An HTTPS endpoint if you are serving capabilities. Cheela calls in, so a local runtime needs a tunnel.
Which packages
Serving capabilities
The common case: your product exposes things a model can do. You need the CLI to deploy, and the runtime to serve.
npm install @cheela/runtime @cheela/sdk
npm install -D @cheela/cli@cheela/sdk is a peer of the runtime — it holds the Capability and Action types, plus the naming rules both the CLI and the control plane enforce. You will also want a schema library; every example here uses Zod, but anything exposing parse(value) satisfies the Schema interface.
Embedding chat in React
npm install @cheela/ui@cheela/ui re-exports the types you need from @cheela/client, so most React projects never depend on it directly.
Embedding chat without a build step
<script src="https://unpkg.com/@cheela/web-component/dist/cheela-chat.js"></script>
<cheela-chat api-key="ch_pk_..."></cheela-chat>The custom element registers itself and lazily fetches its own core chunk, so the tag in the markup costs almost nothing until it mounts.
Everything else
| PACKAGE | INSTALL IT WHEN |
|---|---|
| @cheela/client | You are building a chat UI for a framework that is not React. |
| @cheela/protocol | You need the wire types (Message, ExecutionResult) without a client. |
| @cheela/provider | You are calling OpenAI, Anthropic, Gemini or OpenRouter through one interface, outside Cheela. |
| @cheela/adp | You are reading or validating Agent Discovery Specification manifests. |
Project layout
cheela init writes a conventional layout. Nothing here is magic — every path is configurable — but the defaults are what the CLI looks for.
.
├── .cheela/
│ ├── runtime.ts # you write this — capabilities live here
│ ├── generated/ # commit this — reviewable in PRs
│ │ ├── capability-manifest/capabilities.json
│ │ ├── runtime-manifest/runtime.json
│ │ ├── openapi/openapi.json
│ │ └── adp/agent-discovery.json
│ └── generate.cache.json # gitignored — incremental build cache
├── cheela.config.ts
├── .env
└── package.jsonThe generated artifacts are diffable. Committing them means a pull request shows exactly how a capability’s published schema changed, which is the review you want before a stranger’s agent starts relying on it. Only generate.cache.json is local.
To keep capabilities somewhere else, point runtime at it:
export default defineConfig({
apiKey: process.env.CHEELA_API_KEY!,
runtime: "src/cheela/capabilities.ts",
});Environment variables
The CLI loads .env from the project root before it evaluates cheela.config.ts, so process.env is populated by the time your config reads it.
| VARIABLE | USED BY | WHAT IT IS |
|---|---|---|
| CHEELA_API_KEY | CLI | The deploy key, ch_sk_…. Authorises deploy and status. Secret. |
| CHEELA_RUNTIME_SECRET | Your endpoint | Verifies Cheela’s request signature. Shown when the runtime is created. |
| CHEELA_RUNTIME_ID | Your endpoint | Optional. Pins signatures to one runtime, so a signature minted for another is rejected. |
Reading it as process.env.CHEELA_RUNTIME_SECRET ?? "" verifies every signature against the empty string, so every request fails as signature_mismatch — which reads like a wrong key and sends you off rotating a credential that was fine. Throw instead.
TypeScript and bundlers
Every package ships ESM with type declarations and no CommonJS build. Set "type": "module" in your package.json, and use "moduleResolution": "bundler" or "nodenext".
The CLI evaluates cheela.config.ts and your runtime module through tsx, so neither file needs compiling before cheela deploy — and neither ends up in your application bundle unless you import it there.
@cheela/ui marks its components "use client" internally. In the Next.js App Router you can render <CheelaProvider> directly from a Server Component; the boundary is drawn for you.