Skip to content

Pumice desktop app integration — vendor as a co-tenant, converge to shared

Status: open/proposed

Pending acceptance on merge. The trajectory is settled (vendor now, converge later); the open items in Open questions are sequencing and mechanism details, not blockers.

  • Pumice — an existing standalone Tauri v2 + Nuxt 4 desktop application with its own Rust crates and code-generation pipeline — is brought into this monorepo as apps/pumice, fulfilling D-0012-monorepo-tooling’s polyglot brief with a real, load-bearing second ecosystem rather than a thin validating wrapper. See Context.
  • The integration is phased. Short term, pumice lands as a self-contained co-tenant: it shares the monorepo’s tooling substrate (moon graph, CI, justfile, lefthook) but no application code. Long term, it converges — shared Rust crates promote to packages/rust/, and any substrate consumption goes through the S-0008-apps-consume-substrate-through-published-surfaces adapter seam. See Decision.
  • The JS/TS ecosystem unifies on Bun, per D-0012-monorepo-tooling. Pumice’s frontend migrates from pnpm to Bun as part of onboarding; the three pnpm lockfiles are retired. See Decision.
  • Pumice is a fat app (its own frontend, domain crates, ontogen codegen, template-sync, release pipeline), which distinguishes it from the thin Tauri wrapper drafted in T-CKC1. Their relationship is resolved in Notes. See Why.

D-0012-monorepo-tooling fixed the workspace shape (apps/ + packages/<ecosystem>/ on moon) and named “a Rust Tauri app” as the polyglot validating case. T-CKC1 drafts that case as a thin wrapper: a minimal src-tauri embedding the dashboard SPA as a committed static bundle.

Pumice is a different and larger opportunity. It is an already-built Tauri v2 desktop application maintained in sksizer/pumice, with:

LayerTechnologyNote
Desktop shellTauri v2 (src-tauri, crate pumice-app)beforeBuildCommand drives the frontend build
FrontendNuxt 4 + Vue 3 (src-nuxt)Own pnpm project plus Storybook
Domain logicThree Rust crates (pumice, pumice-config, pumice-desktop)Path deps; git dep on rust-ontogen pinned by rev
Shared TSpackages/admin-types, packages/nuxt_admin_layerConsumed via file: deps
Codegenontogen via src-tauri/build.rsEmits committed .ts/.rs on every cargo build
Toolchainmise (node/pnpm/rust/python/uv)Dynamic dev ports via exec() scripts
Orchestrationjustfile + Tauri config + lefthook + release-itFour GitHub workflows

Bringing pumice in tests the workspace against a genuinely polyglot, non-trivial application — the outcome D-0012-monorepo-tooling wanted proof of — instead of a scaffold with nothing behind it.

This decision settles the trajectory and the package-manager stance. Status is open/proposed; it flips to open/accepted on merge. The per-task mechanics are decomposed in M-0014-pumice-desktop-app-integration.

  1. Adopt pumice as apps/pumice. An app stays flat (not partitioned by ecosystem) per D-0012-monorepo-tooling — pumice is polyglot internally (Rust core plus a web frontend), exactly the case that rule anticipates.
  2. Phase the integration: co-tenant first, converge later.
    • Phase 1 (co-tenant): vendor pumice’s tree under apps/pumice intact; wire a thin apps/pumice/moon.yml whose tasks shell to pumice’s existing commands (system toolchain), matching the apps/dashboard pattern. Pumice shares tooling only — no application-code coupling to the substrate.
    • Phase 2 (converge): promote genuinely shared Rust crates to packages/rust/, introduce a workspace-level Cargo.toml once two Rust projects share code, and route any substrate consumption through the S-0008-apps-consume-substrate-through-published-surfaces seam.
  3. Unify pumice’s frontend on Bun. Per D-0012-monorepo-tooling’s Bun-everywhere standard, migrate src-nuxt and the packages/* frontend libraries from pnpm to Bun and retire the three pnpm lockfiles. moon’s system-toolchain tasks then drive bun/cargo/tauri uniformly.
  4. Keep pumice’s crates an isolated cargo unit in Phase 1. There is no workspace-wide Cargo.toml today; pumice’s crates keep their relative path deps under apps/pumice and build under moon’s rust toolchain. A shared cargo workspace is a Phase-2 concern gated on the first shared crate.
  • A real polyglot load, not a scaffold. D-0012-monorepo-tooling wanted the Rust toolchain proven under moon against a genuine app. Pumice is that app — a maintained Tauri product — where T-CKC1 is a thin wrapper with no domain behind it. Pumice validates the workspace harder.
  • Phasing bounds blast radius. Vendoring intact and shelling to pumice’s own commands lets pumice build under moon in days, deferring the invasive work (Bun migration, crate promotion, adapter seams) to isolated, reviewable tasks. This mirrors D-0012-monorepo-tooling’s own “add trees now, sequence the lift separately” stance.
  • Bun-everywhere is a standing standard. D-0012-monorepo-tooling chose one JS package manager and made “no stray lockfiles” a success criterion. Admitting pumice’s pnpm lockfiles permanently would reopen exactly the dual-lockfile mess that decision closed, so the migration is not optional — only its sequencing is.
  • Fat app, flat placement. Pumice pairs a Rust core with a web frontend, so apps/pumice (flat) is the honest placement; splitting it by ecosystem would misrepresent a single deployable.
OptionShapeVerdict
Co-tenant then converge (chosen)Vendor intact; share tooling; promote shared code laterFast to land, defers risk, reaches full integration
Full integration up frontBun migration + crate promotion + adapter seam in one pushHonest end state but a large, hard-to-review single move
Submodule / external referenceKeep pumice its own repo, reference itNo shared graph/CI; fails the “one monorepo” goal

Co-tenant-then-converge is chosen: it reaches the same end state as full integration while keeping each step independently reviewable.

OptionVerdict
Migrate pnpm → Bun (chosen)Satisfies D-0012-monorepo-tooling; one PM, no stray lockfiles
Keep pnpm as a per-app exceptionMechanically possible under system tasks, but reopens the dual-lockfile mess D-0012 closed

Whether the tree lands as a clean vendored copy (pumice history stays in sksizer/pumice) or via git subtree (history grafted into this monorepo) is recorded as an open question — it is a one-way door for this repo’s history and wants explicit sign-off before the Phase-1 move.

  • M-0014-pumice-desktop-app-integration decomposes the implementation; this ADR ships the decision and standards only.
  • Pumice’s own justfile, lefthook, and codegen stay intact under apps/pumice; the root justfile/lefthook/moon graph gain pumice entries but are not replaced — consistent with D-0012-monorepo-tooling’s “moon sits alongside” stance.
  • CI grows a pumice-affected path that installs Tauri’s Linux system dependencies and runs the Rust + codegen-drift gates pumice already defines.
  • Two Tauri apps may coexist (apps/pumice and the thin apps/desktop from T-CKC1) until Notes’s convergence question resolves.
  1. Land this ADR and M-0014-pumice-desktop-app-integration (this arc’s first PR).
  2. Phase 1 tasks: vendor to apps/pumice + thin moon.yml; migrate frontend to Bun; reconcile the Rust toolchain; model codegen as a moon task; fold CI; repoint template-sync scripts.
  3. Phase 2 tasks: promote shared crates to packages/rust/; converge with T-CKC1 and wire the S-0008-apps-consume-substrate-through-published-surfaces seam if pumice consumes the substrate.
  • Code-move mechanism. Clean vendored copy versus git subtree with grafted history. Recommendation: clean copy (matches how D-0013-dashboard-app scaffolds apps; keeps this repo’s history legible), tagging a handoff commit in sksizer/pumice. Confirm before the Phase-1 move.
  • Relationship to T-CKC1. Does the fat apps/pumice supersede the thin apps/desktop wrapper, or do both persist? Resolved in Phase 2, not here.
  • Rust version. Pumice pins 1.93.0 exact; this workspace tracks stable. Relax pumice to stable or pin apps/pumice locally — decided in T-P4LZ.
  • Template-sync ownership. Pumice’s upstream-template sync assumes a repo-root CWD; under apps/pumice the helper scripts need repointing (T-V6JD), or the sync workflow retires.
  • This is the “application decision” D-0012-monorepo-tooling defers to: how a given application builds and ships is decided in that application’s own decision. D-0013-dashboard-app is the sibling for the dashboard.
  • Pumice is fat, T-CKC1 is thin. This ADR does not delete or supersede T-CKC1; it introduces a parallel, larger app and flags the convergence question for Phase 2.
  • Filename follows D-0002-entity-identifier-shape: D-0016- prefix (incrementing decision id), slug pumice-app-integration. Hand-authored against the decision body template — there is no sdlc decision create verb.

← Back to Decisions