Skip to content

Add a local-only escape hatch in onboarding when api.tinyhumans.ai is unreachable #151

@ElioNeto

Description

@ElioNeto

Issue imported from tinyhumansai/openhuman#2037
Created at: unknown


Summary

When api.tinyhumans.ai is unreachable during onboarding (region-blocked, DNS failure, Cloudflare outage, corporate firewall, simply offline), the desktop app is currently a hard wall — the user is stuck on the sign-in screen. This proposal adds a single visible "Continue in local-only mode" escape hatch on the sign-in surface when a reachability probe determines the backend is unavailable, letting the user reach a functional (degraded) experience using on-device inference and storage only.

I'd like to confirm direction with maintainers before writing code — there are a few open product questions in the Maintainer questions section below.

Problem

Several recent issues point to the same gap:

Constraints / context:

  • The product is positioned as Private, local-first in the README (every edition). Memory Tree / Obsidian Wiki / TokenJuice / Ollama integration / scheduler_gate are complete enough to run a useful agent without the hosted backend.
  • The infrastructure to enter a signed-out / offline mode partially exists: src/openhuman/scheduler_gate::set_signed_out / is_signed_out are already exported.
  • Endpoint configuration is mature: BACKEND_URL / VITE_BACKEND_URL envs, config.api_url, staging↔prod selector all work today. The gap is not "endpoint can't be changed" — it's "user has no in-product path forward when the default endpoint is unreachable."

Solution (draft for discussion)

Scope: core (src/) + app (app/).

Core:

  1. Add a lightweight reachability probe to the existing doctor domain — short-timeout HEAD against the resolved effective_api_url. Exposed via a new RPC openhuman.doctor_backend_reachable -> { reachable: bool, latency_ms?, error? }.
  2. Add local_only_mode as a first-class boolean on app_state (paired with set_signed_out so the LLM router only consults local-AI providers and same-host integrations).

App:
3. In the sign-in / BootCheckGate surface, when not yet authenticated AND the probe returns reachable: false, render a banner:

"We can't reach the OpenHuman backend right now. You can continue in local-only mode — your data stays on this machine and the agent uses your local Ollama/LM Studio model. You can sign in later from Settings."

  1. "Continue in local-only mode" button → new RPC openhuman.app_state_enter_local_only that flips set_signed_out(true) + local_only_mode = true, then routes the user to /home.
  2. In local-only mode, disable backend-dependent surfaces (Composio integrations, hosted-LLM routing, billing/rewards). Most already gate on signed-in elsewhere — point them at the new flag.

Out of scope (call out so reviewers can correct):

  • Auto-recovery: backend returning ≠ auto re-enter signed-in.
  • Endpoint customization UI in onboarding: BACKEND_URL is already settable; this proposal does not change that surface.

Acceptance criteria

  • Reachability probedoctor_backend_reachable RPC exists, short-timeout, single HEAD, no other side effects.
  • Local-only RPCapp_state_enter_local_only flips set_signed_out(true) + new local_only_mode flag, emits an event.
  • Sign-in banner + button — appears only when probe is unreachable, dismissable, keyboard-reachable + ARIA-labelled.
  • LLM routing in local-only mode — agent uses local-AI provider only; hosted calls gated with a clear "you're in local-only mode" error.
  • Exit local-only mode — user signs in from Settings; flipping back requires a fresh successful auth handshake.
  • Tests — Vitest covers banner show/hide + button RPC; Rust covers probe + flag mutation; at least one failure-path case (probe timeout → banner renders).
  • Diff coverage ≥ 80% — meets the gate enforced by .github/workflows/coverage.yml.

Maintainer questions

Before writing any code, I want to confirm direction. Specifically:

  1. Is "ship a local-only escape hatch in onboarding" the right shape? If you'd rather see "configure your own self-hosted backend URL in onboarding" instead (since BACKEND_URL already works but is undocumented in the UI), happy to write that.
  2. local_only_mode as a new flag vs. ride on set_signed_out? I'm proposing a separate flag because "signed-out by choice / region-blocked" is a different intent from "signed-out before first login," but you may have a cleaner model.
  3. Probe target. effective_api_url HEAD, or a dedicated /health? Does one exist?
  4. Re-auth UX. Where in Settings should the "Sign in" path live?

Happy to break this into smaller PRs (probe alone, banner alone, RPC alone) if that's easier to review.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions