Pipecircuit CLI
Create and run a workspace with a portable core and a routing-only switchboard:
The finite example activates a core machine, reports its outcome, and exits via
pipecircuit.conduct(). core/src owns primitives, machines and pipe contracts;
core/switchboards owns routing; src owns physical assembly. Both semantic crates
are no_std and every package shares strict Rust/Clippy lints. Architecture and
behavior snapshots are derived from the actual source and compiled tests.
For a matching unpublished checkout:
Without this option, the template uses the exact registry version pinned in
src/new.rs. --name overrides the destination's package name. Existing destinations
are refused. Generation uses embedded assets and performs no network requests,
Cargo execution or Git initialization. On I/O failure it retains the partial new
directory for inspection.
Choose the existing Mio host instead of the portable startup reactor:
This uses the same core and named pipe roster, with a one-slot SPSC exchange and real Mio wake. It is a finite, single-threaded example: one local request, one reply, then exit. The generated application chooses bindings, queue bounds, submission policy and completion; the framework supplies polling and dispatch. Output errors preserve the confirmed reply. No worker thread or socket is created.
These variants are starting examples, not production service templates. Long-running
intake needs admission and lifecycle policy. With --framework-path, native mode
also uses libraries/mio from that checkout. Separate physical executables may
later live under apps/, sharing portable cores.
Run the same semantic program in a dedicated browser worker:
Requires Node, Rust's wasm32-unknown-unknown target, and the wasm-bindgen CLI
matching the generated manifest's exact version. npm run dev builds the Rust
worker before starting Vite, then automatically rebuilds on Rust/Cargo edits.
Edits during compilation coalesce into one follow-up build. A failed build keeps
the previous worker running; a successful build reloads the page with fresh state. npm run build creates static output in
web/dist; npm run preview serves that output locally.
web/src/main.ts page: events and presentation
⇅ generated codec / bounded transferable messages
src/lib.rs worker: installed Rust program
⇅
core/switchboards same routes as portable/native
⇅
core/src same authoritative Latch
The page has one pending request slot; no polling or retry loop. Disconnect closes
pending work, while initialization failures surface as unavailable confirmation.
A hung worker remains pending until explicit close; there is no automatic timeout
or retry. Reload starts a fresh worker. web/vite.config.mjs installs rustWorker from
pipecircuit/vite, using web/worker.config.mjs for both dev and manual generation.
It also rejects generated worker/WASM modules in production page chunks. This is
a build guard for that boundary, not a sandbox
against arbitrary application JavaScript.
The explicit request/reply fitting requires one immediate worker reply. It is not
a general streaming browser host. flow_to_worker_reply conducts the unchanged
switchboard; the worker export and generated codecs enforce the actual pipe types.
The small generator uses the plain pipe API because a unit command does not need
an artificial command/reply enum wrapper. Core serialization/binding derives are
optional; generation runs on the host. JavaScript owns DOM and browser bootstrap,
not domain state. Buffers transfer between realms; WASM boundary copies and codec
allocations remain—this is not an end-to-end zero-copy claim.
Run npm test after npm run build and installing Chromium with
npx playwright install chromium. It exercises real WASM workers in development
and production builds, repeat requests, capacity rejection, transferable buffer
detachment, pending shutdown, and initialization failure. Commit the generated
project's npm/Cargo lockfiles after installation. With --framework-path, the
browser variant uses the checkout's browser crate and binding generator; its npm
transport remains pinned to the published package.
The starter uses generate_worker_pipe::<ActivationWorker>() from
pipecircuit-browser 0.0.9. The framework derives the binding inventory and worker
entry from that export; the page connects through generated startWorker.
tools/check-browser-scaffold checks real development and production workers;
--registry verifies the published dependencies without checkout paths. The
check also edits a disposable starter to verify compile-error recovery and live
Rust rebuilds; it never edits a consumer application. See the browser tooling
contract
for generated-directory ownership, extra watch inputs and interrupted-build recovery.
One behavior, three placements
Start with the behavior: a user asks to activate something, and repeated requests
must tell them it was already active. Latch is only this starter's example owner,
not a framework type. The core owns these steps:
inactive + Activate → Activated, now active
active + Activate → AlreadyActive, still active
The Client pipe sends Activate out and accepts Activation in, from the
client's perspective. Activator exposes the opposite direction. The switchboard
routes the two closed families:
match from
The application chooses the placement:
| Variant | External trigger and reply | Authority placement | Who drives it? |
|---|---|---|---|
| Portable | One startup request; stdout reply | Inline in the executable | Startup reactor and pipecircuit.conduct() |
| Native | One-slot queues; local peer prints reply | Inline in the same native thread | Mio wake and hosted pipecircuit.conduct() |
| Browser | Button request; rendered reply | Inline inside a dedicated Rust/WASM worker | Browser message event; flow_to_worker_reply conducts the synchronous route |
Browser main thread Worker thread
button → generated pipe ══ ArrayBuffer ══▶ decode → switchboard → Latch
status ← generated pipe ◀═ ArrayBuffer ═══ encode ← switchboard ← outcome
The worker retains the machine between messages. The page does not remember whether activation happened; it renders the authority's reply. Moving between variants leaves the core steps and switchboard route unchanged. The application still chooses capacities, completion/shutdown and response presentation. Browser serialization and worker boot are representation/placement work, not new domain behavior.
Render other formats from the same source: