Small process orchestration for host/child IPC workflows in Rust.
pork helps you start child processes, establish a bootstrap handshake, exchange raw IPC messages, and shut children down gracefully using a shared control protocol. The workspace also includes pork-proto, a companion crate that provides the shared control-plane protocol types and codec implementations.
Use pork when you want to:
- supervise one or more child processes,
- connect parent and child over IPC without building the handshake yourself,
- send application-defined payloads between host and child,
- and keep framework-level shutdown behavior consistent.
This repository uses a workspace-first layout:
- repository root — shared workspace files, Nix development setup, and top-level documentation
pork/— mainporklibrary cratepork-proto/— shared protocol crateexamples/pork-comms/— small host/child example showing typed message exchange
This keeps the workspace root focused on coordination while each crate owns its own manifest, source tree, and tests.
pork— high-level orchestration API for starting, tracking, messaging, restarting, and stopping managed child processes through explicit modules such asorchestrator,spec,child, anderror.pork-proto— shared protocol definitions inprotocolplus feature-gated codec implementations incodecs.
A typical setup has two sides:
- A host process creates a
pork::orchestrator::ProcessOrchestratorand starts a child from apork::spec::ProcessSpec. - A child process reads bootstrap information from the environment and connects back to the host with
pork::child::bootstrap. - Both sides exchange raw
Vec<u8>payloads throughpork. - Shared control messages, typed IPC envelopes, and codec selection live in
pork_proto::protocol.
If you only need process orchestration and raw byte transport, depend on pork.
If you want typed IPC payloads and the shared codec helpers, depend on both pork and pork-proto.
For the actual API, examples, and behavior details, use the crate documentation:
porkcrate docs: seepork/src/lib.rspork::orchestratorfor host-side process managementpork::specfor child process configurationpork::child::bootstrapfor child-side bootstrap helpers
pork-protocrate docs: seepork-proto/src/lib.rspork_proto::protocolfor protocol models, shared control messages, and typed IPC envelopespork_proto::codecsforJsonCodecandPostcardCodec
If you are browsing locally, the crate-level docs are the best starting point because they include the intended usage flow and focused examples for the namespaced API.
You need:
- Rust toolchain (this workspace targets Rust
1.85) - Cargo
- Unix-like local IPC support for the current process model
- Optional: Nix with flakes enabled if you want the provided development shell
Using Nix (recommended for reproducible developer shells):
nix develop -c cargo build --workspace
nix develop -c cargo test --workspace --all-targets
nix develop -c cargo test --workspace --all-features --all-targetsWithout Nix (plain Cargo):
cargo build --workspace
cargo test --workspace --all-targets
cargo test --workspace --all-features --all-targetsIf you prefer an interactive shell, enter it first and then run the same Cargo commands inside that shell:
nix develop
cargo test --workspace --all-features --all-targetsA typical workflow has three parts:
- define how the child process should be started with
pork::spec::ProcessSpec - start and manage the child from
pork::orchestrator::ProcessOrchestrator - connect from the child side with
pork::child::bootstrap::child_connect_from_env
For a complete typed example, see examples/pork-comms/.
Host side sketch:
use pork::orchestrator::ProcessOrchestrator;
use pork::spec::ProcessSpec;
async fn run_host() -> Result<(), pork::error::OrchestratorError> {
let orchestrator = ProcessOrchestrator::new();
let child = orchestrator
.start_process(
ProcessSpec::new("./child-binary")
.managed_name("worker")
.capture_output(),
)
.await?;
child.send(b"ping".to_vec())?;
let _status = orchestrator.graceful_shutdown_process(child.id()).await?;
Ok(())
}Child side sketch:
use pork::child::bootstrap::child_connect_from_env;
use pork::DEFAULT_BOOTSTRAP_ENV;
async fn run_child() -> Result<(), pork::error::OrchestratorError> {
let (from_host, to_host) = child_connect_from_env(DEFAULT_BOOTSTRAP_ENV).await?;
let _ = (from_host, to_host);
Ok(())
}Run these checks before making a release or merging large changes. These match what CI enforces.
Formatting and lints
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warningsTests and docs
cargo test --workspace
cargo test --workspace --doc
cargo test --workspace --all-features --all-targetsSecurity & license checks
# install tools if you don't have them already
cargo install --locked cargo-audit cargo-deny
# run the checks
cargo audit
cargo deny checkMSRV (verify compilation on minimum supported Rust)
rustup toolchain install 1.85.0
rustup run 1.85.0 cargo check --workspaceNix-based validation
nix flake checkThis repository uses cargo-audit and cargo-deny to enforce advisories and license policies in CI. The cargo-deny configuration lives at deny.toml (root of the pork/ workspace). CI runs cargo audit and cargo deny check as part of the security job; run the same commands locally before releasing.
The deny.toml file also contains any temporary advisory suppressions that have been reviewed and accepted with a plan to remediate (for example, a transitive unmaintained crate that currently has no safe upgrade path). Treat suppressions as temporary and track follow-up work to remove them.
The examples/pork-comms/ crate demonstrates a small end-to-end setup with:
- a host binary
- a child binary
- typed messages encoded with
pork-proto - coverage for both JSON and Postcard codec flows
Use that example when you want a concrete reference before integrating pork into your own application.
Note: example crates are publish = false in their Cargo.toml to avoid accidental publishing.
This workspace is prepared for the 1.0.0 release line: the main orchestration API lives in the pork crate, while shared protocol details live in pork-proto.
Before publishing, ensure CI is green and perform these validation steps locally (see the Validate locally section above). Publishing tips:
- Identify which workspace crates are intended for crates.io (libraries) and which are examples or tools (set those to
publish = false). - Crates that depend on
path = "..."dependencies must be published in topological order. Typical sequence:- Publish the low-level crate (e.g.
pork-proto) first:cargo publish -p pork-proto(use--dry-runto validate). - Update dependent crates to use the published version instead of
path = ...and bump their versions. - Publish the dependent crate (e.g.
pork).
- Publish the low-level crate (e.g.
Recommended pre-publish commands (examples)
# dry-run packaging and publish for pork-proto
cargo package --manifest-path pork-proto/Cargo.toml
cargo publish --dry-run -p pork-proto
# publish pork-proto, then update dependent manifests and publish pork
cargo publish -p pork-proto
# update pork/Cargo.toml to depend on the published pork-proto version (remove path dep)
cargo package --manifest-path pork/Cargo.toml
cargo publish --dry-run -p pork
cargo publish -p pork
# tag and create a GitHub release
git tag -a vX.Y.Z -m "Release vX.Y.Z"
git push origin vX.Y.Z
# (optional, using GitHub CLI)
gh release create vX.Y.Z --notes-file CHANGELOG.mdCI is defined in .github/workflows/ci.yml and runs the following gates on PRs and pushes to release branches:
- formatting (
cargo fmt --check) - clippy (
cargo clippy) - unit tests (
cargo test) - documentation tests (
cargo test --doc) - MSRV compile check (Rust 1.85)
- security and license checks (
cargo audit,cargo deny check) nix flake check
- See
pork/src/lib.rsandpork-proto/src/lib.rsfor crate-level documentation and examples. - Look at
.github/workflows/ci.ymlfor the exact CI jobs and expected checks.
If you want, I can also add a RELEASE.md that codifies the publishing sequence and the exact git commands to use during a release.