Skip to content

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.


ModuleRole
std.utcp.registryRegister tools and required capabilities
std.utcp.sessionPresent caps and invoke
std.utcp.wirePack / validate SBI frames; fingerprint; one-shot TCP loopback
std.utcp.peerPersistent peer: multi-invoke, STAGE/CHNK, LRES/MANL accessors
std.utcp.protocolStatus codes and wire kind constants

Profile: :core (JPEN-as-tool demos need :cluster to pack envelopes).


  1. Every tool invoke is capability-checked. No silent bypass.
  2. Native wire serialization is SBI (SBI\0 + LE payload).
  3. TCP carries u32 LE length + SBI frame.
  4. Connection-scoped sessions support multi-invoke until RESET or EOF.
  5. JSON-line and HTTP manuals are interop, not the normative path.

NameValue
OK1
FAIL0
ERR_CAP_MISMATCH-1403
ERR_JPEN_APPLY-1404
ERR_LEASE-1405

KindValue
INVOKE_REQ1
INVOKE_RES2
PRESENT3
RESET4
STAGE5

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.


{.profile: core.}
use std.utcp.registry as registry
use 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_MISMATCH

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.


Tools

IdxName
0janus.compile_module
1janus.version
2pipeline.envelope.apply
3registry.lease.register
4registry.lease.heartbeat
5registry.state
6utcp.manual

Caps

IdxToken
0fs.read:/workspace
1fs.write:/workspace/zig-out
2cluster.pipeline:apply:local
3registry.lease.register:local
4registry.lease.heartbeat:local
5registry.state:local

Terminal window
./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-dogfood

  • janusd default: SBI + HTTP dual-stack.
  • --json: line-delimited JSON INTEROP.
  • Zig std/utcp_registry.zig remains the janusd lease registry backend for SBI LEAS hooks.

Details: UTCP over SBI.