docs(vault): destroy the dead weight — 53 pages and the change diary
The vault was 155 pages / 31,210 lines, most of it measurement ledgers for payloads that no longer run. A throughput figure for a runtime nobody operates is not a record: AI moves faster than the vault, so the number is wrong before anyone reads it, and a wrong number in a runbook gets believed. Per the new purpose test in `AGENTS.md` → *Documentation Policy*, it is destroyed. Gone (`.AGENTTRASH/20261019-destruction/`, KILL-LIST.txt is the manifest): - the `frank-medium` endpoint and its five era pages, `frank-npu`, FastFlowLM, the ikllama/kingjones/dealign/frank-redo eras, the ling/swift15/freetoken/ubatch campaign pages, qwen3.8 spec-matrix and strix-optimizations, the two "Running Qwen3.6 …" pages; - the whole `Pipeline Parallelism/` folder (no live script passes a pipeline flag) and the multi-device/x4-pair/hybrid/offload experiment pages; - every vLLM page — no vLLM endpoint exists on this fleet; - `LLM/deployment.md` (`Architecture/Deployment Flow.md` is the test-referenced owner) and the external surveys (SGLang, Lemonade, llama.cpp forks/diff, self-hosted app census, the TTS survey) that were obsolete by construction; - `log.md`, 2,380 lines. Git holds the chronology; a causal law belongs to the page that owns the thing it governs, never to a diary. Survivors: 101 pages, 17,542 lines, 0 OKF violations, 0 unresolved links. Eras tables keep the window, payload, runtime, reason and rollback pointer; the rate columns are blanked. The live shapes stay verbatim — those numbers are what the deployer and `models.yml` consume.
This commit is contained in:
1 parent
8775e64ed0
commit
327e78b950
126 files changed
+443
-14157
No files matched your search
@@ -56,8 +56,8 @@ sampling), `sampler_name: euler`, `scheduler: simple`, `denoise: 1.0`, seed
|
||||
fixed in the file (`1930` in the art workflow, `2026` in the text one) —
|
||||
read from `dankclaw/comfyui/workflows/*.json` node `9`.
|
||||
|
||||
Node `class_type`s in both files: `CLIPTextEncode` ×2, `UNETLoader`,
|
||||
`CLIPLoader`, `VAELoader`, `EmptySD3LatentImage`, `KSampler`, `VAEDecode`,
|
||||
Node `class_type`s in both files: `CLIPTextEncode` ×2, `UNETLoader`
|
||||
`CLIPLoader`, `VAELoader`, `EmptySD3LatentImage`, `KSampler`, `VAEDecode`
|
||||
`SaveImage` (ids 3–11).
|
||||
|
||||
| Workflow | File | Shape | Steps | Made for |
|
||||
@@ -113,9 +113,9 @@ only `models`, `input`, `output`, `custom_nodes` and the healthcheck file
|
||||
Quantized preferred, sized for the 8060S iGPU (GTT-backed — `/system_stats`
|
||||
reports 122.4 GB of device VRAM on `cuda:0`, `curl http://127.0.0.1:8188/system_stats`
|
||||
2026-10-18; the RTX 3090 is frank-zealot's). All repos verified 2026-10-05 and
|
||||
all four still resolve today (`huggingface.co/lightx2v/Qwen-Image-Lightning`,
|
||||
`huggingface.co/unsloth/Qwen-Image-Edit-2511-GGUF`,
|
||||
`huggingface.co/Comfy-Org/Qwen-Image-DiffSynth-ControlNets`,
|
||||
all four still resolve today (`huggingface.co/lightx2v/Qwen-Image-Lightning`
|
||||
`huggingface.co/unsloth/Qwen-Image-Edit-2511-GGUF`
|
||||
`huggingface.co/Comfy-Org/Qwen-Image-DiffSynth-ControlNets`
|
||||
`huggingface.co/QuantStack/Wan2.2-TI2V-5B-GGUF`, 2026-10-18). None are on disk
|
||||
yet: `models/` holds no lora/, controlnet/ or Wan/Edit file (`ls -R` 2026-10-18).
|
||||
|
||||
@@ -126,7 +126,7 @@ yet: `models/` holds no lora/, controlnet/ or Wan/Edit file (`ls -R` 2026-10-18)
|
||||
| 3 | **DiffSynth ControlNets** (structure control) | `Comfy-Org/Qwen-Image-DiffSynth-ControlNets` | `split_files/model_patches/` canny + depth | ~2–3 GB each | Pose/edge/depth-guided layouts — pairs with the legible-text workflow for exact poster composition. The `QwenImageDiffsynthControlnet` node is already in the running ComfyUI (`GET http://127.0.0.1:8188/object_info/QwenImageDiffsynthControlnet` → 200, 2026-10-18) |
|
||||
| 4 | **Wan 2.2 TI2V-5B GGUF** (first video model) | `QuantStack/Wan2.2-TI2V-5B-GGUF` | Q4/Q5 GGUF (~6–8 GB) | ~6–8 GB | T2V+I2V in one dense 5B model; the gentlest on-ramp into video generation, runs in ComfyUI core (`wan` is in this build's `CLIPLoader` type enum — `GET http://127.0.0.1:8188/object_info/CLIPLoader` 2026-10-18) |
|
||||
|
||||
Placement: #1 → `models/lora/` (create it), #2 → `models/diffusion_models/`,
|
||||
Placement: #1 → `models/lora/` (create it), #2 → `models/diffusion_models/`
|
||||
#3 → `models/controlnet/` (create it), #4 → `models/diffusion_models/`.
|
||||
Fetch with `scripts/download-frank-*.sh` discipline (`-f` + byte-count +
|
||||
sha256 checks) or a plain `hf download` with the token in the environment —
|
||||
|
||||
@@ -43,7 +43,7 @@ Dankclaw is an AMD Strix Halo APU (gfx1151). Standard PyTorch ROCm wheels do not
|
||||
|
||||
## GPU device access (rootless), and why the unit exists
|
||||
|
||||
The unit passes `/dev/kfd` and `/dev/dri` (`AddDevice=`,
|
||||
The unit passes `/dev/kfd` and `/dev/dri` (`AddDevice=`
|
||||
`dankclaw/comfyui/quadlet/comfyui.container:45-46`) and uses
|
||||
`GroupAdd=keep-groups`. A literal `render` entry cannot work: rootless Podman
|
||||
cannot map the group name into the user namespace. The companion udev rule
|
||||
@@ -115,7 +115,7 @@ generated units.
|
||||
The web UI responds on `/` (200 `text/html`, `curl http://127.0.0.1:8188/`
|
||||
2026-10-18). ComfyUI also exposes `/system_stats`. On this APU, `/system_stats`
|
||||
reports `device=cuda:0 Radeon 8060S Graphics` (type `cuda`, the ROCm device). The
|
||||
health probe is the repo file `dankclaw/comfyui/comfyui-healthcheck.py`,
|
||||
health probe is the repo file `dankclaw/comfyui/comfyui-healthcheck.py`
|
||||
bind-mounted to `/usr/local/bin/comfyui-healthcheck.py` and run as `HealthCmd`
|
||||
(`dankclaw/comfyui/quadlet/comfyui.container:52,57`); it GETs
|
||||
`http://127.0.0.1:8188/` inside the container, and the container reports
|
||||
@@ -135,5 +135,5 @@ bind-mounted to `/usr/local/bin/comfyui-healthcheck.py` and run as `HealthCmd`
|
||||
- [[Dankclaw Stack]]
|
||||
- [[ComfyUI ROCm and Vulkan]] — the live-verified GPU path research
|
||||
- [[ComfyUI Qwen-Image Workflows]] — the Qwen-Image 2.1 payload, proven workflows, and recommended model/LoRA additions
|
||||
- [[Lemonade and sd.cpp]] — the ggml-family alternative
|
||||
- the ggml-family alternative
|
||||
- Knowledge base: [[ComfyUI]] (tools)
|
||||
@@ -52,11 +52,10 @@ graph LR
|
||||
|
||||
The LLM rows are bare-metal systemd services, not containers, and this repo
|
||||
owns their scripts, units and knowledge base (see
|
||||
[LLM fleet knowledge base](../LLM/index.md)). Which payload and runtime sits on
|
||||
). Which payload and runtime sits on
|
||||
each port is era state and lives on the endpoint page, not here. `frank-npu`
|
||||
(the XDNA2 NPU endpoint) and `frank-medium` (the predecessor of `frank-archon`
|
||||
on the Dankserver port) are both retired — see [[frank-npu]] and
|
||||
[[frank-medium-radiance-mxfp4]].
|
||||
on the Dankserver port) are both retired — see and
|
||||
|
||||
## Boot Persistence
|
||||
|
||||
@@ -72,7 +71,7 @@ Deploy the SearXNG trio with `scripts/deploy-searxng-quadlet.sh dankclaw`, open-
|
||||
|
||||
## See Also
|
||||
|
||||
- [[index]] — repository index
|
||||
- repository index
|
||||
- [[Network Architecture]] — routing and proxy
|
||||
- [[Observability]] — Grafana, Prometheus, logs
|
||||
- [LLM fleet knowledge base](../LLM/index.md) — the model-serving endpoints on this host
|
||||
- the model-serving endpoints on this host
|
||||
@@ -37,7 +37,7 @@ timestamp: 2026-10-18
|
||||
|
||||
## Why this engine, and not the alternatives
|
||||
|
||||
The criterion Frank set on 2026-10-18 was **"whatever is better for live output"**, and live output is decided by time-to-first-audio and by whether the stream stays ahead of real time — not by benchmark throughput. RTF only has to stay under 1.0 with margin; what separates the arms is first-byte latency and **spread**. Measured on this host the same day (CPU; the full A/B is the section *"Decision: arm A for live output (2026-10-18)"* in [[Local TTS and Voice Cloning]], which is the source of these numbers):
|
||||
The criterion Frank set on 2026-10-18 was **"whatever is better for live output"**, and live output is decided by time-to-first-audio and by whether the stream stays ahead of real time — not by benchmark throughput. RTF only has to stay under 1.0 with margin; what separates the arms is first-byte latency and **spread**. Measured on this host the same day (CPU; the full A/B is the section *"Decision: arm A for live output (2026-10-18)"* in , which is the source of these numbers):
|
||||
|
||||
| Measure | Resident `tts-server` (arm A, chosen) | Mainline per-request CLI path (arm B) |
|
||||
|---|---|---|
|
||||
@@ -128,6 +128,6 @@ still open.
|
||||
| Everything is ~2× slower after a systemd tweak | a cpuset/cap pin changed `hardware_concurrency()` and the engine resized its thread pools | remove the pin (law 2) |
|
||||
| `502` from the façade with `frank-tts upstream request failed` | the façade cannot resolve or reach the engine | `podman network inspect systemd-frank-tts-engine` and `podman inspect frank-tts --format '{{json .NetworkSettings.Networks}}'` — the façade must be attached to the bridge; a `127.0.0.1:8880` or `host.containers.internal:8880` upstream in `scripts/frank-tts.env` is the old shape and cannot work |
|
||||
| A voice is missing from the list | its directory has no `reference.wav`, or the name is not lowercase | fix the pack; both are refused loudly by design |
|
||||
| `podman exec` in the deploy says `no such file or directory` for `/app/warm-voices.sh` | the image predates the warmer | re-deploy: since 2026-10-18 `build_compose_image` hashes every file the image `COPY`s, not only `Containerfile.engine`, so editing the warmer rebuilds it — see [[deployment]] |
|
||||
| `podman exec` in the deploy says `no such file or directory` for `/app/warm-voices.sh` | the image predates the warmer | re-deploy: since 2026-10-18 `build_compose_image` hashes every file the image `COPY`s, not only `Containerfile.engine`, so editing the warmer rebuilds it — see |
|
||||
| The warm pass logs `registered, but the warm synthesis failed` for EVERY voice, while a hand-run `/app/warm-voices.sh` succeeds | `WARM_TEXT` arrived **with its quotes**. podman's `--env-file` does no shell parsing — it takes the literal remainder of the line — so the env-file reader got `"Warm up, one two three."` where `source` gives `Warm up, one two three.`; the quotes plus a backslash then make the synthesis body invalid JSON | the hook strips one matched pair and escapes what is left; prove the value with `podman exec frank-tts-engine env \| grep WARM_TEXT`. The seam pins both readers, because a test that only sources the env file cannot see this |
|
||||
| A `502` for `/v1/voices` where the engine answers `200` on `/health` from the same boot | the engine restarted and its in-memory registry is empty again — `/health` is model-loaded, NOT voices-registered | re-run `podman exec frank-tts-engine /app/warm-voices.sh`; that is the same distinction the `frank-tts` healthcheck enforces |
|
||||
@@ -18,10 +18,10 @@ audio in that cloned voice. Everything else in the voice stack sits behind it
|
||||
the engine ([[Frank TTS Engine]]) publishes no port on purpose, and consumers
|
||||
never learn a path.
|
||||
|
||||
**Deployed 2026-10-18** — `./scripts/deploy.sh dankclaw --service frank-tts`,
|
||||
**Deployed 2026-10-18** — `./scripts/deploy.sh dankclaw --service frank-tts`
|
||||
both units `active`, no drop-ins, and the homepage card's `wip` gate came off in
|
||||
the same change. Probes on the deployed endpoint: `/health` answers
|
||||
`{"status":"ok","backend":"omni-http","voices":["narrator1","narrator2","narrator3"]}`,
|
||||
`{"status":"ok","backend":"omni-http","voices":["narrator1","narrator2","narrator3"]}`
|
||||
and two different voices rendered the same sentence into **different** bytes
|
||||
(24 kHz mono PCM16, 4.24 s, healthy RMS) — so name resolution is real, not a
|
||||
pass-through of one default. The operator harness routes its `speech` role here;
|
||||
@@ -147,7 +147,7 @@ A `/health` probe job would therefore be structurally never-green, and because
|
||||
`LlmEndpointDown` is scoped across the whole `frank-*` job family (the rule set
|
||||
lives on [[Prometheus]]), a permanently red `frank-tts` target would page on
|
||||
Signal every few minutes for an endpoint that is fine. The engine cannot be
|
||||
scraped at all: it publishes nothing. Status lives in `systemctl --user status`,
|
||||
scraped at all: it publishes nothing. Status lives in `systemctl --user status`
|
||||
`podman healthcheck run`, the two unit journals, and the homepage card, which
|
||||
probes `127.0.0.1:7772` for real now — the `wip: down` gate came off with the
|
||||
2026-10-18 deploy.
|
||||
@@ -155,7 +155,7 @@ probes `127.0.0.1:7772` for real now — the `wip: down` gate came off with the
|
||||
## The harness speech role
|
||||
|
||||
The operator harness reaches this endpoint through
|
||||
`~/.omp/agent/models.yml` — provider `frank-tts (dankclaw)`,
|
||||
`~/.omp/agent/models.yml` — provider `frank-tts (dankclaw)`
|
||||
`baseUrl: http://192.168.0.143:7772/v1`, `auth: none`, and the runner api
|
||||
`openai-speech` on the **model** row (naming a runner api at *provider* level
|
||||
fails the whole file's validation and disables every custom provider, which is
|
||||
@@ -171,7 +171,7 @@ harness bundle and measured the day of the flip:
|
||||
`speech.voice` is the TUI's **speak-aloud** voice — its enum is Kokoro's list,
|
||||
and it never reaches an HTTP request. So a harness call arrives voice-less by
|
||||
default, which is exactly why the endpoint grew `DEFAULT_VOICE`: the declared
|
||||
pack answers a voice-less request and the journal marks that line `(default)`,
|
||||
pack answers a voice-less request and the journal marks that line `(default)`
|
||||
while an **unknown** name still 400s with the list that exists.
|
||||
- **`speech.voice` must stay a Kokoro name.** Setting it to a pack name does not
|
||||
select a pack; it hands the vocalizer a value outside its enum. (The first
|
||||
|
||||
@@ -33,7 +33,7 @@ The containers share the private bridge network `systemd-gitea`. The quadlet net
|
||||
| `dank/command-center` | second public repo on the instance (`GET http://127.0.0.1:3000/api/v1/repos/search` 2026-10-18) |
|
||||
| `dank/vllmScripts` | retired 2026-08-22 — merged into `dank/serverAppConfigs` (history preserved) *(unverified 2026-10-18: the anonymous API search returns no match and `/dank/vllmScripts` is 404, so whether the repo still exists privately cannot be checked without a token)* |
|
||||
|
||||
The LLM fleet knowledge base: [serverAppConfigs-docs/LLM/index.md](../LLM/index.md)
|
||||
The LLM fleet knowledge base:
|
||||
|
||||
## Management
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ entrypoint does not start the dashboard. The dashboard is a separate process, so
|
||||
it runs in its own Quadlet unit
|
||||
([`dankclaw/hermes/quadlet/hermes-dashboard.container`](../../dankclaw/hermes/quadlet/hermes-dashboard.container):
|
||||
image `localhost/hermes-agent:latest`, `Pull=never`, `Exec=hermes dashboard
|
||||
--host 0.0.0.0 --port 9119 --no-open --skip-build`, `Restart=always`,
|
||||
--host 0.0.0.0 --port 9119 --no-open --skip-build`, `Restart=always`
|
||||
`RestartSec=5`). All three Hermes containers mount the same `/data` bind mount.
|
||||
|
||||
Unlike its two siblings — `hermes.container` and `hermes-webui.container` both
|
||||
|
||||
@@ -40,7 +40,7 @@ from another LAN host: `/health` → 200, `/` → 302) — **Vhost:**
|
||||
|
||||
## Why a container, not a host process
|
||||
|
||||
The gateway's state files are owned by the container-mapped uid (`109999`,
|
||||
The gateway's state files are owned by the container-mapped uid (`109999`
|
||||
from rootless Podman's `1 → 100000/65536` subuid range — `/etc/subuid` →
|
||||
`dank:100000:65536`, and the agent's runtime uid is 10000, so 100000 + 9999 =
|
||||
109999; `ls -ld /home/dank/Containers/hermes/data` → uid 109999, 2026-10-18). A fresh rootless
|
||||
@@ -82,12 +82,12 @@ the sibling dashboard on `9119` is not.
|
||||
|
||||
- Dedicated `tunnel` account on Dankclaw (`getent passwd tunnel` → uid 994,
|
||||
shell `/usr/sbin/nologin`, 2026-10-18; password locked). Authentication is key-only
|
||||
*(unverified 2026-10-18: `/home/tunnel/.ssh/authorized_keys` is not readable
|
||||
- (unverified 2026-10-18: `/home/tunnel/.ssh/authorized_keys` is not readable
|
||||
without `sudo`)*; the account can do nothing except
|
||||
authenticate — `ForceCommand /usr/sbin/nologin` kills any session channel
|
||||
while the transport stays up for port forwarding.
|
||||
- sshd drop-in `/etc/ssh/sshd_config.d/99-tunnel.conf` (exists, 118 B, 2026-08-31)
|
||||
scopes `AllowTcpForwarding yes` to that user only, plus `PermitTTY no`,
|
||||
scopes `AllowTcpForwarding yes` to that user only, plus `PermitTTY no`
|
||||
`X11Forwarding no` and `ForceCommand /usr/sbin/nologin` — all four lines are
|
||||
present under `Match User tunnel` (`cat` 2026-10-18).
|
||||
- Key options on the authorized key pin the blast radius:
|
||||
@@ -130,7 +130,7 @@ only if inactive (it is never restarted on deploy, so in-flight browser
|
||||
sessions survive), re-tags the image alias, then restarts
|
||||
`hermes.service`, `hermes-dashboard.service` and
|
||||
`hermes-webui.service` in the **user** manager of `dank` (linger must be on for
|
||||
them to come up at boot — `loginctl show-user dank -p Linger` → `yes`,
|
||||
them to come up at boot — `loginctl show-user dank -p Linger` → `yes`
|
||||
2026-10-18), so gateway/dashboard/webui restarts stay isolated from
|
||||
inference deploys.
|
||||
Before first deploy, set a strong `HERMES_WEBUI_PASSWORD` in the live
|
||||
|
||||
@@ -18,7 +18,7 @@ bindings, 2026-10-18). Note the **container name drift**: the unit is
|
||||
`podman run --name systemd-%N …` (`systemctl --user cat hermes.service`), so
|
||||
`podman ps` shows the gateway as **`systemd-hermes`** — the repo unit sets no
|
||||
`ContainerName=` key even though its header comment says "container name:
|
||||
hermes". The user-facing web surface is [[Hermes-WebUI]] on `:8787`, reached via
|
||||
hermes". The user-facing web surface is [[Hermes-WebUI]] on `:8787`, reached
|
||||
`hermes.franksdank.cloud` — internal-only by DNS absence (no public Porkbun A
|
||||
record; the name resolves from the Pi-hole hosts file,
|
||||
`dankclaw/pihole/addn-hosts:39`) — **Docs:**
|
||||
@@ -37,7 +37,7 @@ designed wiring; the remedy for both halves is in the log line
|
||||
|
||||
**Persistent state:** `/home/dank/Containers/hermes/data` on Dankclaw, bind-mounted
|
||||
at `/data` in all three Hermes containers (gateway, webui, dashboard —
|
||||
`hermes.container:36`, `hermes-webui.container:46`,
|
||||
`hermes.container:36`, `hermes-webui.container:46`
|
||||
`hermes-dashboard.container:24`). Each
|
||||
container additionally gets an anonymous volume at `/opt/data`, which is
|
||||
re-created empty on every container recreation — anything that lives only there
|
||||
@@ -80,7 +80,7 @@ is not durable. The tracked, sanitized configuration baseline is
|
||||
`frank-dragoon` — verified from the host with `curl
|
||||
http://127.0.0.1:7770/v1/models` → a single served id (2026-10-18; write
|
||||
`127.0.0.1`, not `localhost`, because that port is a rootless pasta publish
|
||||
and is IPv4-only);
|
||||
and is IPv4-only)
|
||||
`dankserver-small` reaches `http://192.168.0.235:7770/v1` and, **as of
|
||||
2026-10-18, that endpoint serves only `frank-archon`** (`GET
|
||||
http://192.168.0.235:7770/v1/models` → `[{"id":"frank-archon"}]`). The name
|
||||
@@ -115,7 +115,7 @@ per session; the browser itself lives in a dedicated daemon container, the
|
||||
digest-pinned headless-shell unit `chrome-devtools-protocol.container` (host
|
||||
network, loopback-only bind on 127.0.0.1:9222 — `ss -ltnp` 2026-10-18 shows
|
||||
`127.0.0.1:9222 headless-shell` and nothing on `0.0.0.0`; image
|
||||
`docker.io/chromedp/headless-shell@sha256:2d349b544a1ea6b5…`,
|
||||
`docker.io/chromedp/headless-shell@sha256:2d349b544a1ea6b5…`
|
||||
`dankclaw/hermes/quadlet/chrome-devtools-protocol.container:28`). Both consumers — the Signal
|
||||
gateway and the webui server — run in the host network namespace (`podman
|
||||
inspect` → `net=host` for both, 2026-10-18), so they can
|
||||
@@ -248,7 +248,7 @@ What actually breaks, and the fix:
|
||||
effort: none # mandatory, see below
|
||||
```
|
||||
|
||||
Before copying this: which id is served on which port is endpoint state — see
|
||||
Before copying this: which id is served on which port is endpoint state —
|
||||
[[frank-zealot]] and [[frank-archon]]. The provider/model
|
||||
pairing above is the shape that was landed in 2026; re-derive it from the live
|
||||
config before reusing it.
|
||||
@@ -282,7 +282,7 @@ Auth contract (verified live 2026-08-31, re-checked 2026-10-18): `POST /api/auth
|
||||
on match, 401 on miss. No username field. `/health` answers 200
|
||||
unauthenticated (`curl http://127.0.0.1:8787/health` → 200 with
|
||||
`{"status":"ok", …}` today) and `/` answers 302 (`curl -o /dev/null -w
|
||||
%{http_code} http://127.0.0.1:8787/` → 302 today) — **never verify auth via
|
||||
%{http_code} http://127.0.0.1:8787/` → 302 today) — **never verify auth
|
||||
those**; probe
|
||||
login with a deliberately wrong password (expect 401) and the real one
|
||||
(expect 200). Details on the webui surface: [[Hermes-WebUI]].
|
||||
@@ -311,7 +311,7 @@ login with a deliberately wrong password (expect 401) and the real one
|
||||
instead of loopback" — live bind `0.0.0.0:8787`, `ss -ltnp` 2026-10-18;
|
||||
off-network ingress is SSH tunnel only —
|
||||
user `tunnel`, port **22** (`sshd -T` → `port 22`, 2026-10-18), key-only auth
|
||||
*(unverified 2026-10-18: the per-user `Match` block needs `sudo` to read)*,
|
||||
- (unverified 2026-10-18: the per-user `Match` block needs `sudo` to read)*
|
||||
forward remote end
|
||||
localhost:8787).
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ returns a stripped, readable version of the page — no paywall chrome, no
|
||||
tracking, no cookie walls. It is a Laravel 13 app on the
|
||||
`serversideup/php:8.4-fpm-nginx` image (`composer.json` requires
|
||||
`php: ^8.4`, `laravel/framework: ^13.0`, `filament/filament: ^5.7` —
|
||||
<https://raw.githubusercontent.com/manualdousuario/marreta/main/composer.json>),
|
||||
<https://raw.githubusercontent.com/manualdousuario/marreta/main/composer.json>)
|
||||
with an optional headless-browser companion for JavaScript-heavy pages.
|
||||
|
||||
**Host:** Dankclaw — **vhost:** `marreta.franksdank.cloud` (Caddy, guard-chained)
|
||||
@@ -31,7 +31,7 @@ with an optional headless-browser companion for JavaScript-heavy pages.
|
||||
- Fetches a target URL with a cascade of strategies: plain HTTP (curl), a
|
||||
headless browser (Lightpanda) for JS pages, and the Internet Archive
|
||||
(Wayback) as a last resort — the three `app/Services/Fetch/*FetchStrategy.php`
|
||||
files upstream (`BrowserFetchStrategy`, `CurlFetchStrategy`,
|
||||
files upstream (`BrowserFetchStrategy`, `CurlFetchStrategy`
|
||||
`WaybackFetchStrategy`, dispatched by `app/Services/FetchManager.php`).
|
||||
- Strips paywall/consent/tracking markup and re-renders clean HTML.
|
||||
- Ships a Filament admin panel at `/admin` (login = `ADMIN_EMAIL` /
|
||||
@@ -69,7 +69,7 @@ graph LR
|
||||
| `marreta-browser.service` | `dankclaw/marreta/quadlet/marreta-browser.container` | `docker.io/lightpanda/browser:nightly` (`:26`) | `gluetun.container` (`:25`) | `9222` (CDP) |
|
||||
|
||||
Both units are boot-persistent (`WantedBy=default.target`) and self-healing
|
||||
(`Restart=always`, `RestartSec=10` — `marreta.container:62-69`,
|
||||
(`Restart=always`, `RestartSec=10` — `marreta.container:62-69`
|
||||
`marreta-browser.container:30-34`), per the repo's Boot Persistence rule. Live
|
||||
2026-10-18 both report `systemctl --user is-enabled` → `generated` and
|
||||
`is-active` → `active`, and `podman inspect` reports marreta **healthy**
|
||||
@@ -87,14 +87,14 @@ The fix is a single env var, verified against the serversideup source:
|
||||
|
||||
- The image sets `ENV NGINX_HTTP_PORT="8080"` and the site template is
|
||||
`listen ${NGINX_HTTP_PORT} default_server;`.
|
||||
- The image does **not** bake `conf.d/*.conf` (it `rm -rf`s them at build);
|
||||
- The image does **not** bake `conf.d/*.conf` (it `rm -rf`s them at build)
|
||||
the entrypoint `10-init-webserver-config.sh` runs `envsubst` over every
|
||||
`NGINX_*` variable **at container start**.
|
||||
- So `Environment=NGINX_HTTP_PORT=8085` in the quadlet relocates the listen
|
||||
port off the collision with no custom build.
|
||||
|
||||
Marreta then publishes **nothing** of its own — the netns owner (Gluetun)
|
||||
publishes `8082:8085` on its behalf (`dankclaw/searxng/quadlet/gluetun.container:32`),
|
||||
publishes `8082:8085` on its behalf (`dankclaw/searxng/quadlet/gluetun.container:32`)
|
||||
exactly as it publishes `8081:8080` for SearXNG. Caddy dials
|
||||
`192.168.0.143:8082` (`dankclaw/Caddyfile:419-422`). Live env confirms the
|
||||
relocation: `podman inspect marreta` carries `NGINX_HTTP_PORT=8085`
|
||||
@@ -127,7 +127,7 @@ on the mechanism: `BrowserFetchStrategy.php` only calls
|
||||
(`dankclaw/Caddyfile:159-163`).
|
||||
2. **Auth decision** — Anubis dials Caddy's `http://:8016`, which proxies
|
||||
whole-request to `authentik-server:9000` (`dankclaw/Caddyfile:22-24,94`).
|
||||
3. **Post-auth routing** — authenticated traffic returns to `http://:8017`,
|
||||
3. **Post-auth routing** — authenticated traffic returns to `http://:8017`
|
||||
where `@marreta host marreta.franksdank.cloud` routes to
|
||||
`reverse_proxy 192.168.0.143:8082` (`dankclaw/Caddyfile:419-422`).
|
||||
|
||||
@@ -164,7 +164,7 @@ Marreta ships `trustProxies(at: '172.16.0.0/12,10.0.0.0/8,192.168.0.0/16,127.0.0
|
||||
— that is the `TRUSTED_PROXIES` fallback in upstream `bootstrap/app.php`, and
|
||||
this container sets no `TRUSTED_PROXIES`, so the default is what runs
|
||||
(`podman inspect marreta` 2026-10-18) — and forces `https` when `APP_URL`
|
||||
starts with `https://` (`app/Providers/AppServiceProvider.php:23-24`,
|
||||
starts with `https://` (`app/Providers/AppServiceProvider.php:23-24`
|
||||
`URL::forceScheme('https')`). With
|
||||
`APP_URL=https://marreta.franksdank.cloud` (`dankclaw/marreta/quadlet/marreta.container:41`) the app honors the forwarded
|
||||
scheme and client IP through the whole chain, so there is no redirect loop
|
||||
@@ -234,7 +234,7 @@ netns down and would otherwise orphan it).
|
||||
Deployed via `deploy.sh dankclaw --service gluetun --service marreta --service
|
||||
caddy` (gluetun first to recreate the tunnel with the new `8082:8085` publish,
|
||||
which also cycles SearXNG's netns ref). Authentik `ProxyProvider` `marreta`
|
||||
registered (pk 13, `external_host=https://marreta.franksdank.cloud/`,
|
||||
registered (pk 13, `external_host=https://marreta.franksdank.cloud/`
|
||||
`internal_host=http://caddy:8017`). Results:
|
||||
|
||||
- Unauth edge → Anubis challenge page (not 502). TLS cert issued via DNS-01.
|
||||
@@ -245,14 +245,14 @@ registered (pk 13, `external_host=https://marreta.franksdank.cloud/`,
|
||||
(`GET 127.0.0.1:9222/json/version` → `Lightpanda/1.0`).
|
||||
- SearXNG unaffected: `:8081` → 200 after the tunnel recreate.
|
||||
|
||||
> **Gotcha hit during deploy:** the first seed used a bare-base64 `APP_KEY`,
|
||||
> **Gotcha hit during deploy:** the first seed used a bare-base64 `APP_KEY`
|
||||
> which 500s every app route (see Secrets above). Fixed by re-keying with the
|
||||
> `base64:` prefix before any encrypted data was persisted.
|
||||
|
||||
## Citations
|
||||
|
||||
- Marreta upstream: <https://github.com/manualdousuario/marreta> (README,
|
||||
`compose.yml`, `bootstrap/app.php`, `app/Services/Fetch/BrowserFetchStrategy.php`,
|
||||
`compose.yml`, `bootstrap/app.php`, `app/Services/Fetch/BrowserFetchStrategy.php`
|
||||
`lang/` directory listing).
|
||||
- serversideup/php fpm-nginx port mechanism: `serversideup/docker-php`
|
||||
`src/variations/fpm-nginx/Dockerfile` (`NGINX_HTTP_PORT="8080"`) and
|
||||
|
||||
@@ -111,7 +111,7 @@ The Ollama connection is disabled (`ollama.enable=false`).
|
||||
|
||||
- Working dir for imports: `/app/backend`; package name `open_webui`
|
||||
(underscore), NOT `openwebui`. `os.environ["WEBUI_SECRET_KEY"]` MUST be set
|
||||
BEFORE importing any `open_webui` module (import-time hard requirement);
|
||||
BEFORE importing any `open_webui` module (import-time hard requirement)
|
||||
the secret lives at `/app/backend/.webui_secret_key`.
|
||||
- **The `sqlite3` CLI is NOT in the container** — use Python's `sqlite3`
|
||||
module (`podman exec open-webui python3 -c "import sqlite3;
|
||||
@@ -122,8 +122,8 @@ The Ollama connection is disabled (`ollama.enable=false`).
|
||||
pydantic `ModelModel` instances (attribute access, not `.get()`), with NO
|
||||
`status`/`enabled` attribute — use `is_active` from the DB.
|
||||
- **API auth for verification:** `create_token` lives in
|
||||
`open_webui.utils.auth` (NOT `open_webui.utils.utils`);
|
||||
`get_verified_user` requires an `id` claim (not just `sub`);
|
||||
`open_webui.utils.auth` (NOT `open_webui.utils.utils`)
|
||||
`get_verified_user` requires an `id` claim (not just `sub`)
|
||||
`SESSION_SECRET = WEBUI_SECRET_KEY`. Mint an admin token inside the
|
||||
container:
|
||||
|
||||
@@ -148,7 +148,7 @@ The Ollama connection is disabled (`ollama.enable=false`).
|
||||
`ClientConnectorError`: a network-reachability problem (host LAN IP vs
|
||||
`host.containers.internal`), not a model problem.
|
||||
|
||||
**Durability:** the model table + connections are DB-only (not git-managed);
|
||||
**Durability:** the model table + connections are DB-only (not git-managed)
|
||||
a fresh data volume loses them — including the public access grant above.
|
||||
For reproducibility, add an idempotent first-start seed script or document
|
||||
the setup in the service doc.
|
||||
@@ -156,7 +156,7 @@ the setup in the service doc.
|
||||
## API access (auth-gated)
|
||||
|
||||
Every `/api/*` endpoint requires an authenticated session (SSO login JWT)
|
||||
or a per-user API key (`auth.enable_api_keys=true`; keys are minted per
|
||||
or a per-user API key (`auth.enable_api_keys=true`; keys are minted
|
||||
account under Profile → API Keys). Anonymous web visitors get the `pending`
|
||||
role (`ui.default_user_role=pending`), which cannot chat. Verified
|
||||
2026-10-07 from loopback `:3005` and over the public vhost:
|
||||
@@ -166,13 +166,12 @@ bogus bearer token); only `/api/config`, `/api/version` and `/health`
|
||||
`POST /api/chat/completions` all return **401** with no key (also with a bogus bearer
|
||||
token); only `/api/config`, `/api/version` and `/health` answer publicly, and none of
|
||||
them expose the model list. An external program needs an account + API key — there is
|
||||
no keyless access. Re-verified 2026-10-18 from loopback: `/health` → `{"status":true}`,
|
||||
no keyless access. Re-verified 2026-10-18 from loopback: `/health` → `{"status":true}`
|
||||
`/api/version` → 0.11.4, `/api/v1/models/list`, `/api/v1/models` and
|
||||
`POST /api/chat/completions` → 401; `/api/config` additionally publishes
|
||||
`features.enable_login_form=false`, `features.enable_signup=false` and
|
||||
`oauth.providers.oidc="authentik"` — the SSO-only posture, visible from outside.
|
||||
|
||||
|
||||
## Web search
|
||||
|
||||
Chat web search is served by [[SearXNG]] on this host, wired in the quadlet
|
||||
@@ -186,7 +185,7 @@ Chat web search is served by [[SearXNG]] on this host, wired in the quadlet
|
||||
The Anubis→Authentik guard chain is a browser mechanism (proof-of-work +
|
||||
session flow); a plain HTTP client cannot solve it, and the internal port
|
||||
bypasses Caddy entirely.
|
||||
- **Limiter:** SearXNG caps non-HTML (JSON) requests at 4/IP/hour (`API_MAX`,
|
||||
- **Limiter:** SearXNG caps non-HTML (JSON) requests at 4/IP/hour (`API_MAX`
|
||||
a hardcoded Python constant — no config knob). The `pass_ip` list is checked
|
||||
FIRST and short-circuits the whole botdetection chain, and OpenWebUI's bridge
|
||||
egress (`10.89.x`) is in `pass_ip`, so the cap never applies. Verified: an
|
||||
@@ -249,7 +248,6 @@ browser-driven and only touches the two exempt vhosts (`ai.` and `auth.`).
|
||||
restore the password form: set `ui.enable_login_form` back to `true` in the
|
||||
Admin Panel (or DB) and drop the two env vars from the quadlet.
|
||||
|
||||
|
||||
## Boot persistence (Quadlet)
|
||||
|
||||
The unit lives at `dankclaw/open-webui/quadlet/open-webui.container`. On the host it installs to `~/.config/containers/systemd/open-webui.container`. The generator turns it into `open-webui.service`. Because the unit sets `[Install] WantedBy=default.target` and user linger is on, it starts at boot. `systemctl --user is-enabled open-webui.service` reports `generated` (the quadlet boot-start state).
|
||||
@@ -296,7 +294,7 @@ TTS is the fleet's one OpenAI-compatible speech endpoint —
|
||||
`http://host.containers.internal:7772/v1` (`audio.tts.openai.api_base_url`
|
||||
in the config DB, 2026-10-18), model `frank-tts`, voice `narrator1`. That
|
||||
port is the rootless quadlet `frank-tts` (this repo:
|
||||
`dankclaw/voiceservice/quadlet/frank-tts.container`,
|
||||
`dankclaw/voiceservice/quadlet/frank-tts.container`
|
||||
`scripts/frank-tts.env`), and its shim resolves `voice=<name>` against
|
||||
`/home/dank/voices/<name>/reference.wav` — a name without a reference is a
|
||||
400 listing the voices that exist, never a silent fallback.
|
||||
@@ -310,7 +308,7 @@ setting). Its engine select takes `""` (Default) or `browser-kokoro`; when
|
||||
`browser-kokoro` is chosen the page synthesizes locally and rejects any
|
||||
voice outside its fixed pack — so `narrator1` fails with
|
||||
`Voice: "narrator1" not found. Should be one of: af_heart, …` **without a
|
||||
single request reaching the server**. Personal audio settings are per
|
||||
single request reaching the server**. Personal audio settings are
|
||||
browser: no `user.settings` row and no container env carries an audio
|
||||
override, yet the toast still appears ⇒ the choice lives in that browser's
|
||||
own storage. Fix in the UI: Settings → Audio → TTS Engine → **Default**,
|
||||
@@ -325,7 +323,6 @@ the failing click — that contrast is the instrument: a server-path failure
|
||||
leaves a log line and a frank-tts error, a `browser-kokoro` failure leaves
|
||||
neither.
|
||||
|
||||
|
||||
## Retired instances
|
||||
|
||||
- The compose `open-webui` service (port 3000) was never run: 3000 is Gitea's HTTP port, so it could not bind.
|
||||
@@ -355,7 +352,7 @@ neither.
|
||||
began serving `frank-zealot` / `frank-dragoon` / `frank-archon`, so three
|
||||
id-keyed objects had to move in the same window as the alias flip:
|
||||
`model.id`+`name` (`frank-zealot` → `frank-zealot`, `params`
|
||||
`{"context":{"length":200704}}` and the `meta.description` kept),
|
||||
`{"context":{"length":200704}}` and the `meta.description` kept)
|
||||
`access_grant` (`resource_type='model'`, `resource_id`, principal
|
||||
`user`/`*`, permission `read`), and `openai.api_configs` per-backend
|
||||
`model_ids` (index 2 = `:7771` is the enabled family backend; indices 0/1
|
||||
|
||||
@@ -88,7 +88,7 @@ never enter this repo. See [[Gitea]] and [[Authentik]].
|
||||
|
||||
## Boot persistence (Quadlet)
|
||||
|
||||
Both units carry `Restart=always` (`gitea-postgres.container:28`,
|
||||
Both units carry `Restart=always` (`gitea-postgres.container:28`
|
||||
`authentik-postgres.container:38`) and `[Install] WantedBy=default.target`
|
||||
(`gitea-postgres.container:31`, `authentik-postgres.container:41-42`), are installed
|
||||
under `~/.config/containers/systemd/`, and report `generated` / `active` with
|
||||
|
||||
@@ -143,7 +143,7 @@ engines:
|
||||
disabled: false
|
||||
```
|
||||
|
||||
Key per-engine keys (each overwrites the engine-module default; see
|
||||
Key per-engine keys (each overwrites the engine-module default
|
||||
`settings_engines.html`):
|
||||
|
||||
| Key | Effect |
|
||||
@@ -164,7 +164,7 @@ Key per-engine keys (each overwrites the engine-module default; see
|
||||
*different* category. When the primary `google` gets CAPTCHA'd it suspends, but
|
||||
`google2` still returns results, and vice-versa.
|
||||
|
||||
**Parser caveat (read before fiddling with `parsers`):** the modern `google`,
|
||||
**Parser caveat (read before fiddling with `parsers`):** the modern `google`
|
||||
`duckduckgo`, and `brave` engines ship a **custom `response()`** with hardcoded
|
||||
XPath and *ignore* the generic `parsers`/`p_parsers` table. So `parsers:
|
||||
[scrapy_html]` under `name: google` mostly does nothing. To make Google
|
||||
@@ -376,14 +376,14 @@ done
|
||||
|
||||
**2. `/config` REST endpoint** lists every engine + enabled/disabled +
|
||||
categories — an inventory of what is live. It answers 200 on this instance today
|
||||
(`curl http://127.0.0.1:8081/config`, 2026-10-18; each entry carries `enabled`,
|
||||
(`curl http://127.0.0.1:8081/config`, 2026-10-18; each entry carries `enabled`
|
||||
`categories`, `timeout`, `shortcut`, and it is the source of the engine counts on
|
||||
[[SearXNG]]). `?engines=<name>` isolates a single
|
||||
provider; `/debug` adds engine diagnostics.
|
||||
|
||||
**3. `check.searx.space`** — the hosted official checker probes every engine of
|
||||
your instance with a **headless Firefox** (catches Cloudflare/CAPTCHA blocks a
|
||||
plain HTTP probe misses) and posts results on searx.space. Add your instance via
|
||||
plain HTTP probe misses) and posts results on searx.space. Add your instance
|
||||
a GitHub issue in `searxng/searx-instances`, then allow `check.searx.space` IPs
|
||||
to reach the SearXNG port.
|
||||
|
||||
@@ -417,10 +417,10 @@ misleading).
|
||||
already replaced — checked 2026-10-18; see [[SearXNG]]). It is
|
||||
also immune to the shared-VPN-exit-IP blocking this page is about: it
|
||||
authenticates, so reputation of the exit IP is irrelevant.
|
||||
5. **Verify first** — `/json` + `?engines=google` and the searx-checker to see
|
||||
5. **Verify first** — `/json` + `?engines=google` and the searx-checker to
|
||||
exactly which engines are down and why. Confirm the running SearXNG version
|
||||
(check whether `parsers`/`rate_limit` exist in the pinned build).
|
||||
6. **Use conservative request tuning** — Dankclaw now allows 5 seconds per
|
||||
6. **Use conservative request tuning** — Dankclaw now allows 5 seconds
|
||||
upstream request (`shared/searxng/settings.yml:26`), caps it at 15 seconds
|
||||
(`:27`), and retries once (`:32`). This addresses
|
||||
modest VPN latency without multiplying 429/CAPTCHA traffic. Adjust only
|
||||
|
||||
@@ -108,7 +108,7 @@ engines:
|
||||
disabled: true
|
||||
```
|
||||
|
||||
The block above is the repo file (`shared/searxng/settings.yml`, 21 engine stanzas);
|
||||
The block above is the repo file (`shared/searxng/settings.yml`, 21 engine stanzas)
|
||||
the deployed render at `/opt/searxng/config/settings.yml` differs only in the baked
|
||||
`secret_key`, `base_url` and `KAGI_API_KEY` values, and the running engine set is
|
||||
censused below.
|
||||
@@ -154,7 +154,7 @@ what keeps the `trusted_proxies` entry meaningful.
|
||||
|
||||
## Unblocking Google & Search Providers
|
||||
|
||||
The current request policy allows a modest amount of VPN latency (`5.0s` per
|
||||
The current request policy allows a modest amount of VPN latency (`5.0s`
|
||||
request, `15.0s` maximum — `shared/searxng/settings.yml:26-27`) while limiting
|
||||
retries to one (`:32`). This can recover slow
|
||||
providers, but it cannot fix an upstream CAPTCHA or 429 caused by the shared
|
||||
@@ -169,10 +169,10 @@ upstream request volume. SearXNG **suspends** offending engines — which is wha
|
||||
up as "Google went unavailable". The default suspension is shorter than the folklore:
|
||||
see the table in [[SearXNG Providers]]. This is upstream, not local.
|
||||
|
||||
Fixes (cheapest first): tune the `outgoing` block (`request_timeout`,
|
||||
Fixes (cheapest first): tune the `outgoing` block (`request_timeout`
|
||||
`retry_on_http_error`, `suspended_times`), duplicate the `google` engine under a
|
||||
fresh `name` so a CAPTCHA ban on one leaves the other returning results, and —
|
||||
if Google still re-blocks — route the Google engines at a clean-IP proxy via
|
||||
if Google still re-blocks — route the Google engines at a clean-IP proxy
|
||||
per-engine `proxies` in `settings.yml`. See [[SearXNG Providers]] for the full
|
||||
root cause, the suspend-model table, the `engines:` config, and the
|
||||
`/json` verification recipe.
|
||||
@@ -212,17 +212,16 @@ root cause, the suspend-model table, the `engines:` config, and the
|
||||
(`searxng.container:21`), and that is one of the variables SearXNG substitutes at
|
||||
load, so both paths carry the same LAN-IP value. Flagged, not fixed here: it is a
|
||||
config change, out of scope for docs.
|
||||
- Keep the valkey cache container on the network SearXNG can actually reach — see
|
||||
- Keep the valkey cache container on the network SearXNG can actually reach —
|
||||
[[Valkey]] Gotchas: SearXNG itself has no network of its own (it borrows Gluetun's
|
||||
netns), so the network that matters is the one Gluetun and `searxng-valkey` share.
|
||||
|
||||
|
||||
## Kagi (paid API engine)
|
||||
|
||||
Added 2026-09-26 (user-ordered) and still enabled: the running build ships a native
|
||||
`kagi` engine module (`searx/engines/kagi.py` at the pinned commit `12f8b6515`),
|
||||
`kagi` engine module (`searx/engines/kagi.py` at the pinned commit `12f8b6515`)
|
||||
which sets `Authorization: Bearer <key>` (`kagi.py:103`) and issues
|
||||
`POST https://kagi.com/api/v1/search` (`base_url` + `/api/v1/search`, `kagi.py:76,104,131`),
|
||||
`POST https://kagi.com/api/v1/search` (`base_url` + `/api/v1/search`, `kagi.py:76,104,131`)
|
||||
and declares `require_api_key: True` (`kagi.py:63`).
|
||||
|
||||
- **Enabled**: `weight: 2` alongside bing/duckduckgo, categories
|
||||
@@ -231,10 +230,10 @@ and declares `require_api_key: True` (`kagi.py:63`).
|
||||
`enabled: true`, categories `general, web` (2026-10-18).
|
||||
- **Cost control**: `paging: false` — exactly one API credit per aggregated
|
||||
query; `timeout: 8.0` so a slow paid query is not wasted (scrapers use 5.0)
|
||||
(`shared/searxng/settings.yml:74-77`; upstream paging default is `True`,
|
||||
(`shared/searxng/settings.yml:74-77`; upstream paging default is `True`
|
||||
`kagi.py:67`, so the `false` here is a real override).
|
||||
- **Key handling**: the repo file keeps `api_key: "${KAGI_API_KEY}"`;
|
||||
`deploy-remote.sh` bakes the real key into the live settings.yml via
|
||||
- **Key handling**: the repo file keeps `api_key: "${KAGI_API_KEY}"`
|
||||
`deploy-remote.sh` bakes the real key into the live settings.yml
|
||||
`scripts/searxng-render-settings.py`, reading `/opt/searxng/.env`
|
||||
(owner `dank`, mode 0600 — `ls -l /opt/searxng/.env` 2026-10-18; its key names are
|
||||
the WireGuard set plus `SEARXNG_SECRET`, `SEARXNG_BASE_URL`, `KAGI_API_KEY`).
|
||||
@@ -262,15 +261,15 @@ and declares `require_api_key: True` (`kagi.py:63`).
|
||||
|
||||
- 262 engines in the build, **75 enabled**, categories of the enabled set led by
|
||||
`other` (12), `it` (11), `general` (9), `videos` (8), `stock images` (7).
|
||||
- Enabled and matching the policy page: `bing`, `duckduckgo`, `wikipedia`, `kagi`,
|
||||
`github`, `mdn`, `stackoverflow`, `askubuntu`, `superuser`, `docker hub`, `pypi`,
|
||||
`arxiv`, `pubmed`, `semantic scholar`, `reuters`, `bing news`, `duckduckgo news`,
|
||||
`wikinews`, `bing images`, `duckduckgo images/videos/news`, `wikicommons.*`,
|
||||
- Enabled and matching the policy page: `bing`, `duckduckgo`, `wikipedia`, `kagi`
|
||||
`github`, `mdn`, `stackoverflow`, `askubuntu`, `superuser`, `docker hub`, `pypi`
|
||||
`arxiv`, `pubmed`, `semantic scholar`, `reuters`, `bing news`, `duckduckgo news`
|
||||
`wikinews`, `bing images`, `duckduckgo images/videos/news`, `wikicommons.*`
|
||||
`youtube`, `vimeo`, `dailymotion`, `bing videos`.
|
||||
- Disabled, as configured: `google`, `google cse`, `google news`, `google scholar`,
|
||||
- Disabled, as configured: `google`, `google cse`, `google news`, `google scholar`
|
||||
`brave`, `brave.images`, `brave.news`, `brave.videos`, `qwant`.
|
||||
- The three `startpage` stanzas in `shared/searxng/settings.yml:113-124` target
|
||||
engines that **no longer exist in this build** — `/config` lists no `startpage`,
|
||||
engines that **no longer exist in this build** — `/config` lists no `startpage`
|
||||
`startpage images` or `startpage news`, so those overrides are no-ops kept as
|
||||
intent. *(labelled 2026-10-18)*
|
||||
|
||||
|
||||
@@ -144,8 +144,8 @@ frank-dragoon `health=200` throughout.
|
||||
The previous 8 GiB `/swap.img` (dated 2026-07-21) was staged, not deleted, at
|
||||
`dankclaw:~/.AGENTTRASH/20260912-swapfile-8g/swap.img` (8.1 GiB). **That staging
|
||||
directory no longer exists** — `ls /home/dank/.AGENTTRASH` on 2026-10-18 lists only
|
||||
`20261005-frank-small-ubatch-ab`, `20261006-frank-large-tuning`,
|
||||
`20261007-openwebui-modelpicker`, `20261010-fleet-rename`, `20261017-bonsai-scratch`,
|
||||
`20261005-frank-small-ubatch-ab`, `20261006-frank-large-tuning`
|
||||
`20261007-openwebui-modelpicker`, `20261010-fleet-rename`, `20261017-bonsai-scratch`
|
||||
`20261017-prism-build`, `20261017-v2abl-trial`, and there is no `/root/.AGENTTRASH`.
|
||||
The old swapfile has therefore been purged; nothing on the host still holds it.
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ voice is how a wrong-voice endpoint stays wrong for weeks.
|
||||
state that stays out of the repo, mounted read-only at `/voices` by the façade
|
||||
unit — **Builder:** `scripts/build-voice-pack.sh` with tunables in
|
||||
`scripts/voice-packs.env` — **Seam:** `tests/voice_pack_unit.bats` — **Engine:**
|
||||
arm A `qwentts.cpp`, decided in [[Local TTS and Voice Cloning]].
|
||||
arm A `qwentts.cpp`, decided in .
|
||||
|
||||
Packs are **world-readable on purpose** (`drwxr-xr-x`, owner `dank`): the façade
|
||||
container runs as uid 10000 and reads the mount from outside its own uid map.
|
||||
@@ -137,7 +137,7 @@ invariant to every crop in the tracked pack list.
|
||||
1. Pick the source file and hash it: `sha256sum /path/to/sample.wav`. A crop
|
||||
offset is a claim about one exact file, so the digest goes in the env with it.
|
||||
2. Find a speech-dense stretch **past 10 s**. The trial's recipe, applied once:
|
||||
`ffmpeg -ss 60 -t 600 -i SRC -af silencedetect=noise=-35dB:d=0.6 -f null -`,
|
||||
`ffmpeg -ss 60 -t 600 -i SRC -af silencedetect=noise=-35dB:d=0.6 -f null -`
|
||||
build the runs of non-silence, keep runs ≥ 18 s, take the longest (earliest
|
||||
on ties), and cap at 25 s. Aim for 20–25 s: shorter than 19.84 s and the
|
||||
`.rvq` falls under the floor.
|
||||
@@ -188,15 +188,15 @@ loud, not a bug. Work through it in order:
|
||||
1. Re-read the tool's own numbers rather than trusting this page: `qwen-codec`
|
||||
prints `SpeakerEncoder] Loaded: enc_dim=…` and `Pipeline] Ready: hop … , …
|
||||
codebooks @ … Hz` on every run, and the pinned tree's
|
||||
`tools/qwen-codec.cpp` documents the packing. `enc_dim × 4` is the `.spk`;
|
||||
`tools/qwen-codec.cpp` documents the packing. `enc_dim × 4` is the `.spk`
|
||||
`codebooks × code_bits / 8` bytes per frame × frames is the `.rvq`.
|
||||
2. Decide whether the new number is intended. A changed `enc_dim` means the old
|
||||
`.spk` files are unreadable by the new engine, so **every** pack must be
|
||||
rebuilt, not just the failing one.
|
||||
3. Update the four arithmetic lines in `scripts/voice-packs.env`
|
||||
(`VOICE_PACK_SPK_BYTES`, `VOICE_PACK_RVQ_MIN_BYTES`, `VOICE_PACK_RVQ_MAX_BYTES`,
|
||||
(`VOICE_PACK_SPK_BYTES`, `VOICE_PACK_RVQ_MIN_BYTES`, `VOICE_PACK_RVQ_MAX_BYTES`
|
||||
and `VOICE_PACK_RVQ_BYTES_PER_FRAME` if the codebook packing changed) **and**
|
||||
`VOICE_PACK_ENGINE_COMMIT`, `VOICE_PACK_TOOL`, `VOICE_PACK_CODEC_MODEL`,
|
||||
`VOICE_PACK_ENGINE_COMMIT`, `VOICE_PACK_TOOL`, `VOICE_PACK_CODEC_MODEL`
|
||||
`VOICE_PACK_TALKER_MODEL` to the new build. An env diff that moves the sizes
|
||||
without moving the commit is the mistake to avoid.
|
||||
4. Rebuild all three packs with `--force` (the retired directories keep the old
|
||||
@@ -226,7 +226,7 @@ loud, not a bug. Work through it in order:
|
||||
narrator1 and narrator2). The builder's first real run is therefore a
|
||||
migration, and it should be a `--force` run per voice so the old directories
|
||||
are retired rather than left half-updated.
|
||||
- The three source files (`/home/blank/audiosample.mp3`,
|
||||
- The three source files (`/home/blank/audiosample.mp3`
|
||||
`audiosample2.m4b`, `audiosample3.m4b`, digests pinned in
|
||||
`scripts/voice-packs.env`) live on the workstation, not on Dankclaw; the
|
||||
builder reads them from `$VOICE_PACK_SOURCE_DIR=/home/dank/voice-sources`, so
|
||||
|
||||
Reference in new issue
Block a user