# Desktop application tasks A [desktop application export](desktop-application-export.md) can carry one task: a prompt for a computer-use agent and checks that grade what the agent left in the application's files. An agent, not REA, writes the prompt and the checks from the change the capture recorded. For file checks, REA validates the task against the capture and keeps it only when its checks fail on the seed and all pass on the captured end state. The checks are declarative; optional [readers](#readers) run commands to interpret files, and [screen judges](#screen-judges) use a model when no file shows the change. The exported verifier uses the same checks and reader runner as REA. ```sh rea describe-desktop-application-task ./mousepad-capture --format json > draft.json # edit the draft's task into task.json: a name, the user's request, the checks rea export-desktop-application ./mousepad-capture ./mousepad-bundle --task task.json agent-env run ./mousepad-bundle --task add-milk --agent claude-code ``` ## Describe the change `rea describe-desktop-application-task ` reads the capture and its [state view](desktop-application-state.md) and returns Evidence with operation `describe_desktop_application_task` and predicate type `rea.desktop-application-task-draft`: - `application`: the environment name the export would use, the title and the window class. - `owned_paths`: the paths the export owns, the only ones whose files the app's `data/get` serves and checks can read. - `checkpoints`: the two checkpoints compared, `baseline` for the seed and `final` for the end. They are the capture's first and last unless `--seed-checkpoint` and `--end-checkpoint` name others, as for the [export](desktop-application-export.md#the-seed-checkpoint), which takes the same options; a name the capture does not hold, or an end before the seed, is refused. - `files`: each file under them whose state differs between those checkpoints, with its home path, role, its versions at both (`baseline` and `final`, the last recorded at or before each) and the net change between them, from the state view's own diff (`lines`, `values`, `keys` or `rows` with what was added, removed and changed, or `created`, `deleted`, `format`, `content`, `unreadable`; `content` also when the views hold only part of a file and match while the file changed). A database is compared by its rows, since its hash leaves out the `-wal` file. Text changes list each line once and add `line_counts`, the lines found at both ends whose number of occurrences changed. An XML file's change names its members by the [selectors](#pointers-and-selectors) checks use, as an archive's already does, and by position only where nothing names a member or where only the members' order changed. Views appear only for the files the suggestions cover, with arrays past 200 items and strings past 2,000 characters cut (`view_cut`). - `values`, in each of those files: the values its change added, changed and removed, each with the `pointer` a check names it by, its `kind` (`added`, `changed` or `removed`), and `before` and `after`: the scalar, an element as compact XML with the text the XML reader kept, spaces between runs included, or a JSON value as compact JSON, cut at 600 characters, and null at the end that lacks it. A file created or deleted lists what its one end holds, `added` or `removed`: an archive's entries, an XML file's root element, a JSON file's members or a key file's keys, each whole once. A value only position reaches has `note: "by_position"`, and its pointer cannot go into a check; noise an app writes as it saves has `view_state`, `renumbered`, `volatile`, `timestamp`, `upkeep` or `layout` (see `task`). A record of text fields added to a list of its kind, as GnuCash's ``, is listed field by field, and a field that lists records, as its ``, record by record, so the cut never hides one. `refers_to` names up to five other elements a value equals the `key` or `id` (`xmi:id` among them) of, outside a view the app keeps of the document, as Umbrello's `listview` mirroring its model by id, with the `attribute` holding it, as HomeBank's `category="44"` names ``, or the id a child element holds, as a GnuCash split's `` names the account whose `` it is, shown with its name, `Groceries…`; an element added whole lists those of the records of attributes it nests too, as a KMyMoney transaction's splits name their `` and ``, each once. Where several elements share that key, the one whose tag shares the attribute's stem, as `payee` and ``, and of those the one named for the attribute, as `account` an `` before an ``. A plain number names an element only through an attribute so named or ending in `id`, `ref` or `key`, so a list's `count="5"` names no ``. A value that changed lists, in `alternatives`, its pointer naming the element by each other identifier or name-like attribute it holds alone among its tag's members, up to three, as an Inkscape text's `[@inkscape:label=Headline]` beside its `[@id=text12]`, for a check to name it by instead; an element its tag alone names inside the first one a condition names, as an EPUB chapter's `h1`, by its `[@id=chapter-two]`. What a check can name comes first, text an edit changed before the rest, so no cut drops the edit, then what only position reaches, then noise. A file lists at most 20 values and 8 KB, the draft 24 KB, and `values_cut` says when a limit left some out. Values cover XML, archives, JSON and key files; a text or SQLite file's change and suggestions already carry its lines and rows. - `task`: a draft with the name `change`, a placeholder prompt the export refuses, and suggested checks derived from the net change of the files with role `document`, or of the app's own state files when no document changed, excluding locks the export leaves out of the seed. App state files ending in `.log` remain eligible for checks. A text file gains `lines_present` for its new lines and `lines_absent` for lines it lost (when either is at most ten), and `line_count` for each line holding a letter whose count changed; a new line holding an XML attribute REA recognizes as generated, such as a named epoch time or `ID_329023692`, gets a `line_count` of the lines `contains` its text up to that value, as `CHILD=VALUE]`, a name-like tag first, as Osmo's record by `[>first_name=Delphine]`, MuseScore's `` by `[>style=Title]`, a spreadsheet row by its label cell, or GnuCash's transaction by `[>trn:description=Greenleaf Market]`: text of at most 64 characters, never a time or a token or id a program generates; then by an identifier a child carries, `[>CHILD@ATTR=VALUE]`, as a GtkBuilder `` by `[>object@id=submit_button]`, never one an app generates or numbers anew as it saves; and then by text a child joins from elements of its own, as Glade's `[>packing=TrueTrue1]` from a widget's packing properties, which moving the widget changes. A pair counts every member holding both its values, whichever attributes that member ranks first. An element with identifiers is named by those alone; an id the app generates, as Freeplane's `ID_329023692`, or a GUID in any attribute, braced or not, as VYM's `uuid="{18eadb5d-…}"`, ranks last, after a child's text, so a new node is named by its `TEXT` and a new VYM branch by `[>heading=Sunset boat tour]`, while a member both versions hold pairs by such an id first, so records that keep their UUIDs and swap titles read as two title edits. A value that stands for none, as Grisbi's `Id="(null)"` on every transaction, names nothing, so a new transaction is named by its `Nb`. A child's text is counted on every sibling, one an identifier names included, so a title two records share names neither. The selector must name the member alone at both ends, with the same values; a child's text names a member that is in one version only when the list's length changed, so a row whose one cell an edit changed stays that row. An element whose one identifier changed, at its place among its tag's members, with every other attribute and its children alike, is that element renamed, as a MyPaint layer renamed from `Layer` to `Sun`: it is paired by its first other attribute naming it alone at both ends, as `[@src=data/sun.png]`, so the rename reads as its `name` changed, and the old name gets a check that it names nothing, unless its change is noise, as an id the app renumbered. Where that attribute's values number the members in document order, as MyPaint 2 writes `src` as `data/layer-00.png`, `data/layer-01.png` and on along the stack and renumbers them when a layer moves, each version is named by its own value of the renamed identifier instead, `[@name=Sun]` and `[@name=Layer]`. - A child of the document's root that its tag alone names, and that holds a list (two or more elements of one tag and no text of its own) and has an identifier, also gets a condition that keeps it named if the app adds a sibling of its tag, as Dia adds an empty `Background` layer each time it reopens and saves a diagram: an id other than `name` both ends hold, as Inkscape's `[name=g][@id=layer1]`, which a new sibling would not share; else the text of a child both ends hold, as Dia's `[name=dia:layer][>dia:object=#Receive order#]`, which an empty sibling lacks; else its `name`, which a new one may repeat. Deeper, a member of a list named for its tag, as Gnumeric's `gnm:Sheet` in `gnm:Sheets`, holding elements and its tag alone naming it, gets an id, else a name-like child's text, `[name=gnm:Sheet][>gnm:Name=Budget]`, else its `name`. Other steps, and elements with neither, stay as they are. An identifier the app numbers by position names nothing: where the members of a tag hold it as 1..N (or 0..N-1) in document order at both ends, members were inserted or removed, and every member another attribute names alone at both ends kept its number or moved it the way the count did, one at least, as Planner's task `id` after a task is inserted, members are paired by their other attributes, so an insertion reads as one task added. A value two members swap, or an id appended at the end, as Tellico's next ``, leaves the ids identity. An identifier numbering the members 0..N-1 in document order at both ends, where members came or went, as Parley numbers its `` by where it saves it, ranks after a child's text where a member has one, so a new entry is `[>translation=library]` and its kept neighbours are named alike; Tellico's ids, which count from 1, Tiled's and Rosegarden's, whose members hold no text, stay identity. An element a change added that holds nothing but the id of a record it added elsewhere, as Parley's lesson membership ``, is `upkeep`, listed with `refers_to` on that record, never a check or a count. - The text check names the paragraph rather than a run inside it: it goes up from an element sitting in its parent's text, and from one named by its tag or position alone to the nearest ancestor named by an attribute, as AbiWord's `p` by its `xid`, unless it is a field its tag names in a record of two or more fields holding text, as QElectroTech's `` beside `` in a ``, or KmPlot's `` beside ``, which is checked itself rather than the record whose text joins its fields; one line of text the app lays out between line breaks, as KmPlot's formula before the next element, is checked, and its siblings guarded, with `normalize_whitespace: true`, and text whose whitespace alone changed, as a formula the app moved to an indented line of its own, gets no check; where no attribute names one, to the nearest ancestor within three levels its tag names with no step by position, as MuseScore's `VBox` around untitled `` elements; and where only position reaches the element, to the ancestor above the outermost step by position, by an attribute of its own that names it alone where one does, as an ODS sheet's `table:table[@table:name=Q1 Sales]` above its rows. The text nodes and runs inside it get no other check, but an element holding no text that is added or removed there, such as an image or a line break, keeps its own, since the text check never reads it. A decimal that is an element's only text, such as a spreadsheet cell's, is checked by its number instead. Free text that gains a line, such as a shopping list, uses `text_equals` on the whole text: the current XML checks cannot compare an unstructured line as a whole item. This can reject a correct edit that puts the item elsewhere or changes spacing. Text an app keeps in an attribute, one element per run, as Scribus's ``, gets a `text_equals` with `text_attribute` on the nearest ancestor an attribute names, as `[name=PAGEOBJECT][@ANNAME=Headline]` with `"text_attribute": "CH"`, where that ancestor holds no text nodes and the attribute's holders are runs, none inside another and none carrying an identifier or a name-like attribute beside it, as Umbrello's ``, a record whose attributes are checked one by one, two or more or one holding words with a space: an element's own attribute, as a Freeplane node's `TEXT` beside the nodes in it, or a lone value, as ``, is checked where it is. The check covers that attribute and the runs holding it; another change in the frame, as a run's `FONT`, keeps its own check. A record added or removed whole, an element holding only elements, its fields, such as Tellico's `` or a record of repeated `` elements, never makes the list holding records of its kind a check, whose text would hold the records the edit left alone, except a record removed whole that only position names, whose absence only the list's text shows. Text made of runs is no record: an element whose tag names a paragraph or a piece of text (`p`, Writer's `text:p` and `text:h`, `h1` to `h6`, `li`, `para`, SVG's `text` and `tspan`, a `span` or an `a`), one inside such an element, as Word's `` run in its ``, one whose elements are all inline formatting (`b`, `i`, `u`, `em`, `strong`, `bold`, `italic`, a `span`, `a`, `code`, `sub`, `sup` and the like, Gnote's `size:` and `link:` runs), as `olive oil`, or whose runs split a sentence at a space, as `Meet ` and a linked `Monday`. Nor does an element holding a date the app stamps in parts take a text check. - An element added to a list, where another element of its tag is at either end, gets a `value_equals` for each of its attributes, best ranked first, at most six, leaving out its selector's attributes, identifiers, times, volatile values, view state and values standing for none, as HomeBank's new `` gets its `amount`, `category` and `payee`; a value two or more like siblings all hold, as Grisbi's `Cu="1"`, comes after those that vary, as its `Pa`, `Ca`, `Dt` and `Am`. Records of attributes alone that it nests, as a KMyMoney `` its `` of ``, get a `value_equals` of each attribute whose values vary among the like records, its own and those under its like siblings, at most three a record and six in all, as each split's `value` and `payee`, but not one every split holds alike, as `price="1/1"`, nor one each holds equal to an earlier one, as `shares` repeats `value`. Each record is named by an identifier that the app neither generates nor numbers anew in every record holding such a list, as KMyMoney's `S0001` in every transaction, else by its best ranked attribute short of a coordinate or an amount, as `[name=SPLIT][@account=A000001]`. An element whose other attributes, two or more, a like sibling holds every one of, as a new Planner task copies its neighbour's defaults, and any other element added whole, get a check that it exists; of those copied, an attribute naming an element the seed holds by an id that is no plain number, as an Umbrello attribute's `type` its data type, is the user's choice and keeps its check. A record added to a list that a selector names, as Tellico's `` or Osmo's `` by its first name, gets a `text_equals` for each field, at most five, each by its selector among the record's fields, as `[name=title]`, leaving out a field repeating the record's identifier, the field its selector names it by unless it is the only one left, as a new VYM branch's ``, a value every like record holds in that field, as Osmo's `None`, noise, a field holding ids of its own, a date the app stamps in parts, and blank text or times; a field that lists records, as GnuCash's ``, gets its records' fields instead, each record by its own selector. An attribute every like record holds alike, as GnuCash's `version`, is the format's and gets no check. A record only position names also gets a `text_contains` for each new field of three or more characters, at most five, at the nearest ancestor a check can name, each absent from that ancestor's text at the seed. - Where members of a list were added or removed, a `member_count` of the list's members of their tag, and of their kind where they share one (`type`, `kind` or `shape`, as `[name=dia:object][@type=Flowchart - Box]`), unless every member of the tag holds a value of its own, as Tiled's objects a free-form `type` (`well`, `door`, `gate`), which labels each rather than grouping them, equal to the end's number, which differs from the seed's: at most two a file, the shallowest lists first, after the other checks. None for a list of one member at both ends, as a style an app adds for a run, for members of an element a text check reads, which are runs of its text, for an element in mixed content, or for noise. - A decimal written as text, such as `146.83`, is suggested as a number with `tolerance: 0.001`, unless the seed's value, read as the evaluator reads a number (`10` and `1e1` included), is that close too. A `value_equals` that would pass on the seed's value is not suggested. - An element placed by its own position, holding numeric `x` and `y` as a like sibling does, as Xournal++ places each `` note on a layer, is an item of its own, never a run of the others' text: one added whole gets a `text_contains` of its text on the element holding the items, which passes wherever it is placed, and that list's `member_count`. - Noise leaves the suggestions when the file's change holds anything else, a change only position reaches included: view state, which a tag or attribute on the way names (the cursor, a selection, as VYM's `