Chio/Docs

ReferenceSDKsnew

JVM SDK

The world.chio core communicates with the chio sidecar; the Spring Boot starter applies fail-closed request filtering.

Package layout

chio-sdk-jvm carries no Spring or streaming dependencies and can be consumed from any JDK 17+ service. The Spring Boot starter (chio-spring-boot) and the Flink connector (chio-streaming-flink) both build on it. Every public type is byte-compatible with the Python SDK wherever the protocol pins a wire shape.

Installation

Add the core, the Spring Boot starter, or both. Gradle Kotlin DSL:

build.gradle.kts
dependencies {
    implementation("world.chio:chio-sdk-jvm:0.1.0")
    implementation("world.chio:chio-spring-boot:0.1.0")
}

Maven:

pom.xml
<dependency>
  <groupId>world.chio</groupId>
  <artifactId>chio-spring-boot</artifactId>
  <version>0.1.0</version>
</dependency>

The core requires Java 17 or newer; the starter requires Spring Boot 3.2 or newer. Both talk to a running chio sidecar, which defaults to http://127.0.0.1:9090.

ChioClient

world.chio.sdk.ChioClient is the blocking HTTP client. It implements AutoCloseable for use-resource parity with the async Python client, and takes a base URL plus a java.time.Duration timeout that defaults to five seconds.

MethodEndpointReturns
evaluateHttpRequestPOST /chio/evaluateEvaluateResponse
verifyHttpReceiptPOST /chio/verifyVerifyReceiptResponse
evaluateToolCallAdvisoryPOST /v1/evaluate/advisoryChioReceipt
verifyReceiptPOST /v1/receipts/verifyBoolean
health / isHealthyGET /chio/healthMap / Boolean

HTTP request evaluation is the API the Spring Boot filter uses. evaluateHttpRequest posts a ChioHttpRequest and returns the kernel verdict plus the signed receipt. A capability token, if present, rides in the X-Chio-Capability header.

kotlin
import world.chio.sdk.CallerIdentity
import world.chio.sdk.ChioClient
import world.chio.sdk.ChioHttpRequest

val client = ChioClient("http://127.0.0.1:9090")

val response = client.evaluateHttpRequest(
    ChioHttpRequest(
        requestId = "req-1",
        method = "GET",
        routePattern = "/pets",
        path = "/pets",
        caller = CallerIdentity.anonymous(),
        timestamp = System.currentTimeMillis() / 1000,
    ),
)

Any allow-shaped response is integrity-checked before it is handed back: the embedded receipt must be a mediated authorization, and verifyHttpReceipt must confirm the signature. A non-authorizing allow raises ChioError with code chio_invalid_receipt rather than letting a forged allow through.

Advisory tool-call evaluation

evaluateToolCallAdvisory posts to /v1/evaluate/advisory, verifies the advisory receipt's integrity, and returns it. The response is wrapped in the chio.sidecar.advisory-evaluation.v1 envelope, which sets authorization: false and authorizationBasis: "advisory_only".

kotlin
val advisory = client.evaluateToolCallAdvisory(
    capabilityId = "cap-fraud",
    toolServer = "flink://fraud-job",
    toolName = "events:consume:transactions",
    parameters = mapOf("body_length" to 42L, "body_hash" to "..."),
)
println("advisory receipt: " + advisory.id)

evaluateToolCall fails closed

evaluateToolCall returns only for an authoritative mediated authorization receipt. Against the current advisory-only sidecar route it always throws ChioDeniedError after integrity-checking the advisory receipt. Treat a returned value as authorization; treat the exception as the expected non-authorization signal.

Client-side chain verification

verifyReceiptChain walks a Merkle chain of receipts with zero network round-trips. Each receipt's contentHash must equal the SHA-256 of the canonical JSON of its predecessor. Hashes are byte-identical to the Python and Rust references.

kotlin
val chained: Boolean = client.verifyReceiptChain(receipts)

Canonical JSON

CanonicalJson is the Jackson-backed canonicalizer that every receipt hash flows through. It matches Python's json.dumps(sort_keys=True, separators=(",", ":"), ensure_ascii=True) byte-for-byte: map keys and object properties sorted in code-point order, no insignificant whitespace, non-ASCII escaped as lowercase \uXXXX, and null map values preserved rather than dropped.

kotlin
import world.chio.sdk.CanonicalJson

val bytes: ByteArray = CanonicalJson.writeBytes(mapOf("b" to 2, "a" to 1))
val text: String = CanonicalJson.writeString(mapOf("b" to 2, "a" to 1))
// text == {"a":1,"b":2}

Bytes over strings when hashing

Prefer writeBytes when the consumer hashes the output. world.chio.sdk.Hashing.sha256Hex accepts either a String or a ByteArray and emits lowercase hex.

Receipt Types

The receipt object graph lives in world.chio.sdk. Every type carries Jackson bindings to the snake_case wire names, implements java.io.Serializable (so it can cross Flink operator boundaries), and mirrors the Rust chio-http-core crate.

TypeRole
ChioHttpRequestRequest posted to /chio/evaluate.
CallerIdentity / AuthMethodExtracted caller and how it authenticated (bearer, api_key, cookie, anonymous).
VerdictKernel HTTP verdict: allow / deny plus reason, guard, http_status.
HttpReceiptSigned receipt for an HTTP evaluation.
EvaluateResponseverdict + receipt + evidence.
VerifyReceiptResponseStructured authority result from /chio/verify.
ChioReceiptSigned tool-call receipt (action, decision, evidence).
Decision / ToolCallActionTool-call verdict and the hashed action parameters.
GuardEvidencePer-guard evaluation evidence.

Authorization predicates are baked into the types, not left to callers. HttpReceipt.isAuthorized() requires receiptKind == "mediated_decision", boundaryClass == "prevent", trustLevel == "mediated", a null observationOutcome, and an allow verdict. See the Receipt Format for the full field set.

Spring Boot Starter

chio-spring-boot auto-configures a servlet filter as soon as it is on the classpath. The starter registers ChioAutoConfiguration through Spring Boot's auto-configuration mechanism; a minimal application needs no extra wiring.

DemoApplication.kt
@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
}

@RestController
class PetsController {
    @GetMapping("/pets")
    fun pets(): Map<String, Any> = mapOf("pets" to emptyList<Any>())
}

The filter is fail-closed. If the sidecar is unreachable the request is denied with a 502 and a structured JSON body. Denied evaluations return the verdict's HTTP status (defaulting to 403). Allowed requests flow through the chain only after the receipt is semantically checked and its signature verified, and carry an X-Chio-Receipt-Id response header pointing at the signed receipt.

Configuration

Configure the filter under the chio prefix in application.yaml:

application.yaml
chio:
  sidecar-url: http://127.0.0.1:9090
  timeout-seconds: 5
  on-sidecar-error: deny   # reserved: the filter always denies sidecar errors
  enabled: true
  url-patterns:
    - "/*"
  filter-order: 1
KeyDefaultPurpose
sidecar-urlCHIO_SIDECAR_URL env, else http://127.0.0.1:9090Base URL of the sidecar kernel.
timeout-seconds5HTTP timeout for sidecar calls.
on-sidecar-errordenyReserved. The filter fails closed on sidecar errors regardless.
enabledtrueToggle the auto-configured filter.
url-patterns["/*"]Servlet URL patterns the filter guards.
filter-order1Filter order; lower runs first.

For header-driven caller lookup and pattern-based routing, supply a ChioFilterConfig with custom identityExtractor and routeResolver functions. The default extractor reads, in order, an Authorization: Bearer token, an X-API-Key header, the first cookie, then falls back to an anonymous identity. The default resolver returns the raw path.

kotlin
import world.chio.ChioFilterConfig

val config = ChioFilterConfig(
    sidecarUrl = "http://127.0.0.1:9090",
    routeResolver = { _, path ->
        if (path.startsWith("/pets/")) "/pets/{petId}" else path
    },
)

A capability token is read from the X-Chio-Capability header or the chio_capability query parameter. A complete example is at examples/hello-spring-boot in the chio repository.

Streaming Primitives

The core carries the envelope builders that chio-streaming-flink emits to Kafka. Each pins a schema version and a fixed header set, and each is byte-identical to its Python counterpart.

  • ReceiptEnvelope. The receipt side-output envelope, version chio-streaming/v1, with X-Chio-Receipt and X-Chio-Verdict headers.
  • DlqRouter. Builds the dead-letter record, version chio-streaming/dlq/v1. Rejects non-deny receipts with ChioValidationError; routes on an exact topic map with a default fallback.
  • SyntheticDenyReceipt. Stamps a deny receipt carrying the chio-streaming/synthetic-deny/v1 marker when the sidecar is unreachable in fail-closed mode. Its reason is prefixed [unsigned] and kernelKey / signature are empty.

Errors

Errors live in world.chio.sdk.errors and all extend ChioError, which carries a stable code string.

  • ChioError — base SDK exception (message, code, cause).
  • ChioDeniedError — structured deny with guard, reason, receipt id, hint, and the rest of the deny payload; fromWire / toWire round-trip the Python shape.
  • ChioConnectionError, ChioTimeoutError — transport failures.
  • ChioValidationError, ChioStreamingError — envelope and streaming invariants.
kotlin
import world.chio.sdk.errors.ChioDeniedError

try {
    client.evaluateToolCall(
        capabilityId = "cap-fraud",
        toolServer = "flink://fraud-job",
        toolName = "events:consume:transactions",
        parameters = mapOf("body_length" to 42L),
    )
} catch (error: ChioDeniedError) {
    println("not authorized: " + error.message)
}

The stable error codes — chio_access_denied, chio_sidecar_unreachable, chio_evaluation_failed, chio_invalid_receipt, chio_timeout — are the same strings the sidecar returns in its error body and match the Schemas & Errors taxonomy.

Parity

Canonical JSON, synthetic-deny, and DLQ builders each carry a parity test tag and assert byte-equality against hand-computed Python vectors. The wire formats track the chio 0.1.x sidecar contract; see the Bindings API for the cross-language invariants every SDK conforms against.