# §16 — The single-window tool that waits

Still one window, but now something slow sits behind it — and gpui's main thread is not where slow things go.

Add a `host` crate: the async service facade, gpui-free, where every operation the app can perform is a method. Views never touch it directly. They dispatch through `atlas::bridge::run`, which puts the future on the process-wide tokio runtime and delivers the result back on the UI thread.

One seam is the whole point. There is one place to look when a result never arrives, and one runtime to reason about rather than a `Runtime::new()` per module and four thread pools fighting over the same cores.

Use `Load<T>` for what comes back. An `Option<Vec<T>>` cannot tell "still loading" from "loaded and empty" from "failed", which is how an empty table ends up spinning forever.

## What you are carrying

- `model` — The domain types.
- `store` — Local persistence.
- `host` — The async facade. Everything slow lives here.
- `app` — The UI, and the one bridge call per dispatch.

## Start it

```bash
scripts/new.sh Acme ~/Dev/acme --template minimal
```

## What it looks like

`crates/app/src/state.rs`

```rust
use atlas::prelude::*;

impl AppState {
    /// Fetch the list and publish it. Three states in one signal, so a view
    /// cannot render a failure as an empty list.
    pub fn reload(&self, cx: &mut gpui::App) {
        let host = Arc::clone(&self.host);
        let items = self.items.clone();
        items.set(cx, Load::Loading);

        bridge::run(cx, async move { host.items().await }, move |result, cx| {
            items.set(cx, result.into());
        });
    }
}
```

## Where now

- Sign it and ship it — turn to §101 (Appendix B)
- Hand it to an agent — turn to §102 (Appendix C)
- Walk it again from the start — turn to §1
