Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CAPABILITIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ improvising or retrying when something is off.
| Check that the saved record matches its source document, not only the parameters: intake keeps each value's line, a second reading must agree before a guarded save, and a round trip compares the read-back with the document | On main | Synthetic (MockMed, text referral) | `openadapt_flow/provenance.py`, `intake`, `verify-run --provenance`, guarded save |
| Guarded save: a safety layer any agent wraps around one write (check the record, hold for approval, read back) | On main ([#1258](https://github.com/OpenAdaptAI/OpenAdapt/pull/1258)) | Synthetic | `GUARDED_SAVE.md` |
| A person's approval in Desktop is signed with a key kept behind Touch ID on a Mac: one-prompt setup in the app, a prompt for every answer, and Flow never sees the key | On main ([#1500](https://github.com/OpenAdaptAI/OpenAdapt/pull/1500)) | Unit tests; opt-in test on a real Secure Enclave | `packages/desktop/openadapt_desktop/approver_keychain.py`, [APPROVAL_MODES.md](packages/flow/docs/APPROVAL_MODES.md#the-approver-key) |
| The approver root Desktop trusts can be pinned by an administrator, in a file this user can't write (macOS, Linux, Windows); Desktop checks the owner, mode or ACL and refuses links. A Mac without one uses the root it set up behind Touch ID, read with Keychain prompts off; the two disagreeing is refused | On main | Unit tests per attack on real files; Windows ACL rules unit-tested, real-ACL test on Windows CI; opt-in test against the real login Keychain | `openadapt-desktop approver-pin`, `packages/desktop/openadapt_desktop/approver_anchor.py`, [APPROVAL_MODES.md](packages/flow/docs/APPROVAL_MODES.md#the-approver-key) |
| Review stops: every stop as one card with the evidence side by side (the item next to each possible match, field by field), answered with one key or tap on the computer or a paired phone, signed with the approver key, with batches for similar stops. The queue presents and collects; a changed or expired card changes nothing | On main ([#1519](https://github.com/OpenAdaptAI/OpenAdapt/pull/1519)) | Unit tests; a keystroke-level estimate on 20 soak stops (26.7 s to 8.2 s to decide, a model, not a person) | `packages/desktop/openadapt_desktop/stop_queue.py`, [benchmark/stop_queue](packages/desktop/benchmark/stop_queue/README.md) |
| Draft a record check from the demonstration's write steps (`scaffold-verifier`) | Released | Synthetic | `openadapt-flow scaffold-verifier` (a person fills in the draft) |
| Build a working record check from the reads the app made while the person viewed the saved record, and test it against injected bad writes before anyone reviews it | On main ([#1284](https://github.com/OpenAdaptAI/OpenAdapt/pull/1284)) | Synthetic (MockMed, OpenEMR fixture) | `openadapt-flow scaffold-verifier` |
Expand Down
1 change: 1 addition & 0 deletions llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ improvising or retrying when something is off.
| Check that the saved record matches its source document, not only the parameters: intake keeps each value's line, a second reading must agree before a guarded save, and a round trip compares the read-back with the document | On main | Synthetic (MockMed, text referral) | `openadapt_flow/provenance.py`, `intake`, `verify-run --provenance`, guarded save |
| Guarded save: a safety layer any agent wraps around one write (check the record, hold for approval, read back) | On main ([#1258](https://github.com/OpenAdaptAI/OpenAdapt/pull/1258)) | Synthetic | `GUARDED_SAVE.md` |
| A person's approval in Desktop is signed with a key kept behind Touch ID on a Mac: one-prompt setup in the app, a prompt for every answer, and Flow never sees the key | On main ([#1500](https://github.com/OpenAdaptAI/OpenAdapt/pull/1500)) | Unit tests; opt-in test on a real Secure Enclave | `packages/desktop/openadapt_desktop/approver_keychain.py`, [APPROVAL_MODES.md](https://github.com/OpenAdaptAI/OpenAdapt/blob/main/packages/flow/docs/APPROVAL_MODES.md#the-approver-key) |
| The approver root Desktop trusts can be pinned by an administrator, in a file this user can't write (macOS, Linux, Windows); Desktop checks the owner, mode or ACL and refuses links. A Mac without one uses the root it set up behind Touch ID, read with Keychain prompts off; the two disagreeing is refused | On main | Unit tests per attack on real files; Windows ACL rules unit-tested, real-ACL test on Windows CI; opt-in test against the real login Keychain | `openadapt-desktop approver-pin`, `packages/desktop/openadapt_desktop/approver_anchor.py`, [APPROVAL_MODES.md](https://github.com/OpenAdaptAI/OpenAdapt/blob/main/packages/flow/docs/APPROVAL_MODES.md#the-approver-key) |
| Review stops: every stop as one card with the evidence side by side (the item next to each possible match, field by field), answered with one key or tap on the computer or a paired phone, signed with the approver key, with batches for similar stops. The queue presents and collects; a changed or expired card changes nothing | On main ([#1519](https://github.com/OpenAdaptAI/OpenAdapt/pull/1519)) | Unit tests; a keystroke-level estimate on 20 soak stops (26.7 s to 8.2 s to decide, a model, not a person) | `packages/desktop/openadapt_desktop/stop_queue.py`, [benchmark/stop_queue](https://github.com/OpenAdaptAI/OpenAdapt/blob/main/packages/desktop/benchmark/stop_queue/README.md) |
| Draft a record check from the demonstration's write steps (`scaffold-verifier`) | Released | Synthetic | `openadapt-flow scaffold-verifier` (a person fills in the draft) |
| Build a working record check from the reads the app made while the person viewed the saved record, and test it against injected bad writes before anyone reviews it | On main ([#1284](https://github.com/OpenAdaptAI/OpenAdapt/pull/1284)) | Synthetic (MockMed, OpenEMR fixture) | `openadapt-flow scaffold-verifier` |
Expand Down
14 changes: 14 additions & 0 deletions packages/desktop/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
# CHANGELOG


## v0.25.0 (2026-10-28)

### Features

- **desktop**: an administrator can pin the approver root for this computer with `openadapt-desktop approver-pin ROOT` (with sudo, or from an elevated prompt on Windows). The pin lives in a file only an administrator can write: `/Library/Application Support/OpenAdapt` (macOS), `/etc/openadapt` (Linux) or `ProgramData\OpenAdapt` (Windows). Desktop trusts it only when no one else can change it or the folders that lead to it: it checks owners, permissions, access lists and links. On Windows and Linux it is the only pin.

### Bug Fixes

- **desktop**: a Mac reads its Keychain approver root with Keychain prompts turned off, so an item another program planted or rewrote counts as no root instead of a prompt someone might allow. A Keychain root that disagrees with the administrator's pin is refused.
- **desktop**: the stop-review screen says when no approver root is pinned, since answers can't count until one is.
- **desktop**: bundles openadapt-flow 2.4.1, which reads a pinned deployment config as exact bytes on Windows, so a config with Windows line endings matches its pinned digest.



## v0.24.1 (2026-10-25)

### Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ release, never another `openadapt-flow` it finds on your `PATH`, and `doctor`
says which one it found:

```bash
pip install openadapt-desktop "openadapt-flow[browser,console]==2.4.0"
pip install openadapt-desktop "openadapt-flow[browser,console]==2.4.1"
openadapt-desktop doctor
```

Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ document defines the outputs, ordering, and release-selection rules.

## Current Flow runtime

`main` pins the published `openadapt-flow[browser,console]==2.4.0` release.
`main` pins the published `openadapt-flow[browser,console]==2.4.1` release.
That release contains the reviewed `openadapt.push-result/v1` contract and the
governed hosted-runner adapter that Desktop calls for leased work. The lockfile
binds the exact wheel and source archive hashes.
Expand Down
12 changes: 12 additions & 0 deletions packages/desktop/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,15 @@ and any suggested remediation when available.
Credential exposure, keychain-boundary failures, unsafe protocol handling,
sidecar command or path injection, installer provenance/signing mismatches, and
release supply-chain findings are explicitly in scope.

## Known limits

- **The approver root on macOS.** macOS builds are ad-hoc signed without the
hardened runtime. A process running as the same user can run code inside
Desktop's engine, so the login Keychain doesn't keep the approver root
safe from it: such a process could replace the root and approve its own
saves. On a computer where agents run as the person's account, have an
administrator pin the root with `sudo openadapt-desktop approver-pin ROOT`.
Desktop then requires that root, and refuses a Keychain root that differs.
Windows and Linux use only the administrator's pin. See
[APPROVAL_MODES.md](../flow/docs/APPROVAL_MODES.md#the-approver-key).
4 changes: 2 additions & 2 deletions packages/desktop/docs/DECISION_PORTAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ the dispatcher, and again in the shell before the plugin is called.
### Packaging: done

The frozen sidecar now carries the console. `pyproject.toml` pins
`openadapt-flow[browser,console]==2.4.0`, `scripts/build_frozen_engine.py`
`openadapt-flow[browser,console]==2.4.1`, `scripts/build_frozen_engine.py`
collects uvicorn's run-time string imports and `openadapt_flow.console`, and
the executable is built unbuffered so the console's one-time capability banner
survives the pipe the portal reads it from. `scripts/smoke_test_frozen_flow.py`
Expand Down Expand Up @@ -467,7 +467,7 @@ sensitive when it derives log redactions. A file like that is not eligible to
sit on disk for the hours a portal session can last.

Re-staging it per run would also be theatre. In the pinned
`openadapt-flow==2.4.0`, `_attended_service_from_args` resolves `--config`
`openadapt-flow==2.4.1`, `_attended_service_from_args` resolves `--config`
eagerly through `load_deployment` **before** it yields, and
`AttendedActionService` is built from the parsed `DeploymentConfig` object and
never sees the path again. Rewriting the file later changes nothing about what
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/docs/RELEASE_CANDIDATE_INSTALLERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ only the fixed `openadapt://connect` action and forwards it to the sidecar's
strict, transactional pairing flow.

The canonical compiler and governed runtime remain in `openadapt-flow`. Each
native installer freezes the exact `openadapt-flow[browser,console]==2.4.0`
native installer freezes the exact `openadapt-flow[browser,console]==2.4.1`
runtime and its `playwright==1.61.0` browser automation dependency into the
Desktop sidecar. The `console` extra is what lets an installed application
serve the attended decision console the mobile decision portal relays; the
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/openadapt_desktop/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@
+-- backends/ Storage backend plugins
"""

__version__ = "0.24.1"
__version__ = "0.25.0"
Loading
Loading