Quickstart
Give your own agents a slice of your project, and read the signed record of everything they tried.
On this page
Start with agents you run. Your kernel grants each one a slice of your project, refuses anything outside it, and signs a record of every decision.
An agent gets a fork of a failing project and two dollars. It fixes the bug, reaches for your secrets once, and is refused. You read the signed refusal, merge the fix, and add a rule it cannot work around. The same project carries through all three parts.
Start- Govern your agentsYour agents, your resources, your kernel.
- Serve other agentsAgents you do not run call your service.
- Work with their agentsAnother operator's kernel, under a treaty.
1. Install Chio
Install the CLI and the SDK for your language, then create your operator identity. Your kernel signs every decision with this key.
curl -fsSL https://chio.computer/install.sh | shnpm install @chio-protocol/sdkpip install chio-sdkcargo add chiochio key initoperator did:chio:z6Mkf3…Qp9 kernel 4f1c…a2e9 stored ~/.chio/keys, mode 600
2. Your project is a computer
A computer is a versioned environment where authority, resources, and work live. The sample is a Python package with three open issues, each pinned by a failing test. The first, #412: discount() accepts a percentage above 100.
chio new quickstart && cd quickstartcreated quickstart, 14 tests, 3 failing: issues #412, #413, #414 computer quickstart, owned by did:chio:z6Mkf3…Qp9
import { Computer, USD } from "@chio-protocol/sdk";
const project = await Computer.open("quickstart");
console.log(project.describe());computer quickstart
owner did:chio:z6Mkf3…Qp9 (you)
revision main @ 7c2e1d0
resources /workspace git, 14 files
/models/default model route, metered in USD
/secrets 3 filesfrom chio import Computer, USD
project = Computer.open("quickstart")
print(project.describe())computer quickstart
owner did:chio:z6Mkf3…Qp9 (you)
revision main @ 7c2e1d0
resources /workspace git, 14 files
/models/default model route, metered in USD
/secrets 3 filesuse chio::{Computer, Grant, Rule, USD};
let project = Computer::open("quickstart").await?;
println!("{}", project.describe());computer quickstart
owner did:chio:z6Mkf3…Qp9 (you)
revision main @ 7c2e1d0
resources /workspace git, 14 files
/models/default model route, metered in USD
/secrets 3 files3. Give your agent a slice
An agent is an identity your kernel issues authority to. Fork the project and grant the fixer part of the fork: the workspace, your model route, and two dollars. /secrets is not in the grant.
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",
});
console.log(authority.describe());grant cap-01a8…31f2, signed by your kernel
to fixer, did:chio:z6MkrT2…8wd
on quickstart, fork 51c07ae
allows /workspace read, write
/models/default invoke
budget USD 2.00, charged at your door
expires in 20 minutesfixer = project.agent("fixer")
fork = project.fork()
authority = fork.grant(
to=fixer,
resources={"/workspace": ["read", "write"], "/models/default": ["invoke"]},
budget=USD(2),
expires_in="20m",
)
print(authority.describe())grant cap-01a8…31f2, signed by your kernel
to fixer, did:chio:z6MkrT2…8wd
on quickstart, fork 51c07ae
allows /workspace read, write
/models/default invoke
budget USD 2.00, charged at your door
expires in 20 minuteslet fixer = project.agent("fixer").await?;
let fork = project.fork().await?;
let authority = fork.grant(
Grant::to(&fixer)
.resource("/workspace", ["read", "write"])
.resource("/models/default", ["invoke"])
.budget(USD(2))
.expires_in("20m"),
)?;
println!("{}", authority.describe());grant cap-01a8…31f2, signed by your kernel
to fixer, did:chio:z6MkrT2…8wd
on quickstart, fork 51c07ae
allows /workspace read, write
/models/default invoke
budget USD 2.00, charged at your door
expires in 20 minutes4. Let it work
Send the task. Every operation the fixer attempts reaches your kernel before it reaches a resource.
const run = await fixer.run("fix issue #412", { on: fork, authority });
for await (const event of run.events()) console.log(event.summary);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
run = fixer.run("fix issue #412", on=fork, authority=authority)
for event in run.events():
print(event.summary)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
let task = fixer.run("fix issue #412").on(&fork).authority(authority.clone());
let mut run = task.start().await?;
let mut events = run.events();
while let Some(event) = events.next().await {
println!("{}", event?.summary());
}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
You should see one refusal. The fixer read the failing test, then tried /secrets/.env. The grant does not cover it, so your kernel refused the read before the file was opened, and the run went on to pass.
Read more in The mediated call.
5. Read why it was refused
Every decision leaves a signed receipt, refusals included.
const [refusal] = await project.history.receipts({ outcome: "deny" });
console.log(refusal.describe());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
refusal = project.history.receipts(outcome="deny")[0]
print(refusal.describe())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
let refusal = project.history().receipts().outcome("deny").first().await?;
println!("{}", refusal.describe());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
The receipt names the request, the verdict and its reason, the grant it was checked against, and the policy in force. Your kernel's signature covers every field.
Read more in Receipts.
6. Keep what works
The fork holds exactly what the fixer changed. Read the diff and apply it.
console.log(await fork.diff());
await project.apply(fork.changes);src/pricing.py
@@ def discount(price, percent):
+ if not 0 <= percent <= 100:
+ raise ValueError("percent must be between 0 and 100")
return price * (1 - percent / 100)
applied main 7c2e1d0 → 8d4b2e7print(fork.diff())
project.apply(fork.changes)src/pricing.py
@@ def discount(price, percent):
+ if not 0 <= percent <= 100:
+ raise ValueError("percent must be between 0 and 100")
return price * (1 - percent / 100)
applied main 7c2e1d0 → 8d4b2e7println!("{}", fork.diff().await?);
project.apply(fork.changes()).await?;src/pricing.py
@@ def discount(price, percent):
+ if not 0 <= percent <= 100:
+ raise ValueError("percent must be between 0 and 100")
return price * (1 - percent / 100)
applied main 7c2e1d0 → 8d4b2e7Apply publishes only if main still matches the fork's base; if it moved, you get a conflict and nothing changes.
7. Add a rule no grant can override
A grant says what an agent may touch. Policy narrows every grant, and no grant widens policy. Make the tests read-only, then hand the fixer the next issue.
// Tests are evidence: no agent may edit them, whatever its grant allows.
await project.policy.add({
name: "tests-are-evidence",
deny: { write: "/workspace/tests/**" },
});
const next = await project.fork();
const run2 = await fixer.run("fix issue #413", {
on: next,
authority: authority.reissue({ on: next }),
});
for await (const event of run2.events()) console.log(event.summary);
await project.apply(next.changes);00:00 admitted fixer runs "fix issue #413" on fork 7d2e914 00:18 write /workspace/src/pricing.py 00:24 test pytest -k issue_413: failed 00:31 refused write /workspace/tests/test_pricing.py: rule tests-are-evidence 00:52 write /workspace/src/pricing.py 01:04 test pytest -k issue_413: passed applied main 8d4b2e7 → 2f60a91
# Tests are evidence: no agent may edit them, whatever its grant allows.
project.policy.add(name="tests-are-evidence", deny={"write": "/workspace/tests/**"})
next_fork = project.fork()
run2 = fixer.run(
"fix issue #413", on=next_fork, authority=authority.reissue(on=next_fork)
)
for event in run2.events():
print(event.summary)
project.apply(next_fork.changes)00:00 admitted fixer runs "fix issue #413" on fork 7d2e914 00:18 write /workspace/src/pricing.py 00:24 test pytest -k issue_413: failed 00:31 refused write /workspace/tests/test_pricing.py: rule tests-are-evidence 00:52 write /workspace/src/pricing.py 01:04 test pytest -k issue_413: passed applied main 8d4b2e7 → 2f60a91
// Tests are evidence: no agent may edit them, whatever its grant allows.
let rule = Rule::new("tests-are-evidence").deny_write("/workspace/tests/**");
project.policy().add(rule).await?;
let next = project.fork().await?;
let task = fixer.run("fix issue #413").on(&next).authority(authority.reissue(&next)?);
let mut run2 = task.start().await?;
let mut events = run2.events();
while let Some(event) = events.next().await {
println!("{}", event?.summary());
}
project.apply(next.changes()).await?;00:00 admitted fixer runs "fix issue #413" on fork 7d2e914 00:18 write /workspace/src/pricing.py 00:24 test pytest -k issue_413: failed 00:31 refused write /workspace/tests/test_pricing.py: rule tests-are-evidence 00:52 write /workspace/src/pricing.py 01:04 test pytest -k issue_413: passed applied main 8d4b2e7 → 2f60a91
The fixer's first patch failed a test, so it tried to change the test. The rule refused that write, and the fixer changed the code instead.
Read more in Guards.
Next: serve other agents
Your agents now work under authority you set. Part 2 opens the same project to agents you do not run.