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:
1 parent
e9a6562dc6
commit
6d5a231f5c
100 files changed
+924
-3295
No files matched your search
@@ -20,19 +20,26 @@ is a new driver — never a session-type branch in shared code (routes,
|
||||
transcript, app screens).
|
||||
|
||||
The second one, for the Rust port on the `rustify` branch: **the phone app
|
||||
and a planned desktop app share almost all of their code.** Screens, widgets,
|
||||
folding, paging, config and the network client live in the shared crates
|
||||
(`iris`, `client-core`, `transcript-ui`, `tabs-ui`); `android-app` and
|
||||
`desktop-app` are thin entry points that own only what the platform forces
|
||||
(JNI and the IME on one side, winit and argv on the other). The two
|
||||
and a planned desktop app share almost all of their code.** Screens,
|
||||
widgets, folding, paging, config and the network client live in
|
||||
`app-rust/`'s `client` and `ui` modules, drawn with `iris`; `src/android`
|
||||
and `src/desktop` are thin entry points that own only what the platform
|
||||
forces (JNI and the IME on one side, winit and argv on the other). The two
|
||||
*layouts* will differ, to suit a phone's screen and a finger against a
|
||||
desktop's screen and a mouse -- but the widgets a layout is made of (a
|
||||
button, a text field, a list, a card) and the styling (colours, spacing,
|
||||
type) are one implementation with no per-platform copy. Anything that could
|
||||
work on both goes in a shared crate the first time it is written, and a
|
||||
platform crate growing a widget or a colour is a defect to move, not a
|
||||
convenience to keep. Iris said this on 2026-09-07; docs/RUST.md carries the
|
||||
details.
|
||||
work on both goes in `ui` the first time it is written, and a platform
|
||||
module growing a widget or a colour is a defect to move, not a convenience
|
||||
to keep. Iris said this on 2026-09-07; docs/RUST.md carries the details.
|
||||
|
||||
The third, from Iris on 2026-09-08: **`iris/` is the UI framework and
|
||||
nothing else.** Nothing in it may know about a session, a transcript, a
|
||||
setup or a server; anything that does belongs in `app-rust/`, and the
|
||||
dependency runs one way only. The port's project code is **one crate**
|
||||
(`ai-app`) rather than the six it was scattered across — see docs/RUST.md's
|
||||
"One app crate" for what forced each of the splits that were removed and
|
||||
the two that remain.
|
||||
|
||||
## Layout
|
||||
|
||||
@@ -44,6 +51,22 @@ Module-by-module intent is in `docs/PLAN.md`'s "Backend layout".
|
||||
|
||||
- `server/` — the Rust backend (`ai-server`). `routes.rs`'s module doc
|
||||
comment is the HTTP table and the surface's source of truth.
|
||||
- `event-model/` — the wire shape `server/` and `app-rust/` both depend on,
|
||||
which is the whole reason it is a crate of its own rather than part of
|
||||
either: it is the contract between them, so the two agree by construction.
|
||||
- `app-rust/` — the Rust app, one crate (`ai-app`) with three faces. `src/
|
||||
client` is everything with no UI in it (the REST and SSE clients, the
|
||||
transcript cache and fold, the highlighter, the ANSI parser, config and
|
||||
the enrolment link); `src/ui` is the screens as iris widget trees;
|
||||
`src/desktop` + `src/bin_desktop.rs` is the winit binary; `src/android`
|
||||
is the `android-view` entry point and `android-project/` its Gradle app;
|
||||
`src/shell` is the separate JNI bridge the Kotlin `app/shellApp` calls.
|
||||
Features pick which face a build is: `screens` (default) for anything
|
||||
that draws, `shell` for the Compose app's bridge, `bench` for P0's
|
||||
fixture build. See its `Cargo.toml` header.
|
||||
- `iris/` — the UI framework, and **only** the UI framework: `core`,
|
||||
`macro`, the `iris` crate itself, `tabs-ui` (its own demo widget tree)
|
||||
and `rig-input`. It must not mention anything this product is about.
|
||||
- `app/` — the Compose app, package `com.example.aiapp`, label "AI Sessions".
|
||||
`AppRoot.kt` is the navigation `when`; `MainScreen.kt` the root's four tabs
|
||||
(sessions, import, models, setups); `Api.kt`/`EventStream.kt` the REST + SSE
|
||||
@@ -66,6 +89,9 @@ Module-by-module intent is in `docs/PLAN.md`'s "Backend layout".
|
||||
Read it before touching `TranscriptCache.kt`, `TranscriptSource.kt`, or
|
||||
the opening and stream effects in `SessionScreen.kt`.
|
||||
- `docs/TODO.md` — the working list.
|
||||
- `docs/SUBAGENTS.md` and `docs/SUBAGENTS_DECISIONS.md` — a session's
|
||||
subagents (the wire shape, the phone's view) and the choices behind
|
||||
them still awaiting review.
|
||||
- `docs/RUST.md` — the plan for moving the app to Rust (on the `rustify`
|
||||
branch of the `ai-app-2` clone): what has to be reproduced, the
|
||||
framework decision, and the ordered experiments with their pass
|
||||
@@ -74,8 +100,8 @@ Module-by-module intent is in `docs/PLAN.md`'s "Backend layout".
|
||||
`docs/LAYOUT.md`, `docs/TEXTURES.md`, `docs/CLIENT_CORE.md` — iris's
|
||||
own build log (**any major addition or design decision, not only
|
||||
public API** -- Iris, 2026-09-08), working list, decisions log,
|
||||
layout/render design, and texture-atlas design, and the client-core
|
||||
crate's design, respectively.
|
||||
layout/render design, texture-atlas design, and the design of
|
||||
`app-rust`'s `client` module, respectively.
|
||||
- `docs/SCROLL.md` — how anything in iris scrolls: one
|
||||
`ScrollController` holds the position, the gesture, the fling and the
|
||||
pin, and the two widgets that scroll (`ScrollArea`, `LazySpan`) own
|
||||
@@ -121,10 +147,15 @@ guaranteed to have.
|
||||
|
||||
## Checking your work
|
||||
|
||||
- **Server**: `./run-tests.sh` from the repo root (or `cargo test` from
|
||||
`server/`), plus `cargo clippy --all-targets` and `cargo fmt`. The build
|
||||
stays warning-clean and rustfmt-clean at the defaults — there is no
|
||||
`rustfmt.toml` and there should not be one.
|
||||
- **Rust**: `./run-tests.sh` from the repo root runs `event-model`,
|
||||
`server/` and `app-rust/`; `cd iris && cargo test` runs the framework's
|
||||
own suite, which is slower and not about this product. Each workspace
|
||||
also gets `cargo clippy --all-targets` and `cargo fmt`. The build stays
|
||||
warning-clean and rustfmt-clean at the defaults — there is no
|
||||
`rustfmt.toml` and there should not be one. `app-rust/` and `iris/` are
|
||||
pinned to the same dated nightly (`rust-toolchain.toml`, one copy each,
|
||||
because a pin applies per directory); `server/` and `event-model/` are
|
||||
stable.
|
||||
- **App**: from `app/`,
|
||||
`. ./android-env.sh && ./gradlew :androidApp:ktfmtFormat
|
||||
:androidApp:compileDebugKotlin :androidApp:lintDebug
|
||||
@@ -295,25 +326,30 @@ Each exists because something was invisible without it.
|
||||
framework, from `atrace` text output with no trace processor needed. It is
|
||||
how the cost of a layout node per link was attributed to the framework
|
||||
rather than guessed at.
|
||||
- **`iris/android-app/build-apk.sh [debug|release] [--abi ...] [--features
|
||||
...]`** builds iris-android-app's cdylib (`cargo ndk`) and its APK
|
||||
(Gradle) in one step and verifies the result (`aapt2`/`apksigner`), and
|
||||
**`iris/android-app/run-bench.sh [--apk PATH]`** installs it on this
|
||||
checkout's own emulator, taps "Run benchmark" by label, and prints the
|
||||
report -- written so the P0 build/install/tap/read-report cycle stops
|
||||
being retyped by hand each time (docs/RUST.md's P0 box).
|
||||
- **`app-rust/build-apk.sh [debug|release] [--abi ...] [--features
|
||||
...]`** builds the Rust app's cdylib (`cargo ndk` from `app-rust/`,
|
||||
straight into `android-project/app/src/main/jniLibs/`) and its APK
|
||||
(Gradle, from `android-project/`) in one step and verifies the result
|
||||
(`aapt2`/`apksigner`), and **`app-rust/run-bench.sh [--apk PATH]`**
|
||||
installs it on this checkout's own emulator, taps "Run benchmark" by
|
||||
label, and prints the report -- written so the P0
|
||||
build/install/tap/read-report cycle stops being retyped by hand each
|
||||
time (docs/RUST.md's P0 box). It passes `--no-default-features`, so
|
||||
`--features` alone decides what is in the `.so`; that is what keeps the
|
||||
1.9 MB bench fixture out of a build that did not ask for `bench`.
|
||||
- **iris's three test layers** (docs/RUST.md's "Three test layers" has
|
||||
the commands and what each cannot answer): test at the cheapest one
|
||||
that can answer the question. `cargo test -p transcript-fixture` runs
|
||||
the real transcript screen over the bench fixture with **no window, no
|
||||
that can answer the question. `cd app-rust && cargo test` runs the real
|
||||
transcript screen over the bench fixture with **no window, no
|
||||
compositor and no GPU** (`iris::harness`), on a clock the test owns and
|
||||
a gesture replayed from a `t_ms action x y` file under
|
||||
`iris/transcript-fixture/touch/` -- which is how the batched 120Hz
|
||||
`app-rust/touch/` -- which is how the batched 120Hz
|
||||
flick a finger actually makes is testable at all, since a `ui-trace`
|
||||
swipe is many evenly-spaced events. `iris/run-headless.sh phone --phone
|
||||
--shot …` opens the same screen in a window at the phone's own size and
|
||||
density for looking at, and `--replay FILE` drives the same recording
|
||||
into it. The emulator is for JNI, the IME, insets, the surface
|
||||
--dir ../app-rust --shot …` opens the same screen in a window at the
|
||||
phone's own size and density for looking at, and `--replay FILE` drives
|
||||
the same recording into it (`--dir` names the workspace to build in,
|
||||
since the rig lives in iris and the app's examples do not). The emulator is for JNI, the IME, insets, the surface
|
||||
lifecycle and one verification run before a build goes to the phone --
|
||||
not for iterating on layout.
|
||||
- **The emulator is a GLES rig, deliberately** (Iris, 2026-09-08;
|
||||
|
||||
Reference in new issue
Block a user