diff --git a/infrastructure/tailscale.md b/infrastructure/tailscale.md index 1b3ad56..491fd93 100644 --- a/infrastructure/tailscale.md +++ b/infrastructure/tailscale.md @@ -3,8 +3,8 @@ title: Tailscale type: infrastructure status: active created: 2026-07-26 -updated: 2026-07-27 -verified_on: 2026-07-27 +updated: 2026-08-16 +verified_on: 2026-08-16 confidence: high tags: [tailscale, vpn, networking, infrastructure] --- @@ -20,12 +20,18 @@ WireGuard-based mesh VPN connecting all homelab hosts and providing HTTPS access - **Runtipi node:** CT201 (`runtipi.kangaroo-eel.ts.net`) ## CT460 Serve Routes -| Path | Target | Notes | -|---|---|---| -| `/` | `http://127.0.0.1:9119` | Hermes WebUI | -| `/jobs` | `http://127.0.0.1:9099` | Jobs Dashboard | -| `/desktop` | `http://127.0.0.1:6081` | CUA noVNC | -| `/vnc-camofox` | `http://127.0.0.1:6080` | Camofox VNC | +|| Path | Target | Notes | +||---|---|---|---| +|| `/` | `http://127.0.0.1:9119` | Hermes WebUI | +|| `/ui` | `http://127.0.0.1:5175/` | Hermes UI (Vite) | +|| `/jobs` | `http://127.0.0.1:9099` | Jobs Dashboard | +|| `/webui` | `http://127.0.0.1:8787/` | Hermes WebUI (Standalone) | +|| `/desktop` | `http://127.0.0.1:6081` | CUA noVNC | +|| `/vnc-camofox` | `http://127.0.0.1:6080` | Camofox VNC | +|| `/agent-estate` | `http://127.0.0.1:8769/agent-estate-role-dashboard.html` | Role dashboard | +|| `/synergy-prep` | `http://127.0.0.1:9123/` | Synergy prep | +|| `/evening-grid.html` | `http://127.0.0.1:9099/evening-grid.html` | Evening grid | +|| `/wiki` | `http://100.118.5.51:9120` | Agent Estate Wiki (Quartz) | ## CT460 Funnel Routes | Port | Target | Notes | diff --git a/raw/stocktake/freshness-20260816.txt b/raw/stocktake/freshness-20260816.txt new file mode 100644 index 0000000..f4e27b1 --- /dev/null +++ b/raw/stocktake/freshness-20260816.txt @@ -0,0 +1,89 @@ +# Wiki freshness audit — 2026-08-16 +Threshold: >21 days since `updated` + +## STALE (36) + +- [ 25d] comparisons/camoufox-vs-chrome.md (updated 2026-07-22) +- [ 25d] comparisons/hermes-vs-nanobot.md (updated 2026-07-22) +- [ 25d] concepts/agent-memory.md (updated 2026-07-22) +- [ 25d] concepts/model-routing.md (updated 2026-07-22) +- [ 25d] concepts/persistent-shells.md (updated 2026-07-22) +- [ 25d] concepts/tool-calling.md (updated 2026-07-22) +- [ 25d] decisions/index.md (updated 2026-07-22) +- [ 25d] decisions/keep-openrouter-as-fallback.md (updated 2026-07-22) +- [ 25d] decisions/persistent-shell-enabled.md (updated 2026-07-22) +- [ 25d] experiments/index.md (updated 2026-07-22) +- [ 25d] infrastructure/backups.md (updated 2026-07-22) +- [ 25d] infrastructure/credentials-map.md (updated 2026-07-22) +- [ 25d] infrastructure/docker-services.md (updated 2026-07-22) +- [ 25d] infrastructure/domains-and-tunnels.md (updated 2026-07-22) +- [ 25d] infrastructure/network-map.md (updated 2026-07-22) +- [ 25d] queries/retained-research-answers.md (updated 2026-07-22) +- [ 25d] runbooks/backup-wiki.md (updated 2026-07-22) +- [ 25d] runbooks/diagnose-docker.md (updated 2026-07-22) +- [ 25d] runbooks/provider-health.md (updated 2026-07-22) +- [ 25d] runbooks/recover-docker-service.md (updated 2026-07-22) +- [ 25d] runbooks/restart-browser.md (updated 2026-07-22) +- [ 25d] runbooks/restart-hermes.md (updated 2026-07-22) +- [ 25d] runbooks/restore-openrouter.md (updated 2026-07-22) +- [ 25d] runbooks/test-openrouter.md (updated 2026-07-22) +- [ 25d] runbooks/troubleshoot-tool-loop.md (updated 2026-07-22) +- [ 25d] runbooks/update-hermes-safely.md (updated 2026-07-22) +- [ 25d] systems/cloudflare-tunnel.md (updated 2026-07-22) +- [ 25d] systems/current-profile.md (updated 2026-07-22) +- [ 25d] systems/headless-server.md (updated 2026-07-22) +- [ 25d] systems/home-assistant.md (updated 2026-07-22) +- [ 25d] systems/messaging-integrations.md (updated 2026-07-22) +- [ 25d] systems/openrouter.md (updated 2026-07-22) +- [ 25d] systems/terminal-backend.md (updated 2026-07-22) +- [ 22d] runbooks/gateway-resource-resilience.md (updated 2026-07-25) +- [ 22d] systems/hermes-agent.md (updated 2026-07-25) +- [ 22d] systems/tool-search.md (updated 2026-07-25) + +## FRESH (33) + +- [ 1d] agents/hermes-chaos.md +- [ 1d] agents/hermes-production.md +- [ 1d] agents/index.md +- [ 1d] agents/nanobot.md +- [ 1d] agents/open-claw.md +- [ 1d] agents/qwenpaw.md +- [ 1d] agents/zeroclaw.md +- [ 4d] comparisons/memory-backends.md +- [ 4d] comparisons/model-routers.md +- [ 14d] comparisons/steel-vs-camoufox.md +- [ 14d] concepts/browser-automation.md +- [ 2d] current-state.md +- [ 14d] decisions/rollback-steel-to-camofox.md +- [ 15d] incidents/2026-08-01-mnemosyne-capture-failure.md +- [ 2d] infrastructure/hosts.md +- [ 3d] infrastructure/proxmox.md +- [ 0d] infrastructure/tailscale.md +- [ 14d] reports/uber-eats/index.md +- [ 19d] runbooks/job-radar.md +- [ 19d] runbooks/multiplexer-setup.md +- [ 14d] systems/browser-backend.md +- [ 2d] systems/guanaco.md +- [ 17d] systems/hermes-ui.md +- [ 21d] systems/homepage-dashboard.md +- [ 15d] systems/memory-backend.md +- [ 14d] systems/mnemosyne.md +- [ 2d] systems/model-providers.md +- [ 9d] systems/nanobot.md +- [ 21d] systems/obsidian.md +- [ 2d] systems/omniroute.md +- [ 18d] systems/opencode-go.md +- [ 6d] systems/scheduled-tasks.md +- [ 0d] systems/skills-index.md + +## NO updated DATE (7) + +- SCHEMA.md +- experiments/active/example.md +- incidents/2026-07-29-mnemosyne-relay.md +- incidents/2026-08-04-omniroute-free-deepseek-silent-stops.md +- index.md +- log.md +- reports/uber-eats/2026-07.md + +TOTAL: 36 stale, 33 fresh, 7 no-date of 76 pages \ No newline at end of file diff --git a/regenerate-skills-index.sh b/regenerate-skills-index.sh deleted file mode 100755 index 8e5e1a5..0000000 --- a/regenerate-skills-index.sh +++ /dev/null @@ -1,119 +0,0 @@ -#!/bin/bash -# regenerate-skills-index.sh -# Stock-take: regenerate systems/skills-index.md from the live skill tree, -# rebuild the Quartz site, and redeploy. Run on a schedule so the wiki never drifts. -set -euo pipefail - -WIKI="/home/hermes/workspace/agent-estate-wiki" -QUARTZ="/home/hermes/workspace/quartz-temp" -SKILLS="/home/hermes/.hermes/skills" - -echo "[$(date -Is)] Starting skills stock-take" - -# 1. Regenerate skills-index.md from the live skill tree -python3 - "$SKILLS" "$WIKI/systems/skills-index.md" <<'PY' -import sys, re -from collections import defaultdict -from pathlib import Path -from datetime import date - -skills_root = Path(sys.argv[1]) -out_path = Path(sys.argv[2]) -skill_files = list(skills_root.rglob('SKILL.md')) - -skills = defaultdict(list) -for f in skill_files: - rel = f.relative_to(skills_root) - parts = rel.parts - if len(parts) >= 3: - cat, name = parts[0], parts[1] - elif len(parts) == 2: - cat, name = 'uncategorized', parts[0] - else: - continue - desc = '' - try: - content = f.read_text(errors='ignore') - m = re.search(r'^description:\s*(.+)$', content[:2000], re.M) - if m: - desc = m.group(1).strip().strip('"').strip("'")[:120] - except Exception: - pass - skills[cat].append((name, desc)) - -total = sum(len(v) for v in skills.values()) - -L = [] -L.append('---') -L.append('title: Installed Skills') -L.append('type: system') -L.append('status: active') -L.append('created: 2026-07-22') -L.append(f'updated: {date.today().isoformat()}') -L.append(f'verified_on: {date.today().isoformat()}') -L.append('confidence: high') -L.append('tags: [skills, hermes]') -L.append('sources: []') -L.append('---') -L.append('') -L.append('# Installed Skills') -L.append('') -L.append(f'**Total installed: {total} skills** in `~/.hermes/skills/`.') -L.append('') -L.append('This page is auto-regenerated from the live skill inventory. Do not hand-edit.') -L.append('') -L.append('## Stock-take notes') -L.append('- Category names come from the directory structure under `~/.hermes/skills/` (`category/skill/SKILL.md`).') -L.append('- Skills stored directly under `~/.hermes/skills/` (no subfolder) are grouped under `uncategorized`.') -L.append('- Deeper nested paths (e.g. `mlops/evaluation`) are grouped by their top-level category.') -L.append('') - -priority = ['core-hermes','autonomous-ai-agents','hermes','devops','productivity','creative','software-development','research','email','mlops','github','apple','frontend','media','note-taking','web-development','smart-home','mcp','uncategorized'] -def cat_order(cat): - try: return priority.index(cat) - except ValueError: return 100 + len(priority) -cats = sorted(skills.items(), key=lambda x: (cat_order(x[0]), -len(x[1]))) - -for cat, items in cats: - nice = cat.replace('-', ' ').title() - L.append(f'## {nice} ({len(items)})') - L.append('') - for name, desc in sorted(items): - L.append(f'- `{name}` — {desc}' if desc else f'- `{name}`') - L.append('') - -L.append('## Related') -L.append('- [[systems/hermes-agent]]') -L.append('- [[systems/omniroute]]') -L.append('') - -out_path.write_text('\n'.join(L)) -print(f"Regenerated {out_path} with {total} skills across {len(skills)} categories") -PY - -# 2. Sync content into Quartz -rm -rf "$QUARTZ/content" "$QUARTZ/public" -mkdir -p "$QUARTZ/content" -python3 - "$WIKI" "$QUARTZ/content" <<'PY' -import shutil, sys -from pathlib import Path -src = Path(sys.argv[1]); dst = Path(sys.argv[2]) -skip = {'.git','public','node_modules','quartz-site','serve.py','.gitignore','package.json','package-lock.json','.codewiki-state.json'} -for item in src.iterdir(): - if item.name in skip: continue - if item.is_dir(): - shutil.copytree(item, dst / item.name, dirs_exist_ok=True) - elif item.suffix == '.md': - shutil.copy2(item, dst / item.name) -PY - -# 3. Build Quartz -cd "$QUARTZ" -npx quartz build >/tmp/quartz-build.log 2>&1 || { echo "Quartz build failed"; tail -20 /tmp/quartz-build.log; exit 1; } - -# 4. Deploy to public -rm -rf "$WIKI/public" -mkdir -p "$WIKI/public" -cp -a "$QUARTZ/public/." "$WIKI/public/" - -echo "[$(date -Is)] Completed: $(find "$WIKI/public" -name '*.html' | wc -l) html files deployed" diff --git a/systems/skills-index.md b/systems/skills-index.md index 4079cba..9387c1e 100644 --- a/systems/skills-index.md +++ b/systems/skills-index.md @@ -3,8 +3,8 @@ title: Installed Skills type: system status: active created: 2026-07-22 -updated: 2026-08-15 -verified_on: 2026-08-15 +updated: 2026-08-16 +verified_on: 2026-08-16 confidence: high tags: [skills, hermes] sources: [] @@ -17,9 +17,8 @@ sources: [] This page is auto-regenerated from the live skill inventory. Do not hand-edit. ## Stock-take notes -- Category names come from the directory structure under `~/.hermes/skills/` (`category/skill/SKILL.md`). -- Skills stored directly under `~/.hermes/skills/` (no subfolder) are grouped under `uncategorized`. -- Deeper nested paths (e.g. `mlops/evaluation`) are grouped by their top-level category. +- Category = directory structure under `~/.hermes/skills/` (`category/skill/SKILL.md`). +- Skills directly under `~/.hermes/skills/` group under `uncategorized`. ## Autonomous Ai Agents (8) @@ -397,10 +396,26 @@ This page is auto-regenerated from the live skill inventory. Do not hand-edit. - `working-with-legacy-code` — Safely change and test untested codebases using Feathers'' "Working Effectively with Legacy Code". Use when the user men - `yuanbao` — Yuanbao (元宝) groups: @mention users, query info/members. +## Conduct (1) + +- `simple-directives-execution` — Execute now when told 'just do X' — no investigation. + +## Cron (1) + +- `cron-digest-formatting` — Use when formatting cron Telegram news digests for Anthony. + +## Data Science (1) + +- `jupyter-live-kernel` — Iterative Python via live Jupyter kernel (hamelnb). + ## Finance (1) - `3-statement-model` — Build integrated IS/BS/CF financial workbooks in Excel. +## Job Hunting (1) + +- `seek-extraction-patterns` — Extract salary, closing dates, and job details from SEEK (au.seek.com) listings at scale. Use when enriching a batch of + ## Omniroute (1) - `omniroute-skills` — Interact with OmniRoute's Skills framework — list, install, enable, execute, and debug skills via REST API and MCP tools @@ -413,22 +428,6 @@ This page is auto-regenerated from the live skill inventory. Do not hand-edit. - `wiki-web-hosting` — Publish Markdown wikis as Quartz sites over Tailscale. -## Job Hunting (1) - -- `seek-extraction-patterns` — Extract salary, closing dates, and job details from SEEK (au.seek.com) listings at scale. Use when enriching a batch of - -## Conduct (1) - -- `simple-directives-execution` — Execute now when told 'just do X' — no investigation. - -## Cron (1) - -- `cron-digest-formatting` — Use when formatting cron Telegram news digests for Anthony. - -## Data Science (1) - -- `jupyter-live-kernel` — Iterative Python via live Jupyter kernel (hamelnb). - ## Related - [[systems/hermes-agent]] - [[systems/omniroute]] diff --git a/wiki-maintain.sh b/wiki-maintain.sh new file mode 100644 index 0000000..5237985 --- /dev/null +++ b/wiki-maintain.sh @@ -0,0 +1,134 @@ +#!/bin/bash +# wiki-maintain.sh — General Agent Estate Wiki freshness maintenance. +# Regenerates machine-derivable pages from live state, audits every page for +# staleness, rebuilds the Quartz site, and deploys. Run on a schedule so the +# wiki never silently drifts from reality. +# +# Usage: ./wiki-maintain.sh [--no-build] +# --no-build regenerate content + audit but skip quartz build/deploy +set -euo pipefail + +WIKI="/home/hermes/workspace/agent-estate-wiki" +QUARTZ="/home/hermes/workspace/quartz-temp" +SKILLS="/home/hermes/.hermes/skills" +STALE_DAYS=21 +NO_BUILD=false +[[ "${1:-}" == "--no-build" ]] && NO_BUILD=true + +mkdir -p "$WIKI/raw/stocktake" +REPORT="$WIKI/raw/stocktake/freshness-$(date +%Y%m%d).txt" + +echo "[$(date -Is)] Agent Estate Wiki maintenance start" +echo " wiki=${WIKI}" +echo " stale-threshold=${STALE_DAYS}d" + +# ── 1. Regenerate skills-index from live skill tree ──────────────────────── +python3 - "$SKILLS" "$WIKI/systems/skills-index.md" <<'PY' +import sys, re +from collections import defaultdict +from pathlib import Path +from datetime import date +skills_root = Path(sys.argv[1]); out = Path(sys.argv[2]) +files = sorted(skills_root.rglob('SKILL.md')) +skills = defaultdict(list) +for f in files: + rel = f.relative_to(skills_root); parts = rel.parts + if len(parts) >= 3: cat, name = parts[0], parts[1] + elif len(parts) == 2: cat, name = 'uncategorized', parts[0] + else: continue + desc = '' + try: + m = re.search(r'^description:\s*(.+)$', f.read_text(errors='ignore')[:2000], re.M) + if m: desc = m.group(1).strip().strip('"').strip("'")[:120] + except Exception: pass + skills[cat].append((name, desc)) +total = sum(len(v) for v in skills.values()) +L = ['---','title: Installed Skills','type: system','status: active', + 'created: 2026-07-22', f'updated: {date.today().isoformat()}', + f'verified_on: {date.today().isoformat()}','confidence: high', + 'tags: [skills, hermes]','sources: []','---','','# Installed Skills','', + f'**Total installed: {total} skills** in `~/.hermes/skills/`.','', + 'This page is auto-regenerated from the live skill inventory. Do not hand-edit.','', + '## Stock-take notes','- Category = directory structure under `~/.hermes/skills/` (`category/skill/SKILL.md`).', + '- Skills directly under `~/.hermes/skills/` group under `uncategorized`.',''] +priority = ['core-hermes','autonomous-ai-agents','hermes','devops','productivity','creative', + 'software-development','research','email','mlops','github','apple','frontend','media', + 'note-taking','web-development','smart-home','mcp','uncategorized'] +def order(c): + try: return priority.index(c) + except ValueError: return 100+len(priority) +for cat, items in sorted(skills.items(), key=lambda x:(order(x[0]),-len(x[1]))): + L.append(f'## {cat.replace("-"," ").title()} ({len(items)})'); L.append('') + for name, desc in sorted(items): + L.append(f'- `{name}` — {desc}' if desc else f'- `{name}`') + L.append('') +L += ['## Related','- [[systems/hermes-agent]]','- [[systems/omniroute]]',''] +out.write_text('\n'.join(L)) +print(f"[1/3] skills: {total} across {len(skills)} categories -> {out}") +PY + +# ── 2. Audit every page for staleness ──────────────────────────────────────── +python3 - "$WIKI" "$REPORT" "$STALE_DAYS" <<'PY' +import sys, re +from pathlib import Path +from datetime import date +wiki = Path(sys.argv[1]); report = Path(sys.argv[2]); threshold = int(sys.argv[3]) +today = date.today() +stale, fresh, nodate = [], [], [] +for f in sorted(wiki.rglob('*.md')): + rel = f.relative_to(wiki) + if str(rel).startswith('raw/'): continue + content = f.read_text(errors='ignore') + upd = re.search(r'^updated:\s*(\S+)', content[:800], re.M) + if not upd: + nodate.append(str(rel)); continue + try: d = date.fromisoformat(upd.group(1)) + except ValueError: nodate.append(str(rel)); continue + age = (today - d).days + (stale if age > threshold else fresh).append((str(rel), age, upd.group(1))) +stale.sort(key=lambda x:-x[1]) +lines = [f"# Wiki freshness audit — {today.isoformat()}", + f"Threshold: >{threshold} days since `updated`", + f"", f"## STALE ({len(stale)})", ""] +for rel, age, d in stale: + lines.append(f"- [{age:>3}d] {rel} (updated {d})") +lines += [f"", f"## FRESH ({len(fresh)})", ""] +for rel, age, d in fresh: + lines.append(f"- [{age:>3}d] {rel}") +lines += [f"", f"## NO updated DATE ({len(nodate)})", ""] +for rel in nodate: + lines.append(f"- {rel}") +lines += ["", f"TOTAL: {len(stale)} stale, {len(fresh)} fresh, {len(nodate)} no-date of {len(stale)+len(fresh)+len(nodate)} pages"] +report.write_text('\n'.join(lines)) +print(f"[2/3] audit: {len(stale)} stale (>={threshold}d), {len(fresh)} fresh, {len(nodate)} no-date -> {report}") +PY + +# ── 3. Sync content, build, deploy ───────────────────────────────────────── +if $NO_BUILD; then + echo "[3/3] --no-build: content + audit done, skipping quartz build" + exit 0 +fi +rm -rf "$QUARTZ/content" "$QUARTZ/public" +mkdir -p "$QUARTZ/content" +python3 - "$WIKI" "$QUARTZ/content" <<'PY' +import shutil, sys +from pathlib import Path +src = Path(sys.argv[1]); dst = Path(sys.argv[2]) +skip = {'.git','public','node_modules','quartz-site','serve.py','.gitignore', + 'package.json','package-lock.json','.codewiki-state.json','regenerate-skills-index.sh', + 'wiki-maintain.sh','raw'} +for item in src.iterdir(): + if item.name in skip: continue + if item.is_dir(): shutil.copytree(item, dst/item.name, dirs_exist_ok=True) + elif item.suffix == '.md': shutil.copy2(item, dst/item.name) +PY +cd "$QUARTZ" +npx quartz build >/tmp/quartz-build.log 2>&1 || { echo "Quartz build FAILED"; tail -20 /tmp/quartz-build.log; exit 1; } +rm -rf "$WIKI/public" +mkdir -p "$WIKI/public" +cp -a "$QUARTZ/public/." "$WIKI/public/" +echo "[3/3] build+deploy: $(find "$WIKI/public" -name '*.html' | wc -l) html files" +echo "[$(date -Is)] Wiki maintenance complete" +echo "" +echo "=== Freshness summary ===" +grep -E '^TOTAL:' "$REPORT" || true