create-op-node 0.12.4 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,18 +32,21 @@ Configures macOS power settings, installs Homebrew + the CLI tool list, sets up
32
32
 
33
33
  When you run `bootstrap` interactively (no `-y`, no `--llm-model` flag),
34
34
  you'll get a curated picker that **pre-selects** a model based on the
35
- Studio's detected unified memory:
36
-
37
- - `qwen2.5:72b` — 72B, ~50 GB Ollama RAM. Pre-selected on 96 GB+ Studios.
38
- Best Spanish + multilingual quality.
39
- - `qwen2.5:32b` — 32B, ~22 GB Ollama RAM. Pre-selected on 48–95 GB Studios
40
- (e.g. 64 GB).
41
- - `qwen3.5:9b` — 9B, ~8 GB Ollama RAM. Pre-selected on smaller Studios
42
- (< 48 GB), and the default for non-interactive `-y` runs (see below).
35
+ node's detected unified memory. Tiers are conservative — the LLM shares
36
+ memory with ~22 containers + Postgres, so they size on *total* footprint,
37
+ not param count:
38
+
39
+ - `qwen3.6:35b-a3b` — 35B MoE (~3B active, fast on Apple Silicon),
40
+ ~24 GB footprint. Pre-selected on 64 GB+ nodes. Best Spanish +
41
+ multilingual quality.
42
+ - `qwen3:14b` ~9 GB footprint. Pre-selected on 32–64 GB nodes.
43
+ - `qwen2.5:7b` — ~5 GB footprint. Pre-selected on 16–32 GB nodes, and
44
+ the default for non-interactive `-y` runs (see below).
45
+ - `qwen2.5:3b` — ~2–3 GB footprint. Pre-selected on ≤ 16 GB nodes (Mac Mini).
43
46
  - `Other…` — any Ollama model name you specify.
44
47
 
45
- (If memory detection fails, the picker falls back to pre-selecting
46
- `qwen2.5:72b`.)
48
+ (If memory detection fails, the picker falls back to pre-selecting the
49
+ conservative scripted default, `qwen2.5:7b`.)
47
50
 
48
51
  The picker is Qwen-only because the Opus Populi platform serves
49
52
  Spanish-speaking civic users and Qwen has the strongest Spanish (and
@@ -51,7 +54,7 @@ broader multilingual) capability of the open-weight models in this
51
54
  size class. Pick "Other…" for non-Qwen models.
52
55
 
53
56
  For non-interactive runs (`-y`) or scripted invocations, the LLM
54
- defaults to `qwen3.5:9b` (small, fast) — pass `--llm-model` to override:
57
+ defaults to `qwen2.5:7b` (small, fast) — pass `--llm-model` to override:
55
58
 
56
59
  ```bash
57
60
  # Just swap the LLM, keep the default embedding model:
@@ -69,29 +72,43 @@ The chosen models flow two places:
69
72
  1. **Ollama**: bootstrap pulls + warms them so the daemon has them
70
73
  resident before the stack comes up. The embedding model pulls first
71
74
  (small, fast feedback); the LLM pulls second (can be tens of GB).
72
- 2. **LaunchAgent**: the plist exports `LLM_MODEL` and `EMBEDDINGS_MODEL`
73
- into the launchd session, which Docker Desktop inherits so compose
74
- services read them via env, no `.env.production` edits needed.
75
-
76
- > **`--embedding-model` only takes effect when the knowledge service
77
- > runs with `EMBEDDINGS_PROVIDER=ollama`.** The default provider is
78
- > `xenova` (in-process), which bundles its own embedding model and
79
- > ignores both `EMBEDDINGS_MODEL` and the local Ollama model. Setting
80
- > `EMBEDDINGS_PROVIDER=ollama` is a separate decision (set in your
81
- > region repo's `.env.production`) see `docs/provider-pattern.md`.
82
-
83
- > **Template contract**: for `--llm-model` to actually change the
84
- > running model, the region repo's `docker-compose-prod.yml` must use
85
- > `${LLM_MODEL:-qwen3.5:9b}` (or similar) on the knowledge service's
86
- > `environment:` block. The current `opuspopuli-node` template does;
87
- > a fork that hardcodes the value would ignore the flag silently.
75
+ 2. **The node `.env`**: bootstrap writes `LLM_MODEL`, `EMBEDDINGS_MODEL`,
76
+ and `EMBEDDINGS_PROVIDER` into a managed block of the region repo's
77
+ `.env`, which docker compose auto-loads. This is the **single source of
78
+ truth** — every service (and every future partial recreate) resolves
79
+ `${LLM_MODEL:-…}` to the same value, regardless of shell/launchd env.
80
+ Model config is deliberately *not* exported via the LaunchAgent: a
81
+ `launchctl setenv` value would shadow `.env` at interpolation time
82
+ (shell env > `.env`), reintroducing the exact drift the `.env` prevents.
83
+
84
+ > **Managed block, not full ownership.** bootstrap owns only the region
85
+ > between `# >>> op-node managed >>>` and `# <<< op-node managed <<<` in
86
+ > your `.env` anything you hand-add outside it is preserved. On first
87
+ > run against a pre-existing `.env`, your existing model values are adopted
88
+ > into the block rather than overwritten; the block is only rewritten when
89
+ > you explicitly (re)select a model. Secrets never go in `.env` they stay
90
+ > in the macOS Keychain and are hydrated by `bin/op-compose`.
91
+
92
+ > **`--embeddings-provider` picks where embeddings run.** The default is
93
+ > `xenova` (in-process), which bundles its own embedding model and ignores
94
+ > `EMBEDDINGS_MODEL`. Pass `--embeddings-provider ollama` to use the host
95
+ > daemon with `--embedding-model` — the value is written to `.env` as the
96
+ > single source of truth. See `docs/provider-pattern.md`.
97
+
98
+ > **Template contract**: for `LLM_MODEL` to actually change the running
99
+ > model, the region repo's `docker-compose-prod.yml` must use
100
+ > `${LLM_MODEL:-…}` on the knowledge service's `environment:` block. The
101
+ > current `opuspopuli-node` template does; a fork that hardcodes the value
102
+ > would ignore the `.env` silently.
88
103
 
89
104
  For RAM sizing, the [Docker resources doc](https://github.com/OpusPopuli/opuspopuli-node/blob/main/docs/docker-resources.md)
90
- has a tier table: 9B-class needs ~8 GB Ollama; 70B-class needs ~50 GB;
91
- frontier MoE needs ~80 GB. Allocate Docker the remainder.
105
+ has a tier table: a 7B-class model needs ~5 GB, the 35B-a3b MoE ~24 GB.
106
+ Allocate Docker the remainder of unified memory.
92
107
 
93
- To switch models post-bootstrap, re-run with the new flag and
94
- `docker compose down && up -d` to pick up the changed env.
108
+ To switch models post-bootstrap, either re-run bootstrap with the new
109
+ `--llm-model` (rewrites the managed block) or edit `LLM_MODEL` in the
110
+ managed block of your `.env` directly, then `./bin/op-compose -f
111
+ docker-compose-prod.yml up -d` to pick up the change.
95
112
 
96
113
  ### Local-only mode (no Cloudflare)
97
114
 
@@ -221,7 +238,7 @@ npx create-op-node verify --domain your-domain.example
221
238
  ```
222
239
 
223
240
  Off-LAN health probe of a live node, runnable from anywhere with internet
224
- access. Five phases:
241
+ access. Six phases:
225
242
 
226
243
  1. **TLS handshake** to `api.<domain>:443` — surfaces cert subject, issuer,
227
244
  and days-to-expiry. Warns when the cert is within `--cert-warn-days`
@@ -231,12 +248,22 @@ access. Five phases:
231
248
  3. **`POST https://api.<domain>/api`** with `{ __typename }` must return a
232
249
  valid GraphQL envelope (catches the "TLS green, but a misconfigured
233
250
  proxy returns HTML" case).
234
- 4. **Cloudflare Tunnel status** (optional) — looks up `connections` via
251
+ 4. **Ollama model presence** (optional, node-local) — asserts the configured
252
+ `LLM_MODEL` is actually pulled into the local Ollama, failing loudly with
253
+ the exact `ollama pull <model>` remedy if not. This catches the
254
+ config↔runtime drift that otherwise 404s at inference time (a node set to
255
+ a model that was never downloaded). The model is read from `--llm-model`
256
+ or, when omitted, the node's `.env` (`--repo-dir`, default cwd) — so
257
+ running `verify` **on the node** needs no flags. **Skipped** when no model
258
+ resolves, which keeps an off-LAN `verify --domain …` from tripping it. The
259
+ embedding model is asserted only under `--embeddings-provider ollama`
260
+ (xenova computes embeddings in-process).
261
+ 5. **Cloudflare Tunnel status** (optional) — looks up `connections` via
235
262
  the CF API. Zero connectors registered → warning that cloudflared on
236
263
  the Studio is offline. Requires all three of `--cf-token` (or
237
264
  `--cf-token-file`), `--cf-account-id`, `--tunnel-id`; partial
238
265
  configuration warns + names the missing flag.
239
- 5. **`cosign verify`** (optional, repeatable `--image`) — keyless
266
+ 6. **`cosign verify`** (optional, repeatable `--image`) — keyless
240
267
  verification against the GitHub Actions OIDC issuer + Fulcio +
241
268
  the Rekor transparency log. Silently skipped when `cosign` isn't on
242
269
  `PATH` (install with `brew install cosign` to enable).
@@ -264,6 +291,17 @@ invocations — the latter ends up in `ps` output, the former doesn't.
264
291
  Use `--api-host <host>` to override the default `api.<domain>`
265
292
  construction when your node exposes the API at a different subdomain.
266
293
 
294
+ Run it **on the node** (from the region repo dir) to also catch model
295
+ drift with zero extra flags — the Ollama phase reads `LLM_MODEL` from the
296
+ `.env` bootstrap wrote:
297
+
298
+ ```bash
299
+ cd ~/Development/opuspopuli-node-us-ca
300
+ npx create-op-node verify --domain yournode.example.org
301
+ # or pin the model explicitly from anywhere:
302
+ npx create-op-node verify --domain yournode.example.org --llm-model qwen3.6:35b-a3b
303
+ ```
304
+
267
305
  ## Bootstrapping a region config
268
306
 
269
307
  A node serves data; **what** data it serves is defined by a declarative region