Skip to content

Remove the C++ engine; upstream Vicinae releases are the reference (ADR-0021) - #235

Merged
hanthor merged 22 commits into
mainfrom
claude/modest-bell-xqa0vv
Sep 25, 2026
Merged

hanthor merged 22 commits into
mainfrom
claude/modest-bell-xqa0vv

Conversation

@hanthor

@hanthor hanthor commented Sep 25, 2026

Copy link
Copy Markdown
Member

The Rust engine covers 152 of 152 parity rows, so the legacy C++/Qt engine is removed. Benchmarks and differential tests now use the pinned upstream Vicinae release, which scripts/bench already downloads and SHA-checks.

Removed (about 1,400 files, about 20 MiB)

  • Engine and helpers: src/server, src/lib, src/cli, src/data-control-server, src/file-indexer, src/snippet and src/wayland-protocols. The Rust crate already has identical copies of the protocol XML.
  • Browser integration: src/browser-extension. Its native host only spoke to the C++ daemon, and browser control was left out of the port (ADR-0008).
  • Build and tooling: CMake (CMakeLists.txt, presets, cmake/), the clang-format/clang-tidy/clangd/qmlformat configs, and vendor/ except fuzzy-trigram, which compass-sqlcipher-sys compiles.
  • CI:
    • The build-linux/macos/windows/appimage workflows, plus build-appimage-image, macos-dmg and cpp-on-target.
    • The C++ jobs in release.yml, which now resolves the tag, publishes to npm and cuts a GitHub release.
    • g++-14 everywhere.
  • Nix: the soulver/numen inputs and nix/vicinae.nix. The macOS and Windows bundle files and the old vicinae desktop, service, icon and config files in extra/.
  • Tests that only parsed C++ sources. Their values stay pinned in the Rust tests.

Moved

  • Glyph data → crates/compass-core/glyph/
  • Builtin icons → extra/builtin-icons/
  • DB migrations → crates/compass-db/migrations/vicinae/ and crates/compass-clipboard/migrations/
  • Script-command fixtures → crates/compass-core/tests/fixtures/
  • Qt translation catalogues → extra/translations/qt/. All 7,347 messages are still accounted for by ts-to-ftl.py --check.
  • Upstream's fuzzy scorer and crypto → scripts/bench/upstream/. They are checked byte-for-byte against v0.29.0 and still drive the scorer and crypto differentials in rust.yaml.

Ported

figura, the IDL generator, is now crates/compass-figura. Its output is byte-identical to the C++ figura for all six .fig files, and the extension runtime's bindings are committed, with a staleness test. Building the runtime now needs only npm, so Flatpak, Nix, Arch and CI no longer need g++ or CMake.

Cleanup

  • AGENTS.md is rewritten for the Rust codebase: crate roles, the unsafe exceptions, the seam test, the test ladder, fmt/clippy/Biome/alejandra, and the i18n rules.
  • nix: Home Manager programs.compass (with a user service and compass.json) and NixOS programs.compass.input-server. programs.vicinae.* stay as renamed-option aliases; soulver, numen and browser are removed with a reason.
  • PARITY.md: the "C++ deleted" column is ✅ throughout.
  • CONTRIBUTING, packaging README, .gitignore and .envrc: C++-era text is gone.
  • ADR-0021 records the removal. It supersedes ADR-0013's plan to keep the C++ build for macOS and Windows; those platforms use upstream releases.

Verification

Local: cargo fmt --check, workspace clippy -D warnings and cargo test --workspace all pass (4,669 passed, 0 failed). parity-score.py reports 152/152. The runtime build and npm test pass, and every workflow file parses. The nix modules pass alejandra, but nix was not evaluated here; the Nix package CI job covers that.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn


Generated by Claude Code

iced's default scrollbar is a 10px square rail and scroller. Every
scrollable now goes through crate::scroll::scrollable, which draws the
C++ ViciScrollBar: 6px wide, radius 3, no rail, the text colour faint at
rest and stronger under the pointer or while dragging.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Every Markdown view (an extension's Detail, the store detail page, the
store intros, the created-extension page) built its settings with
`markdown::Settings::with_text_size(14, &theme)`, whose `style.font` is
`Font::default()` -- the generic sans-serif -- while every other text
widget uses `LauncherApp::font()`. cosmic-text maps generic sans-serif
to a hard-coded "Open Sans"; where that family is missing (a stock
GNOME install) each span goes through its fallback list instead, and
bold spans of a variable default family land on whichever family has a
static 700 face (DejaVu Sans Bold, Cantarell Bold...), so the page's
text was in a different, mixed face from the rest of the launcher.

`LauncherApp::markdown_settings` now sets `style.font` to the launcher
font (code keeps iced's monospace) and all four views use it; the
store viewer's image placeholder uses the same font.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
publish-flatpak.yaml takes the bundle a green Flatpak run on main
already built and smoke-tested, exports it as an OCI image to
ghcr.io/tuna-os/compass and records it in the remote's index through the
org's shared publish-flatpak-index step. It refuses to publish an image
without AppStream labels.

The metainfo gains a developer, screenshots, branding colours and a
first release. The screenshots are rendered through the paint tier by an
ignored test, regenerated with `just screenshots`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
… behind the card

Closes the last amber parity cell, src/services/window-material Rust ✓
(152 of 152). The maintainer approved an unsafe exception (ADR-0019):

- compass-wayland-foreign: a Linux-only crate that does not inherit the
  workspace's forbid(unsafe_code); it denies unsafe, restates the other
  lints, and allows it in one function (adopt) with two blocks,
  Backend::from_foreign_display and ObjectId::from_ptr. Its safe API,
  bridge(&window), takes both raw-window-handle handles from one window,
  accepts only Wayland ones, checks the pointer is a wl_surface, refuses a
  surface that is not a wayland-rs proxy, names the client_system backend
  so the wrong one does not compile, and keeps one Connection per display
  for the process's life.
- compass_platform::WindowMaterial (the seam), implemented by
  vicinae::window_material over the bridge and
  compass_wayland::material::BackgroundEffects, handed to
  compass_ui::run_resident by the binary.
- compass-ui measures the card with a sensor keyed on tint and corner
  radius and asks through iced::window::run for the card's rounded
  rectangle while the card is translucent, none when it is not.
- BackgroundEffects drops effects of destroyed surfaces before sending,
  since set_blur_region on one is a protocol error on winit's display.

Under the xdg_toplevel presentation only: iced_layershell drops
window::run, a declared difference. Tested on headless Sway (the bridge)
and an in-process compositor that blurs (the region traffic); real blur
on KWin is VM tier.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
The README now leads with what Compass is and a measured comparison against
the pinned, unmodified Vicinae v0.29.0 AppImage: cold start (96 ms vs 1,746 ms
to IPC ready; 0.9 s vs 2.3 s to a populated launcher), keystroke to frame
(56 vs 153 ms), idle PSS (218 vs 263 MiB), 46 vs 136 shared objects and
72 MB vs 310 MB of program files. It also says where Compass loses: its fuzzy
scorer is 2-3x slower per core, and it runs more threads.

- scripts/bench/compare.sh and compare.py (just bench-compare): headless Sway,
  a private D-Bus bus with no activation, throwaway HOME/XDG, both engines
  under unshare --net, alternating runs, process trees found by an
  environment tag.
- scripts/bench/fuzzy/cpp_rank.cpp and compass-testkit's fuzzy-throughput
  bin: the two scorers over the same 10k haystack and queries.
- docs/rust-engine/BENCHMARKS.md: method, machine, raw per-run numbers,
  the SLA benches, and a still-to-measure list. The raw report is archived
  under benchmarks/2026-09-25-compare.
- Install: the TunaOS Flatpak remote (com.vicinae.Vicinae), CI bundle,
  flatpak-builder, the other packages and cargo. Stale migration-status
  prose and Vicinae-only instructions are gone; credit to Vicinae is kept.
- CONTRIBUTING.md points at Compass's tracker, not Vicinae's; CUTOVER.md
  no longer quotes 70/158.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…mand broker, and an overrides manifest

Measured first: of the top 300 Raycast store extensions, 153 carry a
macOS-only signal (90 AppleScript/JXA, 39 ~/Library paths, 28 `open`,
27 Homebrew prefixes, 0 pbcopy/pbpaste); docs/rust-engine/RAYCAST-LINUX-SHIM.md
has the table and scripts/suite1/macos_signals.py reproduces it.

- The runtime's shim (extension-manager/src/linux-shim): child_process and
  fs behind proxies for the extension's require. `open` runs xdg-open,
  pbcopy/pbpaste use the runtime's clipboard, osascript and other
  macOS-only programs fail by name (CompassRefusal/ENOTSUP) instead of
  ENOENT, Homebrew's macOS paths map to Linuxbrew's. process.platform
  stays linux.
- The broker (HostCommand/run, vicinae::host_commands): `brew`, for any
  extension, runs on the host as the engine's child (flatpak-spawn --host
  inside the Flatpak) once the person allows it: Allow Once / Always Allow
  (Ctrl+Enter) / Deny. Grants in $XDG_CONFIG_HOME/compass/
  host-command-grants.json, listed and revoked in Script Permissions. The
  extension's Landlock policy is not widened. IPC v22 for the alert's
  third answer. The Qt engine refuses the call by name.
- The overrides manifest (extensions/raycast-linux-overrides.json): per
  extension host programs, path and command maps, load-time patches and
  install redirects, read by the runtime and the engine.

Raycast's real Brew bundle renders Show Installed and Search against a
Linuxbrew `brew` behind the sandbox; an end-to-end test covers the same
path with a fake brew. The runtime gets unit tests (npm test).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Clicks on the root search list did nothing: its rows were the only list
rows not wrapped in a mouse_area, so a press reached no handler. A click
now sends ResultClicked, which selects the row and does what Enter on it
does, and hands focus back to the search field. Hover still never moves
the selection, as the C++ SelectableDelegate.

The window painted a light rectangle behind the card on both the layer
surface and the xdg_toplevel: no program style was set, so iced cleared
every frame to the theme's background (the card's surface colour).
LauncherApp::style clears to transparent and is wired into run,
run_resident and run_resident_layer_shell.

Tests: Simulator clicks on a root application row (launches that row,
not the selected one), on a root command and then a store row (opens the
store, then that extension), and a hover that must not select; the paint
tier checks the window below the card's shadow is alpha 0 with the app's
style, with the theme's base colour as a failing control.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
The Rust side of the Phase 7 cutover (ADR-0012; spec in ADR-0020).

- crates/vicinae is now crates/compass: package, library and binary
  `compass`; the helpers are `compass-file-indexer` and
  `compass-input-server`, looked for in ../libexec/compass or
  ../lib/compass.
- Config, data, cache and state live under `compass`, the config file is
  `compass/compass.json`, the schema `compass.schema.json` (regenerated), and
  the IPC socket is `$XDG_RUNTIME_DIR/compass/ipc.sock`
  (`/tmp/compass-$USER` without a runtime dir).
- On `compass serve`, before anything creates a `compass` directory, each
  `vicinae` base directory is moved to `compass` and left as a symlink. When
  `compass` already exists (the pre-cutover engine kept scripts, grants and
  caches there), the entries it lacks are moved in and nothing is
  overwritten; `vicinae.json` becomes `compass.json` the same way.
- `COMPASS_*` environment variables, with the `VICINAE_*` spelling read as a
  fallback that logs a deprecation once. `VICINAE_API_URL` is
  `COMPASS_VICINAE_API_URL`.
- Compass emits `compass://` and accepts `vicinae://` and `raycast://`.
- D-Bus: `org.tunaos.compass.WindowTracker` for KWin, and the shell
  extension contract is `org.tunaos.compass.Shell.{Windows,Clipboard}` at
  `/org/tunaos/compass/Shell/*`. App id, tray item and icon are
  `org.tunaos.compass`; layer-shell namespaces `compass` and `compass-hud`.
- User-facing strings say Compass. Report Bug files against tuna-os/compass;
  the Discord builtin and tray entry are now "Compass on GitHub", and the
  sponsor entry is labelled as upstream credit.
- The extension runtime is given COMPASS_VERSION/COMMIT and reads the
  `VICINAE_*` names only as a fallback; the SDK dev client dials the new
  socket and emits compass:// links.

Kept on purpose: @vicinae/api, store.vicinae.* ids and the Vicinae store,
the keyring labels the importer reads, the vicinae-hotkey-v1 protocol, the
@Vicinae script-command scope, the vicinae-dark/-light theme ids and C++
references.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Rename the Flatpak manifest, desktop entries and metainfo to the
org.tunaos.compass ID and ship the `compass` binary, with libexec/compass
and share/compass layouts, across the Flatpak, AppImage, Arch and Nix
outputs. The metainfo <replaces> com.vicinae.Vicinae, the URL handler
takes compass:// alongside vicinae://, raycast:// and com.raycast:, and an
opt-in compass.service user unit is installed.

The GNOME Shell extension becomes compass@tunaos.org with its interfaces
under org.tunaos.compass.Shell.*. The config schema moves to
compass.schema.json and nix/vicinae.nix to nix/compass.nix. CI workflows,
the VM tier, Suite 1/5, tier 2, wlroots and the bench scripts build
`-p compass` and run target/*/compass; the benchmarks still launch the
pinned upstream Vicinae AppImage under its own name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…R-0020)

The README, CONTRIBUTING and the Rust engine docs use the new app ID, the
compass command, the compass crate and the compass config, data, cache,
state and runtime directories. The README says an existing
~/.config/vicinae is moved on first start instead of saying the old names
are kept.

ADR-0020 records the rebrand: the new names, what keeps the vicinae name
and why (@vicinae/api, vicinae:// deeplinks, the Vicinae Store, VICINAE_*
fallbacks, upstream credit, the C++ tree), the directory migration, and
why no Flatpak data migration is needed. It supersedes ADR-0012's
compatibility list.

The TypeScript READMEs and package metadata describe Compass. The
@vicinae/api module name stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
The Vicinae store's Linuxbrew extension now reaches brew through the
consent-gated broker, so a headless run sees its 'Allow Linuxbrew to run
brew?' prompt and nothing answers it. Record that as its own verdict, like
needs-sign-in for OAuth, rather than as an empty frame, and expect it in
the ledger.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
…DR-0021)

The parity ledger reads 152/152 and the benchmarks already measure the
pinned upstream v0.29.0 AppImage, so the in-tree C++/Qt engine goes.

Removed: src/{server,cli,lib,data-control-server,file-indexer,snippet,
wayland-protocols,browser-extension}, CMake (top level, cmake/,
src/typescript's), clang-format/tidy/clangd/qmlformat configs, vendor/
except fuzzy-trigram, nix/vicinae.nix and default.nix, the C++ build
scripts (scripts/runners, macOS/Windows packaging scripts), the C++
Makefile targets and the C++ CI workflows (build-linux, build-macos,
build-windows, build-appimage, build-appimage-image, macos-dmg,
cpp-on-target) and release.yml's C++ jobs. The HostCommand C++ stub goes
with src/server.

Moved what Rust reads: the glyph table to crates/compass-core/glyph, the
builtin icons to extra/builtin-icons (names now from @vicinae/api's Icon
enum), the migrations into compass-db and compass-clipboard, the
script-command corpus to a compass-core fixture, the Qt catalogues to
extra/translations/qt, and upstream's fuzzy and crypto sources plus the
probes to scripts/bench so the differentials run against upstream.

figura is ported to Rust (crates/compass-figura, TypeScript only,
byte-identical output); the extension runtime's bindings are committed
and a test keeps them current, so building the runtime needs only npm.
Tests that parsed C++ sources pin upstream's values or are dropped where
Rust tests already pin them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
- AGENTS.md rewritten for the Rust workspace: separation between
  compass-ui and the logic crates, the workspace lints, the platform seam
  test, the test ladder, cargo fmt/clippy/alejandra, and i18n as it stands
  (fluent-rs decided, catalogues not yet converted).
- nix/: programs.compass (Home Manager) and programs.compass.input-server
  (NixOS), with upstream's programs.vicinae names renamed or removed. The
  soulver/numen, browser-host, launchd and settingOverrides options go:
  the calculator is fend-core and the engine is Linux only.
- extra/: delete the C++ build's macOS, Windows, desktop, systemd,
  modules-load.d and config.jsonc files; nothing in the Rust build reads them.
- PARITY.md's C++ deleted column is green everywhere; the scorer's
  docstring says why it still reads 152/152.
- CONTRIBUTING.md, packaging/README.md, manifest.yaml, .envrc, .gitignore
  and helper comments lose their C++-era references.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
The C++ removal's rewrite of extension-runtime.nix kept the pre-rename
share/vicinae path, so the compass derivation found no runtime bundle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtGVEzDmYTdpsuEQErmmLn
@hanthor
hanthor merged commit 9c664d5 into main Sep 25, 2026
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants