std.utcp – Native Tool Calling
std.utcp – Native Tool Calling
Section titled “std.utcp – Native Tool Calling”SPEC-244 (RATIFIED 2026-07-21). Native Janus Universal Tool Calling Protocol: in-process registry + sessions, SBI-only wire, length-prefixed TCP peer.
For transport doctrine and interop modes (HTTP / JSON-line), see UTCP over SBI. SBI preamble doctrine: SBI.
Modules
Section titled “Modules”| Module | Role |
|---|---|
std.utcp.registry | Register tools and required capabilities |
std.utcp.session | Present caps and invoke |
std.utcp.wire | Pack / validate SBI frames; fingerprint; one-shot TCP loopback |
std.utcp.peer | Persistent peer: multi-invoke, STAGE/CHNK, LRES/MANL accessors |
std.utcp.protocol | Status codes and wire kind constants |
Profile: :core (JPEN-as-tool demos need :cluster to pack envelopes).
Doctrine
Section titled “Doctrine”- Every tool invoke is capability-checked. No silent bypass.
- Native wire serialization is SBI (
SBI\0+ LE payload). - TCP carries
u32LE length + SBI frame. - Connection-scoped sessions support multi-invoke until RESET or EOF.
- JSON-line and HTTP manuals are interop, not the normative path.
Status codes
Section titled “Status codes”| Name | Value |
|---|---|
| OK | 1 |
| FAIL | 0 |
| ERR_CAP_MISMATCH | -1403 |
| ERR_JPEN_APPLY | -1404 |
| ERR_LEASE | -1405 |
Wire kinds
Section titled “Wire kinds”| Kind | Value |
|---|---|
| INVOKE_REQ | 1 |
| INVOKE_RES | 2 |
| PRESENT | 3 |
| RESET | 4 |
| STAGE | 5 |
STAGE: max 1024 bytes per frame; optional CHNK reassembly up to 16 KiB. INVOKE_RES may carry LRES (lease result) or MANL (binary manual) bodies.
Schema fingerprint: BLAKE3-128 domain-separated KDF – see UTCP over SBI.
Quick start (in-process)
Section titled “Quick start (in-process)”{.profile: core.}
use std.utcp.registry as registryuse std.utcp.session as session
_ = registry.reset()let compile_id = registry.register_compile_module_demo()let s = session.open()_ = session.present_known(s, 0) // fs.read:/workspace_ = session.present_known(s, 1) // fs.write:/workspace/zig-out// session.invoke(s, compile_id) → OK or CAP_MISMATCHPeer (SBI over TCP)
Section titled “Peer (SBI over TCP)”use std.utcp.peer as peer
let port = peer.listen(0)_ = peer.start_accept_pool(2, 2)let h = peer.client_connect(port)_ = peer.client_present2(h, 0, 1)_ = peer.client_invoke(h, tool_id)_ = peer.client_close(h)_ = peer.join()_ = peer.close_listen()Discovery: register / bootstrap utcp.manual, invoke with no caps, read
MANL via client_last_has_manl / client_manual_*.
Leases: STAGE a LEAS payload (client_stage_lease or chunked), present
lease caps, invoke register/heartbeat – LRES fields on the client.
JPEN-as-tool: STAGE a pipeline envelope, present
cluster.pipeline:apply:local, invoke pipeline.envelope.apply.
Known intern indices (v1)
Section titled “Known intern indices (v1)”Tools
| Idx | Name |
|---|---|
| 0 | janus.compile_module |
| 1 | janus.version |
| 2 | pipeline.envelope.apply |
| 3 | registry.lease.register |
| 4 | registry.lease.heartbeat |
| 5 | registry.state |
| 6 | utcp.manual |
Caps
| Idx | Token |
|---|---|
| 0 | fs.read:/workspace |
| 1 | fs.write:/workspace/zig-out |
| 2 | cluster.pipeline:apply:local |
| 3 | registry.lease.register:local |
| 4 | registry.lease.heartbeat:local |
| 5 | registry.state:local |
Proof smokes
Section titled “Proof smokes”./scripts/zb test-utcp-local-registry./scripts/zb test-utcp-sbi-wire./scripts/zb test-utcp-tcp-loopback./scripts/zb test-utcp-peer-session./scripts/zb test-utcp-peer-pool./scripts/zb test-utcp-jpen-tool./scripts/zb test-utcp-lease-response./scripts/zb test-utcp-manual-sbi./scripts/zb test-utcp-stage-chunk./scripts/zb test-janusd-sbi-dogfoodInterop and legacy
Section titled “Interop and legacy”- janusd default: SBI + HTTP dual-stack.
--json: line-delimited JSON INTEROP.- Zig
std/utcp_registry.zigremains the janusd lease registry backend for SBI LEAS hooks.
Details: UTCP over SBI.