Deploy a runtime
`cheela deploy` compiles your capability set into a manifest, writes four artifacts alongside it, and pushes the result to the control plane. It stops at the first validation failure, before anything is written or sent.
The pipeline
- Load configuration.
cheela.config.tsis evaluated throughtsx, after.envis read, so your config sees the same environment your app does. - Validate configuration. Against a schema. A bad
endpointor a missingapiKeystops here. - Discover the runtime. The module at
.cheela/runtime.tsmust default-export aRuntime. - Discover capabilities. Every registration, with its schemas serialized to JSON Schema.
- Run generators. Every enabled generator is validated first, then each runs and has its output checked immediately.
- Compile the manifest. Capabilities, your
websiteblock, your namespace, the CLI version. - Authenticate and push.
POST /v1/deploymentswith the deploy key.
Nothing is written to disk or sent over the network past the first thrown error.
Dry runs
--dry-run runs everything except the push. Generators still write their files, so this is also how you regenerate artifacts without creating a deployment.
npx cheela deploy --dry-runCheela Deploy
✓ Config loaded
✓ Runtime loaded
✓ Found 4 capabilities
✓ Found 4 actions
✓ Deployment manifest valid
Generators
capability-manifest .cheela/generated/capability-manifest/capabilities.json (unchanged)
runtime-manifest .cheela/generated/runtime-manifest/runtime.json (unchanged)
openapi .cheela/generated/openapi/openapi.json (updated)
adp .cheela/generated/adp/agent-discovery.json (updated)
Dry run complete.
No deployment was created.After a real deploy, the CLI names any capability published without an input schema. The model is told those take no parameters. That is correct for something genuinely nullary and a bug for everything else — usually a schema that was not exported, or one that could not be serialized.
Generators
Four run by default. Each turns your capability set into a different artifact.
| GENERATOR | OUTPUT | WHAT IT IS FOR |
|---|---|---|
| capability-manifest | capability-manifest/capabilities.json | The canonical list of what this runtime exposes. |
| runtime-manifest | runtime-manifest/runtime.json | Runtime-level metadata, including SDK and CLI versions. |
| openapi | openapi/openapi.json | An OpenAPI document, so existing API tooling can read your capabilities. |
| adp | adp/agent-discovery.json | An Agent Discovery Specification manifest, for publishing. |
Disable any of them by name:
export default defineConfig({
apiKey: process.env.CHEELA_API_KEY!,
generators: {
disabled: ["openapi"],
},
});Runs are incremental. A generator whose inputs have not changed is skipped and reported as skipped (cached); the cache lives in .cheela/generate.cache.json, which is gitignored.
What gets written
.cheela/
├── generated/ # commit this
│ ├── capability-manifest/capabilities.json
│ ├── runtime-manifest/runtime.json
│ ├── openapi/openapi.json
│ └── adp/agent-discovery.json
└── generate.cache.json # gitignoredCommit generated/. The files are diffable, which means a pull request shows exactly how a published schema changed — the review you want before a stranger’s agent starts depending on it. Only the cache is local and derived.
Capability drift
Before pushing, deploy compares your local capability names against what is currently live and prints the difference. Same check, on demand:
npx cheela statusIf they disagree, status shows the diff and tells you to deploy. A failed status call never blocks a deploy — the diff is information, not a gate.
If you have published a manifest, other people’s agents may have cached the capability’s address. The discovery spec has deprecation fields for exactly this — mark it deprecated and leave it serving before you delete it.
Deploying from CI
Deploy needs the deploy key and nothing else. Your endpoint should already be live at the URL in your config — deploying does not start anything.
- name: Deploy Cheela runtime
run: npx cheela deploy
env:
CHEELA_API_KEY: ${{ secrets.CHEELA_API_KEY }}Add a dry run to pull requests to catch a broken capability set before it merges:
- name: Validate Cheela capabilities
run: npx cheela deploy --dry-run
env:
CHEELA_API_KEY: ${{ secrets.CHEELA_API_KEY }}Sequence matters: deploy after your application, so the endpoint serving the new capability set exists before the control plane starts routing to it.
Custom generators
A generator is an object with a name, an inputs() function used for cache invalidation, and a generate() function returning files to write. Register yours in config — they are appended to the built-ins, never a replacement.
export default defineConfig({
apiKey: process.env.CHEELA_API_KEY!,
generators: {
custom: [
{
name: "typed-client",
inputs: (context) => context.capabilities.map((c) => c.capability.name),
generate: (context) => [
{
path: "typed-client/client.ts",
contents: renderClient(context.capabilities),
},
],
},
],
},
});Names must be unique across built-ins and custom generators; a collision is an error rather than a silent override. Anything that is not generator-shaped is rejected at load time with a message saying what was missing.
Full command syntax is in the CLI reference, and every config field in Configuration.