iris is the framework alone; the app is one crate in app-rust/

Iris: "the organization of the rust rewrite is a mess right now... there
shouldn't be anything related to the app inside of iris. Iris is supposed
to be the UI framework alone." And, on the crate count: "I'm confused why
the app only code needs more than one crate though."

Nine cargo workspaces become three, and the port's project code -- which
sat in five places, four of them inside the framework -- becomes one crate,
`ai-app`, in `app-rust/`:

  client-core                -> app-rust/src/client
  iris/transcript-ui         -> app-rust/src/ui
  iris/transcript-fixture    -> app-rust/src/ui/fixture.rs + tests/ + touch/
  iris/desktop-app           -> app-rust/src/desktop + src/bin_desktop.rs
  iris/android-app           -> app-rust/src/android + android-project/
  android-shell              -> app-rust/src/shell

iris/ keeps core, macro, the iris crate, tabs-ui and rig-input, and now
mentions no session, transcript, setup or server anywhere.

Only two of the old splits had a reason that survived reading. event-model
stays a crate at the repo root because server/ depends on it too, so a
crate is what makes the backend and the app agree by construction. The two
Android .so names looked like a hard constraint -- a package produces one
library artifact -- until P2 turned out to already plan merging those two
Android apps into one; both faces now come out of libai_app.so, picked
apart by features so `--no-default-features --features shell` keeps wgpu,
parley and iris out of the Compose app's APK. docs/RUST.md's "One app
crate" has the rest, including what each remaining feature is for.

DECISIONS.md and SUBAGENTS.md move into docs/ with everything else.

Verified: ./run-tests.sh and `cd iris && cargo test` green, clippy and fmt
clean in all five workspaces, `cargo ndk -t x86_64` links libai_app.so,
build-apk.sh produces an APK that installs and launches on this checkout's
emulator (Gl ... virgl, as expected), and the phone-sized headless
screenshot renders the transcript unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Opus 5 committed 2026-09-08 23:36:38 -04:00
1 parent 7b54aaf3c4
commit a9312e9431
113 files changed
+23221 -2992

No files matched your search

+124 -13
View File
@@ -8,35 +8,146 @@ edition.workspace = true
[dependencies]
iris-core = { workspace = true }
iris-macro = { workspace = true }
cosmic-text = { workspace = true }
unicode-segmentation = { workspace = true }
winit = { workspace = true }
arboard = { workspace = true, features = ["wayland-data-control"] }
parley = { workspace = true }
swash = { workspace = true }
pollster = { workspace = true }
wgpu = { workspace = true }
image = { workspace = true }
accesskit = { workspace = true }
tokio = { workspace = true, features = ["sync", "rt", "rt-multi-thread"] }
# For diagnostics visible through android_logger (or whatever logger the
# app crate installs) -- this crate never installs one itself. Not in the
# android-only block below any more: the lines that matter most are in
# shared widget code, which the host backend compiles too.
log = "0.4.34"
# winit everywhere except Android; android-view (below) is what stands in
# for it there. Both backends live in this crate (see `src/android/mod.rs`'s
# doc comment) but are never compiled together: winit's own Android support
# pulls in `android-activity`, which panics at compile time unless one of
# its own backend features is picked, and picking one is exactly what
# `iris-core` was kept free of (RUST.md's I0b). Confirmed by trying it
# 2026-09-05: `cargo ndk -t x86_64 -P 26 build -p iris` failed inside
# `android-activity` itself with "Either game-activity or native-activity
# must be enabled" before this split existed.
[target.'cfg(not(target_os = "android"))'.dependencies]
winit = { workspace = true }
arboard = { workspace = true, features = ["wayland-data-control"] }
# I4 (RUST.md): the desktop half of the AccessKit push, `winit`'s own
# adapter over `accesskit`. No pin needed the way android-view's rev is
# pinned -- this is an ordinary crates.io release with no local abort to
# track (that finding is Android-only, see below).
accesskit_winit = "0.34.0"
# Pinned to the exact commit RUST.md's E1 (2026-09-04) measured on this
# emulator -- real Vulkan rendering, a working `InputConnection`, and the
# accesskit-detach abort, all against this rev specifically. Advancing it
# wants re-running E1's checks, the same reason the nightly toolchain pin
# is dated rather than floating.
[target.'cfg(target_os = "android")'.dependencies]
android-view = { git = "https://github.com/rust-mobile/android-view.git", rev = "bec6c62a96cef8239b0fd7fedeef9b184d02e3a1" }
# I4 (RUST.md): the Android half of the AccessKit push, over android-view's
# `AccessibilityNodeProvider`. **0.8.0 carries the same detach-abort E1
# found on 0.4.0** (the `State` enum still never returns to `Inactive`,
# and `send_completed_event` still unwraps a Java exception) -- advancing
# the version is not the fix, so pinning to a specific rev buys nothing
# here the way it does for android-view itself. `android/view.rs`'s
# `raise_if_enabled` is the mitigation, carried from E1.
accesskit_android = "0.8.0"
# Not re-exported by android-view (only `jni` and `ndk` are), and needed
# for `android/insets.rs`'s own id -> state map -- the same reason
# android-view's own `PEER_MAP` carries one.
send_wrapper = "0.6.0"
[features]
# RUST.md's I5 "Where iris's frame time goes" diagnosis: pins the
# `wgpu::Instance` to `Backends::GL` instead of `Backends::PRIMARY`, so one
# build can be measured on either backend. A compile-time feature rather
# than an env var because nothing on this machine can hand an env var to an
# already-launched Android process (there is no `am start` environment and
# no system-property reader here to add one).
#
# **Not needed to get GLES in the emulator**, whatever the history here
# says: the emulator's guest has no hardware Vulkan at all, so an ordinary
# build's runtime fallback lands on GLES by itself (docs/RUST.md, "What the
# emulator gives a GPU app"). Keeping the emulator on the same binary the
# phone runs is the point. What this feature is still for is forcing GLES
# on a machine that *does* have Vulkan -- the desktop -- which is why
# `default/render.rs` reads it too:
# ./run-headless.sh transcript --shot /tmp/x.png -- -p transcript-ui \
# --features iris/force-gles
force-gles = []
[dev-dependencies]
tokio = { workspace = true, features = ["sync", "rt", "rt-multi-thread", "time"] }
# The tabs example's widget tree. A dev-dependency cycle back to this
# package is fine -- cargo excludes dev-dependencies from the graph used
# to build the library itself, so this only matters for `--examples`.
tabs-ui = { path = "tabs-ui" }
# `tests/mask_sdf.rs` only: the grid it hands the GPU and the coverages it
# reads back. wgpu and pollster are ordinary dependencies already.
bytemuck = { workspace = true }
# Plain Instant-timed binaries, not criterion -- see benches/message_list.rs's
# header for why. `harness = false` opts out of the unstable `#[bench]`
# test-crate harness cargo would otherwise want, in favour of an ordinary
# `fn main()`.
[[bench]]
name = "message_list"
harness = false
[workspace]
members = ["core", "macro"]
members = [
"core",
"macro",
"tabs-ui",
"rig-input",
]
[workspace.package]
version = "0.1.0"
edition = "2024"
# Debug info is the reason a `cargo test --workspace` here was taking half
# an hour, and it is worth the paragraph. Measured 2026-09-08: with rustc's
# default `debug = true`, linking this workspace's test binaries wrote
# **~54 GB** (one single test binary's linker wrote 16.9 GB) and left an
# **88 GB** `target/`. Eight test binaries each statically link the whole
# wgpu + naga + winit + parley graph, and at the default every one of them
# gets a full copy of that graph's DWARF written into it. On a btrfs at 83%
# full the linkers then sat in `handle_reserve_ticket` -- uninterruptible,
# waiting on space reservation -- at about 20 MB/s between them, which is
# what "the tests are slow" actually was. Not CPU: the machine was 87% idle
# throughout.
#
# `line-tables-only` keeps what is actually read from a backtrace -- the
# file and line of every frame, which is what a panicking test prints and
# what gdb needs to name the frames of a segfault. What it gives up is
# inspecting variables in a debugger; when that is wanted, ask for it on
# the command line for that one run rather than paying for it on every
# build:
#
# RUSTFLAGS="-C debuginfo=2" cargo test -p iris --test whatever
[profile.dev]
debug = "line-tables-only"
# The tests are what this is really for; `cargo test` uses `dev` for
# dependencies and `test` for the test targets themselves, so setting only
# `dev` leaves the eight big binaries at the default.
[profile.test]
debug = "line-tables-only"
[workspace.dependencies]
pollster = "0.4.0"
winit = "0.30.12"
wgpu = "28.0.0"
bytemuck = "1.23.1"
image = "0.25.6"
cosmic-text = "0.16.0"
unicode-segmentation = "1.12.0"
pollster = "1.0.1"
winit = "0.30.13"
wgpu = "30.0.1"
bytemuck = "1.25.2"
image = "0.25.10"
parley = "0.11.1"
swash = "0.2.10"
fxhash = "0.2.1"
arboard = "3.6.1"
accesskit = "0.25.0"
iris-core = { path = "core" }
iris-macro = { path = "macro" }
tokio = "1.49.0"
tokio = "1.53.1"