diff --git a/agent/config.yml b/agent/config.yml index 18d197c..1672be0 100644 --- a/agent/config.yml +++ b/agent/config.yml @@ -158,6 +158,7 @@ task: security-reviewer: llamacpp (dankclaw)/frank-dragoon sonic: llamacpp (dankclaw-3090)/frank-zealot task: llamacpp (dankserver)/frank-archon + seance: llamacpp (dankclaw-3090)/frank-zealot eager: default enableLsp: true maxRuntimeMs: 1800000 diff --git a/agent/managed-skills/docs-refresh-scout-summaries/SKILL.md b/agent/managed-skills/docs-refresh-scout-summaries/SKILL.md new file mode 100644 index 0000000..670cbf1 --- /dev/null +++ b/agent/managed-skills/docs-refresh-scout-summaries/SKILL.md @@ -0,0 +1,85 @@ +--- +name: docs-refresh-scout-summaries +description: "Refresh a stale documentation cluster without delegating the writing: scout subagents produce per-line verdict tables (holder verified by comma-insensitive grep), the parent makes every edit, and a port-before-cut census proves nothing was lost. Use for dedupe-our-docs, fix-the-stale-runbooks, pointers-instead-of-copied-numbers jobs." +--- + +# Refresh stale docs with scout summaries, parent-side writes + +Use when a cluster of documentation pages is stale and/or restates facts another page owns, and +the fix touches many files. **Scouts read and classify; the parent writes.** Sibling skill +`vault-one-fact-one-owner-dedupe` covers collapsing era pages into owner pages - its section 3 +(orphan census), section 7 (edit-tool hazard) and section 9 (verify/PR) apply unchanged. + +## Why not writer subagents (measured cost) + +Writer agents produce plausible output and cannot be trusted on the one claim that matters - the +owner page already holds this fact. In one run they asserted every cut was grep-confirmed while +FOUR cuts left pointers to pages that did not contain the fact (118->238 GiB, 16,095 tokens, +0.739/0.554/0.427/0.340, PR #23897). Each became a broken promise the next reader trusts. +Classification is the only part that parallelizes; writing is where taste (ownership, era +naming, what counts as a law) lives. So fan out read-only scouts and keep the pen. + +If writer agents were already spawned and are no longer wanted: `write agent://all` to stop +them, then `git status` the target tree - `proc://` does not list agent jobs, and a finished +worker may already have edited files. + +## Pipeline + +1. **Cluster** targets into groups of 3-4 pages sharing subject matter (one cluster per scout). + Know the owner map first (endpoint/service/host pages, plus the repo documentation law). +2. **Wave of 2 scouts** (harness cap is `task.maxConcurrency`, usually 2). Scout contract: + + > READ-ONLY, no writes of any kind. Per file, one table row per candidate fact: + > `| lines | verbatim figure + 6 words | holder elsewhere (file:line) or none | VERDICT |` + > Verdicts: `CUT -> [[Owner]]` (holder verified), `KEEP(owned here)` (no holder, this page is + > the record), `PORT(parent)` (rightful owner lacks it - name page and section), `STALE` + > (contradicted by current state; quote the contradicting line), `INDEX` (locator page). + > Verify every holder claim with a COMMA-INSENSITIVE grep: a holder writing 1,350,182 + > satisfies a page writing 1350182 and vice versa; 16,095 does NOT satisfy a check for 16095 + > unless commas are stripped. Never name a holder line you have not read. + > End with a per-file tally: kept / cut / port / stale. + + Put the law, the owner map and the verification rule in the batch-level `context`, never per + task. +3. **Write while the next wave runs**: edit cluster N from wave N, launch wave N+1 in the same + turn. Never launch a wave you have nothing to write. +4. **Verify each CUT yourself** before cutting - read the holder line. A scout row is a + hypothesis, not evidence. +5. **PORT items are your edits**: add the fact to the owner page section (Eras row / Laws / spec + table), then cut it from the technique page in the same commit. +6. **STALE items: check live state**, not another document - `ssh systemctl is-active + `, the endpoint `/health`, the env file. Then rewrite with a date, or drop transient + live state an owner page already records. + +## The ownership test that stops wasted ports + +Two pages carrying one figure is the defect - a figure with exactly one holder is fine wherever +it lives. A technique page that is the sole record of a campaign owns that campaign's arm +tables; do not port such ledgers into an endpoint Eras table. Write the clause into the repo +documentation law so the next pass stops porting single-owner facts. Corollary: a worked example +may repeat a live number if it declares itself dated and names the owner (a snapshot, not fleet +state - recompute from the live files). + +## Census after each cluster (catches your own slips too) + +Run the sibling skill's section 3 census over `git diff -U0` for the cluster (deleted lines x +distinctive numeric keys vs the whole vault **plus AGENTS.md**), comma-insensitively; drive the +count to zero or list each accepted loss in the commit message. + +```python +flat = corpus.replace(',', '') +pres = lambda n: n in corpus or n.replace(',', '') in flat +toks = lambda l: [n for n in re.findall(r'\d[\d,]*(?:\.\d+)?', l) + if len(n.replace(',', '').split('.')[0]) >= 4 + or (len(n.split('.')[-1]) >= 2 and len(n.replace(',', '')) >= 5)] +orphan = [l for l in deleted if toks(l) and not any(pres(n) for n in toks(l))] +``` + +## Verify and land + +- Vault link seam must print `0 unresolved links`; hard-wrapped `[[Two Word Page]]` links split + across lines are the usual cause - unwrap them. +- Full suite once at the end, not per cluster; a docs seam running while scouts are live may + read half-written files, so re-run after the last edit. +- Commit per cluster (docs-only means **no deploy**); push, open the PR through the API with a + 600-perm curl config, `xdg-open` the PR URL immediately. diff --git a/agent/managed-skills/omp-bundle-implementation-port/SKILL.md b/agent/managed-skills/omp-bundle-implementation-port/SKILL.md new file mode 100644 index 0000000..6c1cc12 --- /dev/null +++ b/agent/managed-skills/omp-bundle-implementation-port/SKILL.md @@ -0,0 +1,38 @@ +--- +name: omp-bundle-implementation-port +description: "Extract and port a working implementation from omp's minified dist/cli.js bundle (copy-not-invent requests); anchors, python slicing, regex-constant sweep, trace-driven test prediction." +--- + +# Porting built-in omp behavior out of the minified bundle + +Use when Frank says "copy the omp implementation / work off known-working code" — i.e. port a built-in feature (vocalizer segmentation, retry logic, formatting rules) into our own file instead of hand-rolling a heuristic. For merely *auditing behavior claims*, use `omp-bundle-claim-audit`; this skill is extraction-for-porting. + +Bundle: `~/.bun/install/global/node_modules/@oh-my-pi/pi-coding-agent/dist/cli.js` (minified; single-letter names, private `#x` fields survive). + +## Extraction recipe + +1. **Find the setting/entry strings first.** `grep -o 'ce({id:"[^"]*"[^}]\{0,200\}' cli.js` — setting descriptions state semantics verbatim (e.g. `speech.enhanced` = "Rewrite assistant output into natural spoken prose with the tiny/smol model"). Descriptions are quotable ground truth. +2. **Anchor to code with a distinctive token**, not guesses: a method name (`pushDelta`), a state init, or a string. Then slice generously with python (bash heredoc), NOT grep -o which truncates: + ```python + src = open('cli.js').read() + i = src.index('pushDelta'); print(src[i-1500:i+3000]) + ``` +3. **Follow the constructor**: pipeline classes instantiate collaborators there (`this.#t ??= new fHe` → `fHe` is the real worker; `#g()` returned `{speakable:new fHe, pending:[]…}`). Dump `class fHe{` +4000 chars. +4. **Regex/helper sweep**: minified code declares shared constants in a trailing `var a,b,c,…` list and initializes them elsewhere (`Xyr=`, `Pwc=function`). Loop the names with `re.search(rf'{name}=', src)` and print ~400 chars each — the actual boundary/cleanup rules live in these one-liners. +5. Write slices to `/tmp/*.txt` and `read` them; don't eyeball megabyte greps. + +## Port rules + +- Rename fields/methods to readable names but keep logic **1:1** — the value is behavioral fidelity (Frank's "known-working set of code"). +- Private `#x` fields port cleanly: TS classes in Bun extensions support `#`. +- Global-regex `.lastIndex=0` before each scan loop — minified code relies on it; keep it. + +## Verification shortcut + +Before running tests, **hand-trace** each test input through the ported rules (boundary indices, state transitions) and predict exact segment counts/strings; then run — predicted-vs-actual mismatch localizes port errors faster than test output alone. Worked example (2026-10-19, dankvoice PR #26): traced `"First stop here. Second one goes!!! Really? Third ... done"` → predicted 3 segments incl. `"Third ... done"` merged via flush (10-char boundary < 24-char started-min) → bats green first run. + +## Known anchors (2026-10-19 bundle) + +- Speak-aloud vocalizer pipeline: class `I6o` (gating on `speech.enabled`, suspend counter, enhancer, `#g()` per-message state). +- Utterance segmenter: class `fHe` + helpers `Pwc` (line-head classify), `Iwc`/`_wc`/`b6o`/`w6o` (boundary search), `Cwc`+`y6o` (cleanup: links→label, URL→host, path→basename). Regex consts: `Xyr` sentence-end runs, `pHe` weak breaks, `mwc` abbreviations, `hwc` undecided line-heads, `g6o` horizontal rules. +- Port already living in `agent/extensions/dankvoice.ts` (`SpeechSegmenter`) — when the bundle updates, re-extract `fHe` and diff against it before assuming our copy still matches. diff --git a/agent/managed-skills/vault-one-fact-one-owner-dedupe/SKILL.md b/agent/managed-skills/vault-one-fact-one-owner-dedupe/SKILL.md new file mode 100644 index 0000000..27b1217 --- /dev/null +++ b/agent/managed-skills/vault-one-fact-one-owner-dedupe/SKILL.md @@ -0,0 +1,115 @@ +--- +name: vault-one-fact-one-owner-dedupe +description: "Collapse per-payload/per-attempt vault pages into one owner page per endpoint without losing a fact: port-before-cut orphan census, index regeneration, the one-page seam, and the merge-resolution order." +--- + +# One fact, one owner: dedupe the vault without losing a fact + +Use when a repo has accumulated one page per attempt/era (runbooks, bench logs, swap +narratives) and the law is **one page owns one thing**. Applies to +`serverAppConfigs-docs/` (Obsidian vault, `AGENTS.md` → *Documentation Policy*), but the +mechanics are general. + +## 1. Decide ownership before touching files + +- Endpoint/service page owns: current shape, **Eras** table (window | payload | runtime | + shape | replaced because | rollback), **Laws**, wire contract, files. +- Technique page owns the mechanism and the arithmetic — **no per-endpoint throughput + table or boot ledger**. +- `log.md` owns incidents and laws only. A swap is an Eras row, never a log entry. +- `AGENTS.md` carries operator-critical numbers + cross-border laws; everything else links. + +## 2. Single-writer rule (the mistake that costs the most) + +Facts get **ported into the owner page before they are cut** anywhere else. So while any +subagent may port facts, only ONE writer may touch the owner pages. Spawn children with an +explicit `DO NOT EDIT ` and require a `needsPort` list in their report instead +of letting them append. Send the narrowing message early — a child already editing them has +to be reconciled by hand. + +## 3. Port-before-cut census (proves nothing was lost) + +For every deleted line, extract distinctive keys (integers ≥ 4 digits with commas stripped, +decimals with ≥ 2 fraction digits) and check them against the whole vault minus the file +being rewritten. Any line with **no** surviving key is an orphan → port, or accept +deliberately and say so. + +```python +num = re.compile(r'\d[\d,]*(?:\.\d+)?') +def keys(line): + out = set() + for n in num.findall(line): + i = n.split('.')[0].replace(',', '') + if len(i) >= 4: out.add(i) + if '.' in n and len(n.split('.')[1]) >= 2: out.add(n.replace(',', '')[:6]) + return out +# orphan = deleted line whose keys are absent from corpus(vault minus target file, minus .AGENTTRASH) +``` + +Expect ~30 orphans per 1,000 deleted lines, of which ~40 % are process trivia recoverable +from git (PR/commit hashes, per-boot log lines). Port the measurement/law ones to the owner +page's Laws/Eras, and list the accepted losses in the commit message and PR body. Also grep +`AGENTS.md` separately — a fact it carries is not an orphan. + +## 4. Deletion mechanics + +- Trash is **gitignored** (`.gitignore` has `.AGENTTRASH/`). Move with plain `mv` into the + repo-root dated dir, e.g. `.AGENTTRASH/-topic/LLM/`. `git mv` a tracked page into + it stages a rename *into an ignored path* (index entry the next agent cannot see); undo with + `git restore --staged ` and let the deletion be the change. +- Never `rm`, never `git clean -f`. + +## 5. Rewire + indexes mechanically + +```bash +grep -rnoE "\[\[(page-a|page-b|...)\]\]" --include="*.md" serverAppConfigs-docs | grep -v AGENTTRASH +grep -rnoE "\((page-a|page-b|...)\.md\)" --include="*.md" serverAppConfigs-docs | grep -v AGENTTRASH +``` +Both wikilinks and markdown path refs must be repointed (Research `See Also` lists and +`ubatch`-style bench pages are where path refs hide). Then **regenerate** index pages with a +script that walks the vault (`os.walk`, skip `.obsidian`/`.AGENTTRASH`, one row = `[[basename]]` ++ first-sentence description stripped of markdown links) rather than hand-editing rows — the +`docs index links every docs page` seam fails on any row left behind. + +## 6. Enforce the law with a seam + +`tests/docs_completeness.bats`: derive the live set instead of hardcoding it — an endpoint is +live when `scripts/` holds **both** `.env` and `.service`; fail if any +`-*.md` page exists in the vault, and guard against a vacuous derivation +(`derived -ge 3`). A re-created era page then cannot pass tests. + +## 7. Edit-tool hazard (costs the most time) + +Body rows beginning with `-` or `+` are op markers. The documented `+-` escape **writes a +literal `+`** — do not use it. Safe rewrites inside an existing bullet: keep the `- ` opener +line untouched and PUT only the indented continuation lines, or convert the note to a nested +bullet whose body lines start with two/four spaces. If a wrapped `[[Two Word Page]]` shows up +as an unresolved link, the target was hard-wrapped across lines — unwrap it. + +## 8. Merge order (a long-lived branch under a moving main) + +1. Commit your work in atomic groups **before** merging (a dirty tree cannot merge cleanly). +2. Inspect the incoming commits first: `git log --oneline --stat HEAD..origin/main`. If they + modify a page you deleted, **port their additions into the owner page**, then merge and + resolve the modify/delete as `git rm`. +3. Resolve a content block with `write conflict://` (`@ours` / `@theirs` / explicit text), + then **`git add` the file** — resolving content does not stage it, and `git commit` refuses + with "you have unmerged files". +4. `git * --no-verify` is forbidden here; commit hooks are fine. +5. Sweep for dead paths left in `AGENTS.md`: `grep -oE "[A-Za-z0-9._-]+\.md" AGENTS.md | sort -u` + then `find` each. Expect false positives from names hard-wrapped across two lines — confirm + each with `ls` before "fixing". + +## 9. Verify, open, land + +- `./tests/run.sh` (full suite) + `bats tests/docs_completeness.bats` + + `python3 scripts/check-vault-links.py serverAppConfigs-docs` → must print `0 unresolved links`. +- Env trims: prove value-neutrality mechanically — `git show HEAD:scripts/.env | grep -E + '^[A-Z_]+=' | sort` vs the working copy, diff must be empty, then run that service's seam. + **Warn that `scripts/.env` is a deploy-planner path**: a comment-only trim makes the + next service-scoped deploy restart a healthy endpoint for identical values. +- Open the PR through the API with a 600-perm curl config (managed skill + `gitea-api-pr-operations`), end the body with the `cwd:` / `session:` footer, then + `xdg-open ` the instant it exists. +- Docs-only change ⇒ **no deploy**. Fast-forward the deploy checkout only + (`git -C ~/Projects/serverAppConfig merge --ff-only origin/main`). diff --git a/agent/memories/sharpshooter/omp-32c11n2wnglul/state.json b/agent/memories/sharpshooter/omp-32c11n2wnglul/state.json index 456d9ef..3fe57b4 100644 --- a/agent/memories/sharpshooter/omp-32c11n2wnglul/state.json +++ b/agent/memories/sharpshooter/omp-32c11n2wnglul/state.json @@ -1,6 +1,6 @@ { "v": 1, - "lastConsolidatedAt": 1792395788647, + "lastConsolidatedAt": 1792398332410, "lastResult": { "at": 1791599865775, "sessions": 1, diff --git a/agent/memories/sharpshooter/tmp-1tpw73408x3e/state.json b/agent/memories/sharpshooter/tmp-1tpw73408x3e/state.json index 74e85f2..0f98aa3 100644 --- a/agent/memories/sharpshooter/tmp-1tpw73408x3e/state.json +++ b/agent/memories/sharpshooter/tmp-1tpw73408x3e/state.json @@ -1,4 +1,4 @@ { "v": 1, - "lastConsolidatedAt": 1792396789735 + "lastConsolidatedAt": 1792398289746 } diff --git a/agent/memories/sharpshooter/wt-20261017-181502-6d1fc1f-1oq2osmoyw03k/state.json b/agent/memories/sharpshooter/wt-20261017-181502-6d1fc1f-1oq2osmoyw03k/state.json index be72ca6..d08cf5c 100644 --- a/agent/memories/sharpshooter/wt-20261017-181502-6d1fc1f-1oq2osmoyw03k/state.json +++ b/agent/memories/sharpshooter/wt-20261017-181502-6d1fc1f-1oq2osmoyw03k/state.json @@ -1,6 +1,6 @@ { "v": 1, - "lastConsolidatedAt": 1792396748497, + "lastConsolidatedAt": 1792400553633, "lastResult": { "at": 1792393886960, "sessions": 1, diff --git a/agent/memories/sharpshooter/wt-20261018-204442-7c8a99d-2u1dm4kttza8t/state.json b/agent/memories/sharpshooter/wt-20261018-204442-7c8a99d-2u1dm4kttza8t/state.json index f105a43..afb5976 100644 --- a/agent/memories/sharpshooter/wt-20261018-204442-7c8a99d-2u1dm4kttza8t/state.json +++ b/agent/memories/sharpshooter/wt-20261018-204442-7c8a99d-2u1dm4kttza8t/state.json @@ -1,8 +1,8 @@ { "v": 1, - "lastConsolidatedAt": 1792396722373, + "lastConsolidatedAt": 1792400453482, "lastResult": { - "at": 1792396071933, + "at": 1792398531282, "sessions": 1, "deltas": 1, "model": "frank-zealot" diff --git a/agent/memories/sharpshooter/wt-20261019-004309-7c8a99d-u0xusjwyvzai/queue/01a1531d-3e48-70b0-8ee0-6d48a197cae3/00mvez49uq-zxrj.json b/agent/memories/sharpshooter/wt-20261019-004309-7c8a99d-u0xusjwyvzai/queue/01a1531d-3e48-70b0-8ee0-6d48a197cae3/00mvez49uq-zxrj.json new file mode 100644 index 0000000..7de4ada --- /dev/null +++ b/agent/memories/sharpshooter/wt-20261019-004309-7c8a99d-u0xusjwyvzai/queue/01a1531d-3e48-70b0-8ee0-6d48a197cae3/00mvez49uq-zxrj.json @@ -0,0 +1 @@ +{"v":1,"kind":"product_decision","statement":"Documentation links to @~/Projects/serverAppConfig/serverAppConfigs-docs/","source":"explicit_user","evidence":"correct our documentation to just link to @~/Projects/serverAppConfig/serverAppConfigs-docs/","friction":{"corrective":false,"regression":false,"subtle":false},"sessionId":"01a1531d-3e48-70b0-8ee0-6d48a197cae3","ts":1792397374946} \ No newline at end of file diff --git a/agent/memories/sharpshooter/wt-20261019-004309-7c8a99d-u0xusjwyvzai/state.json b/agent/memories/sharpshooter/wt-20261019-004309-7c8a99d-u0xusjwyvzai/state.json index b684715..c041cb2 100644 --- a/agent/memories/sharpshooter/wt-20261019-004309-7c8a99d-u0xusjwyvzai/state.json +++ b/agent/memories/sharpshooter/wt-20261019-004309-7c8a99d-u0xusjwyvzai/state.json @@ -1,4 +1,4 @@ { "v": 1, - "lastConsolidatedAt": 1792396749853 + "lastConsolidatedAt": 1792397349857 } diff --git a/agent/memories/sharpshooter/wt-20261019-011132-7c8a99d-y69mcckuzbqu/state.json b/agent/memories/sharpshooter/wt-20261019-011132-7c8a99d-y69mcckuzbqu/state.json new file mode 100644 index 0000000..9487df4 --- /dev/null +++ b/agent/memories/sharpshooter/wt-20261019-011132-7c8a99d-y69mcckuzbqu/state.json @@ -0,0 +1,4 @@ +{ + "v": 1, + "lastConsolidatedAt": 1792400552453 +} diff --git a/agent/memories/sharpshooter/wt-20261019-012533-7c8a99d-4b82ueogvlsj/state.json b/agent/memories/sharpshooter/wt-20261019-012533-7c8a99d-4b82ueogvlsj/state.json new file mode 100644 index 0000000..a358750 --- /dev/null +++ b/agent/memories/sharpshooter/wt-20261019-012533-7c8a99d-4b82ueogvlsj/state.json @@ -0,0 +1,4 @@ +{ + "v": 1, + "lastConsolidatedAt": 1792398333838 +} diff --git a/dotfiles/noctalia/.local/state/noctalia/settings.toml b/dotfiles/noctalia/.local/state/noctalia/settings.toml index b93317f..1b0be25 100644 --- a/dotfiles/noctalia/.local/state/noctalia/settings.toml +++ b/dotfiles/noctalia/.local/state/noctalia/settings.toml @@ -275,13 +275,13 @@ transition = [ "fade" ] interval_seconds = 1200 [wallpaper.default] - path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg" + path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_g7r3vd.jpg" [wallpaper.last] - path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg" + path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_g7r3vd.jpg" [wallpaper.monitors.DP-1] - path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg" + path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_g7r3vd.jpg" [wallpaper.monitors.DP-2] path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_oxex69.jpg" @@ -290,7 +290,7 @@ transition = [ "fade" ] path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_v9e2w3.jpg" [wallpaper.monitors.eDP-1] - path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg" + path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_g7r3vd.jpg" [weather] unit = "imperial"