Direct Artifact Surface
The extension boundary has two nouns: guest and sidecar. An application registers either one directly. A third identity above them would duplicate their id, version, lifecycle, declarations, dependencies, and installation state without adding an execution boundary.
Invariants
Section titled “Invariants”- The installed unit is one executable or one Wasm component.
- Identity is
id + artifact semver; routes and capabilities are not independently versioned. - Static declaration inspection executes no artifact code.
- Dependencies name an artifact id and semver range, never a route.
- Recovery never depends on artifact presence or execution.
- Sidecar transport belongs to
harmos-sidecar; guest WIT belongs toharmos-guestbecause their execution models differ.
Why Routes Remain
Section titled “Why Routes Remain”A sidecar route is the named serialization boundary between two processes. A job is runtime-owned finite work over Rust values. Making a job pretend to be a remote method would merge scheduling, retries, serialization, remote refusal, and transport identity into one concept. Routes stay narrow and jobs stay local.
Static Metadata
Section titled “Static Metadata”Procedural macros emit bounded, NUL-terminated declaration fragments with a fixed Harmos prefix. The final linker output therefore carries metadata next to the implementation that authored it. Inspectors collect fragments, validate ids and semver, reject duplicates, and construct one declaration.
This prevents discovery from requiring execution. It does not make arbitrary native code trustworthy: authenticity and integrity remain installation concerns. Nothing admits or refuses a declared edge today — a declared edge is taken — and whatever eventually does belongs at the one dispatch slot rather than spread across the declaration surface.
Transport
Section titled “Transport”Sidecars use one bidirectional streaming gRPC exchange over stdio. JSON carries
typed configuration and generic registrations; protobuf defines the stable
envelope, batches, routes, and stream rows. Prost derives those payload messages on their Rust types, avoiding
author-written .proto files while keeping framing, multiplexing, limits, and
batching efficient and evolvable.
Guests use the Component Model WIT boundary. Sharing a transport crate would erase the useful distinction between process IO and Wasm imports/exports, so the two protocols remain in their owning crates.
Dependency Planning
Section titled “Dependency Planning”The planner builds a directed graph whose edge points from a dependency to its dependant, validates semantic-version requirements, rejects cycles, and returns a topological order. Planning is pure and happens over inspected declarations, so a missing sidecar required by a guest is a load error rather than an initialization-time surprise.