Chio/Docs

Install an SDK

Add Chio to your application from your language's registry, then run a first program that earns one signed refusal.

Guide chio@5f63e6e

On this page

One package per language puts the Computer API from the Quickstart, and the lower-level clients beneath it, into your application. Each talks to the kernel the CLI installed, so a program in any language opens the same computers, grants the same authority, and reads the same receipts.

By the end of step 3 your program has opened the Quickstart computer, given the fixer agent a slice of it, and printed the receipt for the one read your kernel refused. Install the CLI first.

Start

1. Install the package for your language

Your projectYour projectYour projectYour projectbuild.gradle.ktsYour projectPackage.swiftYour project
npm install @chio-protocol/sdk

The packages need Node.js >=22, Python >=3.11, Rust 1.94, Go 1.23.0, Java 17, or net8.0. The Python distribution is chio-sdk and imports as chio; the PyPI name chio belongs to an unrelated project. The Rust crate starts its own runtime with #[chio::main], and the C++ package links with find_package(ChioCpp CONFIG REQUIRED).

2. Create your identity and the Quickstart computer

Your kernel signs every decision with your operator key, so create it once:

Terminalbash
chio key init
Output
operator   did:chio:z6Mkf3…Qp9
kernel     4f1c…a2e9
stored     ~/.chio/keys, mode 600

Then create the computer the program opens: a Python pricing package with three failing tests, one per open issue.

Terminalbash
chio new quickstart && cd quickstart
Output
created    quickstart, 14 tests, 3 failing: issues #412, #413, #414
computer   quickstart, owned by did:chio:z6Mkf3…Qp9

3. Run a first program and read its refusal

The program opens the computer, forks it, grants the fixer the workspace, your model route, and two dollars for twenty minutes, runs issue #412, and prints the one refusal the run earns.

quickstart.tsquickstart.pysrc/main.rsmain.goQuickstart.ktProgram.csmain.swiftmain.cpp
import { Computer, USD } from "@chio-protocol/sdk";

const project = await Computer.open("quickstart");
const fixer = await project.agent("fixer");
const fork = await project.fork();
const authority = fork.grant({
  to: fixer,
  resources: { "/workspace": ["read", "write"], "/models/default": ["invoke"] },
  budget: USD(2),
  expiresIn: "20m",
});

const run = await fixer.run("fix issue #412", { on: fork, authority });
for await (const event of run.events()) console.log(event.summary);

const [refusal] = await project.history.receipts({ outcome: "deny" });
console.log(refusal.describe());
Output
00:00  admitted   fixer runs "fix issue #412" on fork 51c07ae
00:03  read       /workspace/src/pricing.py
00:05  read       /workspace/tests/test_pricing.py
00:09  refused    read /secrets/.env: outside the grant
00:12  invoke     /models/default, USD 0.21
00:41  write      /workspace/src/pricing.py
00:56  test       pytest -k issue_412: passed
spent  USD 0.48 of 2.00

receipt    rcpt-01a8…9c04
request    fixer read /secrets/.env
verdict    deny: outside the grant
grant      cap-01a8…31f2
policy     sha256 3c7b…8010
signed     your kernel 4f1c…a2e9, signature verifies

You should see one refusal and a passing test. The fixer read the failing test, then tried /secrets/.env. The grant covers /workspace and /models/default only, so your kernel refused the read before the file was opened and signed receipt rcpt-01a8…9c04 for the refusal. The run spent USD 0.48 of its 2.00.

Every call in the program is in your language's reference: TypeScript, Python, Rust, Go, JVM, .NET, Swift, and C++.

An adapter puts the kernel in front of the stack you already run

A service that keeps its own HTTP framework or agent framework adds an adapter instead of rewriting its handlers. Each adapter installs from its registry under its own name and depends on the core package.

Your projectYour projectYour projectbuild.gradle.ktsYour project
pip install chio-fastapi     # FastAPI and other ASGI apps
pip install chio-django      # Django
pip install chio-langgraph   # LangGraph
pip install chio-temporal    # Temporal workflows
pip install chio-prefect     # Prefect flows

Further Python adapters cover chio-langchain, chio-crewai, chio-autogen, chio-llamaindex, chio-dagster, chio-airflow, and chio-ray. Every Python adapter requires Python >=3.11. The CLI and the SDKs write the same chio.receipt.v1 receipts, and chio conformance run executes the conformance scenarios against a peer-language adapter, so a prototype built on the CLI moves into an SDK with its records unchanged.

Read more in Add API Middleware.

Each Dagster, Airflow, and Ray task is admitted before its body runs

The Dagster, Airflow, and Ray adapters wrap the runtime's own unit of work, so the Chio sidecar evaluates each materialization, task, or remote call before its body runs. Each depends on chio-sdk and pydantic>=2.5. The examples are your nightly repricing jobs against the pricing and orders servers. Temporal and Prefect have their own guides: Temporal and Prefect.

Dagster

chio-dagster requires dagster>=1.8,<2. @chio_asset and @chio_op take every @asset and @op option and add a Chio scope, capability, and tool server.

Your projectbash
pip install chio-dagster
repricing/assets.py · a price sheet partitioned by tenantpython
from chio_sdk import ChioScope, Operation, ToolGrant
from dagster import AssetExecutionContext, Definitions, StaticPartitionsDefinition
from chio_dagster import chio_asset

TENANTS = StaticPartitionsDefinition(["harbor-goods", "ostrander"])

QUOTE_SCOPE = ChioScope(
    grants=[
        ToolGrant(
            server_id="pricing",
            tool_name="quote",
            operations=[Operation.INVOKE],
        )
    ]
)


@chio_asset(
    scope=QUOTE_SCOPE,
    capability_id="cap-nightly-reprice",
    tool_server="pricing",
    partitions_def=TENANTS,
)
def price_sheet(context: AssetExecutionContext) -> list[dict]:
    # The partition key is part of the evaluation payload.
    return pricing.quote_catalog(tenant=context.partition_key)


defs = Definitions(assets=[price_sheet])

A deny raises PermissionError and Dagster records a FAILURE run state. An allow attaches chio_receipt_id, chio_verdict, and the capability and tool fields to the emitted AssetMaterialization, so the asset catalog shows each receipt. Because the partition key is evaluated, a guard can admit harbor-goods and refuse ostrander. ChioIOManager wraps an inner IO manager and checks every handle_output and load_input against the destination.

Airflow

chio-airflow requires apache-airflow>=2.8,<4 and covers both operator styles: wrap a classic operator in ChioOperator, or decorate a TaskFlow function with @chio_task.

Your projectbash
pip install chio-airflow
dags/nightly_reprice.py · a TaskFlow taskpython
from airflow.decorators import dag
from chio_airflow import chio_task


@dag(schedule="@daily")
def nightly_reprice():

    @chio_task(
        scope=ORDERS_SCOPE,
        capability_id="cap-nightly-reprice",
        tool_server="orders",
    )
    def load_orders(day: str) -> list[dict]:
        return orders.sql("select sku, qty from orders where day = %s", [day])

    load_orders("{{ ds }}")


nightly_reprice()

A denied task fails with AirflowException, whose __cause__ is a PermissionError. Receipt ids go into XCom, and ChioDAGListener, registered through the bundled AirflowPlugin, aggregates them into a run-level record on on_dag_run_success and on_dag_run_failed. ChioOperator passes standard scheduling arguments such as retries and trigger_rule through to the operator it owns.

Ray

chio-ray requires ray[default]>=2.10,<3. @chio_remote keeps the .remote(...) and ray.get(...) contract and every ray.remote keyword argument.

Your projectbash
pip install chio-ray
bulk_quote.py · a Ray remote taskpython
import ray
from chio_ray import chio_remote


@chio_remote(
    scope="pricing:quote",
    capability_id="cap-bulk-quote",
    tool_server="pricing",
)
def quote_sku(sku: str) -> dict:
    return pricing.quote(sku, percent=10)


quotes = ray.get([quote_sku.remote(sku) for sku in ["sku-118", "sku-204", "sku-301"]])

The node-local sidecar at http://127.0.0.1:9090 evaluates each call. A deny raises PermissionError in the worker, and the driver sees a RayTaskError wrapping it. For long-lived actors, subclass ChioActor with a StandingGrant and mark methods with @ChioActor.requires(...). A method outside the standing grant raises PermissionError with reason scope_exceeds_standing_grant before the sidecar is called, and StandingGrant.attenuate hands a worker actor a narrower scope.

Platform integrations govern workloads rather than application code

A Kubernetes controller with CRDs and admission webhooks, and an AWS Lambda extension (chio-lambda-extension), put the kernel in front of whole workloads. The SDK overview describes both.

Next: merge the agent's fix