Skip to content

Architecture decision register

Terminal retirement — local implementation, 2026-10-20

Section titled “Terminal retirement — local implementation, 2026-10-20”

The current working tree removes interactive terminals and Redis while preserving command/script Remote Actions and authorized session/transcript history with existing retention. Admin has a read-only history viewer; Core advertises no terminal capability and legacy terminal operations cannot create work. This implementation is local and awaits user testing; older published implementation descriptions below remain historical. See the retirement plan and evidence.1

observed describes an implemented choice not accompanied by a historical approval record. accepted records an explicit current decision. proposed, rejected and superseded have their ordinary meanings.

ID State Decision Rationale / consequence
ADR-001 observed Keep a pnpm TypeScript monorepo with separate backend, desktop, admin, website and shared package Current structure supports shared contracts and coordinated changes
ADR-002 observed Keep the backend as a modular monolith Scale does not justify service decomposition; policy and worker boundaries are the real gaps
ADR-003 accepted knowledge/ is the only canonical documentation and planning source Prevents drift; raw sources, compiled wiki and schema are versioned together
ADR-004 accepted Project the documentation website from canonical wiki files Website remains a renderer rather than a parallel source
ADR-005 accepted (2026-08-29) Centralize resource and tenant authorization policies Implemented across tenant-sensitive route families; eliminates inconsistent controller-local checks
ADR-006 accepted (2026-08-29) Store OAuth challenge and asynchronous job state durably in PostgreSQL Implemented with atomic challenge consumption and leased/recoverable jobs; supports multiple replicas
ADR-007 accepted (2026-08-29) Use Authorization Code + PKCE and one-time desktop callback codes Implemented; removes bearer tokens from deep links and binds login to the initiator
ADR-008 accepted (2026-08-29) Use a dedicated durable worker for import and long GitHub synchronization Implemented with persisted import/sync jobs, leases, checkpoints and cancellation
ADR-009 accepted (2026-08-29) Treat idempotency as part of retriable write contracts Implemented for timer, activity and screenshot writes with server records and encrypted desktop retry
ADR-010 accepted (2026-08-29) Model remote-action user approval and privilege as independent per-revision policies; every elevated execution must request native operating-system authorization Supports administrator-defined approval while prohibiting silent root/SYSTEM execution in the initial design
ADR-011 superseded (2026-10-20, local implementation pending publication) Include interactive web terminals in the first Remote Actions release, using an admin WSS terminal, a device-owned PTY/ConPTY and a backend/Redis relay with no direct browser-to-device connection Supports immediate interactive administration while preserving NAT traversal, current authorization, multi-replica routing and OS-mediated elevation
ADR-012 accepted (2026-08-29) Use one embedded llama.cpp runtime per platform with independently signed GGUF AI Packs, an organization default and optional per-installation model assignment Keeps the desktop artifact small, supports Qwen/Gemma through one engine, preserves local-only inference and allows hardware-compatible staged rollout
ADR-013 accepted (2026-08-29) Use one shared Ed25519-authenticated DesktopInstallation identity for every device-scoped feature Prevents competing Device Compliance, Local AI and Remote Actions registrations while keeping organization access derived from the effective-membership resolver
ADR-014 accepted (2026-08-29) Make Device Compliance an administrator-configured, read-only, server-evaluated capability while retaining Remote Actions as a separately authorized execution capability Administrators publish typed immutable requirements; signed clients report bounded posture facts; findings cannot automatically execute or authorize Remote Actions in the first release
ADR-015 accepted (2026-08-29) Make MonStaff core entities provider-independent and retain GitHub as an optional first-class integration Allows complete operation without GitHub while preserving GitHub login, discovery, synchronization, write-back and analytics through explicit identities, connections and external links
ADR-016 accepted (2026-08-29) Treat the current implementation program as a pre-production greenfield cutover with no MonStaff data/client backward compatibility Allows direct schema/API/client replacement and database reset; functional, security and external-source correctness gates remain
ADR-017 accepted (2026-08-29) Use OpenTelemetry as the agent event contract, an authenticated Collector gateway and ClickHouse for telemetry/chat analytics, while PostgreSQL remains the authority for official developer-time allocation; exclude SigNoz Separates high-volume append-only evidence from transactional time invariants and supports first-release chat capture without introducing an external observability product
ADR-018 accepted (2026-08-30) Use DeveloperWorkSession plus ProjectTimeAllocation as the automatic-time authority and project finalized allocations idempotently into closed TimeEntry(source = AGENT_ALLOCATION) rows Gives customer allocation and ordinary reporting one finalized time-entry boundary without treating provisional agent effort as customer-reportable or creating a second customer ledger
ADR-019 accepted (2026-08-31) Open user-level managed-device shells directly from the Admin Devices inventory without administrator reauthentication, reason entry or desktop-user approval Matches the unattended managed-device operating model while retaining role authorization, device proof, audit, bounded tickets, expiry, transcript controls and kill switches
ADR-020 accepted (2026-08-31) Use one shared static en-US/it-IT localization core with separate React, Svelte and Electron-main state Keeps profile/device resolution consistent while leaving machine contracts, timezone and report-recipient locale independent; see the dedicated decision
ADR-021 superseded (2026-09-05 by ADR-024) Build MonStaff Preview as a Rust/Tauri 2 and React/shadcn desktop client that installs and operates alongside the supported Electron client Creates an independently identifiable evaluation path; a server-owned tracking collector lease prevents duplicate activity and screenshots, and replacing Electron requires a later explicit decision
ADR-022 accepted (2026-09-03) Eliminate key translation and rdev from native desktop input monitoring, deriving only coarse aggregate counters via an isolated content-free collector Eliminates macOS main-queue translation crashes, prevents keystroke/layout inspection at FFI boundary, contains affected Preview .15/.16 builds, and establishes fail-closed capability gates
ADR-023 accepted (2026-09-04) Make monstaff-core the single-instance per-user runtime authority with the monstaff CLI and the Tauri GUI as interchangeable clients over one authenticated, versioned local protocol Removes duplicated session, lease, collector and queue ownership between clients; signed installed qualification remains MCC6
ADR-024 accepted (2026-09-05) Retire the Electron client and the TypeScript agent-cli; ship one MonStaff desktop application made of monstaff-core, the Tauri GUI and the monstaff CLI, fenced only by a minimum/maximum desktop version Ends the ADR-021 coexistence exception; removes duplicated desktop domain, dual flag families and the second release track; installed qualification gates (MCC6, TD5) remain and govern rollout; implemented through SDC1–SDC4 on 2026-09-05 (commits 220df7f, 2ccf2d2, 99e1f8e, c2a3eb5); see the dedicated decision
ADR-025 superseded (2026-09-05 by ADR-026) Promote every successful tagged “Release MonStaff” run automatically through a workflow_run trigger on the promotion workflow The trigger never fired: GitHub emits no workflow_run event for a release the tagging workflow created with GITHUB_TOKEN; the goal survives in ADR-026
ADR-026 accepted (2026-09-05) The last job of every successful tagged “Release MonStaff” run dispatches “Promote qualified MonStaff candidate” for its own run, and the promotion preflight waits for that run to complete before applying the unchanged verification Automatic promotion works with the repository token and no new secret; the manual pnpm release:promote dispatch remains for re-promotion and older candidates; a human gate still returns only through environment protection rules
  • Context: current local inference assumes a separately installed Ollama service and organization settings hold only one provider/model string. The accepted product direction requires a background-managed pack, administrator default and different models on different installations.23
  • Alternatives considered: bundle Ollama and a model in every installer; require users to install Ollama; build separate Qwen/Gemma engines; use cloud inference only; or distribute one embedded runtime with independent packs. Bundled weights make every desktop artifact large, external Ollama is unmanaged, separate engines duplicate lifecycle/security work and cloud-only violates the local objective.
  • Choice: use one pinned llama.cpp sidecar per platform, signed approved GGUF packs, organization policy and per-installation override. Keep deterministic classification as the always-available fallback.
  • The runtime is shipped and signed with the desktop application; model weights are not part of the ordinary desktop update artifact.
  • Approved model packs are immutable, independently versioned, signed, hash-verified and downloaded in the background after local-AI disclosure and policy resolution.
  • Organization administrators choose only from the approved catalog. They may set automatic hardware resolution, an organization default or a specific installation override.
  • A local installation or inference failure falls back to deterministic local classification and never enables an external provider.
  • A random reusable desktop installation identity is a shared platform concept. Local AI and the active Remote Actions plan must not create competing installation identifiers.
  • GGUF compatibility remains conditional on a pinned engine build supporting the model architecture, tokenizer/chat template and generation profile.
  • Greenfield cutover: remove free-form local-model and ollama-local compatibility settings; managed Local AI starts with dedicated catalog/policy entities. Server Ollama/OpenRouter remain only if independently supported as separate product options.
  • Verification: follow the phase gates and completion criteria in the Local AI Pack implementation plan; acceptance requires both model families on signed platform clients, tenant-safe policy resolution, tamper rejection and safe rules-only fallback.
  • DesktopInstallation is owned by one user registration and has no permanent organization tenant. Organization visibility is resolved through the shared effective-membership port on every scoped request.
  • The Electron main process owns an Ed25519 private key encrypted through safeStorage; the backend stores the public key and verifies canonical request signatures, nonces and timestamps in addition to the current user session.
  • Core platform/version/lifecycle fields live on the shared record. Device Compliance enrollment/posture, Local AI compatibility/install health and Remote Actions execution/terminal capabilities live in feature-specific extensions.
  • User switching, revocation or key loss cannot silently rebind an installation. A new registration and keypair are required where the foundation plan specifies.
  • Device signatures authenticate an installation but never grant organization access or feature authority by themselves.
  • The initial capability baseline is Windows 11 23H2 x64, macOS 14 arm64/x64 and Ubuntu 24.04 LTS x64; ordinary MonStaff functionality remains available when a feature capability is unsupported.
  • Weakening the cryptographic, replay, tenant or hardware-fingerprint defaults requires a new accepted decision.
  • Verification: execute DI0 in the desktop installation foundation plan before dependent plans complete their persistence phases.
  • Context: the accepted product direction requires organization administrators to define desktop compliance requirements in the web application while commands, scripts and interactive terminals remain part of Remote Actions.4
  • Alternatives considered: implement a native cross-platform MDM first; hard-code one global compliance baseline; let administrators write arbitrary probe scripts; evaluate locally only; or add a typed catalog with server-side policy evaluation. Native MDM is a separate multi-platform program, hard-coded requirements are not organization-manageable, arbitrary probes collapse compliance into remote execution and local-only evaluation makes policy changes dependent on desktop releases.
  • Choice: expose a reviewed typed control catalog and visual policy builder. Published versions are immutable. The desktop main process collects only requested supported read-only facts, and the backend evaluates them against the exact organization policy version.
  • Device Compliance reuses DesktopInstallation but owns separate organization enrollment, settings, policy, snapshot, evaluation, finding, exception, retention, audit and kill-switch state.
  • The initial assurance level is authenticated user-session posture, not hardware attestation, privileged enforcement or native MDM.
  • UNKNOWN, ERROR, UNSUPPORTED, PERMISSION_DENIED and STALE are explicit and never imply compliance.
  • A finding may link to an enabled same-organization Remote Action, but the administrator must explicitly enter the ordinary Remote Actions launch flow. Compliance cannot mint tickets, bypass recent reauthentication or weaken approval/elevation policy.
  • Automatic remediation, access gating, privileged agents and native MDM require later accepted decisions.
  • Verification: follow the gates in the Device Compliance implementation plan; completion requires signed-client platform evidence, deterministic evaluation, tenant/replay tests, privacy approval and independent rollout review.
  • Context: current users and organizations require GitHub IDs; the only interactive authentication is GitHub OAuth; supported project creation requires repository identifiers; issue assignment and several analytics paths use GitHub login as the user key. The product direction requires MonStaff to operate without GitHub while retaining its complete GitHub integration.56
  • Alternatives considered: keep GitHub mandatory and add only manual projects; make GitHub fields nullable without changing service boundaries; fork a separate non-GitHub product mode; or make core entities native and move GitHub behind explicit integration links. Manual projects alone do not solve identity or tenant coupling, nullable columns leave behavioral assumptions intact, and separate modes would duplicate authorization and client behavior.
  • Choice: User, Organization, membership, Project, work item, iteration and time data are provider-neutral MonStaff entities. Authentication identities, provider credentials, membership provenance and external resource links are explicit records. GitHub remains the first and best-supported adapter, not a mandatory tenant root.
  • A clean deployment must support local bootstrap/enrolment, native organizations, native projects and ordinary tracking/reporting without any GitHub configuration.
  • GitHub OAuth login remains supported, but identity scopes and organization integration authority are separated. Provider identity is keyed by immutable subject, never merged automatically by email.
  • GitHub membership synchronization owns only its provenance grant and cannot delete independent native access.
  • Every organization-scoped feature, including Desktop Installation and Device Compliance, authorizes through one provider-neutral effective-membership resolver. PI3 supplies the first supported grant-aware implementation; no compatibility adapter is shipped. Provider provenance cannot become a feature authorization predicate or emit membership loss while another active grant survives.
  • No existing MonStaff IDs or records require preservation under ADR-016; new internal IDs remain stable after the first supported release.
  • Disconnecting GitHub stops synchronization/write-back but does not delete internal time, project, work-item or audit data.
  • GitHub organization/repository discovery, issues, Projects V2, workflow write-back and commit analytics are mandatory functional gates throughout the greenfield cutover.
  • Other providers remain out of the first implementation, but the boundary must permit future adapters without another core-domain migration.
  • Verification: execute the provider-independent platform plan. General availability requires both a network-isolated no-GitHub end-to-end suite and the complete GitHub functional suite, plus clean-install, tenant and security evidence.
  • Context: MonStaff is not in production, has no historical MonStaff data and has no supported deployed clients whose schema/API behavior must remain compatible.7
  • Choice: active plans may replace Prisma schema, migrations, REST/shared/IPC contracts and desktop/admin clients atomically. Development databases may be reset and fixtures reseeded.
  • Remove legacy bridges, compatibility projections, dual reads/writes, data backfills, ID/session preservation and adoption thresholds whose only purpose is supporting an already deployed MonStaff version.
  • Do not preserve obsolete ImportConnection, GitHub-owned core fields, legacy /issues adapters, free-form local-AI settings or old desktop capability behavior solely for compatibility.
  • This decision does not weaken security controls, idempotency, crash recovery, audit/retention, signed-client validation, provider rate/retention semantics or truthful Hubstaff history import.
  • GitHub remains a required product integration. Its desired login, discovery, synchronization, write-back and analytics behavior is verified as a functional suite, not as compatibility with stored production records.
  • Feature flags and rollback drills remain useful for unsafe capabilities and operational failure, but database rollback to a legacy schema and mixed-version client support are not release requirements.
  • After the first supported production release, future changes require an explicit compatibility/migration policy; ADR-016 cannot be reused to discard production data.
  • Verification: every active plan must identify and delete obsolete compatibility work, prove a clean database bootstrap and run its current end-to-end/security gates.
  • Context: the product must integrate Claude Code, Codex and Pi, switch project/work-item context automatically, preserve one ordinary developer timer, sum concurrent agent effort independently and optionally ingest user/assistant chat from the first release.89
  • Alternatives considered: store all events only in PostgreSQL; use ClickHouse as the sole official time ledger; deploy SigNoz/ClickStack as the product UI; implement separate provider-specific collectors; or use OTEL only for infrastructure diagnostics. PostgreSQL-only storage is a poor fit for high-volume traces/chat, ClickHouse alone does not provide the required transactional official-time invariants, an external observability UI duplicates MonStaff policy/authorization, provider-specific pipelines fragment semantics and diagnostics-only OTEL does not solve the requested accounting contract.
  • Choice: provider adapters emit one versioned MonStaff lifecycle contract through OTEL. Traces represent sessions/turns/tools and counted active intervals, log records represent finalized chat messages, and metrics represent operational health. An authenticated Collector gateway redacts, enriches, batches and exports to MonStaff-owned ClickHouse schema. A durable projector derives official allocations into PostgreSQL.
  • ClickHouse stores append-only raw OTEL and normalized analytical projections; PostgreSQL stores policy, context bindings, developer sessions, normalized agent segments, allocation revisions and the official time projection.
  • The standard developer clock is the union of human-active intervals. Agent effort sums concurrent counted agent intervals. Developer time is allocated at event boundaries in proportion to simultaneously active agent effort and must conserve the developer total exactly.
  • User and assistant chat bodies may be enabled in the first release using explicit OFF, METADATA_ONLY and CONTENT policy modes. Content never includes chain-of-thought, hidden prompts, credentials, raw tool output, environment variables or file contents by default.
  • SigNoz, ClickStack and HyperDX are excluded from runtime and UI. MonStaff admin remains the tenant-authorized session, chat and reporting interface.
  • Provider plugins do not receive shared public bearer tokens. Ingestion uses short-lived, revocable grants bound to the accepted Ed25519 DesktopInstallation identity, and the gateway supplies trusted organization/user/installation attributes.
  • Pi is supported through a native extension plus skill and direct local bridge because it does not expose the same MCP client surface; Claude Code and Codex additionally use their supported MCP/hook/skill surfaces.
  • No sampled or lossy signal may drive official effort/allocation or chat audit. Diagnostic-only telemetry may use a separate sampling policy.
  • Source from tst-telemetry may be incorporated only after provenance and license approval and after removal of shared-token, SigNoz, Git-email identity and fixed-retention assumptions.
  • Verification: follow AT0–AT10 in the agent telemetry, chat audit and parallel-time plan. Production enablement requires exact allocation conservation, replay/late-event correctness, signed client canaries, tenant/privacy review and ClickHouse load/restore/deletion evidence.
  • Accepted refinement (2026-09-08): automatic developer tracking may start with an organization and no project when telemetry is available. Unattributed time remains explicit in both the session ledger and timesheet projections; developer corrections revise the projections and take precedence over late telemetry. Implemented locally; release pending.10

  • Context: Agent Telemetry defines provisional/final project allocations, while the Customer plan conserves customer seconds against stopped TimeEntry.duration. Leaving both as possible report authorities would permit omission or double counting of automatic time.1112

  • Choice: DeveloperWorkSession and ProjectTimeAllocation are canonical for automatic developer-time distribution. Locked/finalized allocations project idempotently to closed TimeEntry rows with source = AGENT_ALLOCATION and stable source revision identity.

  • Provisional allocations and raw agent-effort intervals are never customer-reportable.

  • Customer allocation and customer-facing reports consume the finalized TimeEntry projection. They do not read ProjectTimeAllocation as a parallel customer ledger.

  • Reopening or correcting automatic allocation produces a new projection revision and marks dependent customer allocation/report state stale. Frozen report snapshots remain immutable and are superseded rather than rewritten.

  • Manual time entries remain authoritative manual records and are not rewritten by the telemetry projector.

  • Verification: AT0 supplies golden projection/replay/reopen fixtures; CU0/CU1 consume them before customer persistence closes; conservation tests prove automatic developer time, projected time entries and customer allocations never exceed their respective authoritative totals.

  • Context: the implemented interactive-terminal path required device selection, a reason, administrator password/TOTP reauthentication, a native desktop approval and a second password/TOTP reauthentication before attach. That journey conflicts with the accepted unattended administration model for organization-managed devices.13
  • Choice: an online compatible device exposes an SSH action in the Admin Devices inventory. One click creates and attaches a bounded user-level terminal. The server selects the first reported allowlisted shell and fixes approvalPolicy = NOT_REQUIRED, privilegeLevel = USER, the idle timeout and the organization-bounded hard lifetime.
  • Terminal create and connect-ticket routes require the ordinary current OWNER/ADMIN session and current organization access, but not a recent-authentication grant. The request accepts no reason, approval-policy, privilege or arbitrary shell fields from the browser.
  • The desktop claims the signed installation-scoped session and opens the PTY/ConPTY without a user prompt. This grants no elevation; any future elevated terminal remains a separate decision and must retain native operating-system authorization.
  • The Admin Remote access section no longer owns a Terminal tab. It retains action launch, library, history, terminal-session metadata and audit. Closing the shell UI uses the existing bounded disconnect/reconnect behavior, and explicit termination remains available.
  • Organization/deployment terminal switches, current membership, recent signed heartbeat, capability allowlisting, per-device/admin/organization concurrency, single-use audience-bound relay tickets, transcript retention, input non-persistence, frame bounds, revocation and termination continue unchanged.
  • Signed command/script actions retain their approval matrix and recent reauthentication. Transcript disclosure retains its dedicated recent-authentication grant.
  • Verification: backend integration proves server-derived unattended user-level creation without a recent-authentication header, direct CLAIMED → READY, admin ticket issuance, cross-replica relay, ticket replay rejection and device reconnect. Admin/Desktop typechecks, lint and production builds cover the client cutover.14
  • Context: the product owner requested a complete alternative desktop implementation and required both clients to remain available on the public download page. The current Electron application owns collection, native integration, installation identity and updates under one product identity; the server prevents two open timers but does not prevent two installed clients from collecting evidence for the same timer.1516
  • Alternatives considered: rewrite the existing client in place; keep Electron and embed isolated Rust/WASM modules; ship an untracked experimental binary; or build a separately identified Tauri application against shared server contracts. In-place replacement violates the parallel-evaluation requirement, isolated modules do not test a complete alternative shell, and an untracked binary cannot be operated safely.
  • Choice: create MonStaff Preview with Tauri 2, Rust, React, TypeScript and shadcn/ui. Keep Electron supported. Give Preview its own application identifier, executable/product label, URL scheme, data and credential namespaces, updater channel and release artifacts.
  • Each physical installation registers its own Ed25519 identity. DesktopInstallation records client family, release channel and bounded capability metadata; credentials and private keys are never shared between Electron and Preview.
  • The backend owns an expiring, fenced collector lease for the running time entry. Activity heartbeat, activity bulk ingestion and screenshot upload/registration accept collection only from the current lease holder. Electron becomes lease-aware before Preview may collect production evidence.
  • Preview may read shared account and project data but does not import or mutate Electron’s local queues, secrets or settings. Both applications must be uninstallable and updatable independently.
  • Initial parity covers login, timer lifecycle, offline recovery, activity, idle handling, app/window context, screenshots, notifications, tray, autostart, deep links, permissions and signed updates. Device Compliance, Local AI, agent telemetry and Remote Actions follow explicit capability gates; unsupported capabilities remain visible as unsupported rather than silently degraded.
  • Native capture uses platform APIs behind Rust traits: ScreenCaptureKit on macOS, Windows Graphics Capture on Windows and the XDG desktop portal with PipeWire on Wayland, with a separately tested X11 path. UI code never receives unrestricted native primitives.
  • The public /download/ page labels Electron as Stable and Tauri as Preview, shows platform/architecture support and publishes checksums/signing provenance. Preview uses its own updater feed and cannot consume Electron artifacts.
  • Preview is not authorized to replace, migrate or retire Electron. That transition requires qualification evidence and a later accepted decision; rollback consists of disabling Preview distribution/collection while Electron remains available.
  • Verification: follow TD0–TD12 in the alternative Tauri desktop plan, including lease contention tests, native permission matrices, signed installer/update tests, dual-install smoke tests and live download-page validation.
  • Context: MonStaff Preview 0.1.0-preview.15 and 0.1.0-preview.16 experienced macOS EXC_BREAKPOINT (SIGTRAP) crashes caused by rdev 0.5.3 calling TSMGetInputSourceProperty from background input-monitoring threads. Beyond the crash defect, keyboard translation introduces unnecessary privacy surface by converting hardware key events into localized characters and keysyms.1718
  • Alternatives considered: patch rdev to dispatch translation to the main macOS dispatch queue; replace rdev with another generic input-event library; or implement an isolated, content-free native aggregate-input collector crate. Main-queue dispatching preserves unnecessary keystroke translation, hides latency, and introduces event reordering risks. Generic libraries maintain broad event-reading interfaces susceptible to keylogging classification.
  • Choice: implement monstaff-input-activity as an isolated Rust crate and remove rdev completely. The native boundary exposes only unit signals (record_key_down, record_button_down, record_pointer_position) and derives only coarse aggregate counts (keyPressCount, mouseClickCount, mouseDistancePx).
  • All keyboard translation APIs (TIS*, TSM*, UCKeyTranslate, CGEventKeyboardGetUnicodeString, ToUnicode, XLookupString) and key identifiers (keycodes, scan codes, keysyms, Unicode scalars, modifiers) are strictly forbidden at the collector boundary.
  • Aggregate input collection executes only under active tracking eligibility (active lease, signed installation, user tracking active, unlocked screen, OS permissions granted).
  • Builds 0.1.0-preview.15 and 0.1.0-preview.16 on macOS are designated as affected and paused from promotion. In case of instability, rollback returns users to the supported Electron client; rollback to .15 or .16 is prohibited.
  • Reopening the macOS TD5 monitoring gate requires verified passing of RIC5 and RIC6 gates.
  • Verification: verified by contract fixtures (scripts/validate-aggregate-input-contract.mjs), symbol import audits (scripts/verify-macos-input-collector-imports.sh), local arm64 runtime smoke execution, and fail-closed permission tests.19
  • State: accepted on 2026-09-04 by explicit product-owner direction.20
  • Context: the current Preview process combines Tauri presentation, protected session and installation identity, backend transport, timer/lease ownership, monitoring, durable queues, agent telemetry, compliance, Local AI and gated remote execution. UI automation therefore has to drive application state through platform-specific GUI mechanisms, and a separately linked CLI would create another mutable runtime instance rather than an interchangeable client.
  • Alternatives considered: keep the Tauri process authoritative and add a diagnostic-only CLI; link the current Rust library independently into GUI and CLI; or introduce one headless per-user runtime with symmetric clients. A diagnostic CLI does not provide product parity, while independently linked mutable runtimes duplicate session refresh, leases, collectors and queues.
  • Choice: monstaff-core becomes the single-instance per-user runtime authority. The monstaff CLI and Tauri GUI use one authenticated, versioned local protocol and expose the same domain use cases, errors and events. Neither client directly owns secrets, persistence, backend transport or long-running domain work.
  • GUI-specific windows, React rendering, tray menus, dialogs and notifications remain presentation adapters. Every underlying state transition is a core command so a CLI workflow can be continued in the GUI and a GUI workflow can be continued in the CLI.
  • Core and CLI are implemented and comprehensively verified before Tauri business commands migrate. Required evidence includes real Codex/Claude telemetry where locally available, concurrent chats/instances, conserved parallel project allocation and Admin web visibility.
  • Admin web visibility is verification of backend ingestion, projection, authorization and rendering; Admin management/reporting features are not part of CLI parity.
  • Native permission and capture ownership move only after the signed core identity passes platform qualification. During migration exactly one implementation owns each capability; compatibility adapters cannot enable dual writers.
  • Client exit is not core shutdown. Active timers, collectors, delivery queues and agent sessions survive GUI/CLI disconnect; explicit core shutdown must honor bounded safe-stop rules.
  • Refined on 2026-09-05 by product-owner direction: quitting the desktop application (tray “Quit”, Cmd+Q, Dock “Quit”) stops the running timer and then requests Core shutdown; hiding the window and CLI exit still leave the Core running. The Core safe-stop rule is unchanged, so it stays alive when agent capture, remote actions or a remote terminal are active or when the backend is unreachable, and quitting never starts a Core. Implemented in the Tauri exit handler with a bounded quit sequence.21
  • Implemented locally on 2026-09-04: every mutable/runtime Rust module was moved under apps/monstaff-core; Tauri now exposes only six presentation/Core-bridge commands. Real bidirectional GUI↔CLI timers, GUI-exit/Core-survival, Agent/Local AI/Remote Actions/terminal and Admin-observation canaries passed. Signed installed three-platform qualification remains open and does not authorize rollout expansion.22
  • Verification: follow MCC0–MCC6 in the Core, CLI and GUI convergence plan, including protocol security/version fixtures, multi-process singleton tests, provider telemetry canaries, allocation conservation, Admin browser verification and signed installed platform qualification.
  • State: accepted on 2026-09-05 by explicit product-owner direction.23
  • Context: ADR-021 reserved Electron replacement for a later explicit decision. After ADR-023 moved every runtime capability into monstaff-core and the Preview passed four-target installed qualification, coexistence itself became the largest source of duplication: every desktop capability exists in TypeScript and Rust, two flag families gate the same admission, three contract copies drift behind AST-checking scripts and the release pipeline keeps two tracks.24
  • Alternatives considered: clean the Rust client before retiring Electron; keep Electron frozen as a fallback; keep the Preview identity. All three keep coexistence machinery alive or defer a second migration.
  • Choice: remove apps/desktop and apps/agent-cli; converge on the MonStaff identity, one version line for core/CLI/GUI and a version-only admission fence. Execution follows SDC0–SDC5 in the single desktop client consolidation plan.
  • Verification: each phase closes by command-verifiable criteria; rollout still requires MCC6 and TD5 evidence in their own plans.
  • State: superseded on 2026-09-05 by ADR-026: the workflow_run trigger never fired because the release run is created by the tagging workflow with GITHUB_TOKEN, for which GitHub emits no follow-on events.2526
  • Context: a release was a version bump on main, a tag, a Quality-gated release run and then a person running pnpm release:promote. The desktop-production environment has no protection rules, so the promotion of desktop-v0.3.8 ran through in 36 seconds with no approval: the manual dispatch was the only human step and protected nothing.
  • Alternatives considered: dispatch the promotion from the last release job (rejected: the promotion preflight requires the candidate run to be completed and success, which a run cannot be from inside itself); keep the manual dispatch as a deliberate pause (rejected for the development phase: the pause has no approver).
  • Choice: “Promote qualified MonStaff candidate” triggers on workflow_run of “Release MonStaff” (completed, conclusion success, head branch desktop-v*), resolves run id, tag and commit from the event and runs the unchanged preflight and revalidation steps. workflow_dispatch and pnpm release:promote remain for re-promotion and older candidates.
  • Verification: scripts/desktop-release-candidate.test.mjs asserts the trigger, the gate and that the automatic path enters the same resolve/verify steps; the first automatic promotion is the release that follows this change.
  • State: accepted on 2026-09-05 by explicit product-owner direction, after the first real exercise of ADR-025 on desktop-v0.3.10 produced no promotion run at all.26
  • Context: “Tag desktop release” starts “Release MonStaff” through a workflow_dispatch made with GITHUB_TOKEN. GitHub does not emit workflow_run events for runs created that way, so the promotion workflow had zero workflow_run runs in the repository’s history; 0.3.10 was promoted manually with pnpm release:promote (run 33973384303).
  • Alternatives considered: dispatch the release with a personal access token or a GitHub App so that workflow_run fires (rejected: a new long-lived secret for a problem the repository token can solve); keep the manual dispatch (rejected: the same reasoning as ADR-025).
  • Choice: a final dispatch-promotion job in release-desktop.yml (job-level actions: write, still contents: read at the workflow level) runs gh workflow run promote-desktop.yml on main with its own run id, tag, commit and an automatic change reason. promote-desktop.yml is dispatch-only; its “Resolve successful candidate workflow run” step polls the candidate run every 20 seconds for up to 15 minutes until it is completed, then requires success and continues with the unchanged tag, commit and manifest verification. This lifts the objection ADR-025 raised against dispatching from inside the release.
  • Verification: scripts/desktop-release-candidate.test.mjs asserts the dispatch job, its permissions and inputs, the absence of workflow_run and the wait loop; ci-quality-reuse.test.mjs keeps the release workflow read-only at the top level. First exercised by desktop-v0.3.11 (commit 8561e6a): “Release MonStaff” run 33973773736 finished at 2026-09-05T15:19:51Z, the dispatched promotion run 33974462687 started at 15:19:49Z and published at 15:20:45Z with no human action; push to promoted release took about 15 minutes.26

For a new significant decision, add context, considered alternatives, choice, consequences, migration and verification evidence to this register or a dedicated decision concept linked here. Changing state must include a date and, for implementation, a commit or release reference.

Factory control and execution boundary — proposed

Section titled “Factory control and execution boundary — proposed”

See the proposed decision. Monstaff owns product access and costs, Fabric execution/publication, GitHub workflow state. No second WA executor or autonomous permission grant is introduced.

  1. Local interactive-terminal and Redis retirement. ↩

  2. Local AI Pack and per-installation model policy request. ↩

  3. Local AI Pack implementation baseline. ↩

  4. Administrator-defined device compliance request. ↩

  5. Provider-independent MonStaff platform request. ↩

  6. Provider-independence baseline. ↩

  7. Pre-production greenfield compatibility constraint. ↩

  8. Agent telemetry, chat capture and parallel-time request. ↩

  9. Agent telemetry and parallel-time implementation baseline. ↩

  10. Projectless automatic developer tracking implementation ↩

  11. Active-plan coherence and acceptance request. ↩

  12. Customer domain and multi-customer project engagement plan. ↩

  13. Direct administrator shell from managed devices. ↩

  14. Direct managed-device shell implementation. ↩

  15. Alternative Tauri desktop client request. ↩

  16. Alternative desktop client codebase baseline. ↩

  17. Aggregate input without key translation request. ↩

  18. Raw aggregate input and key-translation elimination plan. ↩

  19. Aggregate input without key translation acceptance. ↩

  20. MonStaff Core, CLI and interchangeable GUI request. ↩

  21. Desktop quit stops the timer and shuts the Core down ↩

  22. MonStaff Core, CLI and Tauri convergence evidence ↩

  23. Single Rust desktop client and Electron end-of-life ↩

  24. Desktop client coexistence baseline ↩

  25. Automatic desktop promotion after a successful tagged release ↩

  26. Release-dispatched desktop promotion ↩ ↩2 ↩3