Casals
General-purpose canister lifecycle orchestrator for the Internet Computer — built for managed multi-tenant IC deployments with shared upgrade governance.
Casals is fully on-chain: the conductor is a canister that creates, upgrades, snapshots, and rolls back other canisters by calling the IC management canister directly. Sheets, WASM catalog, cycles policy, and audit history all live in Casals' stable state — there is no off-chain worker in the deploy path. The CLI and frontend are thin clients that submit update calls; execution and rollback logic run inside the conductor.
Any project can operate its own Casals conductor to manage a canister fleet. Realms GOS is the reference consumer — it deploys Casals per network and drives rollouts from consumer-side fleet config. Casals also powers provisioning on the gos.earth GOS-as-a-Service platform.
Casals lets a project create, upgrade, roll back, and retire its canisters under that coordinator — organized into sections, stands, and canisters. Governance is pluggable: each section delegates to one or more commanders (principals or external governance canisters). Casals provides the structure and executes approved actions; it never embeds voting logic inside the conductor.
Live demo — https://igz53-6qaaa-aaaao-bbapa-cai.icp0.io
Design rationale — docs/philosophy (why orchestra / sections / stands / conductor / baton)
Model
| Term | Meaning |
|---|---|
| Section | A logical group of stands with a shared role (e.g. "Application", "Infra"). |
| Stand | A logical unit inside a section — typically one deployed application instance. |
| Canister | An actual canister. Stands contain one or more canisters. |
| Conductor | The Casals orchestrator canister — controller of managed canisters; runs all lifecycle calls on-chain. |
| Commander | A principal authorized by a section or stand to perform scoped lifecycle actions. |
| Baton / Multisig | Optional orchestration canisters (in packages/orchestration/) for managed upgrades and committee approval on target canisters. |
Key features
- Lifecycle — create, chunked install/upgrade, snapshot,
module_hashverification, all-or-nothing rollback across a stand. - Sheets — declare a whole orchestra in one JSON document;
deploy_sheetidempotently brings it to life. - Canister pool — reuses existing canisters before creating new ones (creation is expensive).
- Cycles management — native treasury, per-section/stand/canister policy, optional on-chain autopilot, or an off-chain monitor (
casals-monitor) that polls balances, runs auto top-ups, and serves the Cycles UI without burning conductor cycles on hourly samplers. - Authorized WASMs — ships with hello-world templates (Motoko, Rust, Basilisk, certified-assets frontend) plus orchestration templates (Baton, multisig); more added via governed list.
- Commanders & permissions — multiple commanders per section/stand; granular permission keys for create, upgrade, subnet whitelist, and shell access.
- Frontend — SvelteKit + Internet Identity (1-week delegation, no idle logout): Orchestra tree, Commanders, Orchestration consoles, sheet editor, cycles dashboard, WASM catalog, settings. Open the ☰ menu (top-left) for app navigation.
Off-chain cycle monitor
For production deployments, cycle observation and auto top-ups can run in casals-monitor instead of on-chain timers.
Use the hosted monitor (no account; your conductor's settings are the credential):
- In Settings → Cycle operations, choose Off-chain monitor, paste the service base URL (
https://casals.realmsgos.devorhttps://service.ic-casals.tech) under Hosted monitor service and click Use this service. Casals reads the service's principal fromGET /v1/serviceand fills in Monitor service URL (<base>/v1/<this conductor's canister id>) and Monitor principal. - Save. Casals stores
monitor_enabled/monitor_principal/monitor_service_urlon-chain, grants the monitor read access to managed canisters (Sync controllers), then callsPOST /v1/instanceson the service, which verifies those settings and starts polling. The Hosted monitor status card shows state (active/consent revoked/unreachable), last poll and cadence; Register / check status re-runs the registration. - To leave, switch back to On-chain (or change the principal) and save: the service stops auto top-ups at its next pass and disables the instance after 24 h. Nothing else is needed.
A self-hosted casals-monitor works the same way; its host must be added to connect-src in frontend/static/.ic-assets.json5, or you fill the two fields by hand.
This disables on-chain balance sampling and autopilot on the conductor (cycles_sampling: false, cycles_autopilot: false) while the monitor paymaster tops up from the same Casals treasury. Optional Alert emails in Settings notify operators when the treasury cannot fund a top-up or when the monitor sees consent withdrawn.
For scripted wiring, see scripts/examples/wire_monitor.py (JSON config with monitor_url, monitor_principal, casals_backend, casals_frontend).
Toolchain
icp-clifor build & deploy (icp.yaml); dfx is not used.- Basilisk +
ic-basilisk-toolkitfor the backend. casals-wasms— the WASM store: a certified-assets canister (chunked batch upload, on-chain sha256, pinned directories) thatcasals upcreates and seeds; every install streams from it — and every frontend asset bundle (docs/BUNDLES.md). Upload from the CLI (casals up) or from the browser on/files.
Quick start
pip install ic-basilisk-toolkit
icp network start -e local # terminal 1 — keep replica running
python3 -m casals_cli.main -e local up seed/sheets/demo.json --yes # bootstrap + build the demo orchestra
casals up <sheet> is the day-one deploy path: it validates the sheet, builds and deploys the conductor and the casals-wasms store, uploads the referenced WASMs into it, and builds what the sheet declares (set_sheet → plan → apply). From then on the orchestra is operated imperatively — the UI, casals upgrade, create_stand, upgrade_to, … — with no on-chain reconciliation loop (issue #52).
Open http://casals_frontend.local.localhost:8000/ — log in with Internet Identity using a principal listed on Commanders (or a Casals controller).
After code changes: re-run casals up (it rebuilds the conductor WASM when sources changed).
Mainnet:
python3 -m casals_cli.main -e ic --identity casals up <sheet> --yes
CLI
Install the casals command:
pip install ic-casals
Run from your project directory (where icp.yaml lives):
casals status # version + object counts
casals tree # Section → Stand → Canister tree
casals events # audit log
casals wasms # authorized WASM catalog
casals bundle dist/ -o app-1.2.0.tgz # pack a frontend build into a hashed bundle (docs/BUNDLES.md)
casals up sheet.json --yes # day one: build the orchestra the sheet declares
casals upgrade sheet.json --wasm my-backend # release: move every canister running that family to the pinned build
casals upgrade sheet.json --content my-frontend # release: every frontend with that content serves the pinned bundle
casals cycles # treasury + per-canister balances
casals pool # canister pool
casals export sheet.json # the sheet the conductor was built from + bindings
casals new [-y] # build, deploy, and seed (fresh canisters)
casals new ids.json [-y] # deploy with existing canister IDs
casals new -e ic --identity casals ids.json # mainnet upgrade from ID map
casals -e ic --identity casals status # mainnet, explicit identity
All output is JSON. Errors go to stderr as {"ok": false, "error": "..."} with exit code 1.
Without installing, the same commands are available via:
python3 scripts/casals.py status
make cli ARGS="status"
API
JSON-in / JSON-out text endpoints. Returns {"ok": true, …} or {"ok": false, "error": "…"}.
| Kind | Method | Purpose |
|---|---|---|
| query | get_tree |
full Section→Stand→Canister tree |
| query | get_sheet / list_pool |
stored day-one sheet + canister pool |
| query | get_cycle_history |
balance samples over time |
| query | list_permissions |
assignable commander permission keys |
| query | list_backend_controllers |
Casals canister IC controllers (for Commanders UI) |
| update | create_section / create_stand / create_canister |
structure |
| update | propose_upgrade / sync_content |
imperative release of a baton-governed member / a frontend bundle |
| update | set_commander / set_permissions |
commander principals + permission grants |
| update | upgrade_to |
stand/canister upgrade with snapshot rollback |
| update | add_authorized_wasm / remove_authorized_wasm |
WASM catalog |
| update | top_up / reconcile / set_cycle_policy |
cycles management |
| update | sync_controllers |
add monitor co-controller on managed canisters |
Full endpoint list: AGENTS.md.
About the name
Named after Pablo Casals — cellist and conductor. This project coordinates canisters the way a conductor coordinates an orchestra.
Disclaimer
This software is not production-ready. Do not deploy to mainnet or use with real canisters, cycles, or governance authority you cannot afford to lose.
Casals is in early development (alpha). It may contain bugs, breaking changes, and unknown security vulnerabilities. It has not undergone an independent security audit. Use at your own risk.
- Not recommended for production deployments on the Internet Computer
- No guarantee of correctness, availability, or security
- APIs and behavior may change without notice
License
MIT — see LICENSE.
Release files for ic-casals 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ic_casals-0.2.0.tar.gz | 89.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ic_casals-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 183.9 kB
Release files / ic_casals-0.2.0.tar.gz
| Download URL | ic_casals-0.2.0.tar.gz |
|---|---|
| Size | 89.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8a54bfce89d420a0123967945f2e4e70ee1aafe3a1b4b9761512c32370402e35
|
|
BLAKE2b-256 checksum How to use checksums |
ca8ec1b1f28adda42845e8ae65d3365e02e711668e36443c5df0f566d70661e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / ic_casals-0.2.0-py3-none-any.whl
| Download URL | ic_casals-0.2.0-py3-none-any.whl |
|---|---|
| Size | 94.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8a26d245dd0480e733fbba1ef8e83d8c3af16992206d9ed91894e36d81fe2f55
|
|
BLAKE2b-256 checksum How to use checksums |
ba2f3db861a76da2289229fe752a7b8e67ebd62413fe7138b441e9e89c75271f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|