Skip to content

Commit add10dd

Browse files
yasinBursaliclaudeLightheartdevs
authored
docs: sync documentation with codebase after 50+ merged PRs (#973)
* docs: sync documentation with codebase after 50+ merged PRs Fix stale, contradictory, and missing documentation identified by a systematic audit of the last 50 merged PRs against all existing docs. Fixes: - WINDOWS-QUICKSTART.md: remove "Coming Soon" language, add real install flow, commands, and verified installer flags - MODE-SWITCH.md: add lemonade mode section (auto-configured on AMD) - QUICKSTART.md / README.md: update all Qwen2.5 model names to Qwen3.5/Qwen3 to match current tier-map.sh - POST-INSTALL-CHECKLIST.md: rewrite skeleton with real verification commands - Root README.md: fix Apple Silicon "4B" → "9B" for 16-24GB tier Additions: - SECURITY.md: DREAM_AGENT_BIND / LAN access section - FAQ.md: backup/restore, service templates, bootstrap fast-start, expanded update/rollback documentation - HOST-AGENT-API.md: Windows platform limitation note - CATALOG.md: add missing Langfuse entry - Langfuse README.md: new service README with full configuration, env vars, volumes, and troubleshooting - .env.example: document LLAMA_CPU_LIMIT for macOS/CPU-only mode - SUPPORT-MATRIX.md: link to AMD system-tuning guide Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(host-agent): correct stale Windows entries — host agent now runs on Windows The prior commit in this PR added two Windows entries to HOST-AGENT-API.md based on the docs state at the time the sync was drafted. Windows host agent support shipped via the fix/windows-host-agent-startup branch before this PR's work began, so the 'not yet available' row and the 'dream.ps1 restart' workaround blockquote describe out-of-date behavior. Replaces the table row with the accurate mechanism and removes the workaround blockquote. * docs(security): reflect post-#988 host-agent fallback in SECURITY.md Maintainer audit on PR #973 (Lightheartdevs, 2026-04-28): "Audit follow-up: needs rebase/update after the security merges. #988 is now on `main`, so docs should describe the safer loopback fallback behavior rather than the old exposure story. Please rebase this broad docs pass on current `main`, reconcile it with #988/#959, and make sure the host-agent/native binding sections consistently say `127.0.0.1` where that is now the implementation." #988 (`fix/security-loopback`) changed `bin/dream-host-agent.py:2315` to fall back to `127.0.0.1` instead of `0.0.0.0` when Docker bridge detection fails. The "Host Agent Network Binding" table introduced in this PR (commit `4ef9133c`) described pre-#988 behavior in the Linux row. This commit corrects the cell with a parenthetical pointing at #988 so the rationale isn't lost on future readers. The other entries in the table (macOS/Windows already loopback, override examples, bind-to-LAN warning) are unchanged. #959-related changes: the token-spy proxy/upstream auth split is already correctly captured by extension manifests + service documentation that landed with #959; this PR's diff doesn't touch those paths. Closes the binding-doc audit ask. Branch is now rebased on current upstream/main; rest of the docs sync (Qwen3.5/3 model names, Windows-quickstart rewrite, FAQ expansions, langfuse README, etc.) stands as before. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Lightheartdevs <Lightheartdevs@users.noreply.github.com>
1 parent eda98f8 commit add10dd

13 files changed

Lines changed: 380 additions & 118 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ The installer detects your GPU and picks the optimal model automatically. No man
185185
| Unified RAM | Model | Example Hardware |
186186
|-------------|-------|-----------------|
187187
| < 16 GB | Qwen3.5 2B (Q4_K_M) | M1/M2 base (8GB) |
188-
| 16–24 GB | Qwen3.5 4B (Q4_K_M) | M4 Mac Mini (16GB) |
188+
| 16–24 GB | Qwen3.5 9B (Q4_K_M) | M4 Mac Mini (16GB) |
189189
| 32 GB | Qwen3.5 9B (Q4_K_M) | M4 Pro Mac Mini, M3 Max MacBook Pro |
190190
| 48 GB | Qwen3 30B-A3B (MoE, Q4_K_M) | M4 Pro (48GB), M2 Max (48GB) |
191191
| 64+ GB | Qwen3 30B-A3B (MoE, Q4_K_M) | M2 Ultra Mac Studio, M4 Max (64GB+) |

dream-server/.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ LANGFUSE_INIT_USER_PASSWORD= # auto-generated during install
280280
# llama-server memory limit (Docker)
281281
# LLAMA_SERVER_MEMORY_LIMIT=64G
282282

283+
# llama-server CPU core limit (macOS/CPU-only mode — static default 8.0)
284+
# Tune this to control how many CPU cores llama-server may use.
285+
# LLAMA_CPU_LIMIT=8.0
283286
#=== DreamForge (Local Agentic Coding) ===
284287
# DREAMFORGE_IMAGE=ghcr.io/light-heart-labs/dreamforge:v0.1.0
285288
# DREAMFORGE_PORT=3010

dream-server/QUICKSTART.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ The installer will:
3333
- SH_LARGE (90GB+): qwen3-coder-next (80B MoE), 128K context
3434
- SH_COMPACT (64-89GB): qwen3-30b-a3b (30B MoE), 128K context
3535
- **NVIDIA (discrete GPU)**:
36-
- Tier 1 (Entry): <12GB VRAM → qwen2.5-7b-instruct (GGUF Q4_K_M), 16K context
37-
- Tier 2 (Prosumer): 12-20GB VRAM → qwen2.5-14b-instruct (GGUF Q4_K_M), 16K context
38-
- Tier 3 (Pro): 20-40GB VRAM → qwen2.5-32b-instruct (GGUF Q4_K_M), 32K context
39-
- Tier 4 (Enterprise): 40GB+ VRAM → qwen2.5-72b-instruct (GGUF Q4_K_M), 32K context
36+
- Tier 1 (Entry): <12GB VRAM → qwen3.5-9b (GGUF Q4_K_M), 16K context
37+
- Tier 2 (Prosumer): 12-20GB VRAM → qwen3.5-9b (GGUF Q4_K_M), 32K context
38+
- Tier 3 (Pro): 20-40GB VRAM → qwen3-30b-a3b (GGUF Q4_K_M), 32K context
39+
- Tier 4 (Enterprise): 40GB+ VRAM → qwen3-30b-a3b (GGUF Q4_K_M), 128K context
4040
2. Check Docker and GPU toolkit (NVIDIA Container Toolkit or ROCm devices)
4141
3. Ask which optional components to enable (voice, workflows, RAG)
4242
4. Generate secure passwords and configuration
@@ -100,7 +100,7 @@ Visit: **http://localhost:3000**
100100
curl http://localhost:8080/v1/chat/completions \
101101
-H "Content-Type: application/json" \
102102
-d '{
103-
"model": "qwen2.5-32b-instruct",
103+
"model": "qwen3-30b-a3b",
104104
"messages": [{"role": "user", "content": "Hello!"}]
105105
}'
106106
```
@@ -132,10 +132,10 @@ The installer auto-detects your GPU and selects the optimal configuration:
132132

133133
| Tier | VRAM | Model | Example GPUs |
134134
|------|------|-------|--------------|
135-
| 1 (Entry) | <12GB | Qwen2.5-7B | RTX 3080, RTX 4070 |
136-
| 2 (Prosumer) | 12-20GB | Qwen2.5-14B (GGUF Q4_K_M) | RTX 3090, RTX 4080 |
137-
| 3 (Pro) | 20-40GB | Qwen2.5-32B (GGUF Q4_K_M) | RTX 4090, A6000 |
138-
| 4 (Enterprise) | 40GB+ | Qwen2.5-72B (GGUF Q4_K_M) | A100, H100 |
135+
| 1 (Entry) | <12GB | qwen3.5-9b (GGUF Q4_K_M) | RTX 3080, RTX 4070 |
136+
| 2 (Prosumer) | 12-20GB | qwen3.5-9b (GGUF Q4_K_M) | RTX 3090, RTX 4080 |
137+
| 3 (Pro) | 20-40GB | qwen3-30b-a3b (GGUF Q4_K_M) | RTX 4090, A6000 |
138+
| 4 (Enterprise) | 40GB+ | qwen3-30b-a3b (GGUF Q4_K_M) | A100, H100 |
139139

140140
To check what tier you'd get without installing:
141141

@@ -156,7 +156,7 @@ CTX_SIZE=4096 # or even 2048
156156

157157
Or switch to a smaller model:
158158
```
159-
LLM_MODEL=qwen2.5-7b-instruct
159+
LLM_MODEL=qwen3.5-9b
160160
```
161161

162162
### AMD: llama-server crash loop

dream-server/README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,10 @@ Both tiers use `qwen2.5:7b` as a bootstrap model for instant startup. The full m
130130
| Tier | VRAM | Model | Quant | Context | Example GPUs |
131131
|------|------|-------|-------|---------|--------------|
132132
| NV_ULTRA | 90GB+ | qwen3-coder-next | GGUF Q4_K_M | 128K | Multi-GPU A100/H100 |
133-
| 1 (Entry) | <12GB | qwen2.5-7b-instruct | GGUF Q4_K_M | 16K | RTX 3080, RTX 4070 |
134-
| 2 (Prosumer) | 12-20GB | qwen2.5-14b-instruct | GGUF Q4_K_M | 16K | RTX 3090, RTX 4080 |
135-
| 3 (Pro) | 20-40GB | qwen2.5-32b-instruct | GGUF Q4_K_M | 32K | RTX 4090, A6000 |
136-
| 4 (Enterprise) | 40GB+ | qwen2.5-72b-instruct | GGUF Q4_K_M | 32K | A100, H100, multi-GPU |
133+
| 1 (Entry) | <12GB | qwen3.5-9b | GGUF Q4_K_M | 16K | RTX 3080, RTX 4070 |
134+
| 2 (Prosumer) | 12-20GB | qwen3.5-9b | GGUF Q4_K_M | 32K | RTX 3090, RTX 4080 |
135+
| 3 (Pro) | 20-40GB | qwen3-30b-a3b | GGUF Q4_K_M | 32K | RTX 4090, A6000 |
136+
| 4 (Enterprise) | 40GB+ | qwen3-30b-a3b | GGUF Q4_K_M | 128K | A100, H100, multi-GPU |
137137

138138
### Apple Silicon (Unified Memory, Metal)
139139

@@ -142,7 +142,7 @@ Both tiers use `qwen2.5:7b` as a bootstrap model for instant startup. The full m
142142
| 1 (Entry) | 8–24GB | qwen3.5-9b | GGUF Q4_K_M | 16K | M1/M2 base, M4 Mac Mini (16GB) |
143143
| 2 (Prosumer) | 32GB | qwen3.5-9b | GGUF Q4_K_M | 32K | M4 Pro Mac Mini, M3 Max MacBook Pro |
144144
| 3 (Pro) | 48GB | qwen3-30b-a3b | GGUF Q4_K_M | 32K | M4 Pro (48GB), M2 Max (48GB) |
145-
| 4 (Enterprise) | 64GB+ | qwen3-30b-a3b (30B MoE) | GGUF Q4_K_M | 131K | M2 Ultra Mac Studio, M4 Max (64GB+) |
145+
| 4 (Enterprise) | 64GB+ | qwen3-30b-a3b (30B MoE) | GGUF Q4_K_M | 128K | M2 Ultra Mac Studio, M4 Max (64GB+) |
146146

147147
Override with: `./install.sh --tier 3`
148148

@@ -188,7 +188,7 @@ See [docs/HARDWARE-GUIDE.md](docs/HARDWARE-GUIDE.md) for buying recommendations.
188188
┌─────────────────────▼───────────────────────────┐
189189
│ llama-server (CUDA) │
190190
│ (localhost:8080/v1/...) │
191-
qwen2.5-32b-instruct
191+
qwen3-30b-a3b
192192
└─────────────────────────────────────────────────┘
193193
│ │
194194
┌────────▼────────┐ ┌───────▼────────┐
@@ -244,7 +244,7 @@ The installer generates `.env` automatically. Key settings:
244244

245245
```bash
246246
# NVIDIA
247-
LLM_MODEL=qwen2.5-32b-instruct # Model (auto-set by installer)
247+
LLM_MODEL=qwen3-30b-a3b # Model (auto-set by installer)
248248
CTX_SIZE=32768 # Context window
249249

250250
# AMD Strix Halo

dream-server/SECURITY.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,30 @@ sudo ufw allow from 192.168.0.0/24 to any port 3001 # Dashboard
7777
sudo ufw allow from 192.168.0.0/24 to any port 8080 # LLM API
7878
```
7979

80+
### Host Agent Network Binding
81+
82+
The host agent (`bin/dream-host-agent.py`) has its own bind address, separate from the Docker services above. It is controlled by `DREAM_AGENT_BIND` in `.env`:
83+
84+
| Platform | Default | Behavior |
85+
|----------|---------|----------|
86+
| macOS / Windows | `127.0.0.1` | Docker Desktop routes container traffic via loopback — loopback is sufficient |
87+
| Linux | auto-detected | Detects the Docker bridge gateway IP (e.g. `172.17.0.1`) so containers can reach the agent; LAN devices cannot. Falls back to `127.0.0.1` if detection fails (since #988 — the prior `0.0.0.0` fallback exposed the agent to LAN unnecessarily). |
88+
89+
To override the default, set `DREAM_AGENT_BIND` in `.env`:
90+
91+
```bash
92+
# Restrict to loopback only (e.g. no-Docker Linux or extra hardening)
93+
DREAM_AGENT_BIND=127.0.0.1
94+
95+
# Bind to Docker bridge only (explicit Linux default)
96+
DREAM_AGENT_BIND=172.17.0.1
97+
98+
# Bind to all interfaces — exposes the host agent API on LAN (not recommended)
99+
DREAM_AGENT_BIND=0.0.0.0
100+
```
101+
102+
> **Note:** If you bind to `0.0.0.0`, ensure `DREAM_AGENT_KEY` is set in `.env` — it protects the extension management endpoints with Bearer token authentication.
103+
80104
### Exposing to Internet (Not Recommended)
81105

82106
If you must expose publicly, use a reverse proxy with TLS:

dream-server/docs/FAQ.md

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,102 @@ Options:
195195
### How do I get updates?
196196

197197
```bash
198-
./dream-cli update
198+
dream update
199199
```
200200

201-
That's it. Updates are optional — you control when to apply them.
201+
Updates are optional — you control when to apply them.
202+
203+
**Preview changes without applying:**
204+
```bash
205+
dream update --dry-run
206+
```
207+
208+
**Skip version-compatibility confirmation:**
209+
```bash
210+
dream update --force
211+
```
212+
213+
`dream update` automatically creates a pre-update snapshot before pulling new images, then verifies all services are healthy afterward. If something goes wrong, run:
214+
215+
```bash
216+
dream rollback
217+
```
218+
219+
This restores configuration from the pre-update snapshot and restarts services.
220+
221+
---
222+
223+
### How do I back up and restore my data?
224+
225+
**Create a backup** (saves user data and config to `.backups/`):
226+
```bash
227+
dream backup
228+
```
229+
230+
**Create a compressed backup:**
231+
```bash
232+
dream backup -c
233+
```
234+
235+
**List existing backups:**
236+
```bash
237+
dream backup -l
238+
```
239+
240+
**Verify a backup's integrity:**
241+
```bash
242+
dream backup verify <backup_id>
243+
```
244+
245+
**Restore from a backup** (interactive — lets you choose from available backups):
246+
```bash
247+
dream restore
248+
```
249+
250+
**Restore a specific backup by ID:**
251+
```bash
252+
dream restore <backup_id>
253+
```
254+
255+
**Rollback after a failed update** (restores the pre-update snapshot):
256+
```bash
257+
dream rollback
258+
```
259+
260+
`dream update` always creates a pre-update snapshot, so `dream rollback` is available immediately after any update attempt.
261+
262+
---
263+
264+
### What are service templates?
265+
266+
Templates are curated presets that enable a group of extensions suited to a specific use case — for example, a creative-studio setup (image generation + voice) or a research workflow (RAG + web search + agents).
267+
268+
**List available templates:**
269+
```bash
270+
dream template list
271+
```
272+
273+
**Preview what a template will change before applying:**
274+
```bash
275+
dream template preview <template-id>
276+
```
277+
278+
**Apply a template (enables the template's services):**
279+
```bash
280+
dream template apply <template-id>
281+
```
282+
283+
Applying a template only enables services — it doesn't disable anything you've already set up.
284+
285+
---
286+
287+
### Can I chat while models are downloading?
288+
289+
Yes. During install, a small bootstrap model (~1.5GB, Qwen 3.5 2B) downloads first so you can start chatting within a couple of minutes. The full tier-appropriate model downloads in the background.
290+
291+
When the full model finishes, the system swaps it in automatically — you don't need to do anything. `dream status` shows the current bootstrap state if a swap is still in progress.
292+
293+
---
202294

203295
### Where do I get help?
204296

dream-server/docs/HOST-AGENT-API.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ The Dream Host Agent (`bin/dream-host-agent.py`) is a lightweight HTTP server th
44

55
## Why It Exists
66

7-
The Dashboard API runs inside a Docker container and cannot directly run `docker compose` commands on the host. The host agent bridges this gap: it listens on `127.0.0.1:7710`, accepts authenticated requests from the Dashboard API, and executes Docker Compose operations on its behalf. This avoids mounting the Docker socket into the container (a significant security risk).
7+
The Dashboard API runs inside a Docker container and cannot directly run `docker compose` commands on the host. The host agent bridges this gap: it listens on `DREAM_AGENT_BIND:DREAM_AGENT_PORT`, accepts authenticated requests from the Dashboard API, and executes Docker Compose operations on its behalf. This avoids mounting the Docker socket into the container (a significant security risk).
88

99
## How It Runs
1010

1111
| Platform | Mechanism |
1212
|----------|-----------|
1313
| Linux | systemd user service (`scripts/systemd/dream-host-agent.service`) |
1414
| macOS | Started by the installer (`installers/macos/install-macos.sh`) |
15+
| Windows | Started by the installer (`installers/windows/phases/07-devtools.ps1`, managed via `dream.ps1`) |
1516

16-
The agent is started during installation (phase 07 on Linux) and binds to `127.0.0.1` only — it is not accessible from the network.
17+
The agent is started during installation. macOS and Windows bind to `127.0.0.1` by default. Linux auto-detects the Docker bridge gateway so containers can reach the agent, and falls back to `127.0.0.1` if bridge detection fails. It does not bind to `0.0.0.0` unless `DREAM_AGENT_BIND` is explicitly set.
1718

1819
## Configuration
1920

@@ -22,6 +23,7 @@ The agent reads its configuration from the `.env` file in the DreamServer instal
2223
| Variable | Default | Description |
2324
|----------|---------|-------------|
2425
| `DREAM_AGENT_KEY` | *(none)* | API key for authenticating requests. Falls back to `DASHBOARD_API_KEY` if unset. |
26+
| `DREAM_AGENT_BIND` | Platform-specific | Bind address. macOS/Windows default to `127.0.0.1`; Linux uses the Docker bridge gateway when detected, otherwise `127.0.0.1`. |
2527
| `DREAM_AGENT_PORT` | `7710` | Port the agent listens on. |
2628
| `GPU_BACKEND` | `nvidia` | Passed to `resolve-compose-stack.sh` when building compose flags. |
2729
| `TIER` | `1` | Hardware tier, passed to compose stack resolution. |
@@ -138,7 +140,7 @@ If the container does not exist yet (e.g. image is still pulling), a 200 respons
138140
The host agent is a **critical security boundary** because it can start and stop Docker containers on the host.
139141

140142
Protections in place:
141-
- **Localhost only**: Binds to `127.0.0.1`, not `0.0.0.0`
143+
- **Scoped network binding**: macOS/Windows bind to `127.0.0.1`; Linux binds to the Docker bridge gateway when detected so containers can reach the agent. It does not bind to `0.0.0.0` unless explicitly configured.
142144
- **API key auth**: All mutation endpoints require Bearer token authentication
143145
- **Core service protection**: Core services (loaded from `config/core-service-ids.json` with hardcoded fallback) cannot be managed
144146
- **Service ID validation**: Regex-validated, must map to an actual extension directory with a manifest

dream-server/docs/MODE-SWITCH.md

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ dream restart
2727

2828
## How It Works
2929

30-
One env var (`LLM_API_URL`) controls where all services send LLM requests. Three modes set this automatically:
30+
One env var (`LLM_API_URL`) controls where all services send LLM requests. Three modes are user-selectable via `dream mode`; a fourth (`lemonade`) is auto-configured by the installer on AMD hardware — see [Lemonade Mode](#lemonade-mode-amd--auto-configured) below.
3131

3232
| Mode | `LLM_API_URL` | `DREAM_MODE` | LiteLLM config |
3333
|------|---------------|--------------|-----------------|
@@ -88,13 +88,28 @@ Local llama-server as primary, cloud APIs as fallback via LiteLLM.
8888
dream mode hybrid
8989
```
9090

91+
### Lemonade Mode (AMD — auto-configured)
92+
93+
**Not user-switchable.** This mode is automatically set by the installer on AMD hardware. `dream mode` does not accept `lemonade` as an argument — only the installer sets it.
94+
95+
All LLM traffic routes through the LiteLLM proxy, which delegates to the Lemonade SDK (`lemonade-server`). The dashboard API uses a distinct `/api/v1` URL prefix in this mode (instead of `/v1`).
96+
97+
| Aspect | Details |
98+
|--------|---------|
99+
| **LLM** | Lemonade SDK via LiteLLM proxy |
100+
| **Cost** | $0 (local inference) |
101+
| **Requires** | AMD GPU (auto-detected at install time) |
102+
| **Set by** | Installer (Phase 06), not `dream mode` |
103+
104+
For AMD Strix Halo performance tuning (GRUB, kernel module, sysctl settings), see [`config/system-tuning/README.md`](../config/system-tuning/README.md).
105+
91106
---
92107

93108
## .env Variables
94109

95110
| Variable | Default | Description |
96111
|----------|---------|-------------|
97-
| `DREAM_MODE` | `local` | Active mode: `local`, `cloud`, or `hybrid` |
112+
| `DREAM_MODE` | `local` | Active mode: `local`, `cloud`, or `hybrid`; `lemonade` is auto-set on AMD (not user-switchable) |
98113
| `LLM_API_URL` | `http://llama-server:8080` | Where services send LLM requests |
99114
| `ANTHROPIC_API_KEY` | *(empty)* | Anthropic API key (cloud/hybrid) |
100115
| `OPENAI_API_KEY` | *(empty)* | OpenAI API key (cloud/hybrid) |
@@ -177,14 +192,14 @@ User -> Open WebUI -> LiteLLM -> llama-server (local) -> Response
177192

178193
## Mode Comparison
179194

180-
| Feature | Local | Cloud | Hybrid |
181-
|---------|-------|-------|--------|
182-
| Internet required | No | Yes | Yes (for fallback) |
183-
| API keys required | No | Yes | Recommended |
184-
| GPU required | Yes | No | Yes |
185-
| Response quality | Good | Best | Best of both |
186-
| Cost | $0 | $$$ | $0 or $$$ |
187-
| Privacy | 100% local | Data to cloud | Local unless fallback |
195+
| Feature | Local | Cloud | Hybrid | Lemonade (AMD) |
196+
|---------|-------|-------|--------|----------------|
197+
| Internet required | No | Yes | Yes (for fallback) | No |
198+
| API keys required | No | Yes | Recommended | No |
199+
| GPU required | Yes | No | Yes | Yes (AMD) |
200+
| Response quality | Good | Best | Best of both | Good |
201+
| Cost | $0 | $$$ | $0 or $$$ | $0 |
202+
| Privacy | 100% local | Data to cloud | Local unless fallback | 100% local |
188203

189204
---
190205

0 commit comments

Comments
 (0)