Serve htmx and Pico locally instead of from a CDN - #75
Merged
aaronsmulktis merged 3 commits intoAug 24, 2026
Merged
Conversation
fast_app()/FastHTML() load htmx, Pico and three helper scripts from
cdn.jsdelivr.net by default. The eval nodes have no outbound network, so none
of it arrives there, and nothing anywhere reports that:
* htmx missing makes every hx-* attribute inert. /todo alone carries 15
hx-put attributes. A checkbox still toggles on click -- that is native
browser behaviour, not htmx -- so the screenshot shows the interaction
landing while no PUT is sent, /todo_all never changes, and the task scores
zero. The trajectory reads as a model that clicked the right element.
* Pico missing renders every page unstyled, which changes the observation a
screenshot-scored agent is graded on.
Vendors htmx 2.0.4 (0BSD) and Pico 2.1.1 (MIT) under apps/assets/vendor, served
by the static route that already serves jquery and fontawesome the same way.
Versions are pinned in the filename: the default pulled pico@latest, so a run's
styling depended on the day it ran.
Every FastHTML construction site now passes default_hdrs=False and takes
headers from open_apps.frontend.local_hdrs(). That also removes a duplicate
htmx 1.9.10 from unpkg in messenger, which was racing the 2.0.4 FastHTML
injected, and two picolink references in codeeditor whose hdrs are rebuilt in
set_environment.
Out of scope here, and still listed in the test allowlist: Tailwind, daisyUI,
Font Awesome, highlight.js, phosphor-icons and Leaflet. Those change appearance
rather than behaviour; Leaflet needs the map app rethought.
tests/test_no_egress.py ratchets this. The load-bearing case is
test_interactive_routes_load_htmx_locally: a page with hx-* attributes must
load htmx from local assets. Verified it has teeth by reverting todo_app to
fast_app() -- three tests fail with the fix in the message. Full suite: 704
passed.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR removes the runtime dependency on external CDNs for core frontend assets by vendoring htmx and Pico under local static assets and standardizing FastHTML header construction to serve those assets offline on eval nodes.
Changes:
- Add
open_apps.frontend.local_hdrs()+ pinned local asset URLs forhtmxandPico. - Update apps / start-page host app construction to disable FastHTML default CDN headers and use locally served headers instead.
- Add no-egress regression tests to ensure interactive routes load local
htmxand that static serving of vendored assets works.
Reviewed changes
Copilot reviewed 7 out of 10 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_no_egress.py | Adds offline/egress regression tests for CDN usage and local asset loading. |
| src/open_apps/frontend.py | Introduces local_hdrs() and pinned vendor URLs/constants for htmx + Pico. |
| src/open_apps/apps/todo_app/main.py | Switches fast_app() construction to use default_hdrs=False and local headers. |
| src/open_apps/apps/start_page/helper.py | Ensures the main mounted app uses local headers and disables default CDN headers. |
| src/open_apps/apps/messenger_app/main.py | Replaces CDN htmx/Pico usage with vendored headers and disables default CDN headers. |
| src/open_apps/apps/codeeditor_app/main.py | Replaces CDN Pico usage with vendored headers and disables default CDN headers. |
| src/open_apps/apps/calendar_app/main.py | Switches calendar app headers to include vendored Pico/htmx and disables default CDN headers. |
| src/open_apps/apps/assets/vendor/README.md | Documents rationale, versions, and update process for vendored assets. |
| src/open_apps/apps/assets/vendor/pico-2.1.1.min.css | Adds vendored Pico CSS asset. |
| src/open_apps/apps/assets/vendor/htmx-2.0.4.min.js | Adds vendored htmx JS asset. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
marksibrahim
approved these changes
Aug 24, 2026
marksibrahim
left a comment
Contributor
There was a problem hiding this comment.
This is a great life improvement for us, especially when launching in internet restricted clusters. Thanks Aaron!
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.
Why serve local dependencies?
fast_app()/FastHTML()loadhtmx,Picoand three helper scripts fromcdn.jsdelivr.netby default. Many eval nodes have no outbound network, so in these cases none of those dependencies arrives there, and nothing anywhere reports that:htmx missing makes every hx- attribute inert.
/todoalone carries 15hx-putattributes. A checkbox still toggles on click -- that is native browser behaviour, not htmx -- so the screenshot shows the interaction landing while no PUT is sent, /todo_all never changes, and the task scores zero. The trajectory reads as a model that clicked the right element.Pico missing renders every page unstyled, which changes the observation a screenshot-only agent is graded on.
This PR vendors
htmx2.0.4 (0BSD) andPico2.1.1 (MIT) underapps/assets/vendor, served by the static route that already servesjqueryandfontawesome the same way. Versions are pinned in the filename: the default pulledpico@latest`, so a run's styling depended on the day it ran.Every
FastHTMLconstruction site now passesdefault_hdrs=Falseand takes headers fromopen_apps.frontend.local_hdrs(). That also removes a duplicatehtmx1.9.10 fromunpkgin messenger, which was racing the 2.0.4FastHTMLinjected, and twopicolinkreferences incodeeditorwhosehdrsare rebuilt inset_environment.Tests:
tests/test_no_egress.pyratchets this. The load-bearing case istest_interactive_routes_load_htmx_locally: a page withhx-*attributes must loadhtmxfrom local assets. Verified it has teeth by revertingtodo_app to fast_app()-- three tests fail with the fix in the message. Full suite: 704 passed.