Status: M0 DEPLOYED + DURABLE — reviewer demo, live on GLM. Project
oratis-491316. C1 (edition flag + cloud auth gate + /api/edition) and M0
(Cloud Run lisa-cloud, us-central1, a GLM-glm-4.6 demo soul) are live and
verified (401/401/200 auth gate, cloud edition, end-to-end chat). Persistence
is done (basic C2): a GCS bucket (<project>-lisa-cloud-data) is mounted at
/data, single-writer (min=max=1); a forced restart confirmed the soul is
detected and re-birth is skipped. The live URL + demo token are NOT committed —
they live in the Cloud Run env. Includes a 正反方 debate (below) whose verdict is a
Conditional GO — M0 (reviewer demo) only, defer public multi-tenant. Remaining
before real (non-reviewer) users: per-user isolation — today it's a single
shared soul/bucket; multi-tenant needs a per-uid home + auth (full C2/C3).
Today LISA is a local-first companion: the iOS app (Lisa Pocket) is a thin
client that pairs to the user's own Mac running lisa serve. That's great for
power users but blocks two things:
- People without a Mac can't use LISA at all.
- App Store review — reviewers have no Mac to pair, so the app looks non-functional (Guideline 2.1 rejection risk).
LISA Cloud is a hosted LISA backend on GCP so a phone-only user (and an App Store reviewer) can sign in and use LISA with no Mac. The iOS app stays the same client; it just points at a cloud URL instead of a LAN Mac.
- Not a replacement for the Mac edition. The Mac stays the "full power"
tier (local agent control plane, PTY, dispatch to your real
claude/codex, Sense/screen, mail on your machine). - Not running arbitrary user CLIs in the cloud (no PTY / no spawning the
user's
claudebinary in a shared sandbox — security + cost). - Not a team/multi-seat product. One account = one private LISA.
LISA is stateful (a soul, memory, sessions, desires that evolve over months — the whole thesis) and spawns local processes (dispatch/PTY/Sense). Neither fits a stateless autoscaling box directly. So v1 makes two decisions:
- Per-user persistent state, isolated. Each user's
~/.lisaequivalent lives in their own durable store; a cloud instance hydrates it on start and persists changes. - Feature delta: the cloud edition is the chat + companion + cloud-agent subset. Local-machine features (PTY adopt, dispatch to local CLIs, Sense screen/voice, on-device mail sweep) are Mac-only and hidden/disabled in cloud mode.
A steelman of each side before committing, because this decision touches the product's founding thesis — not just engineering.
- It's the only thing that unblocks the App Store. Reviewers can't pair a Mac, so without a no-Mac path the iOS app is effectively un-shippable (Guideline 2.1). If shipping iOS matters, this is on the critical path.
- Market. Mac-only caps LISA to Mac power users; the overwhelming majority of phone users can't touch it. Cloud is the on-ramp — and an upsell funnel to the Mac "full power" tier.
- Small delta, not a rewrite. The server + iOS client already exist; cloud is
containerize + verify-token + per-user home, and Cloud Run scale-to-zero
keeps idle cost ≈ $0. We're reusing
oratis-491316, already wired for deploys. - Forcing function for multi-user hygiene (auth, isolation, account deletion) that the product will eventually need anyway.
- It contradicts the founding thesis. LISA's whole identity — and the research framing (a local, long-horizon, privacy-first evolving companion) — is "your soul/memory stays on your machine." Storing users' soul + chat + API keys on Google servers is the opposite promise. This is the heaviest weight, and it's a narrative/credibility cost, not just a technical one.
- You become a data processor. Holding chat + provider API keys in a multi-tenant box = a breach target + real legal surface (GDPR/CCPA, deletion, incident response, a privacy policy you must honor). v1's isolation is logical only (one Cloud Run service) — a single cross-tenant bug leaks everyone.
- Ops drift for a solo researcher. Even scale-to-zero, you now run prod infra (LB, Cloud Armor, Firestore, Secret Manager, monitoring, on-call). Time spent here is time not spent on the thesis/paper.
- The cloud edition is the gutted edition. No PTY / dispatch / Sense / agent control plane — i.e. none of the differentiators. Cloud LISA risks being judged as "another chat app with memory," anchoring perception to the weakest tier.
- The unblock has cheaper alternatives. (a) ship iOS later, TestFlight-only for Mac owners now; (b) expose a seeded demo Mac backend to App Review over a tunnel; (c) frame the app honestly as "a companion to your Mac" (remote-desktop -style apps do pass review). None of these require running a business.
- Stateful soul vs stateless box. Hydrate/flush a per-user
~/.lisato GCS on every cold start is fiddly + race-prone — and continuity-over-months is exactly the property the thesis cares most about getting right.
The App-Store-unblock is real but overstated as a forcing reason (cheaper paths exist). The brand/thesis + liability tension is the dominant consideration. Net recommendation:
- Build M0 only, now — the smallest thing that yields a reviewer-usable
demo: C1 (containerize +
LISA_EDITION=cloud+ verify-token gate) + a single seeded demo account. Do NOT open public multi-tenant signups yet. This gets the App Store unblock without committing to a data-processor business. - Re-evaluate the full multi-tenant cloud (C2–C5) separately, only after the iOS app is otherwise ready and you've explicitly accepted the brand/liability trade. It's a real fork, not an automatic follow-on.
- Guardrails if it proceeds past M0 — BYO API key only (never resell
tokens); a cross-tenant isolation test in CI; keep local-first the flagship
and cloud the explicitly-"lite" tier in all copy; in-app account deletion;
move to a dedicated
lisa-cloud-prodproject before real signups; published privacy policy.
This keeps the thesis intact (local stays the headline), clears review, and defers the heavy commitment until it's a deliberate choice.
| Capability | Mac | Cloud v1 |
|---|---|---|
| Chat with Lisa (soul, mood, memory, desires) | ✓ | ✓ |
| Rêve (recap, advisor, while-you-were-away) | ✓ | ✓ |
| Managed agents (LISA's own agent loop, cloud-side) | ✓ | ✓ (sandboxed, no shell) |
| Mail module (IMAP/Gmail digest + alerts) | ✓ | ✓ (runs in the cloud instance) |
| Proactive / autonomy (idle + heartbeat) | ✓ | ✓ |
| Push (APNs) | ✓ | ✓ |
| PTY / adopt real claude·codex CLIs | ✓ | ✗ (no shell sandbox) |
| dispatch_agent to local CLIs | ✓ | ✗ |
| Sense (screen / voice / clipboard) | ✓ | ✗ (no host) |
| Agent control plane over your terminals | ✓ | ✗ |
The cloud edition advertises itself (/api/edition → cloud) so the client
hides Mac-only surfaces (Control tab's PTY/adopt, Sense capture toggles).
iOS app ──HTTPS──▶ [ Cloud Load Balancer + Cloud Armor ]
│
[ API Gateway / router ] ◀─ Firebase Auth (Sign in with Apple)
│ resolves user → instance
▼
[ Cloud Run service: lisa-cloud ] (the lisa serve --web container,
│ one revision, autoscaled, edition=cloud, per-request user ctx)
│ scale-to-zero per-user via concurrency=1 sessions)
┌──────────┼───────────────┐
▼ ▼ ▼
[ GCS / Filestore ] [ Firestore ] [ Secret Manager ]
per-user LISA_HOME accounts, per-user API keys,
(soul/memory/ billing, APNs key, IMAP creds
sessions/mail) device tokens
│
[ APNs ] ◀ push from the instance
- Cloud Run runs the existing
lisa serve --webcontainer withLISA_EDITION=cloud. The image is the repo's Node server, containerized (website/Dockerfilealready exists for the site; we adddeploy/Dockerfilefor the server). - Identity: Firebase Auth / Identity Platform with Sign in with Apple
(required by Apple if we offer any third-party login; for v1 Apple-only is
simplest + privacy-friendly). The ID token authorizes every
/api/*call (replaces the loopback/LISA_WEB_TOKEN gate with a verifieduid). - Per-user state: each
uidmaps to a durableLISA_HOME. Two options to pick in review:- (A) GCS-backed home — sync the user's
~/.lisatree to a per-user GCS prefix; hydrate on session start, flush on change/idle. Cheapest, scale-to- zero friendly; needs a small sync layer + careful write ordering. - (B) Filestore (NFS) per-user dir — closest to "it's just a filesystem", no LISA refactor, but always-on cost + a mount per instance.
- Recommendation: A for v1 (cost), behind a
CloudHomeabstraction so the file-based modules (paths.ts, soul/memory/sessions/mail stores) are untouched — they read/write a local temp dir that's hydrated/flushed.
- (A) GCS-backed home — sync the user's
- Accounts + metadata: Firestore —
users/{uid}: plan, created, APNs device tokens, push prefs, mail-account metadata (secrets in Secret Manager), billing status. - Secrets: Secret Manager — the model API key and any IMAP/OAuth tokens, per user, never in Firestore. (v1: bring-your-own Anthropic key — the user pastes it in the app → stored in Secret Manager → the instance uses it. Avoids us reselling tokens; revisit a LISA-billed tier later.)
- Routing / isolation: Cloud Run is multi-tenant (one service). Isolation is
logical: every request carries the verified
uid; the server scopes all state access to that user's hydrated home. A misrouted/missinguid⇒ 401. (Stronger isolation — a Cloud Run instance per user via a router — is a v2 option if logical isolation proves insufficient.) - Push: the instance sends APNs exactly as the Mac does (
src/web/push.ts), using the LISA APNs key from Secret Manager. Digest/alert/agent pushes work. - Edge: HTTPS LB + Cloud Armor (rate-limit, WAF) in front; Cloud Run ingress restricted to the LB.
- Cloud Run scales to zero — idle users cost nothing. A request (chat, refresh, push-triggered wake) spins an instance, hydrates the user's home, serves, flushes, and can shut down.
- The expensive part is the LLM loop (Anthropic). v1 = user's own API
key → the user pays Anthropic directly; LISA Cloud charges only for hosting
(or is free/beta). A later managed tier (LISA-billed tokens) needs metering
- Stripe — out of scope for v1.
- Heartbeat/idle autonomy in the cloud: gated behind a per-user budget + only when the user has opted in, so a paused tab can't run up cost.
- Sign in with Apple → Firebase
uid. First sign-in provisions an empty LISA (birth ritual runs in the cloud). - The iOS app gets a long-lived session; every API call sends the Firebase ID token; the server verifies it (Admin SDK) and resolves the user's home.
- Account deletion (Apple-required): an in-app "Delete my LISA" → server endpoint that wipes the user's GCS home + Firestore doc + Secret Manager secrets + APNs tokens. (Also satisfies the App Store account-deletion rule.)
- Mode switch in the app: Settings → "Connect to" → My Mac (LAN pairing, today) or LISA Cloud (sign in). Same client, two backends.
- Provide a demo account (or let review use Sign in with Apple to a seeded sandbox) so reviewers exercise the full app with no Mac. Put the creds + a 30-sec flow in App Review Notes.
- This converts the app from "needs hardware we can't test" → "works on its own," clearing Guideline 2.1.
- Per-user logical isolation enforced server-side on the verified
uid; add a test that a token for user A can never read user B's home. - Secrets only in Secret Manager; never logged. Mail stays metadata+snippet.
- TLS everywhere (LB). Cloud Armor rate-limits + blocks abuse.
- Data residency: single region v1 (us-central1, matching the existing
oratis-491316project / Cloud Run site deploy — where meetlisa.ai'slisa-webservice already runs). - Privacy policy must disclose: account (Apple uid), chat content stored to provide the service, the user's API key, optional mail metadata. Feeds the App Privacy nutrition label.
- C1 — containerize + edition flag:
deploy/Dockerfilefor the server;LISA_EDITION=cloudhides Mac-only features + flips the auth gate to "verify Firebase token." Deploy one shared instance (single test user) on Cloud Run. - C2 — per-user home (
CloudHome): hydrate/flush a per-uidGCS home behind the existingLISA_HOME; the file stores stay unchanged. Logical isolation + the cross-user test. - C3 — auth + accounts: Firebase Auth (Sign in with Apple), Firestore user docs, Secret Manager for the API key, in-app sign-in + "Cloud vs Mac" switch + account deletion.
- C4 — push + mail in cloud: APNs from the instance; mail sweep on a Cloud Scheduler tick per active user.
- C5 — harden + demo: Cloud Armor, budgets, the App-Review demo account, the privacy policy page.
The C1 code is merged (src/edition.ts edition flag, the cloud auth gate that
drops loopback trust, GET /api/edition). The container + deploy glue lives in
deploy/:
| File | Role |
|---|---|
deploy/Dockerfile |
multi-stage node:22-slim; builds dist/, ships assets, ENV LISA_EDITION=cloud LISA_HOME=/data, runs entrypoint.sh. |
deploy/entrypoint.sh |
first-boot: seed a demo soul (lisa birth, idempotent via isBorn()) using whichever provider key is set, then lisa serve --web --host 0.0.0.0. |
deploy/deploy.sh |
ensures a GCS bucket + the Cloud Run SA's access, then gcloud run deploy lisa-cloud --source . to oratis-491316/us-central1 with the bucket mounted at /data (gen2), min=max=1 (single writer), secrets via env (comma-safe ^##^ delimiter). |
State (basic C2 done). Cloud Run's own FS is ephemeral, so /data (=$LISA_HOME)
is a GCS bucket mounted via the gen2 cloud-storage volume — the soul +
sessions are durable across restarts/redeploys (verified: a forced new revision
logged soul already present — skipping birth). min=max=1 keeps a single warm
writer (two instances mounting one bucket could race the soul files). Still
single-tenant: one shared soul/bucket — per-uid isolation + auth is the
remaining work before real (non-reviewer) users.
Auth. Cloud Run IAM is --allow-unauthenticated (the reviewer needs to reach
the URL), and the app's own LISA_WEB_TOKEN gate is the real auth — in cloud
edition loopback is no longer trusted, so every request needs the token. Hand the
reviewer https://<service-url>/?token=<LISA_WEB_TOKEN> (opens authed, pins a
cookie). The two secrets are LISA_WEB_TOKEN + one rate-limited LLM key.
Provider/model. The birth + run gates are provider-aware
(hasCredentialsForModel), so any one of these funds the demo and picks the
model: ZHIPU_API_KEY → GLM (LISA_MODEL=glm-4.6, defaulted), ANTHROPIC_API_KEY
→ Claude, OPENAI_API_KEY → GPT. The M0 demo runs on GLM (glm-4.6,
bigmodel.cn OpenAI-compatible endpoint, LISA's built-in Zhipu preset).
Run it (you, with your secrets — this is real prod GCP + spends money):
# GLM (the M0 demo):
LISA_WEB_TOKEN='<demo-password>' \
ZHIPU_API_KEY='<rate-limited-glm-key>' \
deploy/deploy.shOverrides: PROJECT (default oratis-491316), REGION (us-central1),
SERVICE (lisa-cloud), LISA_MODEL. For production-grade secret handling,
swap the --set-env-vars for Secret Manager (--set-secrets) before M1.
- API key model — bring-your-own (v1, simplest) vs LISA-billed managed tier (needs metering + Stripe). Confirm v1 = BYO key?
- State store — GCS-backed home (A, cheap, scale-to-zero) vs Filestore (B, simplest, always-on). Recommend A.
- Login — Sign in with Apple only (simplest, Apple-friendly) vs also email/Google (more friction + Apple then requires Sign in with Apple too).
- Autonomy in cloud — allow proactive/idle loops (cost) or chat-only until a paid tier?
- Region / project — ✅ DECIDED: reuse
oratis-491316+ us-central1 for v1 (a new Cloud Run servicelisa-cloudnext tolisa-web). Graduate to a dedicatedlisa-cloud-prodproject before opening real multi-tenant signups, to isolate user secrets + agent workloads from the marketing site. - Pricing — free beta, or a hosting fee from day one?
Once you've picked answers to the open questions, I'll turn the chosen path into a build plan (C1–C5) and start with C1 (containerize + edition flag), which is also the smallest step that yields a reviewer-usable demo backend.