Stripo email previews now render images correctly in Claude artifacts
When Orbit composed an email and showed the preview as a Claude artifact, all the placeholder images in your modules rendered as broken-image icons. Turns out Claude artifacts run inside an iframe with a strict CSP that blocks external img-src — Stripo's CDN was serving the images perfectly, the artifact just couldn't fetch them. Fix: orbit_sync_stripo_modules now downloads each module's images locally during sync, and orbit_compose_stripo_email inlines them as base64 data: URIs in the preview HTML. The preview now matches what the actual email looks like in your inbox. Images you push to Stripo still use the original CDN URLs (data: URIs never leave Orbit) — Stripo composes server-side from its own copy of the module HTML.
What shipped
•orbit_sync_stripo_modules now downloads every image referenced in your synced modules to a local cache at ~/Orbit/library/_image-cache/. Cache is keyed by SHA-1 of the URL, so the same image used in multiple modules is only downloaded once. Re-syncs skip already-cached images entirely (idempotent).
•Stripo CDN URLs are content-addressed (each image has a unique GUID baked into the URL), which means cache invalidation is automatic — if a module is updated in Stripo to use a different image, the new URL produces a fresh cache entry; same URL is guaranteed-identical bytes. No staleness risk.
•Each sync prunes orphan cache entries for URLs no longer referenced by any module, so the cache doesn't grow indefinitely as old image URLs get replaced. Sync output reports new downloads, cache hits, and bytes freed.
•orbit_compose_stripo_email now inlines image bytes as data: URIs in the preview HTML returned for the Claude artifact. Stripo CDN images render in the artifact preview at full fidelity. If an image isn't in the local cache (sync hasn't run, image was unreachable, etc.), the original URL is left in place — the artifact shows a broken-image icon for that one image but the rest of the preview still works.
•The push half (orbit_compose_stripo_email with push: true) is unchanged: data: URIs never leave Orbit. The canonical-JSON payload sent to Stripo references modules by UID, and Stripo composes server-side from its own copy of the module HTML, which still has the original Stripo CDN URLs. Architecturally guaranteed.
•Preview HTML grows ~33% in size due to base64 encoding overhead (a ~10KB image inlines as ~13KB of base64). Acceptable for a Claude artifact preview; not relevant to the actual email that ships through Stripo.