diff --git a/.config/hakari.toml b/.config/hakari.toml
new file mode 100644
index 00000000..d1a8f5f5
--- /dev/null
+++ b/.config/hakari.toml
@@ -0,0 +1,30 @@
+# This file contains settings for `cargo hakari`.
+# See https://docs.rs/cargo-hakari/latest/cargo_hakari/config for a full list of options.
+
+hakari-package = "homestar-workspace-hack"
+
+# Format version for hakari's output. Version 4 requires cargo-hakari 0.9.22 or above.
+dep-format-version = "4"
+
+workspace-hack-line-style = "workspace-dotted"
+
+# Setting workspace.resolver = "2" in the root Cargo.toml is HIGHLY recommended.
+# Hakari works much better with the new feature resolver.
+# For more about the new feature resolver, see:
+# https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#cargos-new-feature-resolver
+resolver = "2"
+
+# Add triples corresponding to platforms commonly used by developers here.
+# https://doc.rust-lang.org/rustc/platform-support.html
+platforms = [
+  "wasm32-unknown-unknown",
+  "wasm32-wasi",
+  "x86_64-apple-darwin",
+  "aarch64-apple-darwin",
+  "x86_64-unknown-linux-gnu",
+  "x86_64-unknown-linux-musl",
+  "aarch64-unknown-linux-musl",
+]
+
+# Write out exact versions rather than a semver range. (Defaults to false.)
+# exact-versions = true
diff --git a/.dockerignore b/.dockerignore
index 558b181a..c15b9e4d 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,3 +1,4 @@
+
 *
 
 !**/Cargo.toml
@@ -10,5 +11,6 @@
 !diesel.toml
 !**/wit
 
-homestar-functions/src
-homestar-functions/**/wit
+examples
+homestar-functions
+homestar-workspace-hack
diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml
index 6fea695a..583e76a7 100644
--- a/.github/workflows/builds.yml
+++ b/.github/workflows/builds.yml
@@ -25,7 +25,7 @@ jobs:
   binary-builds:
     if: >
       startsWith(github.event.release.name, 'homestar-runtime') ||
-      (github.event_name == 'workflow_dispatch' && github.event.inputs.force-publish)
+      (github.event_name == 'workflow_dispatch' && github.event.inputs.force-builds)
     strategy:
       fail-fast: false
       matrix:
@@ -100,7 +100,7 @@ jobs:
           include: LICENSE,README.md
           token: ${{ secrets.GITHUB_TOKEN }}
 
-  npm-publish:
+  npm-publish-arch:
     needs: binary-builds
     runs-on: ubuntu-latest
     strategy:
@@ -133,7 +133,7 @@ jobs:
         with:
           node-version: lts/*
           registry-url: "https://registry.npmjs.org"
-      - name: Install cargo get
+      - name: Install cargo-get
         run: cargo install cargo-get
       - name: Prepare os/arch packages
         shell: bash
@@ -146,22 +146,25 @@ jobs:
           echo "node_pkg=${node_pkg}" >> "$GITHUB_ENV"
           cd homestar-runtime/npm
           mkdir -p "${node_pkg}/bin"
-          envsubst < package.json.tmpl > "${node_pkg}/package.json"
+          envsubst < package-json-arch.tmpl > "${node_pkg}/package.json"
       - name: Download build artifacts
         uses: actions/download-artifact@v4
         with:
           name: ${{ matrix.target }}
           path: "homestar-runtime/npm/${{ env.node_pkg }}/bin"
-      - name: Publish production
+      - name: Publish arch packages to production
         if: github.event_name == 'release' && github.event.action == 'published'
         run: |
+          cp homestar-runtime/README.md "homestar-runtime/npm/${{ env.node_pkg }}"
           cd "homestar-runtime/npm/${{ env.node_pkg }}"
+          chmod +x bin/${{ matrix.bin }}
           npm publish --access=public
         env:
           NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
-      - name: Publish RC
+      - name: Publish arch packages RC
         if: github.event_name == 'workflow_dispatch'
         run: |
+          cp homestar-runtime/README.md "homestar-runtime/npm/${{ env.node_pkg }}"
           cd "homestar-runtime/npm/${{ env.node_pkg }}"
           chmod +x bin/${{ matrix.bin }}
           npm version $(cargo get package.version)-rc.$(date +%s) --git-tag-version false
@@ -169,6 +172,40 @@ jobs:
         env:
           NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
 
+  npm-publish-main:
+    needs: npm-publish-arch
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-node@v4
+        with:
+          node-version: lts/*
+          registry-url: "https://registry.npmjs.org"
+      - name: Install cargo get
+        run: cargo install cargo-get
+      - name: Publish main package to production
+        if: github.event_name == 'release' && github.event.action == 'published'
+        run: |
+          export node_version=$(cargo get workspace.package.version)
+          cp homestar-runtime/README.md homestar-runtime/npm/base
+          cd homestar-runtime/npm
+          envsubst < package-json-base.tmpl > "base/package.json"
+          cd base
+          npm publish --access=public
+        env:
+          NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
+      - name: Publish main package RC
+        if: (github.event_name == 'workflow_dispatch' && github.event.inputs.force-builds)
+        run: |
+          export node_version="$(cargo get workspace.package.version)-rc.$(date +%s)"
+          cp homestar-runtime/README.md homestar-runtime/npm/base
+          cd homestar-runtime/npm
+          envsubst < package-json-baserc.tmpl > "base/package.json"
+          cd base
+          npm publish --access public --tag rc
+        env:
+          NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
+
   build-packages:
     needs: binary-builds
     runs-on: ubuntu-latest
@@ -238,7 +275,7 @@ jobs:
   docker-build:
     if: >
       startsWith(github.event.release.name, 'homestar-runtime') ||
-      (github.event_name == 'workflow_dispatch' && github.event.inputs.force-publish)
+      (github.event_name == 'workflow_dispatch' && github.event.inputs.force-builds)
     runs-on: ubuntu-latest
     env:
       DOCKER_BUILDKIT: "1"
@@ -265,10 +302,14 @@ jobs:
           sudo apt-get clean
           sudo rm -rf /usr/share/dotnet
 
-      - name: Get Current Version
-        if: (github.event_name == 'workflow_dispatch' && github.event.inputs.force-publish)
+      - name: Install cargo-get
+        if: (github.event_name == 'workflow_dispatch' && github.event.inputs.force-builds)
+        run: cargo install cargo-get
+
+      - name: Set Current Version
+        if: (github.event_name == 'workflow_dispatch' && github.event.inputs.force-builds)
         id: crate-version
-        run: echo version=$(cargo metadata --format-version=1 --no-deps | jq -r '.packages[] | select(.name == "homestar-runtime") | .version') >> $GITHUB_OUTPUT
+        run: echo version=$(cargo get workspace.package.version)-rc.$(date +%s) >> $GITHUB_OUTPUT
 
       - name: Login to GitHub Container Registry
         uses: docker/login-action@v3
@@ -296,7 +337,7 @@ jobs:
             type=sha
 
       - name: Metadata
-        if: (github.event_name == 'workflow_dispatch' && github.event.inputs.force-publish)
+        if: (github.event_name == 'workflow_dispatch' && github.event.inputs.force-builds)
         id: meta-dispatch
         uses: docker/metadata-action@v5
         with:
@@ -320,7 +361,7 @@ jobs:
           labels: ${{ steps.meta-release.outputs.labels }}
 
       - name: Docker Build & Push
-        if: (github.event_name == 'workflow_dispatch' && github.event.inputs.force-publish)
+        if: (github.event_name == 'workflow_dispatch' && github.event.inputs.force-builds)
         uses: docker/build-push-action@v5
         with:
           cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml
index 95ce147c..e53eb95a 100644
--- a/.github/workflows/nix.yml
+++ b/.github/workflows/nix.yml
@@ -33,8 +33,6 @@ jobs:
     needs: changes
     if: ${{ needs.changes.outputs.nix == 'true' }}
     runs-on: ubuntu-latest
-    strategy:
-      fail-fast: false
     steps:
       - name: Checkout Repository
         uses: actions/checkout@v4
@@ -51,8 +49,11 @@ jobs:
           ignore-missing-flake-lock: false
           fail-mode: true
 
-      - name: Nix Build
+      - name: Nix Develop Check
         run: |
           nix develop --show-trace -c irust --version
           nix develop --show-trace -c rustc --version
-          nix build . && ./result/bin/homestar --version
+
+      - name: Nix Homestar Build
+        if: ${{ github.event_name == 'push' }}
+        run: nix build . && ./result/bin/homestar --version
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 41468e38..03660945 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -9,9 +9,9 @@ on:
         description: Publish Releases at Anytime
 
   workflow_run:
-    workflows: [ 🧪 Tests and Checks ]
+    workflows: [🧪 Tests and Checks]
     branches: [main]
-    types: [ completed ]
+    types: [completed]
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
diff --git a/.github/workflows/tests_and_checks.yml b/.github/workflows/tests_and_checks.yml
index 3db5c0d9..51c9c5b6 100644
--- a/.github/workflows/tests_and_checks.yml
+++ b/.github/workflows/tests_and_checks.yml
@@ -2,10 +2,10 @@ name: 🧪 Tests and Checks
 
 on:
   push:
-    branches: [ main ]
+    branches: [main]
 
   pull_request:
-    branches: [ '**' ]
+    branches: ["**"]
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
@@ -48,8 +48,8 @@ jobs:
     needs: changes
     if: ${{ needs.changes.outputs.rust == 'true' || needs.changes.outputs.examples == 'true' }}
     env:
-        SCCACHE_GHA_ENABLED: "true"
-        RUSTC_WRAPPER: "sccache"
+      SCCACHE_GHA_ENABLED: "true"
+      RUSTC_WRAPPER: "sccache"
     strategy:
       fail-fast: false
       matrix:
@@ -90,12 +90,19 @@ jobs:
       - name: Run Linter
         run: cargo clippy --all -- -D warnings
 
-      # TODO: Return upon new version.
-      # - name: Verify Publishing of crates
-      #   uses: katyo/publish-crates@v2
-      #   if: ${{ matrix.rust-toolchain == 'stable' }}
-      #   with:
-      #     dry-run: true
+      - name: Install cargo-hakari
+        if: ${{ matrix.rust-toolchain == 'stable' }}
+        uses: taiki-e/install-action@v2
+        with:
+          tool: cargo-hakari
+
+      - name: Check workspace-hack Cargo.toml is up-to-date
+        if: ${{ matrix.rust-toolchain == 'stable' }}
+        run: cargo hakari generate --diff
+
+      - name: Check Crates Depend on workspace-hack
+        if: ${{ matrix.rust-toolchain == 'stable' }}
+        run: cargo hakari manage-deps --dry-run
 
       # Only "test" release build on push event.
       - name: Test Release
@@ -140,8 +147,8 @@ jobs:
     needs: changes
     if: ${{ needs.changes.outputs.rust == 'true' }}
     env:
-        SCCACHE_GHA_ENABLED: "true"
-        RUSTC_WRAPPER: "sccache"
+      SCCACHE_GHA_ENABLED: "true"
+      RUSTC_WRAPPER: "sccache"
     strategy:
       fail-fast: false
       matrix:
@@ -283,8 +290,8 @@ jobs:
     needs: changes
     if: ${{ needs.changes.outputs.rust == 'true' }}
     env:
-        SCCACHE_GHA_ENABLED: "true"
-        RUSTC_WRAPPER: "sccache"
+      SCCACHE_GHA_ENABLED: "true"
+      RUSTC_WRAPPER: "sccache"
     runs-on: ubuntu-latest
     steps:
       - name: Checkout Repository
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 4fc161e5..e7310957 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -35,9 +35,16 @@ repos:
         args: ["--workspace", "--document-private-items"]
         types: [rust]
         pass_filenames: false
+      - id: cargo-hakari
+        name: workspace-hack
+        description: Ensure workspace-hack works correctly
+        entry: bash -c 'cargo hakari generate --diff && cargo hakari manage-deps --dry-run && cargo hakari verify'
+        language: rust
+        files: Cargo\.(toml|lock)
+        pass_filenames: false
 
   - repo: https://github.com/kamadorueda/alejandra
-    rev: bb7f2ad3f176aa8e9e2944a10061f7989c8fef17  # frozen: 1.3.0
+    rev: bb7f2ad3f176aa8e9e2944a10061f7989c8fef17 # frozen: 1.3.0
     hooks:
       - id: alejandra
         files: \.nix$
@@ -55,6 +62,7 @@ repos:
         args: ["fmt"]
         types:
           - toml
+        exclude: homestar-workspace-hack/Cargo.toml
 
   - repo: https://github.com/compilerla/conventional-pre-commit
     rev: v2.1.1
@@ -75,7 +83,7 @@ repos:
       - id: check-yaml
       - id: check-json
       - id: check-added-large-files
-        args: ['--maxkb=4000']
+        args: ["--maxkb=4000"]
       - id: detect-private-key
         exclude: __testkey
       - id: check-executables-have-shebangs
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 40f1cd2f..b02c3412 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -5,7 +5,7 @@
 In the interest of fostering an open, inclusive, and welcoming environment, all
 members, contributors, and maintainers interacting within our online community
 (including Discord, Discourse, etc.), on affiliated projects and repositories
-(including issues, pull requests, and discussions on Github), and/or involved
+(including issues, pull requests, and discussions on GitHub), and/or involved
 with associated events pledge to accept and observe the following Code of
 Conduct.
 
@@ -67,7 +67,7 @@ This Code of Conduct applies within all project and community spaces, as well as
 in any public spaces where an individual representing the community is involved.
 This covers
 
-- Interactions on the Github repository, including discussions, issues, pull
+- Interactions on the GitHub repository, including discussions, issues, pull
   requests, commits, and wikis
 - Interactions on any affiliated Discord, Slack, IRC, or related online
   communities and forums like Discourse, etc.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index dfe8dea2..97bec669 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -67,7 +67,7 @@ need to be the best programmer to contribute. Our discord is open for questions
       problems they may have encountered on similar issues.
 
  3. **Fork** the repository
-    - A fork creates a copy of the code on your Github, so you can work on it
+    - A fork creates a copy of the code on your GitHub, so you can work on it
       separately from everyone else.
     - You can learn more about forking [here][forking].
 
diff --git a/Cargo.lock b/Cargo.lock
index 989fabae..7cd3ae1c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -626,7 +626,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc"
 dependencies = [
  "memchr",
- "regex-automata 0.4.3",
+ "regex-automata 0.4.4",
  "serde",
 ]
 
@@ -653,9 +653,9 @@ checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205"
 
 [[package]]
 name = "bytemuck"
-version = "1.14.0"
+version = "1.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
+checksum = "ed2490600f404f2b94c167e31d3ed1d5f3c225a0f3b80230053b3e0b7b962bd9"
 
 [[package]]
 name = "byteorder"
@@ -859,9 +859,9 @@ dependencies = [
 
 [[package]]
 name = "ciborium"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
+checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
 dependencies = [
  "ciborium-io",
  "ciborium-ll",
@@ -870,18 +870,18 @@ dependencies = [
 
 [[package]]
 name = "ciborium-io"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
+checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
 
 [[package]]
 name = "ciborium-ll"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
+checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
 dependencies = [
  "ciborium-io",
- "half 1.8.2",
+ "half",
 ]
 
 [[package]]
@@ -1873,13 +1873,13 @@ dependencies = [
 
 [[package]]
 name = "exr"
-version = "1.71.0"
+version = "1.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "832a761f35ab3e6664babfbdc6cef35a4860e816ec3916dcfd0882954e98a8a8"
+checksum = "279d3efcc55e19917fff7ab3ddd6c14afb6a90881a0078465196fe2f99d08c56"
 dependencies = [
  "bit_field",
- "flume",
- "half 2.2.1",
+ "flume 0.10.14",
+ "half",
  "lebe",
  "miniz_oxide",
  "rayon-core",
@@ -1946,6 +1946,19 @@ dependencies = [
  "miniz_oxide",
 ]
 
+[[package]]
+name = "flume"
+version = "0.10.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "nanorand",
+ "pin-project",
+ "spin 0.9.8",
+]
+
 [[package]]
 name = "flume"
 version = "0.11.0"
@@ -2283,16 +2296,11 @@ dependencies = [
 
 [[package]]
 name = "half"
-version = "1.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
-
-[[package]]
-name = "half"
-version = "2.2.1"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0"
+checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872"
 dependencies = [
+ "cfg-if",
  "crunchy",
 ]
 
@@ -2450,6 +2458,7 @@ dependencies = [
 name = "homestar-functions-add"
 version = "0.1.0"
 dependencies = [
+ "homestar-workspace-hack",
  "wit-bindgen",
 ]
 
@@ -2458,6 +2467,7 @@ name = "homestar-functions-test"
 version = "0.1.0"
 dependencies = [
  "base64 0.21.7",
+ "homestar-workspace-hack",
  "image",
  "wit-bindgen",
 ]
@@ -2474,6 +2484,7 @@ dependencies = [
  "enum-assoc",
  "futures",
  "generic-array 1.0.0",
+ "homestar-workspace-hack",
  "libipld",
  "libsqlite3-sys",
  "rand",
@@ -2513,13 +2524,14 @@ dependencies = [
  "dyn-clone",
  "enum-assoc",
  "faststr",
- "flume",
+ "flume 0.11.0",
  "fnv",
  "futures",
  "homestar-invocation",
  "homestar-runtime-tests-proc-macro",
  "homestar-wasm",
  "homestar-workflow",
+ "homestar-workspace-hack",
  "http 0.2.11",
  "http-serde",
  "humantime",
@@ -2528,6 +2540,7 @@ dependencies = [
  "ipfs-api-backend-hyper",
  "itertools 0.11.0",
  "jsonrpsee",
+ "libc",
  "libipld",
  "libp2p",
  "libsqlite3-sys",
@@ -2582,12 +2595,14 @@ dependencies = [
  "url",
  "uuid",
  "wait-timeout",
+ "winapi",
 ]
 
 [[package]]
 name = "homestar-runtime-tests-proc-macro"
 version = "0.0.0"
 dependencies = [
+ "homestar-workspace-hack",
  "proc-macro2",
  "quote",
  "syn 2.0.48",
@@ -2604,6 +2619,7 @@ dependencies = [
  "enum-as-inner",
  "heck",
  "homestar-invocation",
+ "homestar-workspace-hack",
  "itertools 0.11.0",
  "libipld",
  "rust_decimal",
@@ -2627,6 +2643,7 @@ version = "0.1.1"
 dependencies = [
  "fxhash",
  "homestar-invocation",
+ "homestar-workspace-hack",
  "indexmap 2.1.0",
  "json",
  "libipld",
@@ -2635,6 +2652,99 @@ dependencies = [
  "thiserror",
 ]
 
+[[package]]
+name = "homestar-workspace-hack"
+version = "0.1.0"
+dependencies = [
+ "ahash",
+ "anyhow",
+ "arrayvec",
+ "base64 0.13.1",
+ "bitflags 2.4.2",
+ "bytes",
+ "cc",
+ "clap",
+ "clap_builder",
+ "crossbeam-epoch",
+ "crunchy",
+ "crypto-common",
+ "data-encoding",
+ "diesel",
+ "diesel_derives",
+ "digest 0.10.7",
+ "digest 0.9.0",
+ "either",
+ "futures",
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-timer",
+ "futures-util",
+ "generic-array 0.14.7",
+ "getrandom",
+ "gimli",
+ "half",
+ "hashbrown 0.14.3",
+ "heck",
+ "hyper",
+ "iana-time-zone",
+ "image",
+ "indexmap 1.9.3",
+ "indexmap 2.1.0",
+ "itertools 0.11.0",
+ "jsonrpsee",
+ "jsonrpsee-core",
+ "libc",
+ "libsecp256k1-core",
+ "libsqlite3-sys",
+ "linux-raw-sys",
+ "miette",
+ "miniz_oxide",
+ "multibase",
+ "num-traits",
+ "object",
+ "proc-macro2",
+ "rand",
+ "regex",
+ "regex-automata 0.4.4",
+ "regex-syntax 0.8.2",
+ "retry",
+ "ring 0.17.7",
+ "rustc-hash",
+ "rustix",
+ "scopeguard",
+ "serde",
+ "serde_json",
+ "sha2 0.10.8",
+ "signature",
+ "smallvec",
+ "subtle",
+ "syn 1.0.109",
+ "syn 2.0.48",
+ "time",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "tower",
+ "tracing",
+ "tracing-core",
+ "tracing-logfmt",
+ "tracing-subscriber",
+ "typenum",
+ "unsigned-varint 0.7.2",
+ "url",
+ "uuid",
+ "wasi",
+ "wasmtime",
+ "wasmtime-jit",
+ "wasmtime-runtime",
+ "web-sys",
+ "zeroize",
+]
+
 [[package]]
 name = "hostname"
 version = "0.3.1"
@@ -2789,7 +2899,7 @@ dependencies = [
  "iana-time-zone-haiku",
  "js-sys",
  "wasm-bindgen",
- "windows-core",
+ "windows-core 0.52.0",
 ]
 
 [[package]]
@@ -3814,9 +3924,9 @@ dependencies = [
 
 [[package]]
 name = "libp2p-upnp"
-version = "0.2.0"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "963eb8a174f828f6a51927999a9ab5e45dfa9aa2aa5fed99aa65f79de6229464"
+checksum = "b49cc89949bf0e06869297cd4fe2c132358c23fe93e76ad43950453df4da3d35"
 dependencies = [
  "futures",
  "futures-timer",
@@ -4350,6 +4460,15 @@ dependencies = [
  "rand",
 ]
 
+[[package]]
+name = "nanorand"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
+dependencies = [
+ "getrandom",
+]
+
 [[package]]
 name = "natord"
 version = "1.0.9"
@@ -4939,9 +5058,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.76"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
+checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
 dependencies = [
  "unicode-ident",
 ]
@@ -5347,13 +5466,13 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.10.2"
+version = "1.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
 dependencies = [
  "aho-corasick 1.1.2",
  "memchr",
- "regex-automata 0.4.3",
+ "regex-automata 0.4.4",
  "regex-syntax 0.8.2",
 ]
 
@@ -5368,9 +5487,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.3"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a"
 dependencies = [
  "aho-corasick 1.1.2",
  "memchr",
@@ -5887,9 +6006,9 @@ dependencies = [
 
 [[package]]
 name = "serde_with"
-version = "3.5.0"
+version = "3.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f58c3a1b3e418f61c25b2aeb43fc6c95eaa252b8cecdda67f401943e9e08d33f"
+checksum = "f5c9fdb6b00a489875b22efd4b78fe2b363b72265cc5f6eb2e2b9ee270e6140c"
 dependencies = [
  "base64 0.21.7",
  "chrono",
@@ -5904,9 +6023,9 @@ dependencies = [
 
 [[package]]
 name = "serde_with_macros"
-version = "3.5.0"
+version = "3.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2068b437a31fc68f25dd7edc296b078f04b45145c199d8eed9866e45f1ff274"
+checksum = "dbff351eb4b33600a2e138dfa0b10b65a238ea8ff8fb2387c422c5022a3e8298"
 dependencies = [
  "darling",
  "proc-macro2",
@@ -7459,11 +7578,20 @@ dependencies = [
  "leb128",
 ]
 
+[[package]]
+name = "wasm-encoder"
+version = "0.40.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d162eb64168969ae90e8668ca0593b0e47667e315aa08e717a9c9574d700d826"
+dependencies = [
+ "leb128",
+]
+
 [[package]]
 name = "wasm-metadata"
-version = "0.10.15"
+version = "0.10.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "818931c85b1d197909699d36c509fa89550ccfa0d66932ba3c1726faddb4d0c7"
+checksum = "0b313e616ef69d1b4c64155451439db26d1923e8bbc13d451ec24cf14579632e"
 dependencies = [
  "anyhow",
  "indexmap 2.1.0",
@@ -7471,8 +7599,8 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "spdx",
- "wasm-encoder 0.39.0",
- "wasmparser 0.119.0",
+ "wasm-encoder 0.40.0",
+ "wasmparser 0.120.0",
 ]
 
 [[package]]
@@ -7496,14 +7624,25 @@ dependencies = [
  "semver",
 ]
 
+[[package]]
+name = "wasmparser"
+version = "0.120.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9148127f39cbffe43efee8d5442b16ecdba21567785268daa1ec9e134389705"
+dependencies = [
+ "bitflags 2.4.2",
+ "indexmap 2.1.0",
+ "semver",
+]
+
 [[package]]
 name = "wasmprinter"
-version = "0.2.76"
+version = "0.2.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cac2a7745372074e5573e365e17100f5a26058740576313784ef03fb900ea8d2"
+checksum = "d8389a95eb0b3165fea0537a6988960cc23a33d9be650e63fc3d63065fe20dcb"
 dependencies = [
  "anyhow",
- "wasmparser 0.119.0",
+ "wasmparser 0.120.0",
 ]
 
 [[package]]
@@ -7859,23 +7998,23 @@ dependencies = [
 
 [[package]]
 name = "wast"
-version = "70.0.0"
+version = "70.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ee4bc54bbe1c6924160b9f75e374a1d07532e7580eb632c0ee6cdd109bb217e"
+checksum = "f5d415036fe747a32b30c76c8bd6c73f69b7705fb7ebca5f16e852eef0c95802"
 dependencies = [
  "leb128",
  "memchr",
  "unicode-width",
- "wasm-encoder 0.39.0",
+ "wasm-encoder 0.40.0",
 ]
 
 [[package]]
 name = "wat"
-version = "1.0.83"
+version = "1.0.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f0dce8cdc288c717cf01e461a1e451a7b8445d53451123536ba576e423a101a"
+checksum = "8241f34599d413d2243a21015ab43aef68bfb32a0e447c54eef8d423525ca15e"
 dependencies = [
- "wast 70.0.0",
+ "wast 70.0.1",
 ]
 
 [[package]]
@@ -7913,6 +8052,7 @@ version = "0.1.0"
 dependencies = [
  "clap",
  "homestar-runtime",
+ "homestar-workspace-hack",
  "miette",
  "retry",
  "sysinfo",
@@ -8020,7 +8160,7 @@ version = "0.51.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9"
 dependencies = [
- "windows-core",
+ "windows-core 0.51.1",
  "windows-targets 0.48.5",
 ]
 
@@ -8033,6 +8173,15 @@ dependencies = [
  "windows-targets 0.48.5",
 ]
 
+[[package]]
+name = "windows-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets 0.52.0",
+]
+
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
diff --git a/Cargo.toml b/Cargo.toml
index f94f03ea..682fecae 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,6 +6,7 @@ members = [
   "homestar-runtime",
   "homestar-wasm",
   "homestar-workflow",
+  "homestar-workspace-hack",
 ]
 default-members = [
   "homestar-invocation",
@@ -37,6 +38,7 @@ enum-assoc = "1.1"
 enum-as-inner = "0.6"
 faststr = { version = "0.2", default-features = false, features = ["serde"] }
 futures = { version = "0.3", default-features = false }
+homestar-workspace-hack = "0.1"
 humantime = { version = "2.1", default-features = false }
 itertools = "0.11"
 libipld = { version = "0.16", default-features = false, features = [
@@ -112,3 +114,10 @@ strip = "symbols"
 # 0/false: no debug info at all; 1: line tables only; 2/true: full debug info
 debug = false
 debug-assertions = false
+
+# Using the workspace-hack via this patch directive means that it only applies
+# while building within this workspace. If another workspace imports a crate
+# from here via a git dependency, it will not have the workspace-hack applied
+# to it.
+[patch.crates-io.homestar-workspace-hack]
+path = "homestar-workspace-hack"
diff --git a/Cross.toml b/Cross.toml
index 78ef8d29..e51336b8 100644
--- a/Cross.toml
+++ b/Cross.toml
@@ -25,3 +25,6 @@ image = "freeznet/x86_64-apple-darwin-cross:11.3"
 
 [target.aarch64-apple-darwin]
 image = "freeznet/aarch64-apple-darwin-cross:11.3"
+
+[target.x86_64-pc-windows-gnu]
+image = "rustembedded/cross:x86_64-pc-windows-gnu"
diff --git a/README.md b/README.md
index 358c9411..7d86a90d 100644
--- a/README.md
+++ b/README.md
@@ -60,7 +60,7 @@
 - [Running Examples](#running-examples)
 - [Workspace](#workspace)
 - [Contributing](#contributing)
-- [Releases](#releases)
+- [Releases and Builds](#releases-and-builds)
 - [Getting Help](#getting-help)
 - [External Resources](#external-resources)
 - [License](#license)
@@ -167,15 +167,50 @@ We have a focused [development](./DEVELOPMENT.md) guide, as well as a
 more general [contributing](./CONTRIBUTING.md) guide to help you get involved.
 We always adhere to our [Code of Conduct](./CODE_OF_CONDUCT.md).
 
-## Releases
+## Releases and Builds
 
-TBA
+### Crates, Tags, and GitHub Releases
+
+Homestar uses [release-plz][release-plz] to publish [crates][rel-crates],
+[tags][rel-tags], changelogs, and [GitHub Releases][rel-gh]. Upon merging,
+a `release-plz` bot PR, four crates are continuously published,
+**all tied to the same cargo version currently** (though this may change in the
+future):
+
+- [homestar-runtime][crate-runtime]
+- [homestar-invocation][crate-invocation]
+- [homestar-workflow][crate-workflow]
+- [homestar-wasm][crate-wasm]
+
+### Build Targets
+
+Every [GitHub release of the homestar-runtime][rel-latest] contains build assets
+for running the `homestar-runtime` on different target architectures, as well as
+[DEB][deb] and [RPM][rpm] packages (tagged with the architectured they were
+compiled for). Our homebrew package for the runtime is also tied to releases
+and can be installed with `brew install fission-codes/fission/homestar`.
+
+We also leverage [cross][cross-rs] for [locally cross-compiling](./Cross.toml)
+to varying Linux and Apple target platforms.
+
+### NPM Packages
+
+We also release some of our cross-compiled runtime binaries as
+[npm binary packages](./homestar-runtime/npm/README.md):
+
+- [homestar-runtime](https://www.npmjs.com/package/homestar-runtime) - This is
+  the main package that installs the os specific binary package and runs it.
+- [homestar-darwin-arm64](https://www.npmjs.com/package/homestar-darwin-arm64)
+- [homestar-darwin-x64](https://www.npmjs.com/package/homestar-darwin-x64)
+- [homestar-linux-arm64](https://www.npmjs.com/package/homestar-linux-arm64)
+- [homestar-linux-x64](https://www.npmjs.com/package/homestar-linux-x64)
+- [homestar-windows-x64](https://www.npmjs.com/package/homestar-windows-x64)
 
 ## Getting Help
 
 For usage questions, usecases, or issues reach out to us in our [Discord channel](https://fission.codes/discord).
 
-We would be happy to try to answer your question or try opening a new issue on Github.
+We would be happy to try to answer your question or try opening a new issue on GitHub.
 
 ## External Resources
 
@@ -204,6 +239,12 @@ conditions.
 [apache]: https://www.apache.org/licenses/LICENSE-2.0
 [blog-1]: https://fission.codes/blog/ipfs-thing-breaking-down-ipvm/
 [cod-ipvm]: https://www.youtube.com/watch?v=3y1RB8wt_YY
+[crate-runtime]: https://crates.io/crates/homestar-runtime
+[crate-invocation]: https://crates.io/crates/homestar-invocation
+[crate-workflow]: https://crates.io/crates/homestar-workflow
+[crate-wasm]: https://crates.io/crates/homestar-wasm
+[cross-rs]: https://github.com/cross-rs/cross
+[deb]: https://www.debian.org/doc/manuals/debian-faq/pkg-basics.en.html
 [demo-1]: https://www.loom.com/share/3204037368fe426ba3b4c952b0691c5c
 [foundations-for-openworld-compute]: https://youtu.be/dRz5mau6fsY
 [guest]: https://github.com/bytecodealliance/wit-bindgen#supported-guest-languages
@@ -215,6 +256,12 @@ conditions.
 [ipvm-wg]: https://github.com/ipvm-wg
 [ipvm-workflow-spec]: https://github.com/ipvm-wg/workflow
 [mit]: http://opensource.org/licenses/MIT
+[rel-crates]: https://crates.io/search?q=homestar
+[rel-gh]: https://github.com/ipvm-wg/homestar/releases
+[rel-latest]: https://github.com/ipvm-wg/homestar/releases/latest
+[rel-tags]: https://github.com/ipvm-wg/homestar/tags
+[release-plz]: https://release-plz.ieni.dev/
+[rpm]: https://rpm.org/
 [research]: https://github.com/ipvm-wg/research
 [seamless-services]: https://youtu.be/Kr3B3sXh_VA
 [ucan-invocation]: https://github.com/ucan-wg/invocation
diff --git a/SECURITY.md b/SECURITY.md
index 4895ef64..b53f0de0 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -9,7 +9,7 @@ should not be reported via the public GitHub Issue tracker.
 
 The project team is committed to transparency in the security issue disclosure
 process. The Fission team announces security advisories through our
-Github respository's [security portal][sec-advisories] and and the
+GitHub respository's [security portal][sec-advisories] and the
 [RustSec advisory database][rustsec-db].
 
 [fission]: https://fission.codes/
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 30fca72c..3c0bd64a 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -27,6 +27,7 @@ RUN echo "fn main() {}" > ./homestar-runtime/src/main.rs
 RUN mkdir -p ./homestar-runtime/src/test_utils/proc_macro ./homestar-runtime/migrations ./examples ./homestar-functions
 RUN bash -c 'pushd ./examples && cargo init dummy-app-examples && popd'
 RUN bash -c 'pushd ./homestar-functions && cargo init dummy-app-fns && popd'
+RUN cargo init homestar-workspace-hack
 
 # copy cargo.*
 COPY Cargo.lock Cargo.toml diesel.toml ./
diff --git a/examples/websocket-relay/Cargo.toml b/examples/websocket-relay/Cargo.toml
index c6f16faa..052d3f2f 100644
--- a/examples/websocket-relay/Cargo.toml
+++ b/examples/websocket-relay/Cargo.toml
@@ -13,6 +13,7 @@ homestar-runtime = { path = "../../homestar-runtime", default-features = false,
   "monitoring",
   "websocket-notify",
 ] }
+homestar-workspace-hack = { workspace = true }
 miette = { version = "5.10", features = ["fancy"] }
 retry = "2.0"
 sysinfo = { version = "0.29", default-features = false }
diff --git a/examples/websocket-relay/README.md b/examples/websocket-relay/README.md
index 6335b456..ef5c690e 100644
--- a/examples/websocket-relay/README.md
+++ b/examples/websocket-relay/README.md
@@ -66,7 +66,8 @@ need: `brew install rust npm ipfs`
 
 We have packaged homestar binaries using brew, so
 `brew install fission-codes/fission/homestar` will install everything you need,
-including `ipfs`. You will still need `npm` to run this example. From this folder, you can then run the example like this:
+including `ipfs`. You will still need `npm` to run this example. From this folder,
+you can then run the example like this:
 
 ```
 homestar start --db homestar.db
diff --git a/flake.lock b/flake.lock
index d3e258c6..4d47b98f 100644
--- a/flake.lock
+++ b/flake.lock
@@ -79,11 +79,11 @@
         "rust-analyzer-src": "rust-analyzer-src"
       },
       "locked": {
-        "lastModified": 1705645424,
-        "narHash": "sha256-bSw0GDnWBvMSvW4oxdFMyhs7i3rNN0LAcreFDJmw3ks=",
+        "lastModified": 1706077451,
+        "narHash": "sha256-kd8Mlh+4NIG/NIkXeEwSIlwQuvysKJM4BeLrt2nvcc8=",
         "owner": "nix-community",
         "repo": "fenix",
-        "rev": "e514ed523707ec423d34f0748e6e6f18adadf42d",
+        "rev": "77d5a2dd0b186c40953c435da6e0c2215d7e1dec",
         "type": "github"
       },
       "original": {
@@ -445,11 +445,11 @@
     },
     "nixlib_3": {
       "locked": {
-        "lastModified": 1705193289,
-        "narHash": "sha256-oL5EAaZHiA3ABLdyKag/DgT+457vmELv8A+eaox2xsI=",
+        "lastModified": 1705798119,
+        "narHash": "sha256-WPVKxYMcvGW/2X16pfF1ef05EQ0Ql5XPCxqoCDlQSrY=",
         "owner": "nix-community",
         "repo": "nixpkgs.lib",
-        "rev": "da839f74dc77c9826fa333b1bc2c8258fd6ffcbe",
+        "rev": "a26fc04e3d43acfa1dc52065a4ce39ca7a2ec91c",
         "type": "github"
       },
       "original": {
@@ -540,11 +540,11 @@
     },
     "nixpkgs_3": {
       "locked": {
-        "lastModified": 1705666311,
-        "narHash": "sha256-VYdSQm7zq3AStyHhRr3SBCTA8fVzrl6WtIlXTs2Wlts=",
+        "lastModified": 1706006310,
+        "narHash": "sha256-nDPz0fj0IFcDhSTlXBU2aixcnGs2Jm4Zcuoj0QtmiXQ=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "a455c5fb3ee513e2f443838a0e84d52b035adb67",
+        "rev": "b43bb235efeab5324c5e486882ef46749188eee2",
         "type": "github"
       },
       "original": {
@@ -569,11 +569,11 @@
     "rust-analyzer-src": {
       "flake": false,
       "locked": {
-        "lastModified": 1705592412,
-        "narHash": "sha256-jhqkrAhd+lTLmnszaYHKf3Fr/fNXXdeVDwvsPwmmlD8=",
+        "lastModified": 1705864945,
+        "narHash": "sha256-ZATChFWHToTZQFLlzrzDUX8fjEbMHHBIyPaZU1JGmjI=",
         "owner": "rust-lang",
         "repo": "rust-analyzer",
-        "rev": "3f4c6dac3d5e34ccf56587419c2077aec799e60c",
+        "rev": "d410d4a2baf9e99b37b03dd42f06238b14374bf7",
         "type": "github"
       },
       "original": {
@@ -679,11 +679,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1705696331,
-        "narHash": "sha256-jTWF4EIjwdsiL0W1vwK5fyFrpJjMKYMGXz7OHkAyq8I=",
+        "lastModified": 1706062676,
+        "narHash": "sha256-aIgYdyQyKRHZ8gSmke3DE09D5ypK4tP+XYqrKPAd/3M=",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "d20edfd8d4f053f3466c7bb5ca53ed2e70a0bc35",
+        "rev": "81eb4bdb219d97d749f152eb4de6a081b088b08d",
         "type": "github"
       },
       "original": {
diff --git a/flake.nix b/flake.nix
index 8f3fcd0c..b1062ec2 100644
--- a/flake.nix
+++ b/flake.nix
@@ -58,6 +58,7 @@
             "wasm32-wasi"
             "x86_64-apple-darwin"
             "aarch64-apple-darwin"
+            "x86_64-unknown-linux-gnu"
             "x86_64-unknown-linux-musl"
             "aarch64-unknown-linux-musl"
           ];
@@ -72,10 +73,11 @@
         ];
 
         cargo-installs = with pkgs; [
-          cargo-deny
           cargo-deb
+          # cargo-deny -> bring back on new release
           cargo-cross
           cargo-expand
+          cargo-hakari
           cargo-nextest
           cargo-sort
           cargo-unused-features
diff --git a/homestar-functions/add/Cargo.toml b/homestar-functions/add/Cargo.toml
index 408fe173..58554b75 100644
--- a/homestar-functions/add/Cargo.toml
+++ b/homestar-functions/add/Cargo.toml
@@ -6,6 +6,7 @@ edition = { workspace = true }
 rust-version = { workspace = true }
 
 [dependencies]
+homestar-workspace-hack = { workspace = true }
 wit-bindgen = "0.16"
 
 [lib]
diff --git a/homestar-functions/test/Cargo.toml b/homestar-functions/test/Cargo.toml
index 50fed091..52156fc6 100644
--- a/homestar-functions/test/Cargo.toml
+++ b/homestar-functions/test/Cargo.toml
@@ -7,6 +7,7 @@ rust-version = { workspace = true }
 
 [dependencies]
 base64 = "0.21"
+homestar-workspace-hack = { workspace = true }
 image = { version = "0.24", default-features = false, features = ["png"] }
 wit-bindgen = "0.16"
 
diff --git a/homestar-invocation/Cargo.toml b/homestar-invocation/Cargo.toml
index 5f756e9b..70ff8385 100644
--- a/homestar-invocation/Cargo.toml
+++ b/homestar-invocation/Cargo.toml
@@ -9,7 +9,7 @@ readme = "README.md"
 edition = { workspace = true }
 rust-version = { workspace = true }
 documentation = "https://docs.rs/homestar-invocation"
-repository = "https://github.com/ipvm-wg/homestar/homestar-invocation"
+repository = "https://github.com/ipvm-wg/homestar/tree/main/homestar-invocation"
 authors = { workspace = true }
 
 [lib]
@@ -32,6 +32,7 @@ futures = { workspace = true }
 generic-array = { version = "1.0", default-features = false, features = [
   "serde",
 ] }
+homestar-workspace-hack = { workspace = true }
 libipld = { workspace = true }
 libsqlite3-sys = { workspace = true, optional = true }
 rand = { workspace = true }
diff --git a/homestar-runtime/Cargo.toml b/homestar-runtime/Cargo.toml
index aef6b640..c6846737 100644
--- a/homestar-runtime/Cargo.toml
+++ b/homestar-runtime/Cargo.toml
@@ -9,7 +9,7 @@ readme = "README.md"
 edition = { workspace = true }
 rust-version = { workspace = true }
 documentation = "https://docs.rs/homestar-runtime"
-repository = "https://github.com/ipvm-wg/homestar/homestar-runtime"
+repository = "https://github.com/ipvm-wg/homestar/tree/main/homestar-runtime"
 authors = { workspace = true }
 autotests = false
 
@@ -72,6 +72,7 @@ homestar-invocation = { version = "0.1", path = "../homestar-invocation", featur
 ] }
 homestar-wasm = { version = "0.1", path = "../homestar-wasm", default-features = false }
 homestar-workflow = { version = "0.1", path = "../homestar-workflow" }
+homestar-workspace-hack = { workspace = true }
 http = "0.2"
 http-serde = "1.1"
 humantime = { workspace = true }
@@ -211,6 +212,12 @@ tokio-tungstenite = { version = "0.21", default-features = false, features = [
 ] }
 wait-timeout = "0.2"
 
+[target.'cfg(not(windows))'.dev-dependencies]
+libc = "0.2"
+
+[target.'cfg(windows)'.dev-dependencies]
+winapi = "0.3"
+
 [features]
 default = ["wasmtime-default", "ipfs", "monitoring", "websocket-notify"]
 dev = ["ansi-logs", "ipfs", "monitoring", "websocket-notify"]
diff --git a/homestar-runtime/npm/readme.md b/homestar-runtime/npm/README.md
similarity index 96%
rename from homestar-runtime/npm/readme.md
rename to homestar-runtime/npm/README.md
index cd51c934..dfc0755e 100644
--- a/homestar-runtime/npm/readme.md
+++ b/homestar-runtime/npm/README.md
@@ -2,7 +2,8 @@
 
 ## Packages
 
-- [homestar-runtime](https://www.npmjs.com/package/homestar-runtime) - This is the main package that installs the os specific binary package and runs it.
+- [homestar-runtime](https://www.npmjs.com/package/homestar-runtime) - This is
+  the main package that installs the os specific binary package and runs it.
 - [homestar-darwin-arm64](https://www.npmjs.com/package/homestar-darwin-arm64)
 - [homestar-darwin-x64](https://www.npmjs.com/package/homestar-darwin-x64)
 - [homestar-linux-arm64](https://www.npmjs.com/package/homestar-linux-arm64)
diff --git a/homestar-runtime/npm/base/package-lock.json b/homestar-runtime/npm/base/package-lock.json
deleted file mode 100644
index dcf9b431..00000000
--- a/homestar-runtime/npm/base/package-lock.json
+++ /dev/null
@@ -1,263 +0,0 @@
-{
-  "name": "homestar-runtime",
-  "version": "0.0.8",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "": {
-      "name": "homestar-runtime",
-      "version": "0.0.8",
-      "license": "MIT",
-      "dependencies": {
-        "execa": "^8.0.1"
-      },
-      "bin": {
-        "homestar": "index.js"
-      },
-      "optionalDependencies": {
-        "homestar-darwin-arm64": "*",
-        "homestar-darwin-x64": "*",
-        "homestar-linux-arm64": "*",
-        "homestar-linux-x64": "*",
-        "homestar-windows-arm64": "*",
-        "homestar-windows-x64": "*"
-      }
-    },
-    "node_modules/cross-spawn": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
-      "dependencies": {
-        "path-key": "^3.1.0",
-        "shebang-command": "^2.0.0",
-        "which": "^2.0.1"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    },
-    "node_modules/execa": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
-      "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
-      "dependencies": {
-        "cross-spawn": "^7.0.3",
-        "get-stream": "^8.0.1",
-        "human-signals": "^5.0.0",
-        "is-stream": "^3.0.0",
-        "merge-stream": "^2.0.0",
-        "npm-run-path": "^5.1.0",
-        "onetime": "^6.0.0",
-        "signal-exit": "^4.1.0",
-        "strip-final-newline": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=16.17"
-      },
-      "funding": {
-        "url": "https://github.com/sindresorhus/execa?sponsor=1"
-      }
-    },
-    "node_modules/get-stream": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
-      "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
-      "engines": {
-        "node": ">=16"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/homestar-darwin-arm64": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/homestar-darwin-arm64/-/homestar-darwin-arm64-0.0.1.tgz",
-      "integrity": "sha512-ftcZyXJalctBtj3jhTepLVE6LjNaB/k2KB9zAAZjQi6neAKs+MMTqaRt8TV3/X16hOryOeyjDPCshgbGnqpBJw==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "darwin"
-      ]
-    },
-    "node_modules/homestar-darwin-x64": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/homestar-darwin-x64/-/homestar-darwin-x64-0.0.1.tgz",
-      "integrity": "sha512-DT4H2XnKD6bwjY/3ooYRwfqnP8maKlLp53ZOkeSPIWT8HDf7DI/6WJxeZZy8AGkMox5SU0xP64CrIQ3W/D57NA==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "darwin"
-      ]
-    },
-    "node_modules/homestar-linux-arm64": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/homestar-linux-arm64/-/homestar-linux-arm64-0.0.1.tgz",
-      "integrity": "sha512-IKDrLIvZWmp1ZrcYyySV1xp7wOYOCHPELeuiOEd0a3YuHssURXS4CdibUGKXGnTnxv7w7bjNla5HAVyOnC/dNA==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/homestar-linux-x64": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/homestar-linux-x64/-/homestar-linux-x64-0.0.1.tgz",
-      "integrity": "sha512-LuY2HA3SM1B5B4LFpyb+eAKHFaKlEJ0vtkr/aFJCR9d0SA/omf3ZpqmeT4zDrCNgCnqT81rvVDjBOP094890zw==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/human-signals": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
-      "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
-      "engines": {
-        "node": ">=16.17.0"
-      }
-    },
-    "node_modules/is-stream": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
-      "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
-      "engines": {
-        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/isexe": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
-    },
-    "node_modules/merge-stream": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
-      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
-    },
-    "node_modules/mimic-fn": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
-      "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/npm-run-path": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
-      "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
-      "dependencies": {
-        "path-key": "^4.0.0"
-      },
-      "engines": {
-        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/npm-run-path/node_modules/path-key": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
-      "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/onetime": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
-      "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
-      "dependencies": {
-        "mimic-fn": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/path-key": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
-      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/shebang-command": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
-      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-      "dependencies": {
-        "shebang-regex": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/shebang-regex": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
-      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/signal-exit": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
-      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
-      "engines": {
-        "node": ">=14"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
-      }
-    },
-    "node_modules/strip-final-newline": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
-      "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus"
-      }
-    },
-    "node_modules/which": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-      "dependencies": {
-        "isexe": "^2.0.0"
-      },
-      "bin": {
-        "node-which": "bin/node-which"
-      },
-      "engines": {
-        "node": ">= 8"
-      }
-    }
-  }
-}
diff --git a/homestar-runtime/npm/package.json.tmpl b/homestar-runtime/npm/package-json-arch.tmpl
similarity index 100%
rename from homestar-runtime/npm/package.json.tmpl
rename to homestar-runtime/npm/package-json-arch.tmpl
diff --git a/homestar-runtime/npm/package-json-base.tmpl b/homestar-runtime/npm/package-json-base.tmpl
new file mode 100644
index 00000000..9834ef9a
--- /dev/null
+++ b/homestar-runtime/npm/package-json-base.tmpl
@@ -0,0 +1,37 @@
+{
+  "name": "homestar-runtime",
+  "version": "${node_version}",
+  "description": "The IPVM reference implementation",
+  "author": "Hugo Dias <hugomrdias@gmail.com> (hugodias.me)",
+  "homepage": "https://github.com/ipvm-wg/homestar/tree/main/homestar-runtime",
+  "repository": {
+    "url": "ipvm-wg/homestar",
+    "directory": "homestar-runtime"
+  },
+  "keywords": [
+    "homestar",
+    "wasm",
+    "wit",
+    "webassembly",
+    "workflows",
+    "scheduling"
+  ],
+  "bin": {
+    "homestar": "index.js"
+  },
+  "type": "module",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "license": "Apache-2.0",
+  "optionalDependencies": {
+    "homestar-darwin-arm64": "${node_version}",
+    "homestar-darwin-x64": "${node_version}",
+    "homestar-linux-arm64": "${node_version}",
+    "homestar-linux-x64": "${node_version}",
+    "homestar-windows-x64": "${node_version}"
+  },
+  "dependencies": {
+    "execa": "^8.0.1"
+  }
+}
diff --git a/homestar-runtime/npm/base/package.json b/homestar-runtime/npm/package-json-baserc.tmpl
similarity index 75%
rename from homestar-runtime/npm/base/package.json
rename to homestar-runtime/npm/package-json-baserc.tmpl
index d5a6669a..7004638a 100644
--- a/homestar-runtime/npm/base/package.json
+++ b/homestar-runtime/npm/package-json-baserc.tmpl
@@ -1,6 +1,6 @@
 {
   "name": "homestar-runtime",
-  "version": "0.0.8",
+  "version": "${node_version}",
   "description": "The IPVM reference implementation",
   "author": "Hugo Dias <hugomrdias@gmail.com> (hugodias.me)",
   "homepage": "https://github.com/ipvm-wg/homestar/tree/main/homestar-runtime",
@@ -25,12 +25,11 @@
   },
   "license": "Apache-2.0",
   "optionalDependencies": {
-    "homestar-darwin-arm64": "*",
-    "homestar-darwin-x64": "*",
-    "homestar-linux-arm64": "*",
-    "homestar-linux-x64": "*",
-    "homestar-windows-arm64": "*",
-    "homestar-windows-x64": "*"
+    "homestar-darwin-arm64": "rc",
+    "homestar-darwin-x64": "rc",
+    "homestar-linux-arm64": "rc",
+    "homestar-linux-x64": "rc",
+    "homestar-windows-x64": "rc"
   },
   "dependencies": {
     "execa": "^8.0.1"
diff --git a/homestar-runtime/src/settings.rs b/homestar-runtime/src/settings.rs
index 29c6ee58..0e27fbba 100644
--- a/homestar-runtime/src/settings.rs
+++ b/homestar-runtime/src/settings.rs
@@ -408,7 +408,7 @@ mod test {
 
     #[test]
     #[serial_test::file_serial]
-    fn overriding_env() {
+    fn overriding_env_serial() {
         std::env::set_var("HOMESTAR__NODE__NETWORK__RPC__PORT", "2046");
         std::env::set_var("HOMESTAR__NODE__DB__MAX_POOL_SIZE", "1");
         let settings = Settings::build(Some("fixtures/settings.toml".into())).unwrap();
diff --git a/homestar-runtime/src/test_utils/proc_macro/Cargo.toml b/homestar-runtime/src/test_utils/proc_macro/Cargo.toml
index c7b8c1c4..fd76ad6e 100644
--- a/homestar-runtime/src/test_utils/proc_macro/Cargo.toml
+++ b/homestar-runtime/src/test_utils/proc_macro/Cargo.toml
@@ -13,3 +13,4 @@ doc = false
 proc-macro2 = "1.0"
 quote = "1.0"
 syn = "2.0"
+homestar-workspace-hack = { workspace = true }
diff --git a/homestar-runtime/tests/network/dht.rs b/homestar-runtime/tests/network/dht.rs
index f8fe5b25..8b37f738 100644
--- a/homestar-runtime/tests/network/dht.rs
+++ b/homestar-runtime/tests/network/dht.rs
@@ -32,7 +32,8 @@ const SUBSCRIBE_NETWORK_EVENTS_ENDPOINT: &str = "subscribe_network_events";
 const UNSUBSCRIBE_NETWORK_EVENTS_ENDPOINT: &str = "unsubscribe_network_events";
 
 #[test]
-fn test_libp2p_dht_records_integration() -> Result<()> {
+#[serial_test::file_serial]
+fn test_libp2p_dht_records_serial() -> Result<()> {
     let proc_info1 = ProcInfo::new().unwrap();
     let proc_info2 = ProcInfo::new().unwrap();
 
@@ -365,7 +366,8 @@ fn test_libp2p_dht_records_integration() -> Result<()> {
 }
 
 #[test]
-fn test_libp2p_dht_quorum_failure_integration() -> Result<()> {
+#[serial_test::file_serial]
+fn test_libp2p_dht_quorum_failure_serial() -> Result<()> {
     let proc_info1 = ProcInfo::new().unwrap();
     let proc_info2 = ProcInfo::new().unwrap();
 
@@ -564,7 +566,7 @@ fn test_libp2p_dht_quorum_failure_integration() -> Result<()> {
 
 #[test]
 #[serial_test::file_serial]
-fn test_libp2p_dht_workflow_info_provider_integration() -> Result<()> {
+fn test_libp2p_dht_workflow_info_provider_serial() -> Result<()> {
     let proc_info1 = ProcInfo::new().unwrap();
     let proc_info2 = ProcInfo::new().unwrap();
 
@@ -586,6 +588,7 @@ fn test_libp2p_dht_workflow_info_provider_integration() -> Result<()> {
         [node.network.libp2p]
         listen_address = "{listen_addr1}"
         node_addresses = ["{node_addrb}"]
+        idle_connection_timeout = 180
         [node.network.libp2p.dht]
         receipt_quorum = 1
         workflow_quorum = 1
@@ -646,6 +649,7 @@ fn test_libp2p_dht_workflow_info_provider_integration() -> Result<()> {
         [node.network.keypair_config]
         existing = {{ key_type = "secp256k1", path = "./fixtures/__testkey_secp256k1.der" }}
         [node.network.libp2p]
+        idle_connection_timeout = 180
         listen_address = "{listen_addr2}"
         node_addresses = ["{node_addra}"]
         [node.network.libp2p.dht]
@@ -854,7 +858,8 @@ fn test_libp2p_dht_workflow_info_provider_integration() -> Result<()> {
 
 #[ignore]
 #[test]
-fn test_libp2p_dht_workflow_info_provider_recursive_integration() -> Result<()> {
+#[serial_test::file_serial]
+fn test_libp2p_dht_workflow_info_provider_recursive_serial() -> Result<()> {
     // NOTE: We are ignoring this test for now because we do not have a means
     // to properly isolate node a from node c. In the future when nodes are
     // partitioned as private nodes or from NATs, we will bring this test back.
diff --git a/homestar-runtime/tests/network/mdns.rs b/homestar-runtime/tests/network/mdns.rs
index 9459469b..0181dd9c 100644
--- a/homestar-runtime/tests/network/mdns.rs
+++ b/homestar-runtime/tests/network/mdns.rs
@@ -17,8 +17,8 @@ use std::{
 static BIN: Lazy<PathBuf> = Lazy::new(|| assert_cmd::cargo::cargo_bin(BIN_NAME));
 
 #[test]
-#[serial_test::serial]
-fn test_libp2p_connect_after_mdns_discovery_integration() -> Result<()> {
+#[serial_test::file_serial]
+fn test_libp2p_connect_after_mdns_discovery_serial() -> Result<()> {
     let proc_info1 = ProcInfo::new().unwrap();
     let proc_info2 = ProcInfo::new().unwrap();
 
@@ -175,8 +175,8 @@ fn test_libp2p_connect_after_mdns_discovery_integration() -> Result<()> {
 }
 
 #[test]
-#[serial_test::serial]
-fn test_libp2p_disconnect_mdns_discovery_integration() -> Result<()> {
+#[serial_test::file_serial]
+fn test_libp2p_disconnect_mdns_discovery_serial() -> Result<()> {
     // Start two nodes each configured to listen at 0.0.0.0 with no known peers.
     // The nodes are configured with port 0 to allow the OS to select a port.
 
diff --git a/homestar-runtime/tests/utils.rs b/homestar-runtime/tests/utils.rs
index 10b47371..a5618de9 100644
--- a/homestar-runtime/tests/utils.rs
+++ b/homestar-runtime/tests/utils.rs
@@ -14,7 +14,7 @@ use predicates::prelude::*;
 use retry::delay::Fixed;
 use retry::{delay::Exponential, retry};
 use std::{
-    env, fs,
+    env, fmt, fs,
     fs::File,
     future::Future,
     io::Write,
@@ -26,6 +26,8 @@ use std::{
 };
 use tokio::time::{timeout, Timeout};
 use wait_timeout::ChildExt;
+#[cfg(windows)]
+use winapi::shared::winerror::ERROR_ACCESS_DENIED;
 
 /// Binary name, which is different than the crate name.
 pub(crate) const BIN_NAME: &str = "homestar";
@@ -55,11 +57,6 @@ pub(crate) fn multiaddr(port: u16, hash: &str) -> String {
 
 static BIN: Lazy<PathBuf> = Lazy::new(|| assert_cmd::cargo::cargo_bin(BIN_NAME));
 
-/// Guard for a [Child] process.
-pub(crate) struct ChildGuard {
-    guard: Option<Child>,
-}
-
 /// [port_selector::Selector] wrapper for tests.
 pub(crate) struct RpcSelector(pub(crate) Selector);
 
@@ -79,6 +76,21 @@ impl RpcSelector {
     }
 }
 
+/// Guard for a [Child] process.
+#[derive(Debug)]
+pub(crate) struct ChildGuard {
+    guard: Option<Child>,
+}
+
+impl fmt::Display for ChildGuard {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match &self.guard {
+            Some(child) => write!(f, "{}", child.id()),
+            None => write!(f, "None"),
+        }
+    }
+}
+
 #[allow(dead_code)]
 impl ChildGuard {
     /// Create a new [ChildGuard] from a [Child] process.
@@ -125,14 +137,54 @@ impl ChildGuard {
 }
 
 impl Drop for ChildGuard {
+    #[cfg(windows)]
     fn drop(&mut self) {
         if let Some(mut child) = self.guard.take() {
             if matches!(child.try_wait(), Ok(None)) {
-                if let Err(e) = child.kill() {
-                    eprintln!("Could not kill child process: {e}");
+                if let Err(err) = child.kill() {
+                    const ACCESS_DENIED: Option<i32> = Some(ERROR_ACCESS_DENIED as i32);
+                    if !matches!(err.raw_os_error(), ACCESS_DENIED) {
+                        eprintln!("Failed to clean up child process {}: {}", self, err);
+                    }
+                }
+
+                // Sending a kill signal does NOT imply the process has exited. Wait for it to exit.
+                let wait_res = child.wait();
+                if let Ok(code) = wait_res.as_ref() {
+                    eprintln!("Child process {} killed, exited with code {:?}", self, code);
+                } else {
+                    eprintln!(
+                        "Failed to wait for child process {} that was terminated: {:?}",
+                        self, wait_res
+                    );
                 }
             }
-        };
+        }
+    }
+
+    #[cfg(unix)]
+    fn drop(&mut self) {
+        if let Some(mut child) = self.guard.take() {
+            // attempt to stop gracefully
+            let pid = child.id();
+            unsafe {
+                libc::kill(libc::pid_t::from_ne_bytes(pid.to_ne_bytes()), libc::SIGTERM);
+            }
+
+            for _ in 0..10 {
+                if child.try_wait().ok().flatten().is_some() {
+                    break;
+                }
+                std::thread::sleep(std::time::Duration::from_secs(1));
+            }
+
+            if child.try_wait().ok().flatten().is_none() {
+                // still alive? kill it with fire
+                let _ = child.kill();
+            }
+
+            let _ = child.wait();
+        }
     }
 }
 
diff --git a/homestar-wasm/Cargo.toml b/homestar-wasm/Cargo.toml
index 06ac68c4..063fdbf7 100644
--- a/homestar-wasm/Cargo.toml
+++ b/homestar-wasm/Cargo.toml
@@ -9,7 +9,7 @@ readme = "README.md"
 edition = { workspace = true }
 rust-version = { workspace = true }
 documentation = "https://docs.rs/homestar-wasm"
-repository = "https://github.com/ipvm-wg/homestar/homestar-wasm"
+repository = "https://github.com/ipvm-wg/homestar/tree/main/homestar-wasm"
 authors = { workspace = true }
 
 [lib]
@@ -26,6 +26,7 @@ atomic_refcell = { workspace = true }
 enum-as-inner = { workspace = true }
 heck = "0.4"
 homestar-invocation = { version = "0.1", path = "../homestar-invocation" }
+homestar-workspace-hack = { workspace = true }
 itertools = { workspace = true }
 libipld = { workspace = true }
 rust_decimal = { version = "1.33", default-features = false }
diff --git a/homestar-workflow/Cargo.toml b/homestar-workflow/Cargo.toml
index 7f944e6c..446c6981 100644
--- a/homestar-workflow/Cargo.toml
+++ b/homestar-workflow/Cargo.toml
@@ -9,7 +9,7 @@ readme = "README.md"
 edition = { workspace = true }
 rust-version = { workspace = true }
 documentation = "https://docs.rs/homestar-workflow"
-repository = "https://github.com/ipvm-wg/homestar/homestar-workflow"
+repository = "https://github.com/ipvm-wg/homestar/tree/main/homestar-workflow"
 authors = { workspace = true }
 
 [lib]
@@ -20,6 +20,7 @@ doctest = true
 [dependencies]
 fxhash = { version = "0.2", default-features = false }
 homestar-invocation = { version = "0.1", path = "../homestar-invocation" }
+homestar-workspace-hack = { workspace = true }
 indexmap = { version = "2.1", default-features = false }
 libipld = { workspace = true }
 serde = { workspace = true }
diff --git a/homestar-workspace-hack/.gitattributes b/homestar-workspace-hack/.gitattributes
new file mode 100644
index 00000000..3e9dba4b
--- /dev/null
+++ b/homestar-workspace-hack/.gitattributes
@@ -0,0 +1,4 @@
+# Avoid putting conflict markers in the generated Cargo.toml file, since their presence breaks
+# Cargo.
+# Also do not check out the file as CRLF on Windows, as that's what hakari needs.
+Cargo.toml merge=binary -crlf
diff --git a/homestar-workspace-hack/Cargo.toml b/homestar-workspace-hack/Cargo.toml
new file mode 100644
index 00000000..09be57b9
--- /dev/null
+++ b/homestar-workspace-hack/Cargo.toml
@@ -0,0 +1,294 @@
+# This file is generated by `cargo hakari`.
+# To regenerate, run:
+#     cargo hakari generate
+
+[package]
+name = "homestar-workspace-hack"
+version = "0.1.0"
+description = "workspace-hack package, managed by hakari"
+# You can choose to publish this crate: see https://docs.rs/cargo-hakari/latest/cargo_hakari/publishing.
+publish = false
+license = { workspace = true }
+edition = { workspace = true }
+documentation = "https://docs.rs/homestar-workspace-hack"
+authors = { workspace = true }
+# The parts of the file between the BEGIN HAKARI SECTION and END HAKARI SECTION comments
+# are managed by hakari.
+
+### BEGIN HAKARI SECTION
+[dependencies]
+ahash = { version = "0.8", default-features = false, features = ["no-rng", "std"] }
+anyhow = { version = "1", features = ["backtrace"] }
+arrayvec = { version = "0.7" }
+base64 = { version = "0.13", features = ["alloc"] }
+bitflags = { version = "2", default-features = false, features = ["std"] }
+bytes = { version = "1", features = ["serde"] }
+clap = { version = "4", features = ["derive", "env"] }
+clap_builder = { version = "4", default-features = false, features = ["color", "env", "help", "std", "suggestions", "usage"] }
+crossbeam-epoch = { version = "0.9" }
+crunchy = { version = "0.2", features = ["std"] }
+crypto-common = { version = "0.1", default-features = false, features = ["std"] }
+data-encoding = { version = "2" }
+diesel = { version = "2", default-features = false, features = ["chrono", "r2d2", "returning_clauses_for_sqlite_3_35", "sqlite", "with-deprecated"] }
+digest-274715c4dabd11b0 = { package = "digest", version = "0.9", default-features = false, features = ["std"] }
+digest-93f6ce9d446188ac = { package = "digest", version = "0.10", features = ["mac", "std"] }
+either = { version = "1" }
+futures = { version = "0.3", features = ["bilock", "thread-pool", "unstable"] }
+futures-channel = { version = "0.3", features = ["sink", "unstable"] }
+futures-core = { version = "0.3", features = ["unstable"] }
+futures-executor = { version = "0.3", features = ["thread-pool"] }
+futures-io = { version = "0.3", features = ["unstable"] }
+futures-sink = { version = "0.3" }
+futures-task = { version = "0.3", default-features = false, features = ["std", "unstable"] }
+futures-timer = { version = "3", default-features = false, features = ["wasm-bindgen"] }
+futures-util = { version = "0.3", features = ["bilock", "channel", "io", "sink", "unstable"] }
+generic-array = { version = "0.14", default-features = false, features = ["more_lengths"] }
+getrandom = { version = "0.2", default-features = false, features = ["js", "rdrand", "std"] }
+half = { version = "2" }
+hashbrown = { version = "0.14", features = ["raw"] }
+heck = { version = "0.4", features = ["unicode"] }
+hyper = { version = "0.14", features = ["full"] }
+image = { version = "0.24", default-features = false, features = ["jpeg", "openexr", "png"] }
+indexmap-dff4ba8e3ae991db = { package = "indexmap", version = "1", default-features = false, features = ["serde"] }
+indexmap-f595c2ba2a3f28df = { package = "indexmap", version = "2", features = ["serde"] }
+itertools = { version = "0.11" }
+jsonrpsee = { version = "0.21", default-features = false, features = ["client", "server"] }
+jsonrpsee-core = { version = "0.21", features = ["async-client", "async-wasm-client", "http-helpers", "server"] }
+libc = { version = "0.2", features = ["extra_traits"] }
+libsecp256k1-core = { version = "0.3" }
+libsqlite3-sys = { version = "0.27", features = ["bundled"] }
+miette = { version = "5", features = ["fancy"] }
+miniz_oxide = { version = "0.7", features = ["simd"] }
+multibase = { version = "0.9" }
+num-traits = { version = "0.2", features = ["i128", "libm"] }
+rand = { version = "0.8", features = ["small_rng"] }
+regex = { version = "1" }
+regex-automata = { version = "0.4", default-features = false, features = ["dfa-onepass", "dfa-search", "hybrid", "meta", "nfa-backtrack", "perf-inline", "perf-literal", "unicode"] }
+regex-syntax = { version = "0.8" }
+retry = { version = "2" }
+rustc-hash = { version = "1" }
+scopeguard = { version = "1" }
+serde = { version = "1", features = ["alloc", "derive", "rc"] }
+serde_json = { version = "1", features = ["alloc", "float_roundtrip", "raw_value"] }
+sha2 = { version = "0.10" }
+signature = { version = "2", default-features = false, features = ["std"] }
+smallvec = { version = "1", default-features = false, features = ["union"] }
+time = { version = "0.3", features = ["formatting", "macros", "parsing"] }
+tokio = { version = "1", features = ["fs", "io-std", "io-util", "macros", "net", "rt-multi-thread", "signal", "test-util", "tracing"] }
+tokio-stream = { version = "0.1", features = ["net", "sync"] }
+tokio-util = { version = "0.7", features = ["codec", "compat", "io", "time"] }
+tower = { version = "0.4", features = ["balance", "buffer", "limit", "timeout", "util"] }
+tracing = { version = "0.1", features = ["log"] }
+tracing-core = { version = "0.1" }
+tracing-logfmt = { version = "0.3", default-features = false, features = ["ansi_logs"] }
+tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt", "parking_lot"] }
+typenum = { version = "1", default-features = false, features = ["const-generics"] }
+unsigned-varint = { version = "0.7", default-features = false, features = ["asynchronous_codec"] }
+url = { version = "2", features = ["serde"] }
+uuid = { version = "1", features = ["fast-rng", "v4"] }
+wasmtime = { version = "16", features = ["component-model"] }
+wasmtime-jit = { version = "16", default-features = false, features = ["addr2line", "debug-builtins", "demangle", "profiling"] }
+wasmtime-runtime = { version = "16", default-features = false, features = ["async", "component-model", "debug-builtins", "pooling-allocator"] }
+zeroize = { version = "1", features = ["zeroize_derive"] }
+
+[build-dependencies]
+ahash = { version = "0.8", default-features = false, features = ["no-rng", "std"] }
+anyhow = { version = "1", features = ["backtrace"] }
+arrayvec = { version = "0.7" }
+base64 = { version = "0.13", features = ["alloc"] }
+bitflags = { version = "2", default-features = false, features = ["std"] }
+bytes = { version = "1", features = ["serde"] }
+cc = { version = "1", default-features = false, features = ["parallel"] }
+clap = { version = "4", features = ["derive", "env"] }
+clap_builder = { version = "4", default-features = false, features = ["color", "env", "help", "std", "suggestions", "usage"] }
+crossbeam-epoch = { version = "0.9" }
+crunchy = { version = "0.2", features = ["std"] }
+crypto-common = { version = "0.1", default-features = false, features = ["std"] }
+data-encoding = { version = "2" }
+diesel = { version = "2", default-features = false, features = ["chrono", "r2d2", "returning_clauses_for_sqlite_3_35", "sqlite", "with-deprecated"] }
+diesel_derives = { version = "2", features = ["chrono", "r2d2", "sqlite", "with-deprecated"] }
+digest-274715c4dabd11b0 = { package = "digest", version = "0.9", default-features = false, features = ["std"] }
+digest-93f6ce9d446188ac = { package = "digest", version = "0.10", features = ["mac", "std"] }
+either = { version = "1" }
+futures = { version = "0.3", features = ["bilock", "thread-pool", "unstable"] }
+futures-channel = { version = "0.3", features = ["sink", "unstable"] }
+futures-core = { version = "0.3", features = ["unstable"] }
+futures-executor = { version = "0.3", features = ["thread-pool"] }
+futures-io = { version = "0.3", features = ["unstable"] }
+futures-sink = { version = "0.3" }
+futures-task = { version = "0.3", default-features = false, features = ["std", "unstable"] }
+futures-timer = { version = "3", default-features = false, features = ["wasm-bindgen"] }
+futures-util = { version = "0.3", features = ["bilock", "channel", "io", "sink", "unstable"] }
+generic-array = { version = "0.14", default-features = false, features = ["more_lengths"] }
+getrandom = { version = "0.2", default-features = false, features = ["js", "rdrand", "std"] }
+half = { version = "2" }
+hashbrown = { version = "0.14", features = ["raw"] }
+heck = { version = "0.4", features = ["unicode"] }
+hyper = { version = "0.14", features = ["full"] }
+image = { version = "0.24", default-features = false, features = ["jpeg", "openexr", "png"] }
+indexmap-dff4ba8e3ae991db = { package = "indexmap", version = "1", default-features = false, features = ["serde"] }
+indexmap-f595c2ba2a3f28df = { package = "indexmap", version = "2", features = ["serde"] }
+itertools = { version = "0.11" }
+jsonrpsee = { version = "0.21", default-features = false, features = ["client", "server"] }
+jsonrpsee-core = { version = "0.21", features = ["async-client", "async-wasm-client", "http-helpers", "server"] }
+libc = { version = "0.2", features = ["extra_traits"] }
+libsecp256k1-core = { version = "0.3" }
+libsqlite3-sys = { version = "0.27", features = ["bundled"] }
+miette = { version = "5", features = ["fancy"] }
+miniz_oxide = { version = "0.7", features = ["simd"] }
+multibase = { version = "0.9" }
+num-traits = { version = "0.2", features = ["i128", "libm"] }
+proc-macro2 = { version = "1", features = ["span-locations"] }
+rand = { version = "0.8", features = ["small_rng"] }
+regex = { version = "1" }
+regex-automata = { version = "0.4", default-features = false, features = ["dfa-onepass", "dfa-search", "hybrid", "meta", "nfa-backtrack", "perf-inline", "perf-literal", "unicode"] }
+regex-syntax = { version = "0.8" }
+retry = { version = "2" }
+rustc-hash = { version = "1" }
+scopeguard = { version = "1" }
+serde = { version = "1", features = ["alloc", "derive", "rc"] }
+serde_json = { version = "1", features = ["alloc", "float_roundtrip", "raw_value"] }
+sha2 = { version = "0.10" }
+signature = { version = "2", default-features = false, features = ["std"] }
+smallvec = { version = "1", default-features = false, features = ["union"] }
+syn-dff4ba8e3ae991db = { package = "syn", version = "1", features = ["extra-traits", "full", "visit"] }
+syn-f595c2ba2a3f28df = { package = "syn", version = "2", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] }
+time = { version = "0.3", features = ["formatting", "macros", "parsing"] }
+tokio = { version = "1", features = ["fs", "io-std", "io-util", "macros", "net", "rt-multi-thread", "signal", "test-util", "tracing"] }
+tokio-stream = { version = "0.1", features = ["net", "sync"] }
+tokio-util = { version = "0.7", features = ["codec", "compat", "io", "time"] }
+tower = { version = "0.4", features = ["balance", "buffer", "limit", "timeout", "util"] }
+tracing = { version = "0.1", features = ["log"] }
+tracing-core = { version = "0.1" }
+tracing-logfmt = { version = "0.3", default-features = false, features = ["ansi_logs"] }
+tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt", "parking_lot"] }
+typenum = { version = "1", default-features = false, features = ["const-generics"] }
+unsigned-varint = { version = "0.7", default-features = false, features = ["asynchronous_codec"] }
+url = { version = "2", features = ["serde"] }
+uuid = { version = "1", features = ["fast-rng", "v4"] }
+wasmtime = { version = "16", features = ["component-model"] }
+wasmtime-jit = { version = "16", default-features = false, features = ["addr2line", "debug-builtins", "demangle", "profiling"] }
+wasmtime-runtime = { version = "16", default-features = false, features = ["async", "component-model", "debug-builtins", "pooling-allocator"] }
+zeroize = { version = "1", features = ["zeroize_derive"] }
+
+[target.wasm32-unknown-unknown.dependencies]
+crypto-common = { version = "0.1", default-features = false, features = ["getrandom"] }
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+rustix = { version = "0.38", features = ["net", "process", "procfs", "termios", "time"] }
+subtle = { version = "2" }
+web-sys = { version = "0.3", default-features = false, features = ["AbortController", "AbortSignal", "AddEventListenerOptions", "BinaryType", "BlobPropertyBag", "CanvasRenderingContext2d", "CloseEvent", "CloseEventInit", "Document", "DomRect", "ErrorEvent", "File", "FileReader", "FormData", "Headers", "History", "HtmlCanvasElement", "HtmlHeadElement", "Location", "MessageEvent", "Performance", "PerformanceTiming", "ProgressEvent", "ReadableStream", "Request", "RequestCredentials", "RequestInit", "RequestMode", "Response", "ServiceWorkerGlobalScope", "WebSocket", "Window", "Worker"] }
+
+[target.wasm32-unknown-unknown.build-dependencies]
+crypto-common = { version = "0.1", default-features = false, features = ["getrandom"] }
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+rustix = { version = "0.38", features = ["net", "process", "procfs", "termios", "time"] }
+subtle = { version = "2" }
+web-sys = { version = "0.3", default-features = false, features = ["AbortController", "AbortSignal", "AddEventListenerOptions", "BinaryType", "BlobPropertyBag", "CanvasRenderingContext2d", "CloseEvent", "CloseEventInit", "Document", "DomRect", "ErrorEvent", "File", "FileReader", "FormData", "Headers", "History", "HtmlCanvasElement", "HtmlHeadElement", "Location", "MessageEvent", "Performance", "PerformanceTiming", "ProgressEvent", "ReadableStream", "Request", "RequestCredentials", "RequestInit", "RequestMode", "Response", "ServiceWorkerGlobalScope", "WebSocket", "Window", "Worker"] }
+
+[target.wasm32-wasi.dependencies]
+crypto-common = { version = "0.1", default-features = false, features = ["getrandom"] }
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+rustix = { version = "0.38", features = ["net", "process", "procfs", "termios", "time"] }
+subtle = { version = "2" }
+wasi = { version = "0.11" }
+web-sys = { version = "0.3", default-features = false, features = ["AbortController", "AbortSignal", "AddEventListenerOptions", "BinaryType", "BlobPropertyBag", "CloseEvent", "CloseEventInit", "Document", "ErrorEvent", "File", "FileReader", "FormData", "Headers", "History", "HtmlHeadElement", "Location", "MessageEvent", "ProgressEvent", "ReadableStream", "Request", "RequestCredentials", "RequestInit", "RequestMode", "Response", "ServiceWorkerGlobalScope", "WebSocket", "Window", "Worker"] }
+
+[target.wasm32-wasi.build-dependencies]
+crypto-common = { version = "0.1", default-features = false, features = ["getrandom"] }
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+rustix = { version = "0.38", features = ["net", "process", "procfs", "termios", "time"] }
+subtle = { version = "2" }
+wasi = { version = "0.11" }
+web-sys = { version = "0.3", default-features = false, features = ["AbortController", "AbortSignal", "AddEventListenerOptions", "BinaryType", "BlobPropertyBag", "CloseEvent", "CloseEventInit", "Document", "ErrorEvent", "File", "FileReader", "FormData", "Headers", "History", "HtmlHeadElement", "Location", "MessageEvent", "ProgressEvent", "ReadableStream", "Request", "RequestCredentials", "RequestInit", "RequestMode", "Response", "ServiceWorkerGlobalScope", "WebSocket", "Window", "Worker"] }
+
+[target.x86_64-apple-darwin.dependencies]
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+iana-time-zone = { version = "0.1", default-features = false, features = ["fallback"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+ring = { version = "0.17", features = ["std"] }
+rustix = { version = "0.38", features = ["event", "mm", "net", "param", "process", "procfs", "termios", "time"] }
+subtle = { version = "2" }
+
+[target.x86_64-apple-darwin.build-dependencies]
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+iana-time-zone = { version = "0.1", default-features = false, features = ["fallback"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+ring = { version = "0.17", features = ["std"] }
+rustix = { version = "0.38", features = ["event", "mm", "net", "param", "process", "procfs", "termios", "time"] }
+subtle = { version = "2" }
+
+[target.aarch64-apple-darwin.dependencies]
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+iana-time-zone = { version = "0.1", default-features = false, features = ["fallback"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+ring = { version = "0.17", features = ["std"] }
+rustix = { version = "0.38", features = ["event", "mm", "net", "param", "process", "procfs", "termios", "time"] }
+subtle = { version = "2" }
+
+[target.aarch64-apple-darwin.build-dependencies]
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+iana-time-zone = { version = "0.1", default-features = false, features = ["fallback"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+ring = { version = "0.17", features = ["std"] }
+rustix = { version = "0.38", features = ["event", "mm", "net", "param", "process", "procfs", "termios", "time"] }
+subtle = { version = "2" }
+
+[target.x86_64-unknown-linux-gnu.dependencies]
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+iana-time-zone = { version = "0.1", default-features = false, features = ["fallback"] }
+linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "xdp"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+ring = { version = "0.17", features = ["std"] }
+rustix = { version = "0.38", features = ["event", "mm", "net", "param", "process", "procfs", "termios", "thread", "time"] }
+subtle = { version = "2" }
+
+[target.x86_64-unknown-linux-gnu.build-dependencies]
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+iana-time-zone = { version = "0.1", default-features = false, features = ["fallback"] }
+linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "xdp"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+ring = { version = "0.17", features = ["std"] }
+rustix = { version = "0.38", features = ["event", "mm", "net", "param", "process", "procfs", "termios", "thread", "time"] }
+subtle = { version = "2" }
+
+[target.x86_64-unknown-linux-musl.dependencies]
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+iana-time-zone = { version = "0.1", default-features = false, features = ["fallback"] }
+linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "xdp"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+ring = { version = "0.17", features = ["std"] }
+rustix = { version = "0.38", features = ["event", "mm", "net", "param", "process", "procfs", "termios", "thread", "time"] }
+subtle = { version = "2" }
+
+[target.x86_64-unknown-linux-musl.build-dependencies]
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+iana-time-zone = { version = "0.1", default-features = false, features = ["fallback"] }
+linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "xdp"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+ring = { version = "0.17", features = ["std"] }
+rustix = { version = "0.38", features = ["event", "mm", "net", "param", "process", "procfs", "termios", "thread", "time"] }
+subtle = { version = "2" }
+
+[target.aarch64-unknown-linux-musl.dependencies]
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+iana-time-zone = { version = "0.1", default-features = false, features = ["fallback"] }
+linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "xdp"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+ring = { version = "0.17", features = ["std"] }
+rustix = { version = "0.38", features = ["event", "mm", "net", "param", "process", "procfs", "termios", "thread", "time"] }
+subtle = { version = "2" }
+
+[target.aarch64-unknown-linux-musl.build-dependencies]
+gimli = { version = "0.28", default-features = false, features = ["read", "std", "write"] }
+iana-time-zone = { version = "0.1", default-features = false, features = ["fallback"] }
+linux-raw-sys = { version = "0.4", default-features = false, features = ["elf", "errno", "general", "if_ether", "ioctl", "net", "netlink", "no_std", "prctl", "xdp"] }
+object = { version = "0.32", default-features = false, features = ["archive", "read_core", "unaligned", "write"] }
+ring = { version = "0.17", features = ["std"] }
+rustix = { version = "0.38", features = ["event", "mm", "net", "param", "process", "procfs", "termios", "thread", "time"] }
+subtle = { version = "2" }
+
+### END HAKARI SECTION
diff --git a/homestar-workspace-hack/build.rs b/homestar-workspace-hack/build.rs
new file mode 100644
index 00000000..92518ef0
--- /dev/null
+++ b/homestar-workspace-hack/build.rs
@@ -0,0 +1,2 @@
+// A build script is required for cargo to consider build dependencies.
+fn main() {}
diff --git a/homestar-workspace-hack/src/lib.rs b/homestar-workspace-hack/src/lib.rs
new file mode 100644
index 00000000..22489f63
--- /dev/null
+++ b/homestar-workspace-hack/src/lib.rs
@@ -0,0 +1 @@
+// This is a stub lib.rs.