Desktop shell
AncestryLLM 0.5.0 is a bounded, offline Electron control shell. It does not move the genealogy-capable CLI or console into the desktop application and it does not introduce a second command or domain layer.
Supported surface
The supported desktop destinations are deliberately small:
- Home identifies the application, its offline posture, and sanitized startup and capability state. The capability summary reports only whether the bundled local runtime is ready; it does not expose accounts, providers, credentials, genealogy data, or cloud consent.
- Diagnostics shows stable, sanitized lifecycle state and offers bounded retry or restart recovery.
- Settings stores local visual preferences only: color scheme and reduced motion. The internal onboarding flag is not a user-facing setting.
These destinations must remain usable with keyboard navigation and assistive technology, and in loading, empty, degraded, failure, narrow-window, and zoomed layouts.
Accessible design-system shell
Unreleased Issue #106 implements the reusable presentation shell for the 0.6 desktop work. It preserves a persistent primary navigation region, workspace header, context-and-help panel, and explicit Local and offline status across Home, Diagnostics, and Settings. The compact layout keeps the current route and local status visible when the window narrows; at the 720-by-560 minimum size and 200% zoom, primary actions reflow without horizontal clipping.
The shell exposes one typed route and navigation contract rather than another command registry. Ctrl+K or Command+K opens a keyboard destination palette. Its filter receives initial focus, Escape dismisses it and restores the trigger, and choosing a destination focuses that route’s heading. A Skip to workspace link is the first backward-reachable control when route focus starts on a heading. Focus indicators, reduced-motion preferences, and forced-color behavior are explicit rather than dependent on browser defaults.
Shared presentation contracts live under
desktop/src/renderer/src/design-system/:
AppRouteandNavigationItemdefine the bounded destinations and labels.CapabilityGatepresents an already-authorized branch; it cannot create or infer authority.AsyncStateprovides plain-language loading, empty, offline, degraded, error, success, and permission-denied patterns. Meaning is always conveyed by text and semantics, not color alone.CodedErrorViewaccepts only stable coded errors, normalizes an unexpected code toUNEXPECTED_ERROR, and keeps recovery instructions beside the code.- The dialog-focus contract records initial, dismiss, restoration, and route-selection behavior for keyboard regression tests.
These components import no bridge, Electron, Node.js, filesystem, or network API. They consume data only when a route-level hook passes a validated bridge response. The development gallery imports deterministic fictional fixtures, while the production build verifier rejects the gallery and its copy from the shipping renderer.
First run and revisit
The current unreleased 0.6 first launch opens a bounded welcome on Home and presents three explicit deployment intents:
- Local Desktop (Recommended) is the only available choice. It uses the private loopback sidecar and offline-first defaults on this device.
- Connect Remote is visible but unavailable in this release. First run does not discover or contact a remote service.
- Host Remote is an advanced intent that is visible but unavailable. First run never opens a listener or starts a container.
The welcome explains that updates are installed manually and asks for no account, provider, API key, genealogy data, or cloud consent. Before it enables Continue, the renderer validates a schema-v1 startup report containing exactly four components: configuration, SQLCipher, keyring, and workspace. Each component contains only a stable status, code, reviewed message, remediation, restart requirement, and mutation-blocking flag. The report also contains only normalized operating-system and architecture labels.
When a required component blocks startup, the application remains navigable
but read-only. Open read-only diagnostics replaces Continue;
capabilities are not queried, and preference, settings, and credential
mutations are rejected with STARTUP_MUTATION_BLOCKED. Inspection does not
repair configuration, create a workspace or database, replace a database key,
or select a plaintext fallback. One bounded retry is available, concurrent
requests share that launch attempt, and relaunch remains the final local
recovery step.
Continue records only the main-process-owned onboardingCompleted
preference. A new application process skips the welcome after a valid refreshed
preference snapshot reports completion; the flag is not exposed in Settings.
Conflict, unavailable, corrupt, unsupported, or invalid preference responses
fail closed and keep the welcome gated with a stable sanitized code and bounded
Try again, Diagnostics, or restart recovery. The renderer never repairs
or overwrites invalid preference storage.
Completed users can select Review welcome on Home. Review is temporary renderer state: Back to Home neither creates a route nor changes a preference. Keyboard focus begins on the welcome heading, reduced-motion preferences are respected, and degraded runtime state does not block navigation to Diagnostics or its bounded retry.
The 0.5.0 shell has no genealogy, file or folder, GEDCOM or RootsMagic, job, chat, provider or credential, cloud or account, domain-dispatch, updater, or background-channel surface. Those exclusions apply to navigation and hidden controls as well as visible content.
Offline and process boundary
Electron starts the packaged sidecar on a private, ephemeral loopback endpoint
with provider none; the Electron main process is the sole authenticated
client. The preload bridge exposes exactly these six methods:
getAppInfogetStartupDiagnosticsgetCapabilitiesretrySidecargetPreferencesupdatePreferences
The renderer receives no Node.js, Electron, network, filesystem, keyring, provider, database, shell, or arbitrary-path access. It must never receive the sidecar port, bearer token, endpoint, executable path, preference-file path, stderr, raw sidecar or bridge errors, or stack traces. See the packaged sidecar contract and desktop ADR for the underlying process and architecture controls.
Unreleased opaque file-mediation foundation
Issue #103 adds a security boundary for later genealogy workflows without expanding the supported 0.5.0 domain surface. The bridge gains only three strict, asynchronous methods:
requestOpenFileGrantrequestSaveFileGrantrevokeFileGrant
The renderer requests an exact purpose and receives either a cancelled result or a path-free grant containing a random opaque identifier and safe display metadata: basename, kind, byte size, and replacement status. It cannot provide, receive, reconstruct, persist, or redeem a pathname, and it has no direct filesystem method. The reusable selected-file card does not initiate a domain operation.
Electron main owns the native open/save dialogs and the grant-to-path map. It checks the selected object’s regular-file and link state, purpose-specific extension and content signature, bounded size, canonical identity, and filesystem fingerprint. Grants are bound to the requesting renderer, exact purpose and access mode, current application session, and one redemption. Explicit revocation, renderer close or cross-document navigation, and application restart invalidate them. Trusted same-document routes such as the application’s hash-based Home, Diagnostics, and Settings transitions preserve the renderer identity and its grants; each bridge request still rechecks the exact main frame and trusted application URL. Existing-output replacement requires a native confirmation and identity revalidation; source/output aliases and concurrent output grants fail closed under main-owned locks.
Only a trusted main-process adapter may redeem a grant through
resolveReadGrant or resolveWriteGrant. A future genealogy integration must
then pass the internal path to the shared Python file-ingress adapter, which
reopens and revalidates the source under its own bounded policy before parsing
or publication. Until that adapter ships, the grant broker provides no GEDCOM,
RootsMagic, import, export, or report workflow.
Unreleased settings and credential-management foundation
Issue #105 adds the source-level settings and credential-management boundary planned for 0.6.0. It does not expand the released 0.5.0 shell and does not enable provider execution, cloud consent, genealogy operations, or arbitrary sidecar access.
The renderer can read the complete versioned settings catalog and submit one
exact optimistic-revision patch. The catalog exposes only five reviewed,
non-secret settings: the default provider choice and four bounded query/output
limits. Each entry supplies its label, help text, type, safe default, allowed
values or numeric bounds, restart requirement, sensitivity marker, and current
value. The Python SettingsService validates the whole update before
AppConfig atomically replaces the repository-owned configuration; unknown,
sensitive, invalid, or stale-revision changes fail closed.
Credential controls are intentionally write-only. The bridge adds only these five fixed operations:
getSettingsupdateSettingsgetSecretStatussetSecretdeleteSecret
Secret references are selected from a fixed Python-owned allowlist. Reads
return only present, missing, or unavailable; no response can return a
credential value. Save and delete require separate explicit actions, and a
successful delete is reported only after the OS-keyring-backed store proves
the credential is absent. The packaged sidecar uses keyring-only secret
resolution and never consults process-environment credentials. The documented
read-only environment fallback remains available only to explicit CLI and
headless workflows. An unavailable or locked keyring, or any attempted
plaintext fallback, produces a stable redacted failure.
The renderer’s password field is uncontrolled and is cleared before the
asynchronous request begins and again after every success or failure. Secret
values are never retained in React state, query caches, bridge fixtures,
responses, logs, local storage, IndexedDB, Electron safeStorage, or plaintext
configuration. The renderer still has no direct keyring or network access.
Together with the three unreleased file-grant methods, the current development
bridge therefore contains fourteen fixed methods: the six released control
methods, three opaque file-grant methods, and five settings/credential methods.
There is still no generic send, listen, route-selection, or command operation.
The unreleased source implements the non-secret, versioned deployment-profile control plane accepted by the deployment-profile ADR. Local Desktop is preselected and recommended. The shared Python service owns profile validation, exact preview and confirmation, atomic persistence, diagnostics, redacted evidence, and recovery to Local Desktop. Issue #107 now presents that local-only choice during first run and gates mutations on the sanitized startup report; Issue #108 owns the remaining profile-settings presentation. Connect Remote and Host Remote remain visible advanced intents, but neither can be activated until its enrollment or host-runtime dependency is implemented and independently gated.
Selecting or inspecting a profile does not open a listener, start a container, discover a service, move genealogy data, select a provider, or grant cloud consent. The released 0.5 shell still has no supported container, remote, LAN, browser, or public-service surface. Future presentation keeps the renderer sandbox and fixed typed bridge, while authority remains in the shared service contracts and Electron Main’s narrow adapter.
Unreleased Issue #363 adds a separate, deliberately unwired host-only control
foundation inside Electron Main. Its closed schema-v1 policy and plan bind an
app-owned Docker context, Unix socket, runtime profile, Engine identity, exact
resource labels, immutable images, and hardened Compose settings to bounded
start, stop, repair, and uninstall operations. The preload, renderer, and
shared renderer types expose no supervisor, socket, context, executable, or
generic process method, and ordinary shell startup never invokes this source.
The native macOS arm64
issue-363-macos-arm64-container-supervisor.json
record proves only that control subset in an isolated Colima profile. Runtime
acquisition, application images, secret delivery, family-tree grants, storage,
profile activation, budgets, cross-platform evidence, and the remaining G5
and G7 gates still block any container-runtime availability claim.
Installation and updates
The supported 0.5.0 targets are macOS 15 and 26 on arm64 and x64, Windows 11
on arm64, and Ubuntu 24.04 on x64. A supported release is a manually installed
installer that has passed the target-specific release and packaged assurance
gates in the release runbook. Full production/trusted binary
signing is explicitly deferred until the first full version release, v1.0.0.
Project-produced 0.x release installers and annotated release tags must be
unsigned.
Unpacked CI artifacts and development builds are verification inputs, not
supported releases or evidence of installation. For an install or upgrade,
quit AncestryLLM; download the
target-matched full installer and SHA256SUMS from the same immutable release;
verify its digest and declared binarySigningMode; install it over the current
application; relaunch; and confirm the version and healthy Diagnostics. A
0.x binary may produce an unknown-publisher or equivalent operating-system
prompt. At v1.0.0 and later, also verify the trusted platform signature;
Ubuntu then requires the adjacent .deb.asc detached GPG signature.
Application files are replaced while OS-managed AncestryLLM data and
configuration directories are retained.
Version 0.5.0 has no updater feed, no background update, no staged rollout, and
no automatic rollback. It publishes no latest*.yml or blockmap. Updating and
rolling back mean manually installing an appropriate complete installer whose
checksum and version-required platform signature still verify.
Sanitized diagnostics and recovery
When startup is degraded, use the reviewed remediation beside the affected configuration, SQLCipher, keyring, or workspace code. The report never includes a username, hostname, full path, environment value, record, prompt, payload, response body, raw exception, or stack. Keep recovery bounded and generic:
- Open read-only Diagnostics and review the stable component code.
- Correct only the named local prerequisite. Unlock or repair the OS keyring; install the supported SQLCipher build; restore valid configuration; or repair the app-owned workspace directory and owner-only permissions.
- Request the one bounded retry. Do not initialize a replacement database, replace an existing key, or use plaintext SQLite as recovery.
- If the failure remains, close and reopen the application.
- Reinstall the same supported, target-matched build when the sidecar version or local application files may be incomplete.
- When reporting a problem, include only the application version, normalized operating-system and architecture labels, and stable diagnostic code shown by the shell. Do not include local paths, environment values, process details, genealogy data, or raw error output.
Generic recovery text is part of the security boundary: the capability summary and diagnostics must not turn private runtime state into renderer-visible details.
Verification boundary
make desktop-e2e builds the production renderer and launches it in Electron
with a deterministic fictional mock bridge. The flow proves welcome completion,
renderer reload, revisit, degraded startup, retry, destination access,
deterministic route/dialog focus, and minimum-window behavior at 200% zoom. The
real Chromium run also scans every route in light, dark, and high-contrast
modes against WCAG 2.2 A/AA rules from the exact locked axe-core version. A
separate FilePreferencesStore unit test proves that completion survives a
fresh store instance, which models a new application process.
Use the focused checks during shell review:
pnpm --dir desktop test:accessibility
pnpm --dir desktop test:visual
pnpm --dir desktop dev:gallery
Automated checks do not replace a screen reader. Before release credit, review the production shell and fictional gallery with VoiceOver, NVDA, or Narrator and record the operating system, reader and version, commit, and result in the release evidence. The smoke review must confirm:
- Landmarks, the heading hierarchy, Primary navigation, the current-page announcement, and Local and offline status are understandable without visual position or color.
- Route entry focuses the workspace heading; the skip link reaches the workspace; and focus never becomes lost behind navigation or context panels.
- The destination palette announces its dialog and label, focuses its filter, reports an empty search, restores its trigger on dismissal, and focuses the selected route heading.
- Every gallery state announces its state label, title, description, and code where present without exposing a path or private runtime detail.
- The minimum window at 200% zoom, light/dark/high-contrast themes, and reduced motion retain all primary actions and understandable focus order.
The exact-head desktop verification gate separately assembles and launches the literal unpublished unpacked executable on six hosted runner rows, exercises healthy first run, durable settings, corrupt preferences, accessibility and hardening controls, and inspects the packaged fuses. It does not launch an installer. Manual installation and actual Windows 11 execution remain separate release gates; trusted signing becomes a release gate at v1.0.0.
Issue #105’s source suites additionally verify revision conflicts, strict settings metadata, write-only secret schemas, keyring failure behavior, credential deletion, bridge redaction, and password-field lifetime. Packaged settings and credential-management evidence remains owned by the 0.6 desktop verification work; source tests alone do not make the feature released.