Elyra
Elyra The coding agent eTerm The terminal that knows where each command ends Starf An activity monitor for Apple silicon that never invents a number etrans An SSH and SFTP client for macOS Elyra VM Virtual machines for macOS, Linux and Windows on your Mac Litr A small, native web browser for macOS Notr A notebook for macOS e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Refr Local-first PDF workspace for macOS Elyra Workspace A desktop workspace for coding agents Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Release notes
Changelog
Elyra
Single-instance & deep-linking

Single-instance & deep-linking

Two related features for apps that should behave like a single, link-aware program. Both are core (no feature flag).

Single-instance

App::new().single_instance().run()?;

The first process becomes the primary. Any later launch hands its command line to the primary and exits immediately. The primary's window is raised and the payload is delivered on elyra:second-instance:

import { onSecondInstance } from "@elyra/runtime";

onSecondInstance((payload) => {
  // e.g. a forwarded deep-link URL, or "" for a bare re-launch
});

The rendezvous

Platform Endpoint
Unix an AF_UNIX socket in $XDG_RUNTIME_DIR (temp dir as fallback), created with mode 0600 and the uid in its name
Windows loopback TCP (std has no named pipes)

Both require a random per-install token, stored 0600 in the app's config directory. Without it any local process, including another user's, could inject payloads that the app forwards to the frontend as a deep link.

The handshake is a challenge-response on that token. Each side proves it holds the token with an HMAC over fresh nonces, the primary first, and the token is never sent. A process that takes the endpoint before the app (a loopback port, on Windows) learns neither the token nor the payload. The client's proof covers the payload, so it arrives as it was sent. The MCP endpoint uses the same scheme. Forwarded URLs are also parsed and validated (scheme, no control characters or quotes) rather than prefix-matched.

Payloads are limited to a single line of at most 8 KiB. If the endpoint is held by an unrelated process, enforcement is skipped and the app runs normally.

Deep-linking (custom URL scheme)

App::new().deep_link("myapp").run()?;   // handles myapp://…
  • Launch URL — read it once on startup:
    import { deepLink, onDeepLink } from "@elyra/runtime";
    const url = await deepLink.initial();          // "myapp://…" | null
    onDeepLink((url) => { /* URLs delivered while running */ });
    
  • Delivery while running — on macOS the OS open-URL event is forwarded to elyra:deep-link; on Windows/Linux the OS starts a new process with the URL, which single-instance forwards to the primary (also re-emitted on elyra:deep-link). Pair deep_link with single_instance for the best behavior.

Registration

deep_link registers the scheme at startup (idempotent):

  • Windows — HKCU\Software\Classes\<scheme> pointing at the executable.

  • Linux — a .desktop entry with MimeType=x-scheme-handler/<scheme> plus xdg-mime default.

  • macOS — registration belongs in the bundle's Info.plist; the runtime only handles incoming URLs. Add to your .app:

    <key>CFBundleURLTypes</key>
    <array><dict>
      <key>CFBundleURLName</key><string>com.example.myapp</string>
      <key>CFBundleURLSchemes</key><array><string>myapp</string></array>
    </dict></array>
    

Registration writes to the OS (registry / desktop entries) and, on macOS, depends on packaging. Argv delivery and the macOS open-URL path are the parts exercised here; the registration side-effects are best verified on each target in a real install.

Related