--- type: changelog title: Bundle Change Log description: Chronological update history for the OKF knowledge bundle. tags: - okf - maintenance - changelog timestamp: 2026-10-21 --- # Bundle Change Log Entry law (since 2026-10-19): one dated entry = what changed + the durable lesson, a few lines. Full incident narratives are recoverable from git (`git log --follow omp-docs/log.md`); knowledge that outlives an entry lives on its concept page, linked here. Never re-expand an entry in place. This is the bundle's only work log; [references/okf-spec.md](references/okf-spec.md) owns the one-log rule and `scripts/kb-lint.sh` enforces it. A law that a concept page already owns is not restated here — entry, then pointer. That is what the 2026-10-21 audit pass did to the newest twelve entries: the facts stayed, the duplicates went, `git log --follow` keeps the long form. ## 2026-10-21 ### the audit grows an advisory table, and corrects three of its own numbers `omp-docs/reports/fleet-security-audit-2026-10-21.html` folds in the two per-host vulnerability passes ([reports/vuln-dankclaw.md](reports/vuln-dankclaw.md), [reports/vuln-dankserver.md](reports/vuln-dankserver.md)): the "Advisory cross-reference (in progress)" section is now the full matrix and the header links the working files. Three figures fell to re-probing — the mutable-tag census (17 → **19** Dankclaw manifests / 17 unique references, +4 on Dankserver; the vuln pass's 24 also counts rolling release tags as mutable), the OpenSSH advisory count (0 → **5** unpatched CVEs; the first query omitted the version epoch, `10.2p1` for `1:10.2p1`, and OSV answers `0 vulns` rather than "unknown"), and the Plex version ("12.1.0" is Jellyfin's — `podman exec plex cat /build_version` reports `1.43.5.11029-6bf8af3f0-ls329`). Laws: **an empty OSV response is not a clean bill** — verify the query shape against the distro tracker before writing "0 advisories"; and **a version quoted from a subagent gets re-probed before it enters a report**, this being the second mis-attribution the audit caught. ### reviewing a day of work, and finding checks that lie Two-axis review (Standards / Spec) of 51 commits, 30 findings, on `fix/60-review-findings`. Refs #60, merged PR #61. The findings were one shape: **a check that reports confidence it did not earn.** - A guard that loses half its condition when a tool is missing must refuse, not narrow — `pcie-probe.sh` measured beside a live endpoint while its own LAW said not to ([tools/pcie-probe.md](tools/pcie-probe.md)). - A deployer that prints `ENABLE` for a unit systemd refuses to enable (`live-sync.service` has no `[Install]`; its timer arms it) reports a belief, not an outcome, and walking `*.service` only left the heartbeat unarmed on a rebuilt box ([tools/dotfiles-deploy.md](tools/dotfiles-deploy.md)). - A gate handed git's quoted path reads an empty diff and passes. Fail closed means `-z` (`.githooks/pre-commit`, `tests/secret-gate.bats`). Two laws no other page owns: **a stub that echoes its environment instead of its argument cannot see the bug** — the probe suite asserted the mask was set and never read what the tool passed, so per-card bandwidth stayed unobtainable; and **a name is data — split it, never let the shell expand it** (`remote-job.sh status` globbed its own arguments, so job `x*` was reported as whatever matched in the caller's directory: [tools/remote-job.md](tools/remote-job.md)). The heartbeat's three missed ticks were this gate firing on a managed skill that documents the vendor's all-zeros placeholder id: prose about credentials *is* the machine tier, and a gate that blocks it gets worked around — the workaround is the hole. Placeholder judgement reads the matched token and what follows it (a fixed quantifier truncates `EXAMPLE` to `EXA`), never the whole line. `ALLOW_SECRETS` stays the only override. The rest of #60 was claims the machine had stopped honouring: `.gitignore` and `deploy.sh`'s exclusion list drifted apart, `.gitattributes` justified installing `git-lfs` for wallpapers that same week's diff untracked, and the one-log rule had four owners. A coverage claim names what was measured; a tool justified by dead config cannot survive the config. ### an effort map folding against rejections that never existed Refs #62. `agent/models.yml` rewrote `minimal→low`, `high→xhigh`, `max→xhigh` for frank-dragoon to dodge 400s the engine does not send — flash-server's own error names its allow-list and the harness passes an unmapped level through verbatim, so the fold only asked for a different thinking budget than the caller named. The map is identity now, and `reasoningDisableMode: none-effort` was added because the default disable mode does not disable: `:off` still sends `reasoning_effort: "minimal"` and pays for a canned thinking block. Contract owner: [pi/models.md](pi/models.md). Law: **a claim about what the harness sends is worth exactly its last capture** — settle it through a logging proxy, not by reading config. The same pass restored the three pre-callsign model ids the 2026-10-08 rename had overwritten inside its own explanatory comments. ### a documented mode the panel never had The home ultrawide ran at 60 Hz for weeks because `desk-1-home.kdl` asked for `3440x1440@239.999` and the panel advertises `@239.998`. One character: niri matches mode strings verbatim, does not round, and a mode it cannot find does not fail — it falls back to the EDID preferred mode, 60 Hz, on every connector drop. The page that owns the file documented the same phantom mode, so every reader trusted it. Laws, triage table and probes: [tools/niri/displays.md](tools/niri/displays.md). Durable: **a number in a page is a claim, not a measurement** — mode strings, refresh rates and tool availability were wrong on several pages at once (`wlr-randr` listed as installed while `pacman -Qs wlr` matches nothing). Read the hardware, then destroy the stale copies. A correction is itself a measurement: this entry's first pass published a second wrong hardware fact, with a `verified:` date stamped on it. ### a dedupe sweep, and scouts whose ledgers did not survive contact with the files Refs #64. Owners moved, not words. The ghostty and Gitea indexes stopped carrying second copies of the pages they route to — Gitea's index restated the container table, the boot-persistence law, the management commands, and the data layout while its own See Also list named the four pages that own them, and an index that restates an operational table becomes the second authority, which is the one that goes stale. The llama.cpp overview handed Docker and the `LLAMA_ARG_*` rule back to the setup page that had always promised them; the search finish rule has one owner again; fleet hardware and the SearXNG engine count were re-read from the boxes rather than re-derived, and the count is now stated as a size class because it moves weekly. Two laws no other page owns: - **A scout's ledger is a claim, not a finding.** The checkable-false share of the returned rows was large: three pages "missing an H1" that have one; a 215-line `omp-docs/AGENTS.md` that does not exist; a wikilink-and-wall defect in `core/settings.md` that a commit from that same morning had already removed; `core/subagent-limits.md` called superseded while `agent/config.yml` still carries `maxRecursionDepth: 1` and `maxRuntimeMs: 1800000` on the very lines the page cites. Nothing entered the diff until it was re-read against the file it accused. - **A ledger written to a file is not delivered.** One scout yielded against a zero-byte file; three more wrote their path with the tool-call parameter block embedded in the filename, so their ledgers exist under names no caller can ask for. Ask for the ledger as the yield text, then read it before repeating it. Fan-out, measured the hard way: seven audit subagents on one local endpoint produced nothing for seventeen minutes. `task.maxConcurrency` is 2, so five were queued while two thrashed, and `proc://` labels a queued task `running` — which is not the claim it sounds like. Cancelling five let the survivors land within minutes. One mechanical find worth keeping: a generated See Also block had left **five links with empty text** (`- ](index.md)`) across the gitea pages, `tools/cachyos.md`, and `tools/applications.md` — rendered, that is a bullet with nothing in it to click, so it reads as a style choice rather than a broken reference. `grep -rnE '(^|[ ,])\]\('` finds them in one pass. The day's three `## 2026-10-21` sections are now one section with four subsections, which is what the spec's one-dated-section-per-day rule always meant; [references/okf-maintenance.md](references/okf-maintenance.md) says so explicitly now. ## 2026-10-20 — one work log per bundle The bundle had two: this page and `core/log.md` — two entries of pure migration bookkeeping and a conversion date that neither this page nor git agreed with (2026-07-15 there, 2026-01-15 here, `git log` dates the OKF rebuild 2026-08-28); `core/index.md` still pointed readers at it, which is how a stale page stays alive. Trashed to `omp-docs/core/.AGENTTRASH/`. The rule lives in [references/okf-spec.md](references/okf-spec.md) and [references/okf-maintenance.md](references/okf-maintenance.md) and is gated by `scripts/kb-lint.sh`; the agent-side duty is `agent/APPEND_SYSTEM.md` § 1. ## 2026-10-20 — two instruments rescued from `$HOME` script sediment Refs #53. `$HOME` had accumulated 123 loose scripts (archived to `.AGENTTRASH/home-scripts-2026-10-20`; ~1.8 GiB of stray audio consolidated into `~/audiosamples`). Two were durable instruments and now live in the repo with black-box tests and pages: [tools/remote-job](tools/remote-job.md) — a readiness pattern in a log is not evidence of completion, the pattern can match a header printed before the work starts, and `sed -n /x/q` exits the moment it matches, tearing down the job it was watching — and [tools/pcie-probe](tools/pcie-probe.md) — never benchmark beside a live service, never let a tool decide to stop one, and an instrument that segfaults is not an instrument. ## 2026-10-20 — the secret gate was reading the wrong files, and one credential had already escaped Found while deciding what else belongs in `dotfiles/`. The gate whitelisted extensions, so `.env`, `.container`, `.ini` and extension-less dotfiles — the shapes the dotfiles tier is made of — were never read. It now scans the whole staged diff for token shapes and, in non-prose files, for credential assignments, and fails closed when `git diff` itself errors; the rewrite's first attempt passed an invalid flag to `git diff`, got an empty file list, and reported success on every commit — which is what a blind gate looks like, and it looks identical to a clean tree. Bcrypt hashes and Basic-auth headers joined the shape list (issue #40) because the audit found a live Caddy basicauth hash, its plaintext password, and the Pi-hole internal password in a tracked auto-learned memory file. **Redaction does not un-leak history that every machine has already pulled: both credentials needed rotation.** Auto-learned memory is written by a process that has read your terminal, so it is a leak surface and gets gated like any config. Also removed: tracked fiction invisible to `deploy.sh` (`home/dank/.omp/dotfiles/**`, `.pre-pull-backup/**`) and 23 wallpaper JPEGs (80 MiB) riding in every clone. Mechanism: `.githooks/pre-commit` and its tests; details in [dotfiles-deploy](tools/dotfiles-deploy.md) and [home-config-census](inventory/home-config-census.md). Law no other page owns: **`systemctl --user enable` snapshots an absolute path** — enabling from a worktree means the seven-day reap silently kills the unit while `is-enabled` goes on saying `enabled` (`blankpad-desk-autoswitch.service` was dangling that way). ## 2026-10-20 — engineering skills configured against this KB `setup-matt-pocock-skills` ran and its output moved out of the skill's default `docs/agents/` into the knowledge base: [issue tracker](skills/issue-tracker.md), [triage labels](skills/triage-labels.md), [domain docs](skills/domain-docs.md), and an empty [decisions](decisions/index.md) with its format rule. `AGENTS.md` gained the `## Agent skills` pointer block. Law: this repo has one knowledge base, so per-tool configuration is a concept page in `omp-docs/` — a second `docs/` tree means a second set of index rules, which is where documentation starts disagreeing with itself. Known cost: re-running that setup skill will not recognise `omp-docs/skills/*` and will offer to recreate `docs/agents/`; the `AGENTS.md` pointer is what stops it. ## 2026-10-19 — dankvoice auto-speak armed at startup Nothing spoke because the settings file carried no `auto` key (arming is session-scoped by design) and narration rode only `agent_end`, a settle that a scheduled continuation skips; fixed upstream in dank/dankvoice#3. Law: silence at session start is a config state — read `/say status`, then watch `pgrep -a pw-play` for one player per segment — before blaming the endpoint. Law: whether the harness delivers an event to extensions is settled in minutes by a throwaway probe extension that timestamps `turn_end`/`agent_end`, never inferred from audio timing. Details: [core/dankvoice.md](core/dankvoice.md). ## 2026-10-19 — LazyVim installed as an NVIM_APPNAME profile `lazyvim` had never been installed here: shell history shows the command typed twice and dropped, and `~/.config/nvim` held only an orphaned `matugen.lua` palette nothing loaded. Now the starter lives in `dotfiles/lazyvim/` symlinked to `~/.config/lazyvim`, a `lazyvim` zsh function reaches it, and the wallpaper palette applies through `RRethy/base16-nvim` on `ColorScheme`. Law: the distribution stays out of `~/.config/nvim` so bare `nvim` keeps working as a vanilla quick-edit editor. Details: [tools/neovim.md](tools/neovim.md). ## 2026-10-19 — dankvoice cut over to the `dank/dankvoice` package (Refs #34) Drop-in `agent/extensions/dankvoice.ts` and its 26-test suite retired; the package carries the behaviour (41/41 black-box suite) and installs with `pi install git:`. Law: install and prove `/say status` speaks on a box *before* pulling the cutover commit — the shared settings file keeps menu state across both transports, so the swap is stateless once installed. ## 2026-10-19 — dankvoice: silence and timeouts, root-caused (Refs #32) The humanizer's raw `fetch` omitted `chat_template_kwargs.enable_thinking: false`, so the Qwen35 hybrid *thought* instead of answering: 6.9 s of `reasoning_content`, `content: ""` — dead air twice, and when it answered inside the window it spoke silence. Root-caused by replaying the exact wire body against the live endpoint. Fix: pin the kwarg, treat empty-content-with-reasoning as failure, fire the menu's test phrase without blocking its handler. Lesson: the harness injects thinking-off for managed roles; raw HTTP callers must set it themselves. [core/dankvoice.md](core/dankvoice.md). ## 2026-10-19 — dankvoice: humanized narration, segmented speech, `/say` menu (Refs #27, #23, #21) Spoken units are rewritten by the `@tiny` role under the bundle's speech budgets with mechanical cleanup as fallback; the utterance-splitting state machine synthesizes segments strictly sequentially because `agent_end` awaiting one whole-answer synthesis hit the harness's 30 s extension-handler timeout — **extensions must never await work that can exceed 30 s**. `/say menu` routes output device (`wpctl` → `pw-play --target`) with precedence env > settings file > defaults, born from PipeWire's remembered Bluetooth route playing answers into nowhere. The extension exists at all because the harness gates `--voice` against the bundled Kokoro enum, so frank-tts's cloned voices were unreachable in-TUI. [core/dankvoice.md](core/dankvoice.md). ## 2026-10-18 — Noctalia bar layout clobbered by trunk-sync stash, recovered GUI-built bar customizations existed only in the working tree; a trunk-sync stash-then-drop destroyed them. Recovery: `git fsck --lost-found` surfaced the dropped stash as a dangling commit, validated in a sandboxed `XDG_*_HOME` before restore. Lesson: GUI-written config is durable only once committed — the motivation for the heartbeat below. [tools/dotfiles-deploy.md](tools/dotfiles-deploy.md). ## 2026-10-18 — live-sync heartbeat for machine-written paths (Refs #11) A month of silent divergence in the live checkout proved the checkout-is-deployment model needs a committer: `scripts/live-sync.sh` + a systemd user timer auto-commits the allowlisted tiers with hooks armed, merges `origin/main`, pushes, and reaps stale `wt/*`. Non-allowlist dirt is never staged; conflicts abort and alert. [tools/live-sync.md](tools/live-sync.md); tier law in `AGENTS.md`. Same day, two fleet laws into both repos' `AGENTS.md`: every agent-opened issue or PR body ends with a `cwd:` + `session:` footer, so machine-made artifacts trace to the box that spawned them; and `xdg-open ` the moment a PR opens, so Frank never hunts for it in Gitea. ## 2026-10-18 — SDLC switched to trunk-based development; extension route closed unmerged `develop` retired (single-dev repo): branch off freshest `origin/main`, PRs target `main`, `--no-ff` merges, tags `vX.Y.Z` on main — law in `AGENTS.md` § Trunk-based SDLC, managed skill `gitflow-back-merge-plumbing` marked historical. The operator also closed PR #9 (cwd-scoped `before_agent_start` extension) in favour of editing each repo's `AGENTS.md`. Durable finding: every context-file provider (AGENTS.md walk-up, `.omp/` dirs, CLAUDE.md) resolves at or below the repo root, so ancestor-scope files can never load; user-level `APPEND_SYSTEM.md` broadcasts to all sessions. ## 2026-10-18 — Sibling-vault overlap census; system docs realigned to live ground truth Census of `omp-docs/` vs `serverAppConfigs-docs` (subagents + live-ssh probes) found four contradicting pairs; ours fixed, theirs flagged for their PR flow. Recorded then: the RTX 3090 moved Dankserver→Dankclaw 2026-09; dankserver is 2× Radeon AI PRO R9700 (the "board swap" story was false); served models per live units. Current state always: [/system/index.md](/system/index.md). ## 2026-10-18 — Status line rebuilt on custom segments; full-source audit [core/statusline.md](core/statusline.md) carries the audit log — four first-pass claims were false and corrected against the minified bundle plus a live screenshot matrix (context meter is `box`/`band` only; `composer.shape` routes segment arrays; `mode` states = Plan/Prewalk/Goal/Vibe/Loop). Bar rebuilt on `band` + custom segments. ## 2026-10-09 — Blankpad DE redesign: desk profiles, keybinds, Handy wiring Per-desk niri profiles keyed by EDID long name (connector names reshuffle between docks; identity travels) + `scripts/desk.sh`. niri 26.04 has **no hotplug event** (`OutputConfigChanged` is only an ACK per niri-ipc), so the autoswitch daemon diffs output sets on `WorkspacesChanged`. Keybind cheat sheet generated by `scripts/gen-keybinds.sh`; noctalia docs corrected to the v5 `noctalia msg` API. Handy: niri owns autostart; open breaker — frank-secondary answers in `reasoning_content` with empty `content`, and Handy cannot send `chat_template_kwargs.enable_thinking=false`. [tools/niri/displays.md](tools/niri/displays.md), [tools/handy.md](tools/handy.md). ## 2026-10-09 — Incident: agent sudo-loop tripped pam_faillock, locked out the operator A subagent retried `sudo yay` (no TTY) for ~15 min; `pam_faillock` deny=3 locked user `blank`, and correct-password sudo then failed, mimicking a password change. Recovery: `faillock --user blank --reset`. Law: agents never run `sudo`/`yay`/`pacman`/`pkexec`; root steps go to the operator as exact commands. Skill `faillock-sudo-lockout-recovery`. ## 2026-10-09 — Full secret audit of the command-center repo: clean Five layers (live-value scan across 77 revs/765 blobs, whole object store including dangling, shape triage, entropy ≥4.3, LFS payloads) found no secret in any reachable or dangling object; the quarantine list holds. Fixed `hf_token_write` 0644→0600. Open gap: the gate lacks `hf_`/`npm_`/`pypi-`/`AIza`/Stripe/Telegram shapes and basic-auth URLs — widening it is an open decision. ## 2026-10-09 — Gitea token moved out of every remote URL Remotes bare; credential in `~/.config/secrets/gitea` (0600) behind a global `credential.helper store`. Trap (git 2.56.0, measured): `git credential-store` rejects the `protocol=`/`host=` block shape the man page shows — the store file must be one URL per line, port included. Verified with `GIT_TERMINAL_PROMPT=0`. [tools/gitea/client-access.md](tools/gitea/client-access.md). ## 2026-10-09 — Working tree reconciled: callsign renames, compaction move, gitignore quarantine 200-entry dirty tree committed as seven atomic units. Harness model ids renamed `frank-{medium,large,small}` → `frank-{archon,dragoon,zealot}` — **services keep old names on the wire**; the engines accept any request model id, so renames are harness-side only. Server-side compaction moved to zealot (threshold 70→85 %). `.gitignore` quarantine for worktree-keyed memory buckets and runtime dirs. Skill renames are not losses: git renders directory renames as mass delete+add; pre-cutover content intact at `12c5e88`. ## 2026-09-28 — Retired workstation purged from the knowledge base Sold box: hostname, both LAN addresses, Wi-Fi SSID gone bundle-wide; the knowledge distilled into [system/network.md](system/network.md) (multi-link resolver law: a static resolver must be pinned on each *connection*) and [tools/niri/displays.md](tools/niri/displays.md) (portrait transforms, the three ways a multi-monitor rig breaks). Hostname stays only where it is a lookup key (install.sh `--host`, `packages/.pkgs`). ## 2026-09-01 — Retry backoff and thinking default (pi era) Pi `settings.json`: 10 s base retry backoff (10/20/40 s), `defaultThinkingLevel: medium` (no per-model thinking field exists in `models.json`). ## 2026-08-28 — KB rebuilt to OKF v0.1; live-verified fleet facts `omp-docs/` copied from legacy `~/.pi/agent/docs`, rebuilt as git-tracked OKF v0.1 (checkout *is* the deployment); unverifiable claims tagged `unverified`. Conformance pass promoted concept-in-disguise indexes, stripped index frontmatter, resolved all links; `scripts/kb-lint.sh` exits 0. Hardware facts were corrected *then* (3090-on-dankserver since moved — see 2026-10-18). Inventory census recorded under `inventory/` for the pruning session. ## 2026-08-23 — Homepage deployed to production; Caddy KB doc Homepage live on Dankclaw via `scripts/deploy.sh` (status checker timer, `deployed.js`, rendered basicauth hashes, health check). Hard-won Caddy law, now on [caddy/caddyfile.md](caddy/caddyfile.md): top-level directives are *sorted*, so `rewrite` runs before `basicauth` and auth matchers saw rewritten paths — serve each page from its own `handle` block; a `handle` inline matcher is a single token; a leading `@name ` parses as a matcher definition. A compose mount change needs a container *recreate*, not a reload. ## 2026-08-23 — Homepage design settled (grilling complete) All 38 open questions answered; full record lives in serverAppConfigs (`docs/Infrastructure/Homepage Design Grilling.md`). Key deltas: per-service tcp/http probes, 5 s timeout, TUI-style panel grid, no client auto-refresh, git-driven deploy, full TDD. Correction recorded: the Dankserver media stack runs as bare processes, not containers — never probe it as a compose stack. ## 2026-08-22 — vllmScripts merged into serverAppConfigs Full-history two-parent import; one repo, one checkout per host, one `deploy.sh`. The plaintext sudo password from old docs was NOT carried over (a bats leak-check guards it); it remains in both repos' history on the LAN Gitea — rotation recommended. ## 2026-08-21 — Fleet ops: passwordless sudo, Hermes SSH keys `/etc/sudoers.d/dank-nopasswd` on both servers (per-command drop-ins remain); dedicated ed25519 key for the Hermes container, verified into all three machines. ## 2026-08-19 — SearXNG + Gluetun bring-up; pi endpoint re-pointed `searxngBaseUrl` moved off the dead `.235:8081` to `.143:8081`; pi caches `web-search.json` per process, so a new endpoint needs a new session. Durable field notes now on concept pages — [agentic-web-research/vpn-routing.md](agentic-web-research/vpn-routing.md), [searxng-tuning.md](agentic-web-research/searxng-tuning.md), [engineering/infra/containers.md](engineering/infra/containers.md): manual-WireGuard Proton needs `VPN_SERVICE_PROVIDER=custom` + the single-peer `WIREGUARD_*` env names (not `protonvpn`, not `WIREGUARD_PEERS_*`); gluetun ships no curl and `:8000` is the control server, not health; the limiter's JSON cap is hardcoded Python and `pass_ip` is the only bypass; rootless podman strips client IPs on published ports, so SearXNG must sit behind Caddy for XFF; the quadlet generator rejects `CapAdd=`/`Device=` and generated units enable via `[Install] WantedBy=default.target`. ComfyUI on gfx1151: build on AMD's ROCm base and filter the torch family out of ComfyUI's requirements or you clobber the gfx1151 kernels. ## 2026-08-17 — Fleet redo + vLLM tool calling (pi era) Fleet moved off the pipeline-parallel + NPU topology; Quark W8A8 quant chosen over the Avesed INT8 for clean Qwen3 XML tool calls. ## 2026-08-16 — Gitea boot-persistence fix (dankclaw) `unattended-upgrades` reboot exposed that the compose-era Gitea had no systemd units (~1 h down). Stack rewritten as quadlet (names, `systemd-gitea` network, linger + `WantedBy=default.target`, app.ini env-override gotcha, UID 100999 ownership) across `tools/gitea/*`; `podman generate systemd` marked deprecated in [engineering/infra/containers.md](engineering/infra/containers.md). ## 2026-08-13 — Pi subagent limits recorded (pi era) Effective caps: `globalConcurrencyLimit` 2, `parallel.maxTasks` 8 / concurrency 4, `maxSubagentDepth` 2, `turnBudget` 30; no per-model limit. [pi/packages/pi-subagents.md](pi/packages/pi-subagents.md). ## 2026-08-11 — Engineering research area; agentic web research section Created `engineering/` (SDLC, agent instruction files, stacks, infra, plugins, skills ecosystem, Signal remote) and `agentic-web-research/` (8 pages), the latter rewritten on 2025/2026 evidence (SearXNG valkey deployment, real engine defaults, limiter budgets, Gluetun pattern, open-model claim triage, MCP transports). Skills leaderboard replaced with the ranked list from the skills.sh API (zero-based pagination, 200-skill pages). Same pass: 154+ wikilinks resolved, dead external links fixed, `MemorySleepMode=deep` verified valid (systemd 256+), ASD-STE100 style pass, `AGENTS.md` created as the system behavior contract. ## 2026-08-06 — Link fixes; ComfyUI docs; major documentation overhaul Fixed 15 broken wikilinks (missing frontmatter) + title mismatches → zero broken. Added ComfyUI pages, per-host system docs, pi config tree, tools entries; orphaned root duplicates moved to `.AGENTTRASH/`. ## 2026-07-18 — Maintenance tooling Expanded `references/okf-maintenance.md` (cross-links, health metrics, troubleshooting); created `core/log.md` (retired 2026-10-20, above) and `.okf/config.yaml`. ## 2026-01-15 — OKF conversion Docs bundle converted to OKF v0.1; files migrated into `core/`, `tools/`, `packages/`, `references/` with frontmatter on all files. ## 2025-08-05 — Gitea documentation Added [tools/gitea/index.md](tools/gitea/index.md) (topology, management, data persistence) to the tools index — legacy tree, predating the OKF conversion above.