Multi-Party Security
Choose the controls that hold when authority is shared with your own agents, a partner organization, or another hosted tenant.
On this page
Authority reaches past one agent in three ways: to your own agents in a delegated family, to a partner organization's agents, and to other tenants of a hosted service. Each relationship draws its trust from a different place and keeps its own enforcing owner.
Agents in one delegated family hold narrowed grants under a common root. A partner brings its own keys, kernel, and admission policy. Tenants share infrastructure while keeping separate data, jobs, and limits. A sibling's grant authenticates no independent operator, and a treaty is no substitute for tenant row isolation.
Authority crosses a boundary in three shapes
Start from the owner that can accept the requested effect, then name the relationship that gives it a reason to trust the authority presented.
For a family, the question is how each child's grant derives from the parent and which limits stay shared. For a partner, it is which agreement the receiving kernel accepts under its own policy. For hosted tenants, it is how the service keeps partitions apart while it schedules shared resources. An authenticated partner never becomes a local administrator, and a sibling's signed grant never spends another tenant's capacity.
Your own agents share one family and one allowance
Delegation attenuates at every hop. A graph's SwarmBudgetPool checks allocated units against its total ceiling, and the kernel separately enforces the family-wide invocation ceiling at admission. The CLI swarm host requires the root and every worker to carry the same aggregate invocation budget and sizes the pool from its max_invocations, so both ceilings apply.
Sender attribution belongs to the host. chio process serve records the kernel-selected sender of every mailbox message, while an embedded host without attestation records sends with no sender. Swarm budgets covers the pool accounting.
Read more in Secure a swarm and Mailbox attestation.
A partner keeps its own keys, and your kernel admits its calls
An embedded runtime admission hook checks the treaty scope and the precomputed ladder intersection against verifier-owned records, the presented digests, and the current validity windows. Federated grants carry a DPoP proof at your door, and co-signed actions need both kernels' signatures. The CLI swarm host installs the hook without treaty records and refuses every treaty reference.
An offline treaty report helps operators inspect an agreement, and it installs no runtime authority. Cross-organization work adds an independently governed kernel; it never inherits your trust root. Treaties and admission covers composing and inspecting the agreement.
Read more in Cross-org admission, which follows the runtime and offline paths.
Tenants share a hosted service and keep separate rows and limits
One hosted configuration revision binds each tenant's concurrent-job, queue-depth, and monthly-spend ceilings. Authenticated tenant context and forced row-level security scope every query, so a shared identifier selects only that tenant's rows.
Guest workers have no network interface. The host-side release canary dials out under a typed HTTPS egress contract with redirects forbidden and a response-size limit, and a refused endpoint stops the canary. The hosted market modules are optional and off in default builds.
Read more in Hosted tenancy for profile validation, Hosted cognition for provisioning, and Market boundary for release and relocation contracts.
The fixer and the reviewer share a mailbox under different grants
The fixer sends its fix for issue #417, fix-417, to the reviewer. They share one durable host and the jobs mailbox, but the fixer can only send while the reviewer can receive and acknowledge, and nothing in the reviewer's receipt or payload grants the fixer another tool. A separate tester route checks that a shared queue keeps sender identities apart.
kernel:
max_capability_ttl: 3600
delegation_depth_limit: 1
durable_admission_mode: all
capabilities:
default:
tools:
- server: chio-ipc
tool: '*'
operations: [invoke, delegate]
ttl: 3600This is the durable-admission policy from the containment guide. Initialize a fresh host with chio process init --config host-config.json --state ./state, issue each declared process its own connection, and serve it as in Secure an agent and the process quickstart. The Python client is chio-process; an existing application can supply its already configured host and clients.
The process-host configuration: fixer, reviewer, and an alternate sender
{
"schema": "chio.process.host.v1",
"policy": "policy.yaml",
"mailboxes": [
{
"id": "jobs"
}
],
"limits": {
"max_processes": 4,
"max_depth": 1,
"max_calls": 40
},
"children": [
{
"id": "fixer",
"parent": "root",
"budget_share_bps": 3000,
"tools": [
{
"server_id": "chio-ipc",
"tool_name": "send_jobs"
}
]
},
{
"id": "tester",
"parent": "root",
"budget_share_bps": 3000,
"tools": [
{
"server_id": "chio-ipc",
"tool_name": "send_jobs"
}
]
},
{
"id": "reviewer",
"parent": "root",
"budget_share_bps": 3000,
"tools": [
{
"server_id": "chio-ipc",
"tool_name": "receive_jobs"
},
{
"server_id": "chio-ipc",
"tool_name": "ack_jobs"
}
]
}
]
}Withdrawing the fixer stops new work and keeps the handoff
Ending a relationship changes which new work is admitted. A delivered message, a provider attempt, and an already signed record stay as they were, and recovery belongs to the owner of the existing operation. Pass the owner-issued fixer and reviewer clients to this function with mailbox_attribution.py beside it and a new, private evidence path.
"""Withdraw new work while preserving an original writer/reviewer handoff."""
from pathlib import Path
from chio_process import ProcessClient, WorkerError
from mailbox_attribution import completed, invoke_recorded, save
import json
def withdraw_writer(writer: ProcessClient, reviewer: ProcessClient, evidence: Path):
evidence.mkdir(mode=0o700)
if writer.inspect()["process_id"] != "fixer" or reviewer.inspect()["process_id"] != "reviewer":
raise ValueError("Wrong independently supplied process pair")
original = invoke_recorded(writer, evidence, "handoff", "fix-417/send/v1", "send_jobs",
{"message_key": "fix-417", "payload": {"fix": "fix-417"}})
sequence = completed(original)["sequence"]
cancelled = writer.cancel()
save(evidence / "cancellation.json", json.dumps(cancelled) + "\n")
if cancelled["cancelled_processes"] != 1 or writer.inspect()["state"] != "cancelled":
raise RuntimeError("Writer withdrawal did not persist")
try:
invoke_recorded(writer, evidence, "new-work", "fix-418/send/v1", "send_jobs",
{"message_key": "fix-418", "payload": {"fix": "fix-418"}})
except WorkerError as error:
if error.code != "cancelled":
raise # A transport failure would not establish withdrawal.
else:
raise RuntimeError("Cancelled writer admitted new work")
visible = invoke_recorded(reviewer, evidence, "retained", "fix-417/receive/v1",
"receive_jobs", {"after_sequence": str(int(sequence) - 1), "limit": 10})
messages = completed(visible)["messages"]
if len(messages) != 1 or messages[0]["sequence"] != sequence or messages[0]["sender"] != "fixer":
raise RuntimeError("Withdrawal erased original handoff or permitted new work")
if (evidence / "handoff.receipts.jsonl").read_text() != original["receipt_json"] + "\n":
raise RuntimeError("Original receipt changed")
print("WITHDRAW fixer: new operation returns cancelled before a per-call receipt")
print("RETAIN original fixer message and receipt; reviewer can still inspect the handoff")
return originalWITHDRAW fixer: new operation returns cancelled before a per-call receipt RETAIN original fixer message and receipt; reviewer can still inspect the handoff
You should see the cancelled fixer refused with cancelled before any per-call receipt, because cancellation is an early process-host refusal. The original handoff receipt stays byte for byte, and the independently admitted reviewer still observes the original sender and sequence. A transport failure would leave the attempt unresolved, so the function accepts only the cancelled code. Download the complete source.
The comparison runs on a local native host and exercises authority and retained state. Confining the caller is the host's job, and an effect already performed stays with the owner that performed it.
Each boundary trusts an input that another owner keeps
Before sharing work, name the boundary the other party crosses and the independently owned input that boundary relies on.
| Relationship | Independently owned input | Page |
|---|---|---|
Sibling process | The host-issued child grant and original task binding | |
Mailbox producer | The kernel-selected caller and the first key, payload, and sender record | |
Another organization | Reviewed treaty, peer pins, ladder commitment, and verified artifacts | |
Hosted tenant | Authenticated tenant context, durable limits, and forced RLS | |
Market counterparty | The original signed transition and the selected egress contract |
Another task's continuation cannot authorize a sibling, and another sender cannot replace a committed message. Offline treaty acceptance installs no runtime authority, a shared identifier selects only the tenant's own rows, and a valid market record authorizes no other endpoint. Agent Processes, Federation, and Economy document how each boundary runs day to day, and each Security page in the table states what the other party is refused.
Where each boundary is enforced in source
- Swarm admission.
crates/kernel/chio-swarm-authority/src/verifier.rs - Swarm budget pool.
crates/kernel/chio-swarm-authority/src/verifier/budget_accounting.rs - Family invocation ceiling.
crates/kernel/chio-kernel/src/kernel/admission_coordinator.rs - Mailbox sender.
crates/kernel/chio-process/src/mailboxes/mod.rs - Cross-boundary admission.
crates/kernel/chio-runtime-core/src/treaty.rs, called fromcrates/kernel/chio-runtime-core/src/admission_hook/treaty_evidence.rs - Tenant limits.
crates/platform/chio-finding-market-store-postgres/src/tenant.rs - Jailed worker with no guest network.
crates/platform/chio-finding-worker/src/executor.rs - Host-side egress.
crates/protocol/chio-egress-contract/src/pricing.py