> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scomp.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> What's new in scomp — protocol, SDK, and runtime updates.

Product updates for the scomp protocol, Rust SDK, and embedded sandbox runtime.

## Week of May 18, 2026

A huge week. The TypeScript SDK is here, spec v0.2 brings first-class cancellation and timeouts, and two rounds of fuzzing closed dozens of bugs across both SDKs.

### New features

**TypeScript SDK.** The full scomp SDK now ships for TypeScript and Node.js — `@scomp/core`, `@scomp/sdk`, `@scomp/transport-ws`, and `@scomp/runtime-qjs`. Feature parity with the Rust SDK: WebSocket transport, QuickJS runtime, symmetric peer model, function references, and the same wire format. Use it anywhere you'd reach for Node.

**Cancellation and timeouts (spec v0.2).** Long-running evals and invokes can now be cancelled mid-flight. The protocol gained a `$/cancel` notification (§3.6.2), capabilities advertisement at handshake time, and two new error codes — `TimeoutError` (-32011) and `CancelledError` (-32012). QuickJS is wired through to actually interrupt on cancel, not just stop awaiting. See [Wire format](/protocol/wire-format).

**Per-call options with cascading defaults.** Set timeouts and other options per call, per session, or globally. Rust gets `EvalRequest` / `InvokeRequest` builders via `IntoFuture`; TypeScript takes `Partial<EvalOptions>` / `Partial<InvokeOptions>`. Six timeout knobs in total: dial, handshake, and idle on the transport; eval, invoke, and reverse-invoke on the session.

**`server.*` namespace.** Server-provided bindings now live under a `server.*` namespace, matching the symmetric peer model where clients can declare bindings too. Dual-mode for backwards compatibility — old call sites keep working.

**TypeScript DX overhaul.** A four-phase DX pass landed for TS:

* `binding<A,R>()` — typed binding builder with full inference.
* `@scomp/transformer` — TypeScript transformer that lifts plain functions into bindings with schemas derived from their signatures.
* `ScompFunction<A,R>` — typed function-reference helper, with a clear diagnostic when you forget to mark a raw function.
* `scomp init` — new CLI scaffolds a working TS project in one command.

**`scomp init` CLI.** New scaffolder generates a TypeScript scomp project with sensible defaults — transport, runtime, and a sample binding wired up. See the TS quickstart.

**Session lifecycle hardening.** New `Drop` / `dispose()` semantics release session leases deterministically, a default 256 MB memory cap protects QuickJS runtimes, and `RuntimeScope.deactivate()` was renamed to `unsafeDeactivate()` to make the isolation-bypass risk explicit.

### Updates

**Capabilities handshake.** The handshake now carries a `capabilities` slot so peers can advertise what they support (starting with `cancel`). Forward-compatible — unknown capabilities are ignored.

**Richer error metadata.** Eval and invoke errors now carry structured metadata (taxonomy, hints, original error context) instead of stringified blobs. Cross-binding rejections are collapsed to a clean `EvalError` shape with the original details preserved in metadata.

**Stricter handshake validation.** JSON-RPC handshake validation reached parity across both SDKs — bad payloads are rejected at the door with explicit errors instead of leaking through.

**LLM-friendly error messages.** QuickJS runtime errors continue to use LLM-readable descriptions, now with consistent error codes across Rust and TypeScript.

**Outbound payload size cap.** WebSocket sends are bounded to prevent runaway payloads from taking down a peer.

**Typed handshake rejection.** `WsInput::Dial` carries an explicit `session_id` field with a structured rejection path for unsupported values.

### Bug fixes

The fuzz-2 and fuzz-3 sweeps closed dozens of issues across both SDKs:

* Fixed observer exceptions being able to kill a session — `WireObserver` errors are now isolated.
* Fixed a deadlock in WebSocket close: tracked connections are now closed before `wss.close()`.
* Fixed function-reference identity loss when `invokeByRef` returned a function at the top level (Rust QuickJS runtime).
* Fixed `QuickJsRuntime.dispose()` to be terminal — pending operations are rejected before the runtime is freed.
* Fixed `TransportError` to thread the underlying cause instead of dropping it.
* Fixed accept-loop corruption after a per-connection transport failure.
* Fixed `activate()` to preserve server bindings instead of clobbering them.
* Fixed handler panics taking down the dispatcher — `catch_unwind` now wraps handler dispatch and returns `InternalError`.
* Fixed capability input schemas to require `properties` on object types.
* Fixed empty `eval` strings being accepted; they're now rejected with a clear error.
* Fixed `Set`, `Map`, `Symbol`, and `NaN` slipping into binding-argument serialization — all now rejected.
* Fixed the `bind!` macro to produce a targeted error on bad destructuring instead of a wall of compiler noise.
* Fixed a session-slot leak on send error (RAII lease guard).
* Fixed several panic error codes to match the spec.
* Fixed stdio transport EOF handling.
* Fixed `BindScompFns` to reject enums with a clear error.

## Week of May 11, 2026

Two major redesigns landed this week: an API idiomacy pass that reshaped the SDK surface, and a developer-experience pass that overhauls how you declare and call bindings.

### New features

**Ergonomic binding macros.** Define a binding with a single attribute or a `bind!` macro — no more hand-rolling handler structs. The `#[binding]` attribute turns any function into a binding, picks up its `///` doc comment as the description, supports an `effects = [...]` annotation, and emits a unit struct so you can pass `server.bind(add)` without parens. The same binding gains a `.call(...)` inherent method for use from Rust. The `bind!` macro (formerly `bind_fn!`) covers the closure form, with both sync and async arms. See [Runtimes and bindings](/concepts#runtimes-and-bindings).

**Client-declared bindings.** Clients can now declare their own bindings that the server can invoke — bringing the protocol's symmetric peer model fully to the SDK. The server can call back into the client over the same connection.

**Session resumption.** Reconnect to an existing session after a transport drop without losing state. The server keeps your session, replays what it owes, and resumes from where you left off.

**Client-side binding introspection.** Clients can now query the server's declared bindings (`client_bindings`) to discover what's available before invoking — useful for agents that want to inspect a runtime's capabilities at connection time.

**Native `client.invoke`.** Clients can call server bindings directly with a typed `invoke` method, no more hand-building eval strings. Matches the spec's §8.3 invoke shape.

**Builder-style construction with sensible defaults.** Spin up a server with WebSocket + QuickJS preconfigured — `ScompServer::builder()` gives you a working setup in a few lines. Runtime and transport are now feature-gated, so you only pay for what you use.

**Binding hints field.** Bindings can now advertise hints — `kind`, `latency`, and an open key/value map — so agents can make better decisions about when and how to call them. Defined in spec §7.1.1. See [Wire format](/protocol/wire-format).

### Updates

**Typestate client API.** `ScompClient` now splits into `ScompClient` (unconnected) and `ConnectedClient` (connected), so you can't accidentally call connection-only methods on a disconnected client. The compiler catches misuse at build time.

**Unified binding registry.** Client and server now share a single binding registry and a single inbound-invoke parser. Strict validation on both sides, no more divergent code paths.

**`Peer<R>` typestate.** The peer type is now generic over its runtime, making custom runtimes a first-class extension point.

**Idiomatic SDK surface.** Renamed and tightened several public types for consistency: `ServerBindingHandler` → `BindingHandler`, `WireObserver` trait replaces the `set_on_send` / `set_on_recv` pair, and the prelude now re-exports `bind` and `binding` for one-line imports.

**Slimmer dependencies.** `scomp_core` no longer depends on `tokio` or `thiserror`, and `scomp` drops `thiserror` entirely — smaller compile times, fewer transitive deps.

**Better error reporting.** QuickJS runtime errors now use LLM-readable messages, with cross-connection function references properly scoped. Error codes are aligned with the spec.

**JS eval ergonomics.** The runtime now accepts bare object literals and zero-argument binding calls (`add()` instead of `add({})`) — matching what an agent naturally writes.

### Bug fixes

* Fixed non-deterministic compliance failures caused by a close-handshake race.
* Function-reference lifecycle now uses proper refcounting; references with shared lifetime no longer leak.
* `BindScompFns` derive now rejects enums with a clear error instead of producing broken code.
* `default_bindings::help` is sync (it always was — the signature now matches).
* The scomp-agent extends chat history across turns instead of replacing it.
* QuickJS console binding registration fixed; rebind no longer leaves stale handlers.
