Build local edition web console

Task 10131 · Done · Coder · created · updated

## Original requirement (verbatim, epic body) > Build new deployment type for Jaah: local. Do a web research and copy the model of OpenClaw, N8N and other similar products: > - Open source in a public repo (for not private), mirrored some of the components from main repo > - A package of node + CP that user runs on his machine, no multiple machines, single user, no advanced functionality, no networking, no nodes > - Should be a very easy start - one line install and/or build from repo and/or docker compose > - Limited number of accounts > > Analyze and propose options Settled upstream (do not reopen): PRD (Task 10080) decisions D1–D16 + assumptions S1–S9; Architecture (Task 10081) decisions D17–D29 — the **1+3 hybrid**: one codebase with a build-time edition (three literal constants rewritten only by the mirror build), an allowlist manifest + tree builder + per-PR mirror-build gate, caps enforced in the CP and the node, public repo `jaah-ai/jaah-local` (fair-code, read-only mirror). Binding numbers: 1 user, ≤3 AI provider accounts in total, ≤10 concurrent agent sessions (over-cap work queues), no telemetry, loopback only. Business goal (D4): a funnel to Jaah Cloud via upsell links only (D8). ## Scope of this child **C6. Web local edition (Arch §2.8).** Owns AC-12 (UI), AC-14 (UI), AC-21 (UI), AC-23. Builds against C3's and C4's pinned contracts (below) and mocks them until they land — no dependency edge. ## Approach (from the settled architecture — realize it, do not redesign) - **Routes.** Move cloud-only routes and nav entries into `apps/web/src/routesCloud.tsx` exporting `cloudRoutes` and `cloudNavItems`; `App.tsx` and `Sidebar.tsx` load it via `import.meta.glob('./routesCloud.tsx', { eager: true })` (yields `{}` when absent, so the public build compiles with no stub). Settings tabs for removed surfaces follow the same file. The manifest already excludes it; widen `include` for `apps/web`. - **Local-only screens (`IS_LOCAL`):** - first-run screen consuming `GET/POST /api/local/setup` (`{"needs_setup": bool}`; `POST {"email","password"}` ≥12 chars → 201 + cookie; 409 if a user exists); - no sign-up, invite or Users pages; - forge connect shows **token paste only** for GitHub, GitLab, Bitbucket and Azure DevOps (D22); - a **"This machine"** panel in Settings showing `node.online` and `last_seen` from `GET /api/local/limits` (`{"accounts":{"used","cap"},"agents":{"running","cap","queued"},"node":{"online","last_seen"},"upgrade_url"}`) — the only node UI; - the Help button links to the docs (Help assistant removed, D28). - **Cap refusal rendering:** the 409 payload `{"detail","kind","limit","upgrade_url"}` renders inline as one line with the link — no blocking modal. - **Upsell lines — the complete list (AC-23), one line each with the `upgrade_url` link, nowhere else:** (1) the Accounts add-refusal (cap reached); (2) the Tasks board while `agents.queued > 0`; (3) the "This machine" panel: "Run agents on more machines with Jaah Cloud"; (4) the user menu, in place of Users and invites: "Invite your team on Jaah Cloud". - Follow `docs/standards/ui-style-guide.md` and `docs/standards/ui-copy-standards.md`; check phone widths. - **Gate:** add `vite build` of the built tree to `local-edition-check.yml`. Full documents: the epic's settled `prd` and `architecture` artifacts (Tasks 10080/10081). Credentials & reach: - AC-3, AC-17 grep, AC-8 migrations, C1–C6 unit and gate checks — nothing beyond the worktree (plus GitHub Actions for `local-edition-check.yml`) — **verified**: the workflow runs in this repo's existing CI Out of scope: - Do NOT implement the API endpoints (C3/C4 own them — mock to the pinned contract), the router split (C2), node work (C5) or distribution (C7a). - Do NOT add a new alembic revision. - Do NOT add OAuth Connect for forges in local (D22). Do NOT add upsells beyond the four listed. - Cloud nav, routes and settings must render identically when `IS_LOCAL` is False (add a test pinning the cloud nav set). PRD §7 (verbatim) — the local edition, and the work to build it, MUST NOT: - Change the behaviour, UI or data model of the cloud deployments (dev, `dev.jaah.ai`; prod, `app.jaah.ai`). Any edition switch must default to today's behaviour there. - Ship, in the local edition or in the public repo: Stripe or billing; SES or system mail; Slack or Telegram; headscale or tailnet; cloud node launch (`apps/api/app/cloud_node_launch.py`); node groups (`apps/api/app/node_group_reconcile.py`); Multi-Node Hosts (`apps/api/app/vnodes.py`); NodeLink (`apps/api/app/nodelinks.py`); MicroVM (`docs/policies/microvm-nodes.md`); Jarvis (`apps/site-widget/`); the support knowledge base (`apps/api/app/support_kb/`); project memory (`apps/api/app/project_memory/`); SSO, SCIM or multi-org tenancy; the mobile app (`apps/mobile/`); GitHub Actions self-hosted runners (`infra/host/gha-runners/`); `infra/jaah/` (Terraform) and `infra/host/`. - Require pgvector, Redis, S3/MinIO, or any cloud account. - Phone home: no telemetry, no version check, no licence or activation server. - Accept community PRs into the public repo, or require a CLA. - Offer data export from local to Jaah Cloud, or attaching the local node to a cloud org. - Rewrite the control plane for SQLite, or install the control plane natively without Docker. - Expose any port beyond loopback, or support more than one machine. - Make the caps (3 accounts, 10 concurrent sessions) configurable by any setting, env var, flag or UI. Done means: - **AC-12 (R4), UI:** "there is no sign-up page, no invite UI, and no Users management page." — verify: component/e2e test in local mode finds none of them; the first-run screen appears when `needs_setup` is true and signs the user in. - **AC-14 (R6), UI:** "the console has no Nodes list, no 'Add node', no node groups, no Multi-Node Hosts, and no NodeLink screens." — verify: test over the local nav + settings; the "This machine" panel shows online/last-seen from the limits payload. - **AC-21 (R18), UI:** "walk every top-level navigation entry and every Settings tab of the local console. Observe none of the following: billing, plans or Stripe; orgs or tenant switching; users and invites; SSO or SCIM; nodes, node groups, Multi-Node Hosts, NodeLink, MicroVM; Jarvis (site widget, Support → Website chats); the Help assistant knowledge base; project memory; Slack and Telegram; headscale or tailnet; Audit SIEM export; data residency. Quality: no empty tab, dead link, or 'coming soon' placeholder is left where a removed surface was. Where a removed feature is a natural next step, an upsell link (AC-23) stands in its place." — verify: an automated walk of every nav entry and Settings tab in local mode asserts none of those surfaces, no empty tab, no link to a removed route, no "coming soon"; screenshots at desktop and phone width attached to the PR, each page laid out cleanly (no orphan section headers, no gaps where a tab was). - **AC-23 (R20):** "hitting the account cap (AC-15), hitting the concurrency cap while tasks queue (AC-16), and the places of removed cloud features each show one short line with a working link to Jaah Cloud sign-up… no modal blocks work, and no upsell appears on pages where no limit or removed feature is involved. Copy follows `docs/standards/ui-copy-standards.md`." — verify: tests for each of the four lines (present when its condition holds, absent otherwise) and a grep that `upgrade_url`/`CLOUD_SIGNUP_URL` links render nowhere else. - Forge connect in local shows token paste only for all four forges — test. - Cloud nav parity test green; `vite build` of the built tree green in `local-edition-check.yml`; `./dc check quick` green.

Outcome

Local edition console built: cloud routes/nav/Settings panels split into glob-loaded files, local first-run, This machine, token-only forges, 4 upsells; tree build in CI green; quick gate + 12078 web tests green. PR #6944 queued on lane. Follow-up draft 10138. Visual check done at desktop and phone: clean. Memory: used mem-25288, mem-18304; proposed none.

Pull request

Artifacts

Activity

  • Draft
  • Ready
  • Runner started
  • Runner ended (done)