# Path B — `kind = 'Sidecar` (ADR-030 mechanism #6) Phase A — implementable today. The main ontoref daemon proxies dispatch over HTTP to a per-project sidecar process. Each sidecar can ship its own deploy cadence and signing key while sharing a Rust library with sibling instances. Canonical use case: shared-domain (`provisioning`) + Level-3 instances (`libre-daoshi`, `libre-wuji`, `libre-forge`) — see [`reflection/qa.ncl::ontoref-catalog-discovery-shared-domain`](../../.ontoref/reflection/qa.ncl). ## Files | File | Purpose | | --- | --- | | [`catalog/send_email_notification.ncl`](catalog/send_email_notification.ncl) | Catalog declaration with `kind = 'Sidecar` | | [`sidecar/Cargo.toml`](sidecar/Cargo.toml) | Standalone Cargo manifest (own workspace) | | [`sidecar/src/main.rs`](sidecar/src/main.rs) | Minimal axum server on `:7902` — validates inputs, mock-dispatches email, returns `DispatchResponse`-shaped JSON | | [`config-snippet.ncl`](config-snippet.ncl) | `ops.sidecar_url = "http://127.0.0.1:7902"` snippet for `.ontoref/config.ncl` | ## How to run 1. Build and start the sidecar (standalone — not part of ontoref's workspace): cd examples/catalog-extension/02-sidecar/sidecar cargo run You should see: INFO addr=127.0.0.1:7902 example-mail-sidecar listening 2. Test the sidecar directly (bypass the main daemon proxy): curl -s -X POST http://127.0.0.1:7902/ops/send_email_notification \ -H 'Content-Type: application/json' \ -d '{"inputs":{"recipient":"jpl@jesusperez.pro","subject":"hi","body":"hello","template":"plain"}}' \ | jq . Expected response (message_id varies): { "status": "queued", "message_id": "msg-19a3c8...-jpl", "payload": { "recipient": "jpl@jesusperez.pro", "subject": "hi", "template": "plain", "bytes": 5 } } 3. To dispatch via the main daemon (once the Phase A proxy handler lands in `crates/ontoref-daemon/src/api.rs`): curl -X POST 'http://127.0.0.1:7891/ops/send_email_notification?project=' \ -H "Authorization: Bearer $ONTOREF_TOKEN" \ -d '{"recipient":"jpl@jesusperez.pro","subject":"hi","body":"hello","template":"plain"}' The daemon looks up `sidecar_url` for the project, proxies the request to `http://127.0.0.1:7902/ops/send_email_notification`, signs the response envelope as the witness, returns the `DispatchResponse` to the caller. ## Key properties - **`evaluate_ondaod` is mandatory in `constraints.pre`** — ADR-034 Hard constraint. The host runtime invokes ondaod-discipline before proxying to the sidecar; the sidecar itself cannot satisfy it. - **Witness honesty** — `payload_kind = "sidecar_response_envelope"`. The daemon's signature attests it faithfully forwarded the sidecar's reported effect; it does NOT claim to attest the sidecar's internal computation (HTTP boundary is opaque). - **Per-instance signing key** — each instance's sidecar can be configured with its own actor id; the cryptographic blast radius stays per-instance. - **No wasmtime dependency** — Sidecar runtime is HTTP + axum + tokio in the sidecar process; the main daemon adds only a ~80-LOC reqwest-based proxy handler. Honours `protocol-not-runtime` axiom (invariant=true). ## When NOT to use - The op is part of the ontoref piloto self-host → use [Path A `'Rust`](../01-rust/) (zero IPC overhead, full type safety). - You need cross-instance op dispatch with witness chaining → ADR-030 T3 trigger, leans toward Phase B WASM. - You need to author the op in a non-Rust language → Path B works (sidecar can be any language as long as it speaks the HTTP contract) but consider whether toolchain divergence justifies a Phase B spike per ADR-030 T4. ## References - [ADR-030 mechanism #6 — SidecarProcessWithSharedDomainLibrary](../../../.ontoref/adrs/adr-030-catalog-discovery-cross-project.ncl) - [`reflection/qa.ncl::ontoref-catalog-discovery-shared-domain`](../../../.ontoref/reflection/qa.ncl) - [ADR-018 — Delegate / Override / Compose semantics](../../../.ontoref/adrs/adr-018-level-hierarchy-mode-resolution-strategy.ncl)