Chio/Docs
LOGIN · JOIN

Work With Their Agents

Let your agents work with theirs, under terms both kernels enforce.

Guide chio@5f63e6e

On this page

Each side keeps its own kernel, keys, and policy. A treaty sets what crosses between them, and both kernels admit and sign every crossing.

Their agents fix the next bug in your project while your agents review the work. You pair the two kernels, agree on terms, merge the fix with both signatures, verify the history offline, and end the arrangement with one call.

Start
Three rings of reachPart 3 of 3
123aawsyour agentsworkspacesecretsrefusedSccyour serviceagents you do not runa′a′K′treatytheir kerneltheir agentsK123aawsScca′a′K′treatytheir kernelK
  1. Govern your agentsYour agents, your resources, your kernel.
  2. Serve other agentsAgents you do not run call your service.
  3. Work with their agentsAnother operator's kernel, under a treaty.

1. Pair your kernel with theirs

A partner sends you its partner card: the operator identity and kernel key you verify its work against. chio partner demo runs a partner on this machine, with its own kernel, keys, policy, and agents, and writes its card. Add it over iroh, and the kernels connect directly over authenticated QUIC. Use the project and identity from part 1.

Terminalbash
chio partner demo --out partner-card.json
chio partner add partner-card.json --name partner --transport iroh
Output
partner    did:chio:z6MkpA7…c2T, named partner
kernel     9b07…d31c, pinned from its card
transport  iroh, endpoint 3fa8…91be, authenticated at handshake
lanes      signals · revocation · co-sign
partners.tspartners.pysrc/main.rs · in main
import { Computer, USD } from "@chio-protocol/sdk";

const project = await Computer.open("quickstart");
const partner = await Computer.connect("partner");

Read more in Iroh transport.

2. Agree on what crosses

The treaty names the actions the two operators cooperate on and what each requires. Each kernel computes the intersection of both governance ladders on its own, so the stricter requirement wins.

partners.tspartners.pysrc/main.rs · in main
const treaty = await project.treaty({
  partner: partner,
  actions: ["workspace.read", "workspace.write", "model.invoke", "merge"],
  expiresIn: "7d",
});
console.log(treaty.describe());
Output
treaty           trt-01aa…4c19, signed by both kernels
participants     you · partner (did:chio:z6MkpA7…c2T)
action           you       them      admitted as
workspace.read   allow     allow     either kernel admits under its own policy
workspace.write  allow     allow     either kernel admits under its own policy
model.invoke     allow     allow     charged at your door
merge            co-sign   co-sign   both kernels sign
expires          in 7 days

Every action is admitted by the kernel that serves it, under that kernel's own policy. merge needs both signatures. Only the two kernels are joined across the boundary; everything else crosses through them.

Two operatorsInspect what crosses.
Your operatorTheir operatortreaty τ · grant κCProjectKYour kernelr₁r₂Your agentsK′Their kernela₁a₂a₃Their agentsρYour operatorTheir operatortreaty τ · grant κCProjectKYour kernelr₁r₂Your agentsK′Their kernela₁a₂a₃Their agentsρ

Both kernels sign the same terms

The treaty names the actions the two operators cooperate on and what each action requires. Each kernel pins its own governance ladder and computes the intersection itself, so the stricter requirement wins. Your grant then gives their agents a slice of one fork, a budget pool, and limits on how far they delegate. Treaties.

3. Give their agents a slice

Fork the project and grant their agents part of the fork under the treaty: the workspace, your model route, and five dollars they all share.

partners.tspartners.pysrc/main.rs · in main
const fork = await project.fork();
const authority = fork.grant({
  to: partner,
  under: treaty,
  resources: { "/workspace": ["read", "write"], "/models/default": ["invoke"] },
  delegation: { depth: 2, fanout: 4 },
  budget: USD(5),   // one pool for all of their agents
  expiresIn: "30m",
});
console.log(authority.describe());
Output
grant      cap-01a9…7e40, under trt-01aa…4c19
to         partner, delegating up to 2 deep and 4 wide
on         quickstart, fork c4e81b7 of main 2f60a91
allows     /workspace         read, write
           /models/default    invoke
budget     USD 5.00 pool shared by all of their agents, charged at your door
expires    in 30 minutes

Each agent they add holds less than the agent that delegated to it. Model calls reach your route through your kernel, which holds the pool and refuses the call that would overdraw it.

4. Work together

Start two reviewers on your side and send the task. Their agents post candidates to the shared reviews mailbox; your reviewers claim them and answer.

partners.tspartners.pysrc/main.rs · in main
// Your side: two reviewers claim candidates from a shared mailbox.
const reviews = await project.mailbox("reviews", { partner: partner, treaty });
const reviewers = await project.agents("review", { count: 2, reads: reviews });

// Their side: their agents work the issue in your fork.
const run = await partner.exec("fix issue #414", {
  on: fork,
  authority,
  reportTo: reviews,
});

for await (const event of run.events({ include: reviewers })) console.log(event.summary);
await run.joinTree();
Output
00:00  them  admitted   "fix issue #414" under trt-01aa…4c19
00:01  them  delegate   coordinator → fixer-1, fixer-2, tester, each narrower
00:06  them  signal     tester deposits flaky: tests/test_pricing.py::test_issue_414
00:06  you   signal     admitted over iroh, weight 0.62 after decay
00:31  them  refused    fixer-2 read /secrets/.env: outside the grant, at your door
00:58  them  mailbox    fixer-1 sends candidate a41c9e2 to reviews
01:00  you   mailbox    reviewer-1 claims a41c9e2, checks test_issue_414 first
01:19  you   mailbox    reviewer-1 requests a change: round half up, not half even
01:44  them  mailbox    fixer-1 sends candidate 5b93d10
01:46  you   approve    reviewer-2 approves 5b93d10, pytest 14 passed
01:47  them  sealed     fork c4e81b7 → 5b93d10
spent  USD 3.12 of 5.00 across 4 of their agents

A signal from their tester tells your reviewer which test to read first; it ranks work and grants nothing. Fixer-2's read of /secrets/.env stops at your kernel, before a byte leaves your machine.

Read more in Signals between agents.

5. Merge with both signatures

The sealed fork carries exactly what their agents changed. Apply it under the treaty.

partners.tspartners.pysrc/main.rs · in main
console.log(await fork.diff());
const merged = await project.apply(fork.changes, { treaty });
console.log(merged.receipt.describe());
Output
src/pricing.py
@@ def quote(sku, percent):
-    return round(discount(prices[sku], percent), 2)
+    amount = Decimal(str(discount(prices[sku], percent)))
+    return float(amount.quantize(Decimal("0.01"), ROUND_HALF_UP))

merge      main 2f60a91 → 5b93d10
receipt    rcpt-01ab…f2d0, co-signed by your kernel and theirs

Apply publishes only if main still matches the fork's base. The receipt is evidence for both operators: you accepted this change, and they delivered it.

6. Check every decision

Export the run and verify it with the two pinned kernel keys and nothing else.

partners.tspartners.pysrc/main.rs · in main
const evidence = await project.history.export("audit/");
console.log(await evidence.verify());
Output
treaty     trt-01aa…4c19, ladders intersect as signed
receipts   61 signed decisions from 2 kernels
lineage    your grant → their coordinator → 3 agents, narrower at every step
signals    1 deposit admitted, advisory only
mailbox    4 messages, each sent and claimed under its own grant
refusals   1: fixer-2 read /secrets/.env
spend      USD 3.12 of the 5.00 pool
merge      co-signed; main 5b93d10 matches the approved candidate
verified   offline, against both pinned kernel keys
Terminal · the same check from the CLIbash
chio evidence verify --input audit --partner partner
Output
verified   61 receipts from 2 kernels, offline

--partner requires the partner's co-signature on every joint receipt and checks it against the receipt signer chio partner add pinned, so a package missing either side fails. Verification needs no access to either operator's systems, so an auditor outside both can run it.

7. Revoke, and the work stops

Start their agents on a new task, then revoke the treaty while they work.

partners.tspartners.pysrc/main.rs · in main
const next = await project.fork();
const run2 = await partner.exec("add banker's rounding as an option", {
  on: next,
  authority: authority.reissue({ on: next }),   // same terms, new fork
});

await treaty.revoke();
for await (const event of run2.events()) console.log(event.summary);
Output
00:00  them  admitted   "add banker's rounding as an option" under trt-01aa…4c19
00:04  you   revoked    trt-01aa…4c19, revocation root sent over iroh
00:05  them  refused    fixer-1 write /workspace/src/pricing.py: treaty revoked
00:05  them  stopped    their work closed, no effects after revocation

The revocation crosses to their kernel over iroh, and their next call is refused. Every grant issued under the treaty ends with it, including the ones their agents delegated to each other.

Read more in Revocation checkpoints.

Build on it