# Aether Events Launcher: Native Electron Integration > **Status:** Operational / Phase 5 Implementation > **Last Updated:** 2026-05-11 > **Primary Platform:** macOS (Darwin) > **Fallback Platform:** Linux / Windows ## 1. Overview The Aether Events Launcher utilizes an Electron-based "Native Shell" to provide OS-level capabilities that are normally restricted by browser sandboxing. This enables persistent file caching, direct control of presentation software (Keynote, PowerPoint), and hardware telemetry. ### Operational Modes | Mode | Purpose | File Handling | | :--- | :--- | :--- | | **Default** | Standard web browser access. | Direct downloads; no local caching. | | **Onsite** | Web access on event networks. | Faster polling; browser-based file management. | | **Native** | Dedicated Podium Kiosk (Electron). | Full background pre-caching; atomic safe-handover. | --- ## 2. Architecture: The Three-Layer Bridge The integration is built on a decoupled three-layer communication model to ensure security and cross-platform flexibility. ### 2.1 Layer 1: The Engine (Main Process) - **Repo:** `~/OSIT_dev/aether_app_native_electron/` (separate git repo) - **File:** `aether_app_native_electron/src/main/*.ts` - **Role:** Performs the heavy lifting (Filesystem, Shell, AppleScript). - **Responsibilities:** - Managing the **Hashed Cache** directory. - Executing `osascript` intents for presentation control. - Spawn/Kill process management. ### 2.2 Layer 2: The Gatekeeper (Preload Script) - **Namespace:** `window.aetherNative` - **Role:** Securely exposes whitelisted IPC channels to the Renderer. - **Standards:** Uses `contextBridge.exposeInMainWorld` to prevent arbitrary code execution. ### 2.3 Layer 3: The Messenger (SvelteKit Relay) - **File:** `src/lib/electron/electron_relay.ts` - **Role:** Provides a clean, typed API for Svelte components. - **Responsibilities:** - Mapping `camelCase` UI triggers to `snake_case` IPC calls. - Resolving an extension alias to a canonical Launch Profile, then to a single `native_template` string before crossing IPC. The reason for this split is simple: Launch Profiles are policy, while Native Templates are executable strings. Keeping that distinction explicit prevents the bridge from mixing config objects with runtime commands. --- ## 3. The "Zero-Config" Lifecycle To support rapid onsite deployment, the native app requires zero manual setup. 1. **Seed:** On launch, the Main process reads a local `seed.json` (Device ID + API Key). 2. **Identity:** Calls `GET /v3/crud/event_device/{id}` to pull device config and extract `app_base_url` (the event FQDN) and `account_id`. 3. **Site Context:** POSTs to `/v3/crud/site_domain/search?limit=1` with the FQDN to resolve the correct site. No JWT — auth is `x-aether-api-key` + `x-account-id` throughout. 4. **Launch:** Navigates the SvelteKit frontend directly to the assigned Event Launcher route (`/events/{eventId}/launcher/{locationId}`). --- ## 4. Podium Reliability Protocol The system is designed to ensure that a presentation never fails due to network instability. ### 4.1 Hashed Cache Pattern Files are stored persistently using their SHA-256 hash to prevent filename collisions and handle versioning. - **Root:** `~/Library/Caches/OSIT/file_cache/` - **Subdirectory:** First 2 characters of hash (e.g., `ab/`) - **Filename:** `{hash}.file` ### 4.2 Background Sync (File Warming) When a user navigates to a session in the Launcher UI, the `LauncherBackgroundSync` component: 1. Extracts all `event_file_id` values for that session. 2. Checks the native cache via `aetherNative.check_cache`. 3. Triggers background downloads for missing files via `aetherNative.download_to_cache`. ### 4.3 Safe Handover (Launch Sequence) When a user clicks "Open", the system follows a non-destructive sequence: 1. **Verify:** Confirm hash exists in the permanent cache. 2. **Copy:** Create an atomic copy in the system `[tmp]` directory. 3. **Restore:** Rename the copy to its original filename (e.g., `Abstract_101.pptx`). 4. **Execute:** Launch the file via the OS. --- ## 5. Automation & Actuators (Phase 5) The native shell provides specialized handlers for controlling the "Podium Experience." ### 5.1 Presentation Acts | Action | Handler | Actuator (macOS) | | :--- | :--- | :--- | | **Launch** | `launch_presentation` | `open` or `osascript` (slideshow start) | | **Control** | `control_presentation` | `osascript` (next/prev slide) | | **Clean Up** | `kill_processes` | `killall -INT` (graceful exit) | ### 5.2 System Management - **Telemetry:** Pushes `cpu_usage`, `memory_free_gb`, and `foreground_app` via heartbeats using the `get_device_info` relay. - **Self-Update (Roadmap):** Plan to monitor Syncthing `admin_share` for newer `.app` versions and perform atomic swaps. ### 5.3 Implemented Actuators (Phase 5 Complete) - **Recording:** `manage_recording({action})` — Aperture session capture (`start`, `stop`, `status`). macOS only. - **Display Layouts:** `set_display_layout({mode})` — Mirror / Extend via `displayplacer`. macOS only. - **Power Control:** `power_control({action})` — Shutdown, reboot, sleep. macOS + Linux. - **Window Control:** `window_control({action})` — Maximize, minimize, fullscreen, kiosk mode. - **Wallpaper:** `set_wallpaper({path})` — macOS (AppleScript) + Linux (gsettings). > **Note:** `update_app` is implemented as a stub — downloads but does not install. Not yet functional for end users. --- ## 6. Launcher Configuration & Management The Launcher features a standardized, responsive configuration interface designed for onsite technical management. ### 6.1 UI Architecture - **Tabbed Navigation:** Categorized into System, Sync, and General settings. - **Section Wrapper (`Launcher_Cfg_Section`):** A shared component providing a consistent header, icon, and responsive grid container. ### 6.2 3-Way State Logic To manage screen real estate on varying laptop resolutions, all configuration sections utilize a 3-way visibility state: - **`collapsed`**: Content is hidden. - **`auto`**: Expanded by default, but automatically closes if another "auto" section is opened. - **`pinned`**: Expanded and remains open regardless of other section interactions. ### 6.3 Technical Mode (`edit_mode`) The UI dynamically filters fields based on the user's focus. Enabling Technical Mode (`$ae_loc.edit_mode`) reveals advanced diagnostic and writeable fields. | Category | Standard View (Read-Only) | Technical Mode (Read/Write) | | :--- | :--- | :--- | | **Health** | Heartbeat, RAM Usage, Sync Stats | Hostname, IP List, Raw Device JSON | | **OS Bridge** | Folder Buttons, Recording Toggle | Manual Terminal Commands, Reset Wallpaper | | **Sync** | Sync Completion Status | Millisecond Timers, Cache Prefix Logic | | **Update** | Current Version Status | Manual Update Paths, URL Overrides | --- ## 7. Implementation Reference (IPC Whitelist) All functions below are exported from `src/lib/electron/electron_relay.ts` and safely no-op when `window.aetherNative` is not present (i.e., in browser/non-native mode). ### Config & Info - `get_device_config()` — Returns hydrated device settings injected by the native shell on startup. - `get_device_info()` — Returns OS metadata, IP list, hostname, and path placeholders (`[home]`, `[tmp]`). ### File Cache - `check_cache({cache_root, hash, hash_prefix_length?, verify_hash?})` — Verifies a file exists in the local hashed cache. `verify_hash: true` re-hashes to confirm integrity. - `download_to_cache({url, cache_root, hash, api_key, account_id, hash_prefix_length?})` — Streams a file download to the hashed cache with SHA-256 integrity check. Stale `.tmp` files (older than 5 min) from crashed downloads are cleaned up automatically on each call. - `copy_from_cache_to_temp({cache_root, hash, temp_root, filename, hash_prefix_length?})` — **Preferred primitive.** Copies a cached file to temp and returns `{ success, path }`. The Svelte caller decides what to do next (run a script, open it, etc.). - `launch_from_cache({cache_root, hash, temp_root, filename, hash_prefix_length?, native_template?})` — Combines copy + launch in one call. Executes the provided `native_template` string after the file is copied to temp. If no template is supplied, treat it as an error and do not rely on Electron-side defaults. > `hash_prefix_length` defaults to `2` throughout. Do not change without coordinating all devices — mismatched values create orphaned cache subdirectories. ### Shell & OS - `open_folder(path)` — Opens a path in the OS file manager. - `run_cmd({cmd, timeout?, return_stdout?})` — Async shell command execution. - `run_cmd_sync({cmd, return_stdout?})` — Synchronous shell command execution. - `run_osascript(script)` — Executes an AppleScript string. macOS only. **Hardened (2026-05-11):** writes script to a temp `.scpt` file; multi-line scripts and paths with special characters now work correctly. No shell escaping needed in the passed string. - `kill_processes({process_name_li})` — Terminates processes by name. macOS/Linux: `pkill -f`. Windows: `taskkill /F`. - `open_local_file_v2(path)` — Opens a file with its default OS application. ### Presentations (Phase 5) - `launch_presentation({path, app?, os?})` — Platform-aware launcher. macOS: PowerPoint/Keynote via AppleScript. Linux: LibreOffice Impress. Resolves `[home]`/`[tmp]` placeholders. - `control_presentation({app, action})` — Slide navigation (`next`/`prev`/`start`/`stop`) for PowerPoint or Keynote via AppleScript. ### System Management (Phase 5) - `set_wallpaper({path})` — Sets desktop wallpaper. macOS (AppleScript) + Linux (gsettings). - `window_control({action, value?})` — Electron window management: maximize, minimize, fullscreen, kiosk. - `set_display_layout({mode, configStr?})` — Mirror or extend displays via displayplacer. macOS only. - `power_control({action})` — Shutdown, reboot, or sleep the host machine. macOS + Linux. - `manage_recording({action, options?})` — Aperture capture control (`start`/`stop`/`status`). macOS only. - `open_external({url, app?})` — Opens a URL in Chrome, Firefox, or the default browser. - `update_app(args)` — **Stub only.** Downloads but does not install. Not yet functional. - `list_tools()` — Returns a self-documenting manifest of all available native bridge functions. ### Path Placeholders All paths passed to native handlers should use tokens rather than hardcoded OS paths: - `[home]` — Resolved to the user's home directory by the native bridge. - `[tmp]` — Resolved to the system temporary directory. --- ## 8. Launch Profiles and Native Templates (No-Rebuild File Handling) This launcher uses two related concepts: - **Launch Profile**: the Svelte-side config object keyed by file extension. A profile decides which app to use, whether to extend or mirror displays, whether to use an explicit open command, whether to run post-open automation, and how long to wait before running it. - **Native Template**: the single AppleScript or shell command string handed to Electron after Svelte resolves the profile. This is what Electron actually executes. The Svelte launcher resolves a profile and then passes a native template string to `launch_from_cache`. Electron only executes the template it receives. If Svelte has not resolved a template yet, it should stop before IPC and surface a missing-profile error. This keeps all fallback logic in Svelte, where it can be edited without rebuilding Electron. The native layer should not invent or guess a default launch path. The built-in defaults are organized as canonical profile names plus extension aliases. That lets multiple file types share one profile without repeating the same app/script details. The profile object also carries `post_delay_ms`, and a device-specific per-profile `launch_profiles[profile].post_delay_ms` override can tune the delay without changing the bridge contract. URL-based presentations remain a special pseudo-extension handled separately from the cache open flow. ### Native Template Formats | Format | Example | | :--- | :--- | | **AppleScript** (macOS) | Multi-line AppleScript string with `{{path}}` placeholder | | **Shell command** | String prefixed with `shell:` — e.g. `shell:open "{{path}}"` | The placeholder `{{path}}` is replaced with the full resolved path to the file in the temp directory after the atomic copy from cache. ### Where to Configure Launch profiles are resolved in priority order by `get_launch_profile()` in `launcher_file_cont.svelte`: 1. **`event_device.data_json.launch_profiles`** — API-driven, per-device. Highest priority. Set via the `event_device` record (Pres Mgmt → Device Management or direct DB edit). 2. **`$events_loc.launcher.launch_profiles`** — Local persistent config. Editable via the Launcher config UI (planned) or direct `localStorage` manipulation. If neither is set, the resolved native template is `null` and the launcher should not call Electron until an explicit template is available. Why: this avoids a second hidden source of truth. The profile map can evolve independently of the executable string, and Electron stays a thin executor rather than a policy engine. ### Key Format Keys are lowercase file extensions without the dot. A `"default"` key catches all unrecognised extensions. The JSON below illustrates the `native_template` emitted after profile resolution, not the full Launch Profile object schema. ```json // event_device.data_json.launch_profiles example { "launch_profiles": { "pptx": "tell application \"Microsoft PowerPoint\"\n activate\n open (POSIX file \"{{path}}\")\n delay 3\nend tell\ntell application \"System Events\"\n keystroke return using command down\nend tell", "key": "tell application \"Keynote\"\n activate\n open (POSIX file \"{{path}}\")\n delay 1\n start (front document)\nend tell", "pdf": "shell:open \"{{path}}\"", "default": "shell:open \"{{path}}\"" } } ``` ### AppleScript Execution — All Handlers Hardened (2026-05-11) All AppleScript execution in the native shell now writes scripts to a temp `.scpt` file and runs `osascript ""` rather than the old `osascript -e ""` approach. - **`run_osascript`** — hardened (2026-05-11, earlier batch) - **`launch_from_cache`** — hardened (same batch) - **`launch_presentation`** — hardened (2026-05-11, follow-up fix; was the last handler still using `-e`) - **`control_presentation`** — uses single-line scripts with no path interpolation; `-e` is safe here and retained for simplicity The `-e` approach breaks on (1) multi-line scripts and (2) file paths containing spaces, quotes, or parentheses — common in conference presentation filenames. ### Not Exposed via Relay (intentional) - `get_seed_config` / `get_jwt` — Exposed in the preload but not relayed to the UI. The JWT and seed are injected into the environment at startup; components should not call these directly.