Skip to content

SDF control-plane app — Tauri+Nuxt operator surface

Status: open/proposed

  • apps/sdf is the DarkFactory operator surface: the dashboard/observer component D-VSLI-distributed-work-runner-architecture reserves, built as a Tauri 2 + Nuxt 4 app with a first-class browser mode, scaffolded from template-tauri-nuxt by replaying the proven pumice recipe (D-0016-pumice-app-integration). See Context.
  • It supersedes the dashboard SPA and the thin wrapper. apps/dashboard (the D-0013-dashboard-app Vite+Vue SPA) and T-CKC1’s drafted apps/desktop are excised aggressively once SDF’s active-work view lands — good ideas are adopted, the code is removed. apps/pumice and apps/legacy-polish are peers, not part of SDF. See Decision.
  • Contract: ontogen-first, reconciled with the substrate schemas. SDF’s own Rust↔TS contract is generated by ontogen (HTTP + Tauri IPC + MCP transports, typed TS client, drift-gated) — the concrete convergence event D-0017-ontogen-shared-codegen-convergence deferred to. Substrate entities stay owned by the SDLC zod/markdown-contract schemas; a parity gate keeps SDF’s mirrored read-model aligned. See Decision.
  • Observe first, control later. Early phases are read-only over existing data planes (GET /api/state, lease refs, .sdlc/ logs). Bounded operator actions arrive in a later phase behind the platform-core token pattern; the human merge gate is untouched. See Migration / rollout.

Three dashboard/desktop artifacts overlap today, and the target architecture already names the component they should become:

ArtifactStateDisposition
apps/dashboard (Vite+Vue SPA, D-0013-dashboard-app)shipped, v1 viewsuperseded by SDF; excised at view landing
apps/desktop thin Tauri wrapper (T-CKC1)draft, unbuiltabsorbed into SDF; task closes superseded
apps/pumice, apps/legacy-polish (Tauri+Nuxt apps)shippedpeers; recipe donors only
Dashboard slot in D-VSLI-distributed-work-runner-architecturereserved (“Observers: dashboard”)SDF fills it

The polish row is scoped to SDF and still holds: polish is no part of the operator surface. It does not speak to polish’s place in the determined suite, which D-0011-polish-as-platform-experience (2026-07-19) settles separately — polish is ported there as a platform experience while remaining a peer here.

The requirement picture aggregates three sibling repos by the same author, reviewed 2026-07-16 (eight-agent research pass):

SourceContributes
sksizer/ontologicalontology-as-control-plane; live entity graph with containment drill-down; work-execution model (UnitOfWork → WorkflowTemplate → WorkExecution → StepResult); staleness/drift and write-collision signals; one-schema→HTTP/MCP/IPC/SSE codegen
sksizer/agentpantscanonical-Rust-API + ontogen-generated transports; agent-testable UI over plain HTTP; MCP tools mirroring the human UI; harness/terminal machine inventory; workflow graphs with human checkpoints; feature-flagged incremental panes
sksizer/zoosecure-agent cage patterns: deny-by-default egress policy, live event feed (bounded store, batched delivery, virtual scroll), streamed step-runner provisioning, discriminated-union state machines, reconcile-on-startup, blocked-event → one-click-amend

Together they describe one product: a control plane and metaharness for secure agent-based development. The substrate (D-VSLI-distributed-work-runner-architecture) and its adapters already expose the data SDF needs without violating S-0008-apps-consume-substrate-through-published-surfaces.

  1. Create apps/sdf (moon id sdf), scaffolded from template-tauri-nuxt replaying the pumice recipe: peer src-tauri/src-nuxt layout, Bun-ified (no pnpm lockfiles), moon.yml with tags: ['tauri'] + language: 'rust', src-tauri joins the root cargo workspace (pumice pattern — it shares the pinned ontogen rev deliberately).
  2. Supersede and excise. SDF replaces apps/dashboard as the operator surface. Once SDF ships the active-work view (Phase 2), apps/dashboard and its moon/justfile wiring are removed; T-CKC1 and T-JDEV close superseded; T-Z5MK’s two-Tauri-apps question resolves as “SDF is the operator app; pumice/polish are peers”. The Bun/Hono server, the zod contract, and packages/ts/dashboard-client survive — they are the Phase-2 data plane, not part of the excision.
  3. Nuxt supersedes D-0013’s frontend pick for the operator app. D-0013-dashboard-app chose Vite+Vue for a server-served SPA; SDF is a desktop-first app from a maintained template fleet (Storybook, per-worktree ports, drift sync, release pipeline) with two in-repo precedents. D-0013’s serving-model reasoning stays valid for what it decided; its framework choice does not bind SDF.
  4. ontogen-first contract with a reconciliation gate. SDF’s app-local entities are Rust schema structs; one cargo build generates the Axum HTTP and Tauri IPC transports, the MCP tool registry, and the typed TS client — committed and drift-gated (pumice’s codegen_drift.sh pattern). Substrate entities (task, milestone, lease…) remain owned by the SDLC zod/markdown-contract schemas; SDF mirrors them as a read-model and a parity gate asserts the mirror matches the upstream contract (JSON-schema comparison), failing CI on drift. Full single-source convergence is a follow-up decision under D-0017-ontogen-shared-codegen-convergence.
  5. Transport switching, not transport forking. UI code targets the generated Transport interface; desktop builds bind IPC, browser/dev builds bind HTTP — the agentpants/pumice dual-transport pattern. Every view is therefore exercisable in a plain browser, which is how the app’s own UI gets tested by agents building it.
  6. Observe first; controls are token-guarded and bounded. Read-only phases consume sanctioned seams only. Later operator actions (refresh, open worktree/terminal, dispatch tick, reset stuck-loop guard) ride the platform-core x-platform-token pattern on mutating routes; merge stays human.
  • One operator surface. Three overlapping artifacts violate the repo’s decision-first, one-owner convention; the target architecture has exactly one observer slot, and every month of coexistence doubles view maintenance.
  • The recipe is paid for. Pumice already proved template → monorepo conversion (Bun-ify, moon tags, cargo membership, CI shape) — SDF’s scaffold is a replay, not a research project.
  • Generated contracts are the testability story. TS types emitted from Rust structs cannot drift silently; HTTP/IPC/MCP from one definition means the human UI, the web UI, and agent tools cannot diverge; drift gates make the contract a CI property. This is the strongest available answer to “make it as testable as possible”.
  • Reconcile, don’t fork, the entity model. The substrate’s markdown-contract schemas are load-bearing for the whole plugin; SDF re-declaring them in Rust without a gate would create the project’s second competing ontology (the failure mode ontological itself exhibits).
  • Aggressive excision beats parity-someday. The SPA’s view is one screen; carrying it while SDF grows invites divergence. Adopt its good ideas (cross-linked panels, status color language, typed client, one-command dev) and delete it.
OptionVerdict
SDF supersedes dashboard + thin wrapper; pumice/polish peers (chosen)One owner for the operator surface; resolves T-Z5MK
CoexistTwo dashboards maintained indefinitely; rejected
Build into pumiceCouples unrelated domains; rejected
OptionVerdict
ontogen-first + parity gate against substrate schemas (chosen)Generated multi-transport + TS; reconciliation explicit
zod-first, ontogen laterDefers D-0017 again; hand-kept Rust types for the desktop half
Dual pipelines unreconciledTwo ontologies, no gate; the ontological repo’s known failure mode
  • D-0013-dashboard-app is partially superseded (frontend choice and the SPA it governs); its API/serving reasoning survives in the Bun/Hono server SDF consumes. T-CKC1, T-JDEV close superseded at Phase 3; just dev repoints to moon run sdf:dev.
  • The root cargo workspace gains apps/sdf/src-tauri; SDF inherits the pinned ontogen rev and its upgrade cadence (a coordinated-bump cost accepted for the shared model).
  • SDF’s own quality surface lives in moon (moon run sdf:check) + a per-app CI workflow; root sdlc.yaml quality_checks stay substrate-scoped.
  • .sdlc/-adjacent runtime state (SDF’s own pidfiles/registries) follows the existing dashboard-service conventions.
  • The engine event stream (D-VSLI-distributed-work-runner-architecture step 4) is not a dependency: early phases read files/HTTP; the event-stream consumer is added when Engine v0 exists.

Stacked-PR arc; each phase is independently adoptable and lands in dependency order (M-????, member tasks below):

#PhaseTaskShips
0This ADR + milestone + tasksthe decision
1ScaffoldT-WDXJapps/sdf builds desktop + browser; moon run sdf:check green; CI workflow
2Active-work viewT-6S37SDF renders GET /api/state (tasks/leases/worktrees/PRs) with polling + filter; desktop supervises the backend
3ExcisionT-QT7Xapps/dashboard removed; T-CKC1/T-JDEV closed superseded; D-0013 annotated
4ontogen backendT-UBPGgenerated HTTP+IPC+MCP + TS client; transport switch; drift + parity gates
5Read panelsT-0DLCleases (authoritative refs), orchestrator log tail, PR verdict board
6Safe controlsT-DBALtoken-guarded refresh / open-worktree / dispatch-tick / guard-reset
  • Full contract convergence — whether substrate schemas eventually generate from (or into) ontogen structs; owned by D-0017-ontogen-shared-codegen-convergence, triggered after Phase 4 runs.
  • Event-stream contract — SDF’s consumer for Engine v0’s status socket/JSONL logs; decided when the D-VSLI engine lands.
  • Embedded consumer dashboard — whether the plugin ships any web UI for symlink-install consumers after the excision (the INDEX_HTML string’s fate beyond GET /api/state).
  • Filename follows D-0002-entity-identifier-shape: D-0018- prefix, slug sdf-control-plane-app. Hand-authored against the decision body template.
  • Research provenance: eight-subagent review (2026-07-16) of ontological, agentpants (+PR corpus), zoo, template-tauri-nuxt, rust-ontogen (origin/main v0.4.0; local clones of ontogen were 148 commits stale), the existing dashboard stack, the Dark Factory corpus, and monorepo conventions.

← Back to Decisions