Skip to content

research: Browser-Only MeticAI Feasibility Study #305

@hessius

Description

@hessius

Feasibility Study: Zero-Install Browser Version of MeticAI

Executive Summary

Can MeticAI run as a third-party-hosted, zero-install web app that communicates directly with the Meticulous machine from the browser?

Answer: No — not with a publicly hosted HTTPS site. The browser's mixed content policy universally blocks HTTPS pages from making HTTP requests to local network devices. This is an absolute, cross-browser, un-bypassable security restriction. However, alternative architectures exist that achieve similar goals.


The Critical Question: Browser ↔ Machine Communication

What Works ✅

  1. Machine CORS is fully open. The Meticulous backend (base_handler.py) already sets:

    Access-Control-Allow-Origin: *
    Access-Control-Allow-Headers: *
    Access-Control-Allow-Methods: GET,POST,OPTIONS,DELETE
    

    Socket.IO also has cors_allowed_origins="*". OPTIONS preflight handler returns 204.

  2. Browser-compatible TypeScript client exists. @meticulous-home/espresso-api v0.10.11 provides 47+ methods covering all machine operations. Dependencies are axios + socket.io-client — both work in browsers. This package could directly replace our Python pyMeticulous usage for client-side communication.

  3. Type definitions available. @meticulous-home/espresso-profile v0.4.2 provides zero-dependency TypeScript profile types, parsing, and variable resolution.

What Blocks It ❌

Blocker 1: Mixed Content (CRITICAL — All Browsers)

Any publicly hosted web app must use HTTPS (GitHub Pages, Vercel, Netlify, etc. all enforce this). The Meticulous machine runs HTTP only on the local network.

https://meticai.app  →  http://192.168.1.x:8080
     (public HTTPS)         (private HTTP)

All modern browsers block this as "mixed content." This applies to:

  • fetch() / XMLHttpRequest calls
  • WebSocket connections (wss://ws://)
  • Socket.IO connections (uses both)
  • Image/resource loading

There is no workaround that's cross-browser. This has been enforced since ~2020 and is part of the W3C Mixed Content specification.

Blocker 2: Private Network Access (Chrome, Solvable but Moot)

Chrome's Private Network Access specification additionally requires a CORS preflight with Access-Control-Allow-Private-Network: true for public-to-private requests. The machine doesn't include this header, though it would be a trivial 1-line addition to base_handler.py.

However, this is moot — even if the PNA preflight succeeds, mixed content blocking happens first and kills the request.

Chrome has an experimental targetAddressSpace: "private" fetch option with a user permission prompt for HTTPS → HTTP mixed content, but it's:

  • Chrome-only (no Firefox, Safari, or other browser support)
  • Still experimental / behind flags
  • Requires the PNA header on the device
  • Poor UX (repeated permission prompts)

Alternative Architectures

Option A: Machine-Hosted Frontend ⭐ RECOMMENDED

Deploy the MeticAI React frontend as static files served by the Meticulous machine's own web server (Tornado on port 80).

User browser → http://meticulous.local/meticai → Same-origin API calls

How it works:

  • Frontend is a static build artifact (dist/ folder from Vite)
  • Served as a route on the machine's existing Tornado web server
  • All API calls are same-origin — no CORS, no PNA, no mixed content
  • AI features: user enters their own Gemini API key in settings, calls made directly from browser to Google Cloud (HTTPS → HTTPS, no issues)
  • Real-time telemetry: Socket.IO client connects to same-origin :8080

Pros:

  • True "zero install" from user's perspective (just navigate to URL)
  • Works in ALL browsers
  • No cloud infrastructure needed
  • No API key security concerns (user manages their own key)
  • Existing React codebase reusable with minimal changes

Cons:

  • Requires MeticulousHome cooperation to distribute as a machine "app"
  • Updates tied to machine firmware or a sideloading mechanism
  • Machine needs enough storage/CPU for static file serving (trivial)

Required MeticulousHome changes:

  1. Add a static file route to Tornado for /meticai/*
  2. Add Access-Control-Allow-Private-Network: true to base_handler.py (future-proofing)

Option B: Capacitor/Native App (Already Planned — #253)

Our existing plan for milestone 2.4. Sidesteps ALL browser restrictions via native networking.

Pros: Best UX, mDNS discovery, full feature parity, App Store distribution
Cons: Requires install, App Store review, separate build pipeline

Option C: Cloud Relay / Tunnel

Machine establishes outbound WebSocket to a cloud relay server. Browser connects to same relay. Commands and telemetry proxied through the cloud.

Pros: Works from any browser on any network (even remote access)
Cons: Latency, cloud infrastructure costs, privacy concerns, requires machine outbound connectivity, complex architecture

Option D: Progressive Web App from Machine

Combine Option A with PWA capabilities:

  • Serve frontend from machine with a service worker for offline support
  • Register as installable PWA (add to home screen)
  • Cache frontend assets aggressively; only API calls need the machine

Pros: App-like experience without app stores, auto-updates when machine firmware updates
Cons: Still requires machine-side hosting


Feature Portability Matrix

If we pursue Option A (machine-hosted) or Option B (Capacitor), which features can run client-side vs needing a server?

Feature Browser-Direct Needs Server Notes
Profile CRUD espresso-api REST calls
Start / Stop / Preheat espresso-api action methods
Real-time telemetry socket.io-client to machine
Shot history browsing REST API + .zst decompression in JS (via fzstd)
Shot data visualization Recharts already client-side
Profile validation espresso-profile package (pure TS)
Variable resolution espresso-profile has processProfileVariables()
Pour-over mode Timer + machine commands
Profile generation (AI) ⚠️ Gemini API call; can use user-provided key from browser
Shot analysis (AI) ⚠️ Same — user-provided key enables browser-direct
Image generation (AI) ⚠️ Imagen API; same pattern
Espresso compass (AI) ⚠️ Gemini call; same pattern
mDNS discovery Browsers can't do mDNS; user enters IP or uses .local
Scheduled shots ⚠️ Browser must remain open; no wake timers
Data persistence IndexedDB replaces file-based storage
Shot annotations IndexedDB or machine-side storage

Key insight: AI features can work browser-side if users provide their own Gemini API key (which they already do in settings). The Google AI JavaScript SDK (@google/genai) works in browsers. No server-side proxy needed.

Features We Can Live Without

  • mDNS auto-discovery: User enters machine IP manually or uses meticulous.local — perfectly acceptable
  • Server-side scheduled shots: Browser-based timer works while app is open; true scheduled shots need the machine-side scheduler
  • MQTT bridge layer: Use Socket.IO directly via espresso-api instead of our MQTT→WebSocket chain

Recommended Path Forward

Phase 1: Machine-Hosted PWA (Option A + D)

  1. Refactor frontend to optionally use @meticulous-home/espresso-api directly instead of going through our FastAPI backend
  2. Add Gemini browser client using @google/genai JS SDK with user-provided API key
  3. Build static frontend and package for machine distribution
  4. Coordinate with MeticulousHome to add a static file route or "apps" mechanism
  5. Add PWA manifest for installable app experience

Phase 2: Capacitor App (Option B, #253)

  • Same refactored frontend as Phase 1
  • Add Capacitor shell with mDNS plugin for auto-discovery
  • Distribute via App Store / sideload

Both phases share the same core: a frontend that can talk directly to the machine without our Python backend. The Python backend becomes optional (useful for Docker self-hosted deployment but not required for browser/app use).


Technical Research References


Research conducted: Analysis of Meticulous machine API CORS headers, Chrome Private Network Access specification, W3C Mixed Content standard, MeticulousHome TypeScript API packages, and MeticAI backend architecture.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions