Repository navigation
fix: make doctor, deploy and printed commands match what runs - #1155
Merged
Merged
Conversation
The "Author a workflow" section ended with `openadapt flow replay bundle --url https://your-app.example` and then called it a "permissive local rehearsal". Replay drives the app at --url and performs every recorded step, including an irreversible save, with no prompt. A reader who followed the README against a real system of record made real writes that the text described as a rehearsal. The section now says that replay performs every recorded action against the real app, doesn't ask first, isn't a dry run and doesn't certify the bundle, and that --url belongs on a test or staging copy. The example URLs point at a staging placeholder. A new test fails if the prose after a `flow replay ... --url` block calls it a rehearsal or leaves out the write warning. Ledger: B011 Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PyPI keeps a release's description forever. The 1.16.0 page still says
"Not actively admitted" while the GitHub README names seven active
admissions, and the next release would have frozen today's block
("is the admitted runtime (launcher 1.16.0 ...)") the same way, where it
could outlive a revocation. The README block stays true only because a
daily job rerenders and checks it against the live signed record.
The package description now comes from a small hatch metadata hook
(hatch_build.py) that copies README.md and replaces the generated
lifecycle block with a link to the live signed record. The GitHub
README is unchanged. The release artifact verifier now refuses a wheel
or source archive whose description still states a lifecycle state,
next to its existing refusal of a static lifecycle classifier. The
source archive includes the hook so a wheel built from it gets the same
description.
Ledger: B007
Signed-off-by: abrichr <richard.abrich@mldsai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`openadapt quickstart` ended with "See a fail-safe halt: openadapt flow
replay <qs>/bundle --drift modal". The tutorial bundle is recorded
against MockMed's fault server and enters already signed in, while
`replay --drift` serves plain MockMed, which opens at its login screen.
The printed command halted at step_000 ("Could not resolve target")
with or without --drift, so the demo labeled an app mismatch as drift
safety.
The hint now prints three commands that record and compile a separate
demo on plain MockMed and replay that bundle with modal drift. Run as
printed, the replay stops at step_010 (Save Encounter) on the screen
change, and the same bundle without drift runs to the end. The hint
says "See it stop when the screen changes" and makes no claim about
whether anything was written, because that halt ends
RECONCILIATION_REQUIRED.
Ledger: B008
Signed-off-by: abrichr <richard.abrich@mldsai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`openadapt doctor --backend macos|windows|linux|citrix` printed a fixed "[OK]" and exited 0 on a base install, where the AppKit, Quartz, ApplicationServices, gi or requests modules those surfaces import are absent, so the replay failed later. Only rdp probed its dependency. `deploy` printed "[SETUP]" for the same backends, passed, and its failure text called [SETUP] items blocking. A small table now lists, per backend and host, the modules each surface imports and the extra that installs them. doctor and deploy locate them without importing them. A missing module prints [MISSING] with the `pip install 'openadapt[<extra>]'` command and fails the check. A host that can't open the surface (macos off macOS, linux off Linux, citrix on Linux) prints [UNSUPPORTED] and fails. Otherwise [OK] says that only the Python dependencies were checked. deploy keeps its [SETUP] note on target readiness, and its failure text no longer calls it blocking. Ledger: B009 Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Flow 1.33 and 1.34 look up four X11 libraries as "xcomposite", "xdamage", "xfixes" and "xrandr". find_library matches case-sensitively, so on Linux those releases report installed libraries as missing and refuse to download Chromium. The launcher accepted any Flow >=1.29.0, so `pip install --upgrade openadapt` kept an installed 1.34 and quickstart kept refusing. The runtime shim on main corrects the names only for commands that go through `openadapt flow`, and it isn't released. Every openadapt-flow requirement in pyproject.toml, the range that doctor and deploy report, and the version check behind it now start at 1.35.0. With the new wheel, an environment holding Flow 1.34.0 moves to 1.35.1; with the old one it stays on 1.34.0. uv.lock follows the floor (Flow 1.29.0 to 1.35.1, adding openadapt-types and dropping opencv-python-headless). The shim stays as a no-op guard for installs made without dependency resolution. A new test fails if any Flow requirement or the reported range admits a release below 1.35.0. Ledger: B012 Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`openadapt --help` and the quickstart footer printed `openadapt-agent serve ...`. `uv tool install openadapt`, which the openadapt.ai installer runs, and pipx put only the launcher's `openadapt` executable on PATH, so that command failed with "command not found" (exit 127). Flow's printed commands were already rewritten to `openadapt flow`; the agent bridge had no launcher form. A new `openadapt agent` command passes every argument to openadapt-agent's entry point and returns its exit code. It writes nothing to stdout before the bridge starts, so an MCP client can launch it directly. The help, the quickstart footer and the README now name `openadapt agent serve ...`. Tests fail if the launcher prints a bare `openadapt-agent <verb>` command or the passthrough drops an argument. Ledger: B042 Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`openadapt --help` listed `openadapt flow lint bundle --strict` as step 3 of the Manual Demo Lifecycle. Strict lint exits 1 on the demo bundle by design, because its irreversible save has warn-level gaps (no effect contract, a same-channel check). A script that chained the documented steps with `&&` or `set -e` stopped there, and the help didn't say so. Step 3 is now `openadapt flow lint bundle`, which prints the same warnings and exits 0. A line under the block says the demo has warnings, so `lint --strict` exits 1 on it. A test fails if a lifecycle step uses `--strict`. An opt-in test (OPENADAPT_E2E=1) runs the five printed commands in order and requires exit 0 from each; it failed at step 3 before this change and passes after it. Ledger: B006 Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`openadapt run`, `openadapt record` and `openadapt replay` printed only
"No such command", and `replay` suggested `deploy`. They are Flow
commands, spelled `openadapt flow <verb>` through the launcher.
`openadapt quickstart --brek-it` forwarded the typo to the engine, whose
parser printed its 43-verb `openadapt-flow` usage and no hint.
An unknown top-level name that is a Flow verb now fails with "Did you
mean 'openadapt flow <verb>'?". The verbs come from the installed Flow
parser, with a fixed list when it can't be read. quickstart checks each
forwarded long option against the installed Flow tutorial's options
before it announces or creates an output directory, and suggests the
closest name ("Did you mean --break-it?"). Names must match exactly, so
an abbreviation Flow would expand can't change what runs without the
launcher knowing. When Flow's options can't be read, flags forward
unchanged as before.
Ledger: B013
Signed-off-by: abrichr <richard.abrich@mldsai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`openadapt doctor` always printed "PyTorch not installed", "ANTHROPIC_API_KEY not set" and "OPENAI_API_KEY not set", even on a base install. Healthy runs of compiled workflows make no model calls, so those lines suggested that an AI key and a GPU stack were missing when neither is used. On an install without openadapt-ml or openadapt-evals, doctor now prints one line instead: "Model access: not required. Healthy runs of compiled workflows make no model calls." When a research extra is installed, the same checks appear under "Research extras (not used by compiled workflows)", and each missing item names the command that needs it. Exit codes don't change. Ledger: B014 Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`openadapt version` printed openadapt-ml, -evals, -viewer, -grounding and -retrieval as "not installed" on every base install, which looks like a broken install, and never listed openadapt-types, which the base install brings in. `openadapt capture stop` can't stop anything and exits 1, yet the module usage and the `capture` help listed it with the working commands. The module usage also named `train --capture` and `eval --checkpoint`, which don't parse; the commands are `train start` and `eval run`. `version` now lists openadapt, openadapt-flow, openadapt-agent, openadapt-types and openadapt-capture (marked as an optional extra), says that OpenAdapt Desktop is a separate app, and shows research packages under "Research (optional)" only when they're installed. `capture stop` is hidden from help and still explains how to stop a capture, with a non-zero exit because nothing was stopped. The usage lines are corrected, and a test parses each one against the real command tree. Ledger: B015 Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README.md said v0.46.0 was "still installable with `pip install openadapt==0.46.0`", and docs/LEGACY_FREEZE.md gave the same command. It fails on every Python that 0.46.0 supports. Its openai-whisper pin ships only as a source archive whose setup.py imports pkg_resources, and pip builds it with the newest setuptools, which no longer has it. The freeze doc also said to clone main and run `poetry install`, but main now holds the 1.x launcher and has no Poetry project. The freeze doc now gives a marked recipe that upgrades pip to 25.3 or later and installs with `--build-constraint` capping setuptools below 81. On 2026-10-14 it installed v0.46.0 with Python 3.11 on macOS (Apple silicon), and a dry run succeeded with Python 3.10; the runs are in docs/legacy-install-evidence.md. The clone instructions now check out the v0.46.0 tag. The README says the plain command fails and points to the freeze doc. A test fails if either file offers the bare command in a code block or the recipe loses the setuptools cap. Ledger: B017 Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The launcher printed commands that broke when pasted outside a POSIX shell or from a path with a space. The Python remedy offered only `curl ... | sh` and a POSIX install.sh, which don't run in cmd or PowerShell. Package specs were single-quoted (`'openadapt[rdp]'`), which cmd passes to pip with the quotes, or unquoted (`openadapt[ml]`), which zsh rejects as a glob. The quickstart lint and --break-it hints printed the output path unquoted, so a path such as C:\Users\Jane Doe\... split into several arguments. On Windows the Python remedy now gives uv's PowerShell installer and drops the POSIX script link. Every bracketed package spec is double-quoted, which cmd, PowerShell, bash and zsh all accept. Every quickstart hint that carries a path quotes it with shlex on POSIX and with double quotes on Windows. Tests fail if a spaced path splits, a spec is single-quoted or unquoted, or the Windows remedy pipes to sh. Ledger: B019 Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`openadapt deploy` printed `[OK] env:FOO` for any secret reference that matched the env:NAME or keychain:service/item syntax, even when FOO wasn't set. It also printed "Preflight passed" right after a `[SETUP]` line saying the guide doesn't claim the target is ready. An operator read both as a ready host. An env:NAME reference is now `[OK]` only when NAME is set and non-empty in this environment, which is what Flow requires. Otherwise it's `[MISSING]` and the preflight fails. The value is never printed. The launcher can't look inside the OS keychain, so a keychain reference is now a `[SETUP]` item. When any `[SETUP]` item remains, the last line says the preflight is incomplete and counts those items instead of saying it passed. The exit code stays 0 in that case, because the native backends always leave the target check to Flow. A host with nothing left unchecked still gets "Preflight passed". The native-backend deploy test asserted the old "Preflight passed" line, and the rdp guide test passed an unset env reference. Both now match the new behavior. Ledger: B021 Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Several new tests patched launcher helpers (`_flow_tutorial_options`, `_flow_subparsers`, `_host_platform`) with monkeypatch's default raising=True. Against a launcher without those helpers they errored in setup instead of failing an assertion, so a red run said "missing attribute" rather than showing the old behavior. With raising=False, the same tests now fail on main for the reason they guard (no `openadapt flow <verb>` hint, a typo forwarded to the engine, `[OK]` for an unset env reference), and the forwarding controls pass there too. Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`compatibility.launcher_requires` in platform-manifest.json mirrors the openadapt-* pins in pyproject.toml, and `validate_platform_manifest.py --offline`, a pull request check, fails when they differ. The Flow floor moved to 1.35.0 in pyproject.toml, so the manifest's copy moves with it. The `components.launcher` entries still describe the published 1.16.0 metadata and are left alone; the release workflow regenerates them. Ledger: B012 Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI installs the research extras, and on this branch every Python CI lane passed all tests and then crashed at exit with a segmentation fault (exit 139). Several doctor tests replace importlib.util.find_spec with a stub that reports every module as installed. Doctor now runs its GPU check only when a research extra is found, so the first `import torch` of the session moved into one of those stubbed tests. Under the stub, torch's import fails partway (it looks for optional modules the stub claims exist), doctor reports PyTorch as missing, and the half-loaded extension crashes the interpreter at shutdown. On main the first import happened to run under a narrower stub. A session fixture in tests/conftest.py imports torch once with the real finder when it's installed. Reproduced and checked in a local virtual environment with the same packages as CI: exit 139 before, exit 0 on three runs after. Signed-off-by: abrichr <richard.abrich@mldsai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This branch fixes 13 launcher problems found in a review of what
openadaptprints and checks. In each case a check said[OK]or "passed" when it hadn't checked, a printed command failed when pasted, or the docs described an action as safer than it is. Each fix has a regression test that fails onorigin/main(60938ae) and passes here.Fixes
openadapt flow replay bundle --url ...a "permissive local rehearsal". Replay performs every recorded action against that app, including saves that can't be undone, and doesn't ask first.--url, isn't a dry run, doesn't certify the bundle, and belongs on a test or staging copy. The example URLs use a staging placeholder.tests/test_readme_replay_warning.pyhatch_build.py) builds the package description from the README with that block replaced by a link to the live signed record.scripts/verify_release_artifacts.pyrefuses a wheel or sdist whose description states a lifecycle state. The GitHub README doesn't change.tests/test_pypi_description.py,tests/test_release_artifacts.py::test_release_artifacts_reject_a_frozen_lifecycle_description--drift modal. That bundle doesn't match plain MockMed, so it halted atstep_000on the login screen with or without drift.demo-record,compile, andreplay --drift modalfor a separate demo on plain MockMed. That replay stops atstep_010when the screen changes.tests/test_cli_quickstart_polish.py::test_drift_hint_replays_a_bundle_recorded_on_plain_mockmedopenadapt doctor --backendwith macos, windows, linux, or citrix printed[OK]and exited 0 on a base install, where the modules those backends import are missing.doctoranddeploylook up the modules each Flow backend imports (find_spec, nothing is imported). A missing module prints[MISSING]with the install command. A host that can't open the surface prints[UNSUPPORTED]. Both fail the check.tests/test_cli_smoke.py::test_doctor_native_backend_*,::test_deploy_native_backend_*pip install --upgrade openadaptkept 1.34.openadapt-flowrequirement, the range thatdoctoranddeployreport, and the platform manifest's copy of the pins start at 1.35.0.uv.lockis refreshed.tests/test_flow_floor.pyopenadapt --helpand the quickstart printedopenadapt-agent serve .... Afteruv tool install openadaptor pipx, onlyopenadaptis on PATH, so that command failed with exit 127.openadapt agentcommand passes every argument to openadapt-agent and returns its exit code. It writes nothing to stdout first, so an MCP client can launch it. Help, quickstart, and the README use it.tests/test_agent_command.pylint --strict, which exits 1 on the demo bundle, so aset -escript stopped there.openadapt flow lint bundle. A note says--strictexits 1 on the demo.tests/test_help_demo_lifecycle.py(the end-to-end test runs withOPENADAPT_E2E=1)openadapt replaysuggesteddeploy.openadapt quickstart --brek-itprinted Flow's 43-verb usage and no hint.flowfails with "Did you mean 'openadapt flow replay'?". Quickstart checks each forwarded long option against Flow's tutorial parser and suggests the closest name. Abbreviations are refused, because an abbreviation Flow would expand could change what runs.tests/test_cli_dead_ends.pydoctorlisted PyTorch,ANTHROPIC_API_KEY, andOPENAI_API_KEYas missing on every base install. Compiled workflows make no model calls.doctorprints "Model access: not required." With one, the same checks appear under "Research extras" and name the command that needs each item.tests/test_doctor_research_checks.pyopenadapt versionprinted five research packages as "not installed".capture stopwas advertised, though it can't stop a capture. Two module usage lines didn't parse.versionlists the product packages and shows research packages only when installed.capture stopis hidden from help and still exits 1 with the Ctrl+C note. The usage lines are fixed and parsed by a test.tests/test_cli_leftovers.pydocs/LEGACY_FREEZE.mdofferedpip install openadapt==0.46.0, which fails becauseopenai-whisperimportspkg_resources. The freeze doc said to runpoetry installonmain, which has no Poetry project.--build-constraint, and clones thev0.46.0tag. The runs are indocs/legacy-install-evidence.md.tests/test_legacy_install_docs.pycurl ... | sh, single-quoted specs), in zsh (unquotedopenadapt[ml]), or when the output path had a space.tests/test_cli_shell_hints.pydeploy --secret-ref env:FOOprinted[OK]withFOOunset, and the preflight printed "Preflight passed" right after a[SETUP]line that says readiness isn't checked.env:reference is[OK]only when the variable is set and non-empty; otherwise it's[MISSING]and the preflight fails. The value is never printed. Akeychain:reference is[SETUP]. Any[SETUP]item turns the last line into "Preflight incomplete", with a count.tests/test_deploy_preflight_readiness.pyNot fixed here
main, waiting for a release: the base dependency on openadapt-agent (B002; PyPI's 1.16.0 doesn't include it,main's wheel does) and the README lifecycle block naming Flow 1.35.1 (B004; the scheduled check passes again, but README Production lifecycle source has drifted #1123 is still open).certify --policy permissiveprints "certified safe",openadapt flow replyaprintsopenadapt-flowusage, andlint --strictstill printsNext command: openadapt-flow certify ...through the launcher, which rewrites only the tutorial's output.doctoranddeploystill printpython -m pip ..., which is the wrong interpreter underuv tool install.examples/capture_train_eval.pystill printsopenadapt train --captureandopenadapt eval view.docs/LEGACY_FREEZE.mdkeeps unrelated stale statements, such as "Python 3.12+" for the new packages. The legacy recipe was run on macOS only.deployexits 0 when only[SETUP]items remain, because the native backends always leave the target check to Flow. The last line says "Preflight incomplete" in that case.How it was tested
origin/mainin a separate worktree. Every fix has tests that fail there on an assertion about the old behavior and pass here. Control tests (forwarding real flags, Click's own suggestions, a fully checked web host) pass on both.ruff checkandruff format --checkpass onopenadapt/.uv build --wheel --sdist(uv 0.11.29, as in the release workflow) passesverify_release_artifacts.py, and a wheel rebuilt from the sdist is byte-identical. A wheel built fromorigin/mainis refused by the new check.uv lock --checkandvalidate_platform_manifest.py --offlinepass.OPENADAPT_E2E=1); onmainthey stop atlint --strict.lintline and the three drift commands were pasted intoshand ran. The drift replay stopped atstep_010; the same bundle without drift endedCOMPLETED_UNVERIFIED. The old hint's command halted atstep_000.openadapt agent serve --bundles <bundle>answered an MCPinitializeandtools/liston stdout.doctor --backend macosreported[MISSING]withpython -m pip install "openadapt[macos]", and--backend linuxreported[UNSUPPORTED].deploy --secret-ref env:FOOwithFOOunset failed.pkg_resources, and the constrained dry run exits 0.pip install -e ".[dev]"plus the research packages) resolves with Flow 1.35.1 on Python 3.10 and 3.12, for Linux and macOS. In a local environment with those packages, the first CI run's failure reproduced: every test passed and pytest then exited 139. Doctor tests that stubimportlib.util.find_specmade doctor import torch under the stub, which left torch half-loaded.tests/conftest.pynow imports torch once before any stub; three full runs then exited 0.Before merging
mainfor the same reason: openadapt-privacy 1.1.2 is newer than the manifest's 1.1.1 (platform-manifest.json has drifted from the published releases #1110). The offline manifest check passes.uv.lockchange: openadapt-flow 1.29.0 to 1.35.1, openadapt-types 0.17.1 added, opencv-python-headless removed.doctor --backend <native>exits 1 on a base install.deployfails on an unsetenv:reference. Quickstart refuses unknown or abbreviated tutorial flags.deployprints "Preflight incomplete" instead of "Preflight passed" while[SETUP]items remain.openadapt agent serve --allow-runalso needs openadapt-agent 2.0.2.🤖 Generated with Claude Code