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:
- 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? }.
- 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."
- "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.
- 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
Maintainer questions
Before writing any code, I want to confirm direction. Specifically:
- 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.
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.
- Probe target.
effective_api_url HEAD, or a dedicated /health? Does one exist?
- 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
Summary
When
api.tinyhumans.aiis 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:
api.tinyhumans.ai. New users cannot get past the sign-in screen at all. @bookernath reports the same.auth.tinyhumans.aiDNS NXDOMAIN,app.openhuman.aireturns Cloudflare 530, login hangs.Constraints / context:
Private, local-firstin the README (every edition). Memory Tree / Obsidian Wiki / TokenJuice / Ollama integration /scheduler_gateare complete enough to run a useful agent without the hosted backend.src/openhuman/scheduler_gate::set_signed_out/is_signed_outare already exported.BACKEND_URL/VITE_BACKEND_URLenvs,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:
doctordomain — short-timeout HEAD against the resolvedeffective_api_url. Exposed via a new RPCopenhuman.doctor_backend_reachable -> { reachable: bool, latency_ms?, error? }.local_only_modeas a first-class boolean onapp_state(paired withset_signed_outso the LLM router only consults local-AI providers and same-host integrations).App:
3. In the sign-in /
BootCheckGatesurface, when not yet authenticated AND the probe returnsreachable: false, render a banner:openhuman.app_state_enter_local_onlythat flipsset_signed_out(true)+local_only_mode = true, then routes the user to/home.Out of scope (call out so reviewers can correct):
BACKEND_URLis already settable; this proposal does not change that surface.Acceptance criteria
doctor_backend_reachableRPC exists, short-timeout, single HEAD, no other side effects.app_state_enter_local_onlyflipsset_signed_out(true)+ newlocal_only_modeflag, emits an event.unreachable, dismissable, keyboard-reachable + ARIA-labelled..github/workflows/coverage.yml.Maintainer questions
Before writing any code, I want to confirm direction. Specifically:
BACKEND_URLalready works but is undocumented in the UI), happy to write that.local_only_modeas a new flag vs. ride onset_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.effective_api_urlHEAD, or a dedicated/health? Does one exist?Happy to break this into smaller PRs (probe alone, banner alone, RPC alone) if that's easier to review.
Related
src/openhuman/scheduler_gate::set_signed_out/is_signed_outsrc/api/config.rs,BACKEND_URLenv