Aileron
v1.0.0 -- 1198 lib tests, 257 integration, 4 doc (1459 total), ~56,900 Rust LOC
The terminal for the web. A keyboard-driven, tiling web environment with an embedded native terminal, built for developers who live in terminals. Written in Rust with wry (WebKitGTK) for web rendering and Leptos WASM for the browser chrome overlay.
Features
Core
- Vim-style keybindings — modal editing (Normal, Insert, Command) with
h/j/k/lnavigation - Tiling pane management — BSP tree layout with vertical/horizontal splits, pane navigation, and close
- Command palette —
Ctrl+Pfuzzy search (Nucleo engine) across history, bookmarks, commands, and custom Lua commands - Lua scripting —
init.luafor custom keybindings, commands, URL redirect rules, and themes - Keybinding customization — override default keybindings via
config.toml[keybindings]section - Workspace persistence — save/restore pane layouts with URLs via
:ws-save/:ws-load; auto-save every 30s for crash recovery - Tab management —
:tab-restoreto reopen closed tabs,:tab-unloadto free LRU background pane,:tabsto search open tabs - Help panel —
:helpshows full keybinding reference with collapsible sections - Crash recovery —
:crash-reloadreloads a pane after web content crash - MCP bridge — built-in Model Context Protocol server (stdio transport) so LLMs can browse the web
- ARP (Aileron Remote Protocol) — WebSocket server for mobile clients, tab sync, clipboard sharing
- Sync protocol — Local/SSH transport with delta detection and E2EE encryption (Age); WebDAV transport planned
- Cross-platform — PlatformOps trait for Linux, macOS, Windows
Internationalization
- 9 languages — EN, ZH, JA, KO, DE, FR, ES, PT, RU with
:languagecommand - Runtime switching —
:language <code>changes UI language instantly;:language-listshows available languages
Accessibility
- ARIA labels — all UI chrome elements include ARIA labels for screen reader support
Browsing
- Ad blocking — EasyList parser with network + cosmetic CSS rules,
$redirect/$important/$badfiltersupport, filter list auto-update, per-site toggle (:adblock-toggle,:adblock-update) - HTTPS upgrade — auto-upgrade HTTP for known-safe domains (EasyList HTTPS list)
- Tracking protection — blocks known tracker domains, sends DNT/GPC headers, strict referrer policy
- Popup blocker — blocks unwanted
window.open()calls, configurable via:popups - Cookie management — view (
:cookies), clear (:cookies-clear), per-site allow/block - Per-site settings — zoom, adblock, JS, cookies, autoplay per domain (exact/wildcard/regex patterns)
- Download manager — progress tracking, open file, open directory
- Browser import —
:import-firefox/:import-chromefor bookmarks and history - Multiple search engines — pre-configured Google, DuckDuckGo, GitHub, YouTube, Wikipedia; switch with
:engine <name> - Engine selection — choose rendering engine with
:engine auto|servo|webkit(servo: experimental, not yet functional) - Adaptive quality — auto-reduces rendering quality when over frame budget (
:adaptive-quality) - Custom CSS — inject custom stylesheets via config or
aileron://settings - Link hints — press
fto reveal clickable hints on all links, type digits to follow - Find in page —
Ctrl+Fincremental search with next/previous navigation - Smooth scrolling — native smooth scroll behavior
- Print support —
:printtriggers system print dialog - PDF viewer — PDFs render inline via WebKitGTK;
:pdf <path>opens local files - Reader mode —
Ctrl+Shift+Rstrips CSS and extracts article text; toggle per pane - Minimal mode —
Ctrl+Shift+Mhides images/media and removes scripts; toggle per pane
Terminal
- Native terminal — press
`to open a terminal pane usingalacritty_terminal+portable_pty+ egui rendering (no xterm.js, ~2-5MB/pane) - Terminal mouse selection — click and drag to select text, copy to clipboard
- Visual bell — terminal bell triggers a 200ms visual flash
- SSH quick-connect —
ssh user@hostin command palette opens terminal pane and auto-connects - Terminal search —
:terminal-search <pattern>searches scrollback buffer
Tabs & Panes
- Tab system — sidebar (default), topbar, or none; shows title, URL, pane type, audio/mute/pin indicators
- Tab pinning —
Ctrl+Shift+Por:pinpins a pane (prevents accidental close) - Audio mute —
:mute/:unmuteto silence a pane - Pane swap —
:swapswaps URLs between active and previously active pane - Detach pane —
Ctrl+Shift+Ddetaches pane to standalone popup window - Popup windows —
Ctrl+Nopens standalone webview (no tiling, no egui overlay)
Theming
- 7 built-in themes — dark, light, gruvbox-dark, nord, dracula, solarized-dark, solarized-light
- Custom themes — define themes in
config.tomlunder[themes.<name>] - Runtime switching —
:theme <name>to switch instantly
Privacy & Settings
- Settings GUI —
aileron://settingspage for keyboard-navigable configuration - Privacy dashboard —
:privacyshows HTTPS upgrade, tracking protection, adblock status - Bitwarden integration —
bw-unlock/bw-search/bw-autofill/bw-detectfor credential management - Password manager — built-in credential storage with OAuth detection, multi-step login flow support (
:credentials,:credentials-save)
Developer Tools
- DevTools —
F12opens WebKit inspector - Network request log —
Ctrl+Shift+Nor:networkshows intercepted fetch/XHR with status codes - Console capture —
Ctrl+Shift+Jor:consoleshows console.log/warn/error output - Git integration — status bar shows branch with dirty indicator;
:gs,:gl,:gd,:grep - Project search —
:grep <pattern>via ripgrep/grep - File browser —
:filesopens project root (auto-detects git root) - Shell commands —
:! <command>runs shell commands from the command line
Scripting & Extensibility
- Content scripts —
.luafiles in~/.config/aileron/scripts/with@matchand@match-regexppatterns,@run-at(document_start/end/idle) - Lua hooks —
aileron.on("navigate", fn)andaileron.on("mode_change", fn)in init.lua - Command chaining —
:open github.com && mgchains ex-commands - Did-you-mean — fuzzy Levenshtein suggestions for mistyped commands
- Custom protocols —
aileron://for internal pages (welcome, settings, files, error) - WebExtensions — 9 API traits, extension loading from disk,
:extensions/:extension-load/:extension-infocommands
Prerequisites
- Linux (x86_64) — tested on CachyOS (Wayland + NVIDIA), should work on any distro with WebKitGTK 4.1
- macOS (aarch64, x86_64) — WebKit built-in; requires Xcode command line tools
- Windows (x86_64) — WebView2 (Edge); experimental, see
com.github.WyattAu.aileron.yamlfor Flatpak parity - Vulkan-capable GPU — required by wgpu for rendering
- Rust toolchain —
rustc,cargo,pkg-config
Build
cargo build
# Run (with runtime library path for WebKitGTK)
LD_LIBRARY_PATH="/usr/lib:$LD_LIBRARY_PATH" ./target/debug/aileron
Test
# Unit tests (1198 tests)
cargo test --lib -- --test-threads=4
# Integration tests (257 tests, 15 suites)
cargo test --tests -- --test-threads=4
# All tests + clippy (zero warnings)
cargo clippy --all-targets -- -D warnings
cargo test -- --test-threads=4
Install
Binary Download
Pre-built binaries for Linux, macOS, and Windows are available on the releases page.
Cargo
cargo install aileron
Arch Linux (AUR)
paru -S aileron-git
Build from Source
git clone https://github.com/WyattAu/aileron.git
cd aileron
cargo build --release
cargo install --path .
Flatpak (experimental)
A Flatpak manifest is provided at com.github.WyattAu.aileron.yaml:
flatpak-builder build-dir com.github.WyattAu.aileron.yaml --force-clean
flatpak-builder --user --install build-dir com.github.WyattAu.aileron.yaml
flatpak run com.github.WyattAu.aileron
Note: Flatpak support is experimental. Targets Freedesktop 23.08 with Rust and LLVM SDK extensions.
Key Bindings
Commands
Configuration
config.toml
Aileron looks for ~/.config/aileron/config.toml:
# ── General ──────────────────────────────────────
homepage = "aileron://welcome" # Start page URL
window_width = 1280 # Default window width (px)
window_height = 800 # Default window height (px)
devtools = false # Enable WebKit devtools
# ── Privacy ─────────────────────────────────────
adblock_enabled = true # Block ads from filter lists
adblock_filter_lists = ["https://easylist.to/easylist/easylist.txt", "https://easylist.to/easylist/easyprivacy.txt"]
adblock_cosmetic_filtering = true # Hide ad elements via CSS
adblock_update_interval_hours = 24 # Filter list update frequency
https_upgrade_enabled = true # Auto-upgrade HTTP to HTTPS
tracking_protection_enabled = true # Block tracker domains + DNT headers
popup_blocker_enabled = true # Block unwanted window.open()
# ── Appearance ──────────────────────────────────
theme = "dark" # "dark" | "light" | custom name
tab_layout = "sidebar" # "sidebar" | "topbar" | "none"
tab_sidebar_width = 180.0 # Sidebar width in pixels
tab_sidebar_right = false # Sidebar on right side
language = "en" # UI language (ISO 639-1)
custom_css = "" # Inline CSS or path to CSS file
# ── Rendering ──────────────────────────────────
render_mode = "offscreen" # "offscreen" (texture) | "native" (window)
engine_selection = "webkit" # "auto" | "webkit" | "servo"
adaptive_quality = true # Reduce frame rate when slow
# ── Search ──────────────────────────────────────
search_engine = "https://duckduckgo.com/?q={query}"
[palette]
max_results = 20 # Command palette result limit
# ── Session ─────────────────────────────────────
restore_session = false # Restore last workspace on startup
auto_save = true # Auto-save workspace for crash recovery
auto_save_interval = 30 # Auto-save interval (seconds)
init_lua_path = "" # Path to custom init.lua
# ── Proxy ───────────────────────────────────────
# proxy = "socks5://127.0.0.1:1080"
# ── Sync ────────────────────────────────────────
sync_target = "" # SSH target or local path
sync_encrypted = false # E2EE for sync
sync_auto = false # Auto-sync via filesystem watcher
sync_auto_interval_sec = 60 # Auto-sync interval
# ── ARP (Remote Protocol) ──────────────────────
arp_port = 19743 # WebSocket server port
# ── Keybinding overrides (applied on top of defaults) ──
[keybindings]
# Format: "<key>" = "<Action>"
# Keys: crossterm notation — j, <C-p>, <A-S>, <C-S-i>, <F1>-<F12>
# Actions: PascalCase or shorthand (ScrollDown, vs, sp, Hints)
# "k" = "ScrollUp"
# "<C-S-k>" = "ScrollUp"
# ── Per-domain engine overrides ────────────────
[compat_overrides]
# "example.com" = "webkit"
# ── Custom themes ──────────────────────────────
[themes.mytheme]
bg = "#1a1a2e"
fg = "#e0e0e0"
accent = "#4db4ff"
init.lua
aileron.keymap.set("normal", "Ctrl+Shift+R", "reload")
aileron.cmd.create("open-rust", "Open Rust documentation", function()
aileron.navigate("https://doc.rust-lang.org")
end)
aileron.url.add_redirect("github.com", "ghproxy.com")
aileron.on("navigate", function(url)
print("Navigating to: " .. url)
end)
Content Scripts
Place .lua files in ~/.config/aileron/scripts/:
-- ==UserScript==
-- @name Dark Mode for GitHub
-- @match https://*.github.com/*
-- @match-regexp ^https://.*\.github\.com/.*
-- @run-at document_idle
-- @grant none
-- ==/UserScript==
return [[
document.body.style.background = '#1a1a1a';
document.body.style.color = '#d4d4d4';
]]
Use :scripts to list loaded scripts.
Architecture
src/
main.rs -- Event loop, wry pane management, Leptos WASM chrome bridge
app/mod.rs -- AppState (mode machine, palette, keybindings, dispatch bridge)
app/dispatch.rs -- Pure action dispatch (Action -> ActionEffect)
app/commands.rs -- Ex-command handler (60+ commands)
app/events.rs -- Key event routing, panel keyboard navigation
input/ -- Key mapping, mode transitions, keybinding registry with config overrides
wm/ -- BSP tree (tiling), rectangle math, pane metadata
servo/ -- PaneStateManager, PaneRenderer trait, WryPaneManager, ServoPane (skeleton)
terminal/ -- Native terminal (alacritty_terminal + portable_pty + egui painter)
ui/ -- Command palette (Nucleo fuzzy search), panels, omnibox, find bar, help panel
db/ -- SQLite: history, bookmarks, workspaces, downloads, site_settings
lua/ -- Lua sandbox, API bindings (cmd, keymap, theme, url)
arp/ -- Aileron Remote Protocol (WebSocket server, tab sync, clipboard sharing)
mcp/ -- MCP JSON-RPC server, tools, stdio transport
net/ -- AdBlocker (EasyList parser), filter_list (network/cosmetic), privacy (HTTPS upgrade, tracking protection)
downloads/ -- Download manager (async, resume, progress tracking)
extensions/ -- WebExtensions support (9 API traits, extension loading, lifecycle)
i18n/ -- Internationalization (9 languages, locale resolution, message catalog)
passwords/ -- Password manager (credential storage, OAuth detection, multi-step login flows, Bitwarden client)
platform/ -- PlatformOps trait, Linux/macOS/Windows platform implementations
scripts.rs -- Content script manager (Lua to JS injection, @match/@match-regexp, @run-at)
gfx/ -- wgpu surface + renderer setup
git.rs -- Git repo detection, status bar integration
popup.rs -- Standalone popup window management
frame_tasks.rs -- Frame-level task execution, auto-save, ARP sync
offscreen_webview.rs -- Offscreen webview texture compositing
wry_actions.rs -- WryAction queue utilities
sync/ -- Sync protocol (delta sync, E2EE via Age, transports)
profiling/ -- Memory profiling, performance monitoring
event_handlers.rs -- Shared key-to-JS event conversion
workspace_restore.rs -- Workspace save/restore with crash recovery
bootstrap.rs -- Application bootstrap, panic hook, environment diagnostics
chrome/
src/lib.rs -- Leptos WASM chrome UI (StatusBar, UrlBar, TabSidebar, FindBar, CommandPalette)
shared/
src/lib.rs -- Shared types for Rust <-> WASM IPC (Mode, Action, KeyEvent, PaneInfo)
tests/
integration_smoke.rs -- Cross-module integration tests
Action Dispatch Pattern
Key event -> AppState.process_key_event()
-> KeybindingRegistry.lookup() -> Action
-> dispatch_action(Action) -> Vec<ActionEffect>
-> execute_action() applies effects to AppState
-> WryAction queue consumed by main.rs
License
Apache-2.0