| .. | ||
| catalog | ||
| sidecar | ||
| config-snippet.ncl | ||
| README.md | ||
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.
Files
| File | Purpose |
|---|---|
catalog/send_email_notification.ncl |
Catalog declaration with kind = 'Sidecar |
sidecar/Cargo.toml |
Standalone Cargo manifest (own workspace) |
sidecar/src/main.rs |
Minimal axum server on :7902 — validates inputs, mock-dispatches email, returns DispatchResponse-shaped JSON |
config-snippet.ncl |
ops.sidecar_url = "http://127.0.0.1:7902" snippet for .ontoref/config.ncl |
How to run
-
Build and start the sidecar (standalone — not part of ontoref's workspace):
cd examples/catalog-extension/02-sidecar/sidecar cargo runYou should see:
INFO addr=127.0.0.1:7902 example-mail-sidecar listening -
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 } } -
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=<your-project>' \ -H "Authorization: Bearer $ONTOREF_TOKEN" \ -d '{"recipient":"jpl@jesusperez.pro","subject":"hi","body":"hello","template":"plain"}'The daemon looks up
sidecar_urlfor the project, proxies the request tohttp://127.0.0.1:7902/ops/send_email_notification, signs the response envelope as the witness, returns theDispatchResponseto the caller.
Key properties
evaluate_ondaodis mandatory inconstraints.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-runtimeaxiom (invariant=true).
When NOT to use
- The op is part of the ontoref piloto self-host → use
Path A
'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.