SDF control-plane app — Tauri+Nuxt operator surface
Status: open/proposed
Summary
Section titled “Summary”apps/sdfis 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 fromtemplate-tauri-nuxtby 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) andT-CKC1’s draftedapps/desktopare excised aggressively once SDF’s active-work view lands — good ideas are adopted, the code is removed.apps/pumiceandapps/legacy-polishare 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.
Context
Section titled “Context”Three dashboard/desktop artifacts overlap today, and the target architecture already names the component they should become:
| Artifact | State | Disposition |
|---|---|---|
apps/dashboard (Vite+Vue SPA, D-0013-dashboard-app) | shipped, v1 view | superseded by SDF; excised at view landing |
apps/desktop thin Tauri wrapper (T-CKC1) | draft, unbuilt | absorbed into SDF; task closes superseded |
apps/pumice, apps/legacy-polish (Tauri+Nuxt apps) | shipped | peers; recipe donors only |
| Dashboard slot in D-VSLI-distributed-work-runner-architecture | reserved (“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):
| Source | Contributes |
|---|---|
sksizer/ontological | ontology-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/agentpants | canonical-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/zoo | secure-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.
Decision
Section titled “Decision”- Create
apps/sdf(moon idsdf), scaffolded fromtemplate-tauri-nuxtreplaying the pumice recipe: peersrc-tauri/src-nuxtlayout, Bun-ified (no pnpm lockfiles),moon.ymlwithtags: ['tauri']+language: 'rust',src-taurijoins the root cargo workspace (pumice pattern — it shares the pinnedontogenrev deliberately). - Supersede and excise. SDF replaces
apps/dashboardas the operator surface. Once SDF ships the active-work view (Phase 2),apps/dashboardand its moon/justfile wiring are removed;T-CKC1andT-JDEVclose 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, andpackages/ts/dashboard-clientsurvive — they are the Phase-2 data plane, not part of the excision. - 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.
- ontogen-first contract with a reconciliation gate. SDF’s app-local
entities are Rust schema structs; one
cargo buildgenerates the Axum HTTP and Tauri IPC transports, the MCP tool registry, and the typed TS client — committed and drift-gated (pumice’scodegen_drift.shpattern). 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. - Transport switching, not transport forking. UI code targets the
generated
Transportinterface; 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. - 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-tokenpattern 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
ontologicalitself 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.
Options considered
Section titled “Options considered”Lineage
Section titled “Lineage”| Option | Verdict |
|---|---|
| SDF supersedes dashboard + thin wrapper; pumice/polish peers (chosen) | One owner for the operator surface; resolves T-Z5MK |
| Coexist | Two dashboards maintained indefinitely; rejected |
| Build into pumice | Couples unrelated domains; rejected |
Contract source of truth
Section titled “Contract source of truth”| Option | Verdict |
|---|---|
| ontogen-first + parity gate against substrate schemas (chosen) | Generated multi-transport + TS; reconciliation explicit |
| zod-first, ontogen later | Defers D-0017 again; hand-kept Rust types for the desktop half |
| Dual pipelines unreconciled | Two ontologies, no gate; the ontological repo’s known failure mode |
Consequences
Section titled “Consequences”- 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-JDEVclose superseded at Phase 3;just devrepoints tomoon run sdf:dev. - The root cargo workspace gains
apps/sdf/src-tauri; SDF inherits the pinnedontogenrev 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; rootsdlc.yamlquality_checksstay 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.
Migration / rollout
Section titled “Migration / rollout”Stacked-PR arc; each phase is independently adoptable and lands in dependency order (M-????, member tasks below):
| # | Phase | Task | Ships |
|---|---|---|---|
| 0 | This ADR + milestone + tasks | — | the decision |
| 1 | Scaffold | T-WDXJ | apps/sdf builds desktop + browser; moon run sdf:check green; CI workflow |
| 2 | Active-work view | T-6S37 | SDF renders GET /api/state (tasks/leases/worktrees/PRs) with polling + filter; desktop supervises the backend |
| 3 | Excision | T-QT7X | apps/dashboard removed; T-CKC1/T-JDEV closed superseded; D-0013 annotated |
| 4 | ontogen backend | T-UBPG | generated HTTP+IPC+MCP + TS client; transport switch; drift + parity gates |
| 5 | Read panels | T-0DLC | leases (authoritative refs), orchestrator log tail, PR verdict board |
| 6 | Safe controls | T-DBAL | token-guarded refresh / open-worktree / dispatch-tick / guard-reset |
Open questions
Section titled “Open questions”- 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, slugsdf-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.