Elyra
Elyra The coding agent eTerm The terminal that knows where each command ends Huskarl AI colleagues on your own Mac 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

Architecture

Rust backend (Yggdrasil) ↔ Svelte 5 frontend (crown) over the Elyra Framework's typed MessagePack bridge. The Rust binary embeds the built frontend and serves it from elyra://localhost.

elyra-sja/
├── src/
│   ├── main.rs        # App wiring only (~130 lines)
│   ├── app_paths.rs   # data dir, DB URL, migration staging, retention/vacuum
│   ├── http.rs        # one shared, pooled HTTP client + capped body reads
│   ├── cli.rs         # headless `check` subcommand (no window, no database)
│   ├── mcp.rs         # MCP server on stdio, read-only tools (see docs/mcp.md)
│   ├── background.rs  # launchd agent + `tick`: monitors and scheduled probes while closed
│   ├── seo.rs         # single-page analysis engine (GUI-free): checks + scoring
│   ├── extract.rs     # the page as an engine extracts it: reader view, passages
│   ├── schema.rs      # JSON-LD read for completeness, publisher entity, dates
│   ├── dates.rs       # ISO 8601 / HTTP-date / log timestamps → days (no crate)
│   ├── llmstxt.rs     # llms.txt parser (title, summary, links; lists a URL?)
│   ├── intl.rs        # hreflang / language-tag validation (GUI-free)
│   ├── robots.rs      # robots.txt: every user-agent group, not just `*`
│   ├── botlog.rs      # AI-crawler log analysis engine (GUI-free): per bot, per day
│   ├── iprange.rs     # published crawler IP ranges: fetch shape, CIDR, verdicts
│   ├── citations.rs   # citation probe: ask ChatGPT/Claude/Perplexity/Gemini, judge answers
│   ├── jev.rs         # TypeSafe Jev client: typed judgments (coverage, fidelity, stance)
│   ├── links.rs       # internal-link plan from a crawl: candidates in code, judged by Jev
│   ├── gaps.rs        # "why them, not you": your page vs a cited competitor, judged by Jev
│   ├── voice.rs       # AI share of voice from stored probes; questions to track from a crawl
│   ├── generate.rs    # llms.txt + JSON-LD from crawl data (GUI-free)
│   ├── pagespeed.rs   # Core Web Vitals via PageSpeed Insights
│   ├── crawl.rs       # site crawler (sitemap + BFS, robots, aggregation)
│   ├── fs_tools.rs    # sandboxed AI file tools + atomic, confirmed writes
│   ├── license.rs     # offline license validation (ed25519 signature)
│   ├── gsc.rs         # Search Console OAuth (PKCE + loopback) + API client
│   ├── secrets.rs     # macOS Keychain wrapper
│   └── <commands>     # settings, licensing, projects, reports, trends, crawls,
│                      # botlogs, probes, monitors, ai, export, search_console
├── migrations/        # SQLite migrations (0001–0016; embedded)
├── app/               # Vite + Svelte 5 frontend
│   └── src/
│       ├── App.svelte           # shell, nav, views, scheduler timer
│       ├── bindings.ts          # generated by `rata codegen` — do not edit
│       └── lib/                 # Report, SiteReport, Trends, Monitors, locales,
│                                # Settings, Lock, ProjectDialog, Icon, …
├── scripts/           # icns, dmg, updater keygen/sign
├── vendor/elyra-framework   # the framework, as a git submodule
└── .github/workflows/release.yml

Commands (typed bridge)

Frontend calls Rust through the generated api.* facade. Groups:

  • Analysis — analyze_page, analyze_and_save, get_report, list_reports, recent_reports, delete_report.
  • Crawl — crawl_site, cancel_crawl, list_crawls, get_crawl, get_crawl_page, delete_crawl.
  • Internal links — jev_available, plan_internal_links (progress on the links channel), latest_link_plan.
  • AI crawlers — analyze_bot_log, unknown_bot_agents, verify_bot_ips (the log's addresses against the operators' published ranges), bot_visit_trends (visits per crawler per day for a project).
  • Citation probe — probe_engines_available, probe_citations, list_citations, delete_citation, citation_summary; competitor comparisons: compare_competitor, list_gap_reports, delete_gap_report; schedules: create_probe_schedule, list_probe_schedules, toggle_probe_schedule, delete_probe_schedule.
  • Background runner — background_status, set_background_runner (installs or removes the launchd agent that runs elyra-sja tick), list_run_log (every attempted run with outcome and next attempt).
  • Generators — generate_llms_txt, generate_faq_schema, generate_article_schema, save_generated.
  • Trends — url_trends, compare_reports, share_of_voice; questions to track from a crawl: suggest_questions.
  • Projects — list_projects, create_project, update_project, delete_project.
  • Monitors — tick_monitors (also runs due probe schedules), run_monitor_now, list_monitors, create_monitor, toggle_monitor, delete_monitor, list_alerts, unread_alerts, mark_alerts_read.
  • AI — run_fix, respond_write.
  • Search Console — gsc_status, gsc_connect, gsc_disconnect, gsc_properties.
  • Settings & license — get_settings, save_settings, license_status, activate_license.
  • Export — open_report.

After changing any #[command] signature or a specta type, re-run rata codegen before touching the frontend.

Events (Rust → frontend)

Pushed over channels the frontend subscribes to:

  • crawl — crawl progress (status / per-page / done).
  • links — internal-link planning progress (per source page / done).
  • ai:fix — AI agent activity (status / tool / write).
  • ai:confirm — pending write-confirmation requests.

Database (SQLite)

Table Purpose
projects name, site_url, local_path, created_at
reports per-run page report (JSON payload) + score
crawls per-crawl site report (slim: aggregates + page summaries)
crawl_pages full per-page report for a crawl, fetched on drill-in
settings key/value: app (settings JSON) and license (first-run)
monitors scheduled scans (url, recipe, interval, last run/score)
alerts regression / error / improvement events
citations one row per citation probe of one engine: cited?, position, cited URLs, mentioned?, mentions, excerpt, error, and Jev's judgment (JSON: coverage, diagnosis, fidelity, claims) when a TypeSafe key is set
probe_schedules repeating probes (url, query, engines, interval, last run, failures); claimed before running, like monitors
run_log one row per attempted run (monitor / probe / tick): runner, status, error, detail, started/finished, next attempt
gap_reports one comparison of a page with a competitor an engine cited instead (JSON: coverage of both, missing/partial points, verdict, cost)
link_plans one internal-link plan per run over a crawl (JSON payload: suggestions, per-page outcomes, tokens, cost)
bot_visits AI-crawler visits per project, day, crawler and log file (two files add up; the same file replaces)

settings also holds tick_last_run, the unix time of the last background run. Two processes may run monitors and schedules at once — the open app and the tick agent — so both claim a row with UPDATE … SET last_run_at = now WHERE last_run_at = <the value read> before running it; one row affected means "mine".

The reports payload is a PageReport, which since 0.6.0 also carries the extracted reader view (reader), the ranked passages (passages) and the publisher entity (entity), and since 0.8.1 the page's outgoing internal links (links); older payloads load with those defaulted.

Secrets are not in the database — see Security.