diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..890d447 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,203 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Environment + +This is a home-lab / managed-hosting environment. There is no local codebase to build or test — work consists of editing PHP/JS files on remote servers via SSH and managing infrastructure across several machines. All tool calls use `sshpass` with password auth. + +## Server Map + +| Host | IP | SSH | Purpose | +|------|-----|-----|---------| +| DO (main) | 165.22.1.228 | `root / Gonewalk1974!@#` | CyberPanel/OLS — all websites + JARVIS | +| FusionPBX | 134.209.72.226 | `root / Joker1974!@#` | FreeSWITCH PBX | +| PVE1 (Proxmox) | orbisne.fortiddns.com (10.48.200.90) | `root / Joker1974!!!` | Primary hypervisor — FortiGate DDNS, auto-updates if IP changes | +| PVE2 (Proxmox) | 10.48.200.91 | `root / Joker1974!!!` | Secondary hypervisor | +| Ollama VM | 10.48.200.95 | `myron → sudo` | llama3.2 local LLM (PVE1 VM 210) | +| Home Assistant | 10.48.200.97 | `myron → sudo` | HA VM 101 | +| NetworkBackup | 10.48.200.99 | `myron → sudo` | Backup VM (PVE2 VM 302) | +| MediaStack | 10.48.200.35 | `root via PVE1 key` | Sonarr/Radarr/Prowlarr/qBittorrent (PVE1 VM 113) | + +**SSH password order** (try in sequence if first fails): `Joker1974!@#` → `Joker1974!!!` → `Joker1974!` + +**SSH pattern for all remote work:** +```bash +sshpass -p 'Gonewalk1974!@#' ssh -o StrictHostKeyChecking=no root@165.22.1.228 'commands here' +``` + +For PVE1 from anywhere (FortiGate DDNS, survives IP changes): +```bash +sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@orbisne.fortiddns.com 'commands here' +``` + +For commands inside VMs on PVE1: +```bash +sshpass -p 'Joker1974!!!' ssh -o StrictHostKeyChecking=no root@orbisne.fortiddns.com \ + 'qm guest exec 210 -- bash -c "commands here"' +``` + +## Websites on DO (165.22.1.228) + +All sites live at `/home//public_html/` on DO. CyberPanel/OpenLiteSpeed serves them. + +| Site | Path | GitHub | +|------|------|--------| +| jarvis.orbishosting.com | /home/jarvis.orbishosting.com/ | myronblair/jarvis | +| tomsjavajive.com | /home/tomsjavajive.com/public_html/ | myronblair/tomsjavajive | +| epictravelexpeditions.com | /home/epictravelexpeditions.com/public_html/ | myronblair/epictravelexpeditions | +| parkerslingshotrentals.com | /home/parkerslingshotrentals.com/public_html/ | myronblair/parkerslingshotrentals | +| orbishosting.com | /home/orbishosting.com/public_html/ | myronblair/orbishosting | +| orbis.orbishosting.com | /home/orbis.orbishosting.com/public_html/ | myronblair/orbis-hosting-portal | +| tomtomgames.com | /home/tomtomgames.com/public_html/ | myronblair/tomtomgames | + +**Parker Slingshot** is served from epictravelexpeditions.com, not its own domain: +- URL: `https://parkerslingshot.epictravelexpeditions.com` +- Path: `/home/epictravelexpeditions.com/parkerslingshot/` +- GitHub: `myronblair/parkerslingshot` (own repo, auto-deploy active) +- `db.php` and `config.php` are gitignored (credentials); `db.php.example` is the reference template + +## Deployment Workflow + +**Auto-deploy is active.** Push to `main` on any site repo → GitHub webhook → server pulls automatically within 1 minute. PHP syntax is validated before deploy; bad commits are auto-reverted. + +Webhook handler: `https://jarvis.orbishosting.com/webhook.php` (HMAC secret: `4c8805f0285214ff0a0602b5880270b935f36a896946c7f1`) +Deploy queue: `/tmp/jarvis-deploy-queue.txt` | Runner: `/usr/local/bin/jarvis-deploy.sh` (cron every min) +Deploy log: `/home/jarvis.orbishosting.com/logs/deploy.log` + +For hotfixes that can't wait 1 min, SCP directly: +```bash +sshpass -p 'Gonewalk1974!@#' scp -o StrictHostKeyChecking=no /tmp/changed.php \ + root@165.22.1.228:/home/site.com/public_html/changed.php +``` + +GitHub PAT (embedded in remote URLs): `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` — expires ~2026-08-20. +Infra repo: `myronblair/infra` — cloned at `/opt/infra` on DO server. + +**DO server backup:** `myronblair/do-server-config` — scripts, systemd units, WireGuard, OLS vhosts, cron, MySQL creds + 8-phase restore wizard. Weekly Sunday 4am. Launcher: `/usr/local/bin/do-server-backup`. + +Gitignored credentials (never in GitHub): `api/config.php` (JARVIS, epictravelexpeditions), `config/database.php` (tomsjavajive). + +## JARVIS System + +Iron Man-style AI dashboard at `https://jarvis.orbishosting.com`. All files on DO at `/home/jarvis.orbishosting.com/`. + +**Architecture:** +- `public_html/api.php` — API router; has `session_write_close()` guard (must skip for `auth` endpoint to prevent LSAPI session deadlock) +- `api/config.php` — all credentials/constants (gitignored) +- `api/endpoints/chat.php` — 4-tier AI: KB intent → Ollama (10.48.200.95:11434) → Groq (`compound-beta-mini`) → Claude API; includes Tier 0.7 planner intents (tasks/appointments/briefing) +- `api/endpoints/agent.php` — push-based agent registration/heartbeat/metrics +- `api/endpoints/alerts.php` — auto-generates alerts (CPU >85%, RAM >85%, disk >88%, offline agents, site down); dispatches restart commands to agents when their services fail +- `api/endpoints/facts_collector.php` — runs every 3 min via cron; collects agent metrics, KB facts, Proxmox/HA/Ollama status, and all 7 site HTTP health checks +- `api/endpoints/stats_cache.php` — runs every 5 min via cron; weather/news/Proxmox cache refresh +- `api/endpoints/planner.php` — tasks & appointments CRUD; routes: `planner/tasks`, `planner/appointments`, `planner/today`, `planner/done` +- `api/endpoints/ha.php` — HA entity list reads from `ha_entities` table (real-time agent push); service calls go direct to HA_URL (`http://orbisne.fortiddns.com:8123`) + +**Voice system (index.html):** +- Continuous SpeechRecognition; mic stays open always (mute toggle button) +- **Phase 1 wake**: say "wake up JARVIS" or "daddy's home" → activates voice mode once +- **Phase 2 command**: say "JARVIS [command]" → executes; opens 17-second free-listen window (no prefix needed for follow-ups) +- After 30 min of no commands → voice sleeps; full wake phrase required again +- Mic paused during ElevenLabs TTS playback (`isSpeaking` guard) to prevent feedback loop +- Auto-reload after 5 min idle is silent (no greeting speech) + +**Planner system (2026-05-31):** +- DB tables: `tasks` (id, title, notes, category, priority, status, due_date, due_time, completed_at) and `appointments` (id, title, description, category, start_at, end_at, location, all_day, reminder_min, alerted) +- Voice commands: "add task [title]", "my tasks", "mark [x] done", "schedule [title] on [date]", "my calendar", "daily briefing" +- Home page: small top-bar badge "N TASKS · N APPTS" when items due today (no panel added) +- Admin CRUD at `/admin` under PLANNER section → TASKS and APPOINTMENTS tabs + +**Agent system:** Agents phone home every 10s (heartbeat) / 30s (metrics) to `https://165.22.1.228` with `Host: jarvis.orbishosting.com` header (bypasses Cloudflare). Config at `/opt/jarvis-agent/config.json` on each Linux agent. +Agent installer (one-liner for any Linux host): `curl -sk https://jarvis.orbishosting.com/install-agent.sh | bash -s ` + +**Self-healing:** `/usr/local/bin/jarvis-watchdog.sh` runs every 5 min (root cron). Restarts lsws/mysql/redis if down, restarts offline Proxmox VM agents via `qm guest exec`, inserts alerts to DB, rotates logs. +Watchdog log: `/home/jarvis.orbishosting.com/logs/watchdog.log` + +**JARVIS DB:** `jarvis_db` on localhost. User: `jarvis_user / J4rv1s_Pr0t0c0l_2026!`. phpMyAdmin at `/phpmyadmin` (myron / Joker1974!!!). +Tables (18 total): agent_commands, agent_metrics, alerts, api_cache, appointments, conversations, ha_entities, kb_facts, kb_intents, kb_ollama_models, kb_preferences, known_commands, metrics_history, network_devices, registered_agents, tasks, users + (see schema for full column list) + +**Groq API note:** Use model name `compound-beta-mini` directly — NOT `groq/compound-beta-mini` (that's OpenAI router syntax and will 404 on api.groq.com). + +## Tom's Java Jive + +PHP e-commerce site. DB: `toms_tjj_db / toms_tjj_user / +60wlPc+55e@gFq4`. Key quirks: +- No `slug` column on products — URLs use `?id=product_id` +- All tables must be `utf8mb4_unicode_ci` — mixed collation causes MySQL error 1267 on JOINs +- `wallet_transactions.type` and `loyalty_transactions.type` have strict enums (see memory for values) + +## MediaStack + +Automated media server on PVE1 VM 113. All traffic routes through WireGuard VPN → DO, bypassing home ISP. + +**SSH:** From PVE1: `ssh -o StrictHostKeyChecking=no -i /root/.ssh/id_rsa root@10.48.200.35` + +**Services:** +| Service | Port | Login | +|---------|------|-------| +| qBittorrent | :8080 | admin / Joker1974!!! | +| Sonarr | :8989 | API key: `b43e04350a594846b4ee95261c29e9e0` | +| Radarr | :7878 | API key: `53c4268360444feeae5f98c0cc24e0e3` | +| Prowlarr | :9696 | API key: `9d0ce6c5660743b5bf1c7951efc62252` | + +**Media paths:** downloads → `/media/downloads/complete` | movies → `/media/movies` | tv → `/media/tv` +**Jellyfin NFS mounts** (VM 112, 10.48.200.33): `/mnt/mediastack/movies` and `/mnt/mediastack/tv` +**WireGuard:** `wg0` IP `10.200.0.4` → CT110 (10.48.200.19:51821) → DO. Kill-switch active; LAN always allowed. +**DNS:** FortiGate blocks port 53 outbound. PVE1 runs dnsmasq on :53 → 100.100.100.100. MediaStack uses `DNS=10.48.200.90`. +**Indexer:** IPTorrents via Prowlarr (cookie auth). Prowlarr syncs to Sonarr + Radarr automatically. +**GitHub:** `myronblair/mediastack` (private) — config files, systemd units, README with full setup notes. +**JARVIS agent quirks:** needs `jarvis_url`, `registration_key` (`f846a9aaf7ce9a61742c63c87c4186052a71d2a580c65518`), `ssl_verify: false` in config. + +## Parker Slingshot Rentals + +Admin portal at `/admin/index.php` uses HMAC-signed cookie auth (not PHP sessions — sessions were unreliable under LiteSpeed caching). Admin: `admin / Parker2026!`. DB: `epic_parkersling / epic_parkersling / Joker1974!!!`. + +## FusionPBX / FreeSWITCH + +Production at 134.209.72.226. Web: `https://fusion.orbishosting.com` (admin / fY7XP5swgtpbzrYLhkeVYkA4744). SIP profiles served via Lua XML handler — config changes require deleting `/var/cache/fusionpbx/FusionPBX.configuration.sofia.conf` to force reload. Extension 1000 (Yealink T48S at 10.48.200.43) registered on production server via port 5080 with `aggressive-nat-detection=true` to bypass FortiGate SIP ALG. + +**SSH access:** Port 22 firewalled from internet — only from 107.178.2.130 / 97.154.109.245. Relay all SSH through DO: +```bash +sshpass -p 'Gonewalk1974!@#' ssh -o StrictHostKeyChecking=no root@165.22.1.228 \ + 'sshpass -p "Joker1974!@#" ssh -o StrictHostKeyChecking=no root@134.209.72.226 "command"' +``` + +**Backup:** `myronblair/fusionpbx-config` — PostgreSQL dump (gzip, ~29MB) + FreeSWITCH configs + restore wizard. Weekly Sunday 5am. Launcher: `/usr/local/bin/fusionpbx-backup`. + +## Proxmox + +PVE1 at 10.48.200.90, PVE2 at 10.48.200.91. Root login direct. Run commands inside VMs via: +```bash +qm guest exec -- bash -c 'command' +``` +Proxmox `--nameserver` must be space-separated: `"8.8.8.8 1.1.1.1"` (comma causes netplan bug). + +**Backup:** `myronblair/proxmox-config` — shared cluster configs (VM .conf, storage, HA, SDN) + per-node (network, cron, systemd, scripts). Weekly Sunday 3am. Launcher: `/usr/local/bin/proxmox-backup` on both nodes. + +## PHP / OLS Runtime + +CyberPanel uses `lsphp85`. Run PHP scripts directly with: +```bash +/usr/local/lsws/lsphp85/bin/lsphp /path/to/script.php +``` +For PHP syntax checking use `php8.3 -l file.php` — lsphp segfaults on `-l` flag. +When a PHP endpoint uses `ob_start()` + `header.php` pattern, add `ob_end_clean()` before any CSV/JSON response output. + +## GitHub Repos + +| Repo | Site | DB Schema | +|------|------|-----------| +| myronblair/jarvis | jarvis.orbishosting.com | db/schema.sql (15 tables) | +| myronblair/tomsjavajive | tomsjavajive.com | db/schema.sql (45 tables) | +| myronblair/epictravelexpeditions | epictravelexpeditions.com | db/schema.sql (7 tables) | +| myronblair/parkerslingshot | parkerslingshot.epictravelexpeditions.com | (no schema file — DB managed directly) | +| myronblair/parkerslingshotrentals | parkerslingshotrentals.com | db/schema.sql (10 tables) | +| myronblair/orbishosting | orbishosting.com | — | +| myronblair/orbis-hosting-portal | orbis.orbishosting.com | — | +| myronblair/tomtomgames | tomtomgames.com | db/schema.sql (22 tables) | +| myronblair/infra | server configs | cron, systemd, agent configs | +| myronblair/mediastack | MediaStack VM 113 | config/, systemd units, wg0.conf, README | +| myronblair/do-server-config | DO server backup | scripts, systemd, WG, OLS vhosts, restore.sh | +| myronblair/proxmox-config | PVE1+PVE2 backup | shared cluster configs + per-node, restore.sh | +| myronblair/fusionpbx-config | FusionPBX backup | PostgreSQL dump (gzip) + FS configs, restore.sh | + +All repos are private. Each has `config/vhost/` with OLS vhost config. The jarvis repo also has `deploy/` (watchdog, deploy runner, systemd units) and `agent/jarvis-agent.py`.