Repository navigation
feat(quickstart): show it once, run it, break it - #1408
Merged
Merged
Conversation
openadapt quickstart now tells one story in about 30 seconds: a demonstration in the synthetic clinic app ticks by step by step and compiles into a program; the program runs five times with a new note each time and every save is checked in the app's database; then one save fails silently and the screen's saved message sits beside the database's 0 new records, a screen-trusting bot's Done, and OpenAdapt's stop. - openadapt/quickstart: engine adapter (facts read from the runs), the three-act story, a rich terminal view with a plain-line fallback, and inline screenshots on iTerm2, WezTerm, Kitty and Ghostty. - Each checked run's report gets an offline Seal; openadapt seal verify <folder> checks every sealed run in it. - Flow: run_tutorial_workflow(params=...) gives a run its own inputs; the run authorization binds them and the bundle is unchanged. - Engine-only flags and Flow older than 2.2.0 keep the engine tutorial. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Breaking a save is now the quickstart's last act by default; --break-it stays as a hidden alias, so documented commands keep working. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A visible browser on macOS takes focus and keeps it after its window closes, so the Act 3 prompt's Enter would go to the browser. Also lists openadapt seal verify FOLDER in CAPABILITIES.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nadapt on PATH The finale adds "Keep it: uv tool install --python X.Y openadapt" under uvx, and one warning when the shell's openadapt is another version (for example a Conda bin ahead of ~/.local/bin). The receipt's time joins the cost row so the finale stays within 12 lines with every optional line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
openadapt --version and an unknown command now check every openadapt on PATH. When the first one is another version (an old 1.x in a Conda bin ahead of ~/.local/bin keeps answering every new command with "invalid choice"), or a newer one is installed elsewhere, one line names the path and version and how to remove the other install, then hash -r. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Worker processes start while Act 1 demonstrates and compiles: each loads the engine, its own browser and its own copy of the clinic's database. When the program is ready, each runs it once for one note through the same governed path, and the counter ticks as runs finish. Act 2 drops from about 13 s to about 4.5 s. Workers drive Playwright's own Chromium: several installed-Chrome instances at once stalled 2 of 20 runs on a loaded Mac, the bundled build 0 of 30. Without a bundled build on disk nothing is downloaded and the runs go one after another. A run that stalls (45 s) has its worker stopped and is repeated in the main process in a new folder; a run that raised is reported as not finished. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- One background check for the bundled browser instead of a playwright subprocess in each worker; workers start at lower CPU priority with two OCR threads each, so they don't slow Act 1's compile. - Workers shut down during Act 3; the five Seals are signed then too. - The halted run's screenshot is read while the engine waits on the database, and the side-by-side page is written alongside. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Seals use the API Flow 2.2.0 already ships (seal_run with the Seal home, public_key_entry), so the receipt's Seal and seal verify FOLDER work with the released engine too. - The display check no longer imports the engine, so the launcher's quickstart tests pass on Python 3.13+, where the engine isn't installed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
abrichr
marked this pull request as ready for review
October 20, 2026 06:09
…-acts # Conflicts: # CAPABILITIES.md # llms-full.txt
This was referenced Oct 20, 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.
openadapt quickstartis now one short story built around one moment: the screen said "Encounter saved", the database had nothing, a bot that trusts the screen would report Done, and OpenAdapt stopped.(Recorded with VHS, browser hidden, at load average 15–18 from other sessions on this Mac: 21.9 s in all.)
The three acts
--headlesshides it) and the demonstration runs in the synthetic clinic app, MockMed. Each step ticks by in the terminal with its time, read from the recorder's own event log. Then:Compiled into a program: 6 steps.✓ checked in the database, and that run's time. Totals:5 of 5 saved and checked · 0 AI calls · $0.00 · <wall time>.--no-breakskips it). On a terminal it asks "Press Enter to make the next save fail silently". The same program runs once more while the database rejects the write after the app has shown "Encounter saved". Side by side: the halted run's real screenshot (inline on iTerm2, WezTerm, Kitty and Ghostty; a quoted box elsewhere) and the database's0 new records,A screen-trusting bot ✓ Done,OpenAdapt ■ Stopped before reporting success, and one sentence of why.The finale is at most 12 lines: a receipt card (program, 5 of 5 checked, AI calls, cost and total time, Seal key),
Check it: openadapt seal verify openadapt-quickstart, oneDetails:line, and exactly two next steps: record your own app, and serve it to an agent. Underuvxit addsKeep it: uv tool install --python 3.12 openadapt, and one warning when the shell'sopenadaptis another version (for example a Condabinahead of~/.local/bin), naming its path and version. The side-by-side page fromopenadapt flow demoopens when a display is available.--verboseadds the engine detail that used to be the default output.Every number comes from the runs: step times from
events.jsonl, counts and AI calls and cost from eachreport.json, records from the app's database read out of band, the quoted screen text read off the halted run's screenshot. The tests feed the story different facts and check that the output follows.Before and after
Before (
openadapt1.17.0 behavior,quickstart --break-it): 74 lines, three summaries, eight next steps, 42.4 s on this machine.Old output
After: the GIF above (non-TTY output is the same text, one line per fact; see
tests/snapshots/quickstart_plain.snapshot).The inline screenshot on terminals that draw images (WezTerm, iTerm2 protocol; the Kitty protocol renders the same):
Speed
Measured on this Mac (M2 Max, shared with other sessions), headless, not on a terminal, interleaved so load hits both sides (
scripts/quickstart_timing.py; data indocs/quickstart/).--break-it(median)openadapt quickstart(median)timing-2026-10-20-parallel.json)Rounds overlap (before 21.0–23.0 s, after 21.6–24.2 s), but the median is still about 0.7 s slower than the old tutorial, which does one checked run where this does five plus the screenshot read, the page and the Seals. What brought it down from 32.9 s:
What didn't help: three runs instead of five (23.7 s vs 23.8 s, the same), and keeping the workers until after Act 3 (27.8 s). The phases that remain slower than the old tutorial are compile (+0.5 s, sharing the CPU with the workers getting ready) and Act 3 (+0.3 s).
Workers use Playwright's own Chromium. Five installed-Chrome instances at once stalled 2 of 20 runs on this loaded Mac; the bundled build ran 30 of 30. Workers start only when the bundled build is already on disk (or the person set
OPENADAPT_FLOW_BROWSER); otherwise nothing extra is downloaded and the five runs go one after another (the header then doesn't say "all at once"). A run that stalls for 45 s has its worker stopped and is repeated in the main process in a new folder, and its row says "(on a second try)". A run that raised is reported as not finished, not repeated.An older
openadaptearlier on PATHOn the founder's Mac,
openadaptresolves to an Anaconda 1.5.1 launcher ahead of the 1.17.0 one thatuv tool installput in~/.local/bin, and the old one answers new commands with "invalid choice". Old releases can't be changed, so this launcher now names the problem whenever it does run:openadapt --versionand an unknown command check everyopenadapton PATH. If the first is another version, one line names its path and version and the fix (for example/opt/homebrew/anaconda3/bin/python -m pip uninstall openadapt openadapt-flow, then run: hash -r); if a newer one is elsewhere on PATH, one line names it. Copies of the same version get no warning. Checked on this Mac: it names the Anaconda 1.5.1 install and stays quiet about the matching~/.local/bincopy.uvx, the quickstart finale adds the "Keep it" line and the shadow warning described above.tests/test_launcher_conflicts.pyandtests/test_cli_uvx_hints.pycover both.Where I departed from the brief, with evidence
#open-p1, and its record check matchespatient_id='p1'with the idempotency keymockmed-triage-p1-v1(seebundle/workflow.json). Running it on other patients would be a wrong-patient write, which is what OpenAdapt exists to refuse. What the program does generalize over is its input, the note. Flow'srun_tutorial_workflowgainsparams=...; the run authorization binds them and the bundle is unchanged; the record check reads the run's note (bind_effect_params). Picking the patient as a run input needs a recording that selects the patient by a typed value; that's a follow-up.What ships when
--guided,--interactive-record) run the engine tutorial as before.--break-itand--headedstay as hidden aliases, so every documented command still works.paramsyet), Act 2's header says "the program 5 times" and every run uses the demonstrated note. With the Flow in this PR, it says "on 5 new notes". Checked in a fresh environment with Flow 2.2.0 from PyPI: the quickstart runs, the Seal line appears, andseal verifyreports 5 of 5 valid.report.jsonis signed with this computer's Seal key (generated under~/.openadapt/sealon first use, the offline-Seal default), andopenadapt seal verify <folder>checks every sealed run in the folder (a tampered report showsrun-3 not valid, exit 1).docs/quickstart/for the README swap at release.Changes
openadapt/quickstart/:engine.py(drives Flow's tutorial pieces and returns facts),workers.py(Act 2's worker processes),story.py(the three acts),view.py(rich view and plain lines; plain when not a TTY,NO_COLORorTERM=dumb; ASCII marks when the encoding lacks ✓ ■),images.py(iTerm2 and Kitty protocols; detection from the terminal's own variables, never inside tmux or screen,OPENADAPT_INLINE_IMAGES=0|iterm2|kittyto override).openadapt/cli.py: the newquickstart(--headless,--no-break,--verbose),seal verify <folder>, help and the Python remedy point atopenadapt quickstart. Commands print through_hintfrom fix(cli): quickstart's next steps reach the same version under uvx #1404 (this branch is stacked on it), souvxusers get commands that reach the same version.pyproject.toml:rich(MIT; pulls markdown-it-py, mdurl and Pygments), gated to Python < 3.13 like the engine; install-weight allow list updated. Flow's dependencies are unchanged.run_tutorial_workflow(params=...).scripts/quickstart_lifecycle.py: the weekly lifecycle job checks everyrun-Nand that the silent failure stopped.scripts/quickstart_timing.pyanddocs/quickstart/timing-2026-10-20.json: the timing data;docs/quickstart/quickstart.tapere-records the GIF.Tests
tests/test_quickstart_workers.py: the worker pool with stand-in workers in real processes: all runs finish in parallel, fewer workers take turns, a stalled run comes back in a new folder, a run that raised is reported and not repeated, workers that can't start hand every run back.tests/test_quickstart.py: plain-output snapshot; acts in order; no internal vocabulary in default output;--verbosedetail; finale ≤ 12 lines with exactly two next steps; numbers follow the runs (a fake engine with 4 of 5 checked, 3 AI calls, $0.04 and odd times changes every figure); the aha line only when the run showed all of it; no prompt without a terminal, prompt and uncounted wait with one, EOF continues; view choice for pipes,NO_COLOR,TERM=dumb; ASCII marks; a TTY render with colors and boxes; the screenshot inline for iTerm2, WezTerm, Kitty and Ghostty and the box fallback; image-protocol detection (15 cases); Kitty chunking; the event-log ticker with half-written lines; every printed next-step command run with--helpin a fresh process with a minimal environment; the uvx spelling;seal verifyon a folder (valid, tampered, empty); focus returning to the terminal.packages/flow/tests/test_tutorial_run_params.py: a run with a new note verifies against that note and leaves the bundle unchanged.test_real_quickstart(opt in withOPENADAPT_REAL_QUICKSTART=1) runs the real thing; it passed locally at load average 92.Not verified
🤖 Generated with Claude Code