# Desktop application export `rea export-desktop-application ` turns a folder written by [desktop application capture](desktop-application-capture.md) into an agentenv bundle holding one computer app environment: the real application, installed from the distribution archive, its vendor's apt repository or the `.deb` file it was installed from on the `ubuntu-24.04` computer base, launched at boot, seeded with the user's state and serving that state through agentenv's data operations. ```sh rea export-desktop-application ./mousepad-capture ./mousepad-bundle agent-env run ./mousepad-bundle --dry-run ``` The export reads the capture and its [state view](desktop-application-state.md); it does not run the application. `--name` sets the environment name; otherwise it comes from the desktop entry id or the program, with an `app-` prefix when that name would not be a portable bundle name (for example all digits). The output directory must be new or empty. `--task` adds a task an agent wrote for the capture, once REA has validated it against the capture; see [desktop application tasks](desktop-application-tasks.md). `--package-url` says where the computer downloads the package of an application installed from a `.deb` file; see [Applications from a .deb file](#applications-from-a-deb-file). The command returns Evidence with operation `export_desktop_application` and predicate type `rea.desktop-application-export`, listing the environment name, owned paths, seed files and written files. A failed export, cancellation included, removes the bundle it had not yet published, so no partial copy of the user's data remains. If the bundle was published but its output handles could not be closed, the command reports a cleanup error that carries the export Evidence; the bundle itself is complete. ## The bundle | Path | Contents | | -------------------------------- | -------------------------------------------------------------------------------------------------- | | `envs//env.toml` | `type = "computer_app"`, the module and class, `computer = "ubuntu-24.04"`, `driver = "reference"` | | `envs//.py` | The `ComputerAppEnvironment` class | | `envs//SKILL.md` | What the app is, its window class and where its files live | | `envs//seed/` | The application's files from before the capture, by home-relative path | | `envs//apt-keys/` | The signing key of each vendor apt repository the app installs from | | `envs//install-package.sh` | With `--package-url`: the run script that installs the downloaded package with dpkg | | `tasks/smoke.json` | A task that deploys the app | | `tasks/.json` | With `--task`: the agent's task, its verifier in `artifacts/` and the eval in `evals/` | | `README.md` | What was exported, from which capture, and what to keep in mind | The class file is `_app.py` with hyphens as underscores, for example `mousepad_app.py`: agentenv imports it under its stem, so a plain `.py` could shadow a standard library module such as `calendar`. A class name that would collide with a name the module imports or defines, such as `Path`, takes an `App` suffix. The class declares: - `Packages(apt=[...])` with the package the capture found. A vendor package is named `/`, its repository's release (the Suite apt reports as `a=`, or else its Codename), so apt takes it from that repository even when the Ubuntu archive offers a higher version or epoch, as noble's transitional `firefox` does over packages.mozilla.org's; it is named alone when the release names neither, or when the capture was written before releases were recorded. Its library packages follow, so a package that leaves out dependencies on the libraries it loads, as Typora's Electron package does, still starts; library packages the capture found neither the Ubuntu 24.04 archive nor a declared repository offers are left out, with a limitation. An archive package's declared dependencies are trusted as they are. The package must come from the Ubuntu 24.04 archive or a mirror of it, or from a vendor apt repository whose signing key the capture verified and retained. A source counts as the archive when apt reports its origin as `Ubuntu` for a noble suite; a capture made before origins were recorded counts only Canonical's own archive hosts. - For a vendor repository, `sources=[AptSource(apt=..., suite=..., components=[...], key="apt-keys/.gpg")]`, with the retained key copied to that path (`.asc` when it is armored, which agentenv tells by its content). apt takes one key per URI and suite, so sources that share them, such as one repository listed for two architectures, are declared once, with their components merged; one with a different key is left out. A repository whose key the capture did not verify, an Ubuntu Pro (ESM) repository, one whose sources entry's URI held a user name or password (which the capture did not record and the export never writes; the reason names neither them nor the URI), one not reached over http or https, or one whose `arch=` restriction leaves out the capture host's architecture is refused with its reason (a capture written before restrictions were recorded counts as unrestricted); when another usable repository lists the same version it is left out instead, with a limitation. The export also refuses snaps, flatpaks, AppImages, and a package no recorded repository lists unless it was installed from a `.deb` file the capture recorded and `--package-url` is given, since the computer could not install them by name, and a capture written before credentials were removed whose repository URI still holds them, since it counted that repository's libraries as installable; capture it again. - `@computer_app(supports=...)` with both `amd64` and `arm64` for an archive package, which the archive serves for both, and only the capture host's architecture for a vendor package, since its repository may serve no other. A vendor package captured on any other architecture is refused. A package installed from its `.deb` file supports only that file's architecture. - A launch at boot with the captured command, ready when a window of the captured class appears and one of them is listed in the taskbar and is not typed as a splash: a splash screen or a dialog of the class skips the taskbar or says it is a splash, and an app whose splash shows first would otherwise count as ready before its own window opens. Arguments that are the captured home or under it, and `