[EPIC] Offline-first standalone Android Zara: pure symbolics + optional on-device LLM #347

Open
opened 2026-09-08 02:03:36 +00:00 by nsaspy · 0 comments
Owner

Goal

Make the Zara Android app useful without a Zara server, authenticated session, Internet connection, or cloud model.

The current disconnected UI hard-disables chat with:

Chat unavailable until an authenticated Zara session is connected.

That is the wrong product boundary for an owned assistant. Remote daemon mode should add capabilities; it should not be a prerequisite for basic Zara operation.

Zara Android should have an explicit offline-first standalone profile whose hard baseline is the portable symbolic runtime, with an optional on-device LLM layered behind the same semantic/runtime contracts.

Required operating modes

1. Connected daemon mode

Existing authenticated ZARA/1 behavior remains supported:

  • remote zara-server owns conversations, memory, providers and server tools;
  • Android owns local device capabilities;
  • reconnect/session semantics remain governed by #133/#173 and the daemon security model.

2. Standalone symbolic mode — REQUIRED

Works with airplane mode / no server / no account:

  • embedded portable Prolog core from #172 is the primary semantic engine;
  • deterministic intent -> typed slots -> clarification -> capability execution remains Prolog-first;
  • Android local capability adapters can execute allowed local actions;
  • no network/model call is required for supported deterministic commands;
  • the UI remains interactive rather than replacing the composer with a disconnected tombstone;
  • unsupported conversational/model-only requests fail explicitly and usefully rather than pretending Zara itself is unavailable.

This is the minimum offline guarantee and must work even when no local LLM is installed.

3. Standalone hybrid mode — OPTIONAL LOCAL LLM

If the device supports it and the user opts in / installs a compatible model:

utterance
   -> symbolic resolver first
      -> deterministic intent: execute locally
      -> unresolved/conversational: optional local model

The local model must not become a second command authority. It may handle conversation, bounded rewriting/normalization, summarization, extraction and other reviewed model tasks, but actions still pass through typed semantic/capability policy.

Architecture constraint

Do not fork Zara into an unrelated Android assistant stack.

Reuse the same portable contracts wherever possible:

  • IntentFrame / typed slot semantics from #150-#160;
  • portable Prolog core from #172;
  • Android capability registry from #174;
  • canonical conversation/runtime event vocabulary where it can exist locally without ZARA/1 transport;
  • one local runtime coordinator boundary so Compose does not call Prolog, models or device adapters directly.

A clean conceptual boundary is:

Compose UI
   |
Android Local Runtime
   |-- portable symbolic core
   |-- local conversation store
   |-- optional local model backend
   `-- Android capability adapters

         OR

ZARA/1 Client -> zara-server

The UI should consume one client/runtime abstraction and not need to know whether the active backend is local or remote.

Offline identity and data ownership

Research and freeze explicit semantics for local-only operation:

  • standalone mode has a local owner/profile identity, not a forged remote authenticated principal;
  • local conversations and symbolic state are device-owned;
  • routine local operation requires no account;
  • secrets/model files remain app-private;
  • switching to connected mode must not silently upload offline conversations, memories or transcripts;
  • any future local -> server sync/import is explicit, provenance-preserving and separately designed;
  • logout/server disconnect must not destroy unrelated local-only history.

Android UX

Replace the current disconnected dead-end with an honest capability state.

Expected top-level states include at least:

  • Online · <server/profile>
  • Offline · Symbolic
  • Offline · Local model <name>
  • Connecting…
  • Degraded

When offline:

  • composer remains usable;
  • supported local commands work;
  • show which capabilities are local vs unavailable;
  • remote-only actions say they require connection rather than disabling Zara wholesale;
  • local model installation/selection is optional and never required for symbolic mode;
  • diagnostics expose backend/model/runtime state without secrets.

On-device LLM research gate

Before selecting a production backend, run a real Android/device bakeoff. Do not lock a framework from name recognition alone.

Evaluate current maintained candidates capable of quantized local inference on Android, including credible options around:

  • llama.cpp-style GGUF inference / JNI or native embedding;
  • ExecuTorch / platform-native model execution where suitable;
  • MLC-style Android deployment;
  • ONNX Runtime / other maintained Android GenAI runtimes where they satisfy the contract;
  • accelerator paths actually available on target Samsung/Android hardware (CPU, GPU, NPU where supported).

Measure on representative real hardware:

  • supported architectures / min Android API;
  • model formats and quantization;
  • install/model size;
  • cold/warm load time;
  • RSS and peak memory;
  • tokens/sec and first-token latency;
  • battery/thermal behavior under repeated turns;
  • context limits;
  • cancellation;
  • streaming output;
  • JNI/native lifecycle stability;
  • license and redistribution constraints;
  • deterministic offline packaging/update story.

Test at least a small practical range (for example sub-1B, ~1-2B and ~3-4B quantized classes where the device can actually run them) rather than assuming a desktop-sized model belongs on a phone.

The result may legitimately be: symbolic-only by default, local LLM as an optional downloaded capability.

Local model backend contract

If a local LLM is selected, expose it through a provider-neutral bounded interface with:

  • explicit model identity/version/quantization metadata;
  • max input/output limits;
  • deadline and cancellation;
  • streaming text;
  • no arbitrary native/tool invocation from model output;
  • no network fallback unless separately enabled by policy;
  • deterministic unavailable / unsupported / OOM / cancelled / timeout states;
  • safe unload/reload under Android lifecycle pressure.

Required offline symbolic corpus

At minimum prove these with network disabled and no zara-server:

  • set a timer for 2 hours;
  • bare timer -> local clarification -> duration answer;
  • open a supported installed app;
  • open URI;
  • notification / local safe action from the reviewed capability registry;
  • user correction and cancellation of a pending intent;
  • unsupported server-only action returns an explicit connection-required result;
  • conversational question with no local LLM returns a clear model-unavailable response while the app remains usable;
  • same command corpus produces equivalent normalized symbolic result to the server/SWI fixture where the capability semantics overlap.

Tests / release gates

Deterministic CI

  • local runtime boots with no configured server and no credentials;
  • airplane-mode/no-network fixture;
  • no local LLM installed;
  • pure-symbolic corpus passes;
  • disconnected UI still has a functional composer;
  • no attempted socket/network access for symbolic-only requests;
  • remote-only request fails boundedly without hanging/reconnect spam;
  • local conversation persistence survives process/activity restart;
  • backend switch local <-> connected does not leak/stale-apply events across runtime generations;
  • local principal/history never aliases a remote principal by string coincidence;
  • malformed Prolog/model result fails closed;
  • Android lifecycle/memory-pressure recreation.

On-device model gate

If local LLM support ships, require real-device benchmark evidence plus deterministic fake/model-runtime tests. CI must not require downloading a giant model or external network access.

Integration / conflicts to reconcile

  • #133 explicitly preserved standalone fallback during daemon migration. This epic makes Android standalone a supported product mode, not just a migration fallback.
  • #134 must not be interpreted as permission to remove standalone Android behavior after daemon parity.
  • #173 currently targets Android as a remote ZARA/1 client; retain that mode but place it behind the shared client/runtime abstraction.
  • #172 is a direct prerequisite for pure symbolic parity on Android.
  • #174 supplies the reviewed local action boundary.
  • #244's wake-listener fail-closed policy is about the daemonized wake process and should not silently define Android offline product behavior. Any shared policy conflict must be resolved explicitly rather than inherited accidentally.

Suggested implementation slices

  1. Research/design: freeze local-vs-remote runtime abstraction, offline identity/history semantics and failure policy.
  2. Standalone symbolic runtime: wire #172 + typed dialogue + #174 capability execution behind the Android client abstraction.
  3. Offline UX: keep chat/composer functional and render capability-aware offline/degraded state.
  4. Local persistence: device-owned local conversations/state with strict backend-generation fencing.
  5. On-device LLM bakeoff: benchmark frameworks/models on representative Samsung hardware and record decision.
  6. Optional local model provider: implement only if the research clears size/latency/thermal/license gates.
  7. Mode switching/release matrix: local symbolic, local hybrid and connected daemon all pass one behavioral matrix with explicit capability differences.

Acceptance

This epic is complete when I can put the phone in airplane mode, launch Zara with no authenticated server session, type or speak a supported deterministic request and have the pure symbolic Zara runtime actually handle it locally.

A local LLM is a bonus capability, not the foundation. If installed, it extends offline conversation/model tasks without taking command authority away from Prolog or bypassing Android's typed capability policy.

## Goal Make the Zara Android app useful **without a Zara server, authenticated session, Internet connection, or cloud model**. The current disconnected UI hard-disables chat with: > Chat unavailable until an authenticated Zara session is connected. That is the wrong product boundary for an owned assistant. Remote daemon mode should add capabilities; it should not be a prerequisite for basic Zara operation. Zara Android should have an explicit offline-first standalone profile whose hard baseline is the portable symbolic runtime, with an **optional on-device LLM** layered behind the same semantic/runtime contracts. ## Required operating modes ### 1. Connected daemon mode Existing authenticated `ZARA/1` behavior remains supported: - remote `zara-server` owns conversations, memory, providers and server tools; - Android owns local device capabilities; - reconnect/session semantics remain governed by #133/#173 and the daemon security model. ### 2. Standalone symbolic mode — REQUIRED Works with airplane mode / no server / no account: - embedded portable Prolog core from #172 is the primary semantic engine; - deterministic intent -> typed slots -> clarification -> capability execution remains Prolog-first; - Android local capability adapters can execute allowed local actions; - no network/model call is required for supported deterministic commands; - the UI remains interactive rather than replacing the composer with a disconnected tombstone; - unsupported conversational/model-only requests fail explicitly and usefully rather than pretending Zara itself is unavailable. This is the minimum offline guarantee and must work even when no local LLM is installed. ### 3. Standalone hybrid mode — OPTIONAL LOCAL LLM If the device supports it and the user opts in / installs a compatible model: ```text utterance -> symbolic resolver first -> deterministic intent: execute locally -> unresolved/conversational: optional local model ``` The local model must not become a second command authority. It may handle conversation, bounded rewriting/normalization, summarization, extraction and other reviewed model tasks, but actions still pass through typed semantic/capability policy. ## Architecture constraint Do **not** fork Zara into an unrelated Android assistant stack. Reuse the same portable contracts wherever possible: - `IntentFrame` / typed slot semantics from #150-#160; - portable Prolog core from #172; - Android capability registry from #174; - canonical conversation/runtime event vocabulary where it can exist locally without `ZARA/1` transport; - one local runtime coordinator boundary so Compose does not call Prolog, models or device adapters directly. A clean conceptual boundary is: ```text Compose UI | Android Local Runtime |-- portable symbolic core |-- local conversation store |-- optional local model backend `-- Android capability adapters OR ZARA/1 Client -> zara-server ``` The UI should consume one client/runtime abstraction and not need to know whether the active backend is local or remote. ## Offline identity and data ownership Research and freeze explicit semantics for local-only operation: - standalone mode has a local owner/profile identity, not a forged remote authenticated principal; - local conversations and symbolic state are device-owned; - routine local operation requires no account; - secrets/model files remain app-private; - switching to connected mode must not silently upload offline conversations, memories or transcripts; - any future local -> server sync/import is explicit, provenance-preserving and separately designed; - logout/server disconnect must not destroy unrelated local-only history. ## Android UX Replace the current disconnected dead-end with an honest capability state. Expected top-level states include at least: - `Online · <server/profile>` - `Offline · Symbolic` - `Offline · Local model <name>` - `Connecting…` - `Degraded` When offline: - composer remains usable; - supported local commands work; - show which capabilities are local vs unavailable; - remote-only actions say they require connection rather than disabling Zara wholesale; - local model installation/selection is optional and never required for symbolic mode; - diagnostics expose backend/model/runtime state without secrets. ## On-device LLM research gate Before selecting a production backend, run a real Android/device bakeoff. Do not lock a framework from name recognition alone. Evaluate current maintained candidates capable of quantized local inference on Android, including credible options around: - llama.cpp-style GGUF inference / JNI or native embedding; - ExecuTorch / platform-native model execution where suitable; - MLC-style Android deployment; - ONNX Runtime / other maintained Android GenAI runtimes where they satisfy the contract; - accelerator paths actually available on target Samsung/Android hardware (CPU, GPU, NPU where supported). Measure on representative real hardware: - supported architectures / min Android API; - model formats and quantization; - install/model size; - cold/warm load time; - RSS and peak memory; - tokens/sec and first-token latency; - battery/thermal behavior under repeated turns; - context limits; - cancellation; - streaming output; - JNI/native lifecycle stability; - license and redistribution constraints; - deterministic offline packaging/update story. Test at least a small practical range (for example sub-1B, ~1-2B and ~3-4B quantized classes where the device can actually run them) rather than assuming a desktop-sized model belongs on a phone. The result may legitimately be: symbolic-only by default, local LLM as an optional downloaded capability. ## Local model backend contract If a local LLM is selected, expose it through a provider-neutral bounded interface with: - explicit model identity/version/quantization metadata; - max input/output limits; - deadline and cancellation; - streaming text; - no arbitrary native/tool invocation from model output; - no network fallback unless separately enabled by policy; - deterministic `unavailable / unsupported / OOM / cancelled / timeout` states; - safe unload/reload under Android lifecycle pressure. ## Required offline symbolic corpus At minimum prove these with network disabled and no `zara-server`: - `set a timer for 2 hours`; - bare timer -> local clarification -> duration answer; - open a supported installed app; - open URI; - notification / local safe action from the reviewed capability registry; - user correction and cancellation of a pending intent; - unsupported server-only action returns an explicit connection-required result; - conversational question with no local LLM returns a clear model-unavailable response while the app remains usable; - same command corpus produces equivalent normalized symbolic result to the server/SWI fixture where the capability semantics overlap. ## Tests / release gates ### Deterministic CI - local runtime boots with no configured server and no credentials; - airplane-mode/no-network fixture; - no local LLM installed; - pure-symbolic corpus passes; - disconnected UI still has a functional composer; - no attempted socket/network access for symbolic-only requests; - remote-only request fails boundedly without hanging/reconnect spam; - local conversation persistence survives process/activity restart; - backend switch local <-> connected does not leak/stale-apply events across runtime generations; - local principal/history never aliases a remote principal by string coincidence; - malformed Prolog/model result fails closed; - Android lifecycle/memory-pressure recreation. ### On-device model gate If local LLM support ships, require real-device benchmark evidence plus deterministic fake/model-runtime tests. CI must not require downloading a giant model or external network access. ## Integration / conflicts to reconcile - #133 explicitly preserved standalone fallback during daemon migration. This epic makes **Android standalone a supported product mode**, not just a migration fallback. - #134 must not be interpreted as permission to remove standalone Android behavior after daemon parity. - #173 currently targets Android as a remote `ZARA/1` client; retain that mode but place it behind the shared client/runtime abstraction. - #172 is a direct prerequisite for pure symbolic parity on Android. - #174 supplies the reviewed local action boundary. - #244's wake-listener fail-closed policy is about the daemonized wake process and should not silently define Android offline product behavior. Any shared policy conflict must be resolved explicitly rather than inherited accidentally. ## Suggested implementation slices 1. **Research/design:** freeze local-vs-remote runtime abstraction, offline identity/history semantics and failure policy. 2. **Standalone symbolic runtime:** wire #172 + typed dialogue + #174 capability execution behind the Android client abstraction. 3. **Offline UX:** keep chat/composer functional and render capability-aware offline/degraded state. 4. **Local persistence:** device-owned local conversations/state with strict backend-generation fencing. 5. **On-device LLM bakeoff:** benchmark frameworks/models on representative Samsung hardware and record decision. 6. **Optional local model provider:** implement only if the research clears size/latency/thermal/license gates. 7. **Mode switching/release matrix:** local symbolic, local hybrid and connected daemon all pass one behavioral matrix with explicit capability differences. ## Acceptance This epic is complete when I can put the phone in airplane mode, launch Zara with no authenticated server session, type or speak a supported deterministic request and have the **pure symbolic Zara runtime actually handle it locally**. A local LLM is a bonus capability, not the foundation. If installed, it extends offline conversation/model tasks without taking command authority away from Prolog or bypassing Android's typed capability policy.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/zara#347
No description provided.