# TOOLS.md - Local Notes

Skills define *how* tools work. This file is for *your* specifics — the stuff that's unique to your setup.

## James Server Hardware

**Lenovo ThinkServer TS140**
- **CPU:** Intel Xeon E3-1225 v3 @ 3.20GHz (4c/4t, no HT) — *E3-1275 upgrade incoming*
- **RAM:** 16GB DDR3 ECC 1600MHz (2×8GB Hynix) — *MB issue prevents upgrade, 2 slots empty*
- **Storage:** WD Blue SA510 1TB SSD (916GB usable, ~60GB used)
- **GPU:** Intel integrated (Xeon E3-1200 v3)
- **OS:** Ubuntu 24.04.3 LTS headless + minimal GUI for headed Chrome
- **Kernel:** 6.8.0-90-generic

## What Goes Here

Things like:
- Camera names and locations
- SSH hosts and aliases  
- Preferred voices for TTS
- Speaker/room names
- Device nicknames
- Anything environment-specific

## Examples

```markdown
### Cameras
- living-room → Main area, 180° wide angle
- front-door → Entrance, motion-triggered

### SSH
- home-server → 192.168.1.100, user: admin

### TTS
- Preferred voice: "Nova" (warm, slightly British)
- Default speaker: Kitchen HomePod
```

### James Dashboard
- **URL:** http://100.123.216.65:9200 (Tailscale) or http://localhost:9200
- **Purpose:** Visual status board for tasks, briefings, history

**Tasks API:**
- `GET /api/tasks` - list all tasks
- `POST /api/tasks` - add task
- `PATCH /api/tasks/:id` - update task
- `DELETE /api/tasks/:id` - remove task
- **Fields:** title, text, priority, status, owner, domain, notes
- **Priority:** high, medium, low
- **Status:** pending, in-progress, done
- **Owner:** "johan" or "james" (who owns the task)
- **Domain:** Kaseya, inou, Sophia, ClawdNode, Infrastructure, Personal, etc.

**News API:**
- `GET /api/news` - list news (newest first, max 20)
- `POST /api/news` - add news item
- `DELETE /api/news` - clear all news
- `DELETE /api/news/:id` - remove specific item
- **Fields:** title, body, type, source (optional), url (optional)
- **Type:** info, success, warning, error

**Briefings API:**
- `GET /api/briefings` - list briefings (newest first, last 30)
- `POST /api/briefings` - add briefing
- `GET /api/briefings/:id` - get single briefing
- `DELETE /api/briefings/:id` - remove briefing
- **Fields:** title, date, weather, markets, news, tasks, summary

**Deliveries API:**
- `GET /api/deliveries` - list active deliveries (excludes delivered)
- `GET /api/deliveries?all=true` - list all including delivered
- `POST /api/deliveries` - add delivery (prefer upsert instead)
- `PUT /api/deliveries/upsert` - smart upsert: matches by tracking_number or description+retailer, updates existing or creates new. **Always use this for shipping email triage.**
- `GET /api/deliveries/:id` - get single delivery
- `PATCH /api/deliveries/:id` - update delivery
- `DELETE /api/deliveries/:id` - remove delivery
- **Fields:** description, carrier, retailer, tracking_number, tracking_url, expected_date, status, notes
- **Status values:** shipped, in_transit, out_for_delivery, delayed, delivered

**Status API:**
- `GET /api/status` - list all status items
- `POST /api/status` - set status `{"key": "...", "value": "...", "type": "info|warning|error"}`
- `GET /api/status/:key` - get single status
- `DELETE /api/status/:key` - remove status
- **Use for:** Claude usage, system health, key metrics displayed at top of dashboard

**Workflow:**
- Morning brief → POST to /api/briefings, send Signal link to dashboard
- Track tasks with owner field (mine vs Johan's)
- Keep briefing history for reference
- Update Claude usage status: `scripts/claude-usage-check.sh` (auto-updates dashboard)

### Forge Server (GPU Compute)
- **Hostname:** forge
- **IP:** 192.168.3.138
- **CPU:** Intel i7-6700K @ 4.0GHz (4c/8t)
- **RAM:** 64GB DDR4
- **GPU:** NVIDIA GTX 970 4GB (Driver 580.126.09, CUDA 13.0)
- **Storage:** 469GB NVMe
- **OS:** Ubuntu 24.04.1 LTS (Server, headless)
- **Kernel:** 6.8.0-94-generic
- **Purpose:** OCR (GLM-OCR), ML inference, GPU compute
- **Ollama:** Installed (0.15.4), waiting for 0.15.5 for GLM-OCR model
- **Python:** /home/johan/ocr-env/ (venv with PyTorch 2.2 + CUDA 11.8)
- **SSH:** Key auth only (password auth disabled)
- **Firewall:** UFW active, SSH + LAN (192.168.0.0/22) allowed
- **Owner:** James ⚡ (full autonomy)

**OCR Service (GLM-OCR):**
- **URL:** http://192.168.3.138:8090
- **Service:** `systemctl --user status ocr-service` (on forge)
- **Source:** `/home/johan/ocr-service/server.py`
- **Model:** `/home/johan/models/glm-ocr` (zai-org/GLM-OCR, 2.47 GB)
- **VRAM usage:** 2.2 GB idle (model loaded), peaks ~2.8 GB during inference
- **Performance:** ~2s small images, ~25s full-page documents (auto-resized to 1280px max)
- **Endpoints:**
  - `GET /health` — status + GPU memory
  - `POST /ocr` — single image OCR (multipart: file + prompt + max_tokens)
  - `POST /ocr/batch` — multi-image OCR
- **Auto-resize:** Images capped at 1280px longest edge (prevents OOM on GTX 970)
- **Usage from james:** `curl -X POST http://192.168.3.138:8090/ocr -F "file=@image.png"`
- **Patched env:** transformers 5.0.1.dev0 (from git) + monkey-patch for PyTorch 2.2 compat

### Home Network
- **Public IP:** 47.197.93.62 (not static, but rarely changes)
- **Location:** St. Petersburg, Florida
- **Caddy (reverse proxy):** 192.168.0.2 / Tailscale: 100.84.42.55 (caddy)
  - SSH: `tailscale ssh root@caddy` or `ssh root@caddy` (key installed)
  - Config: `/etc/caddy/Caddyfile`

### James Server (Hetzner)
- **LAN IP:** 192.168.1.16
- **Gateway UI:** http://192.168.1.16:18789/
- **Agents:**
  - Main (James): http://192.168.1.16:18789/
  - Mail Agent: http://192.168.1.16:18789/agents/mailagent

### Uptime Kuma
- **URL:** http://zurich.inou.com:3001
- **User:** james
- **Password:** WW8ipJfY27ELf7nnouaKLCL6

### Openprovider (Domain Registrar)
- **URL:** https://cp.openprovider.eu
- **User:** johan.jongsma@iasobackup.com
- **Password:** !!Helder06

### Test Devices
- **ThinkPhone 1** (Motorola/Lenovo) — Johan's Android test device

### Git Server (Zurich)
- **Host:** zurich.inou.com
- **User:** git
- **URL format:** `git@zurich.inou.com:<repo>.git`
- **Repos:** azure-backup, clawdnode-android, inou-mobile, mail-agent
- **Auth:** SSH keys (claude@macbook, james@server, johan@ubuntu2404 authorized)
- **Create new repo:** `ssh git@zurich.inou.com "git init --bare <name>.git"`

### SSH Hosts
- **hostkey50304** → 82.22.36.202 / **zurich.inou.com** (CH/Switzerland VPS)
  - Location: Zürich, likely Equinix ZH (Josefstrasse 225)
  - Upstream: Cogent Communications
  - Specs: 4 vCore, 6GB RAM, 120GB SSD
  - OS: Fresh install (2025-01-27)
  - User: root
  - **Purpose:** Security infrastructure (geographic diversity for monitoring, SOC2 compliance). NOT for hosting inou.com.

- **Home Assistant** → 192.168.1.252
  - User: root
  - Port: 22
  - **⚠️ STRICT RULES:**
    - NO changes without Johan's explicit permission
    - **NEVER** change lights during night hours
    - **NEVER** play audio on speakers/tablets during night hours
    - Night = Sophia's sleep/care time — disruptions are dangerous

### Browser Profiles

| Profile | Type | Port | Use Case |
|---------|------|------|----------|
| **chrome** | Relay (your actual Chrome) | 18792 | X.com, paranoid sites, full auth |
| **fast** | Headless Chromium | 9223 | General automation, tolerant sites |
| **clawd** | Headless (managed) | 18800 | Default, no auth |

#### Chrome Relay (profile="chrome") — Best for authenticated sites
Attaches to your actual Chrome browser via extension. No session copying, no detection issues.

**Setup (one-time):**
1. Extension installed at `~/.clawdbot/browser/chrome-extension`
2. Load in Chrome: `chrome://extensions` → Developer mode → Load unpacked
3. Pin the extension to toolbar

**Usage:**
1. Navigate to site in Chrome, make sure you're logged in
2. Click the Clawdbot extension icon (badge shows **ON**)
3. I use `browser(profile="chrome")` to control that tab

**When to use Chrome Relay:**
- X.com (very aggressive bot detection)
- Sites requiring 2FA/login you've already completed
- Anything that blocks headless browsers

#### Headless Chromium (profile="fast") — For general automation
Runs headless with synced cookies from Chrome. Some paranoid sites (X.com) detect and block it.

**Setup script:** `~/clawd/scripts/browser-setup.sh`
```bash
scripts/browser-setup.sh start-login    # Open Chrome, login to sites
scripts/browser-setup.sh sync           # Close Chrome first! Then sync
scripts/browser-setup.sh start-headless # Start headless on port 9223
scripts/browser-setup.sh status         # Check what's running
scripts/browser-setup.sh stop           # Stop all
```

**⚠️ Important:** Close Chrome before running `sync` — copying a live profile invalidates sessions!

**Usage:** `browser(action="...", profile="fast")`

#### Browsing Tips
- Use `web_fetch` for simple page reads (faster, cheaper than full browser)
- Use `browser` when you need JavaScript rendering, interactions, or auth
- For large pages, use `maxChars` on snapshots to avoid context bloat
- Keep `targetId` from snapshot responses for stable tab references

### bird (X/Twitter CLI)
- **Wrapper:** `~/clawd/scripts/bird` (sets auth tokens automatically)
- **Config:** `~/.config/bird/config.json5` (tokens stored but not read properly - use wrapper)
- **Usage:** `~/clawd/scripts/bird read <tweet-id>` or `bird read <url>`
- **Commands:** `bird search`, `bird home`, `bird mentions`, `bird news`, `bird user-tweets @handle`
- **For X.com access** — use bird instead of browser (faster, no bot detection issues)
- **Auth:** Using @johanjongsma account

### Proton Mail Bridge (Headless)
- **Service:** `systemctl --user status protonmail-bridge`
- **Account:** tj@jongsma.me (Tanya & Johan Jongsma)
- **IMAP:** 127.0.0.1:1143 (STARTTLS)
- **SMTP:** 127.0.0.1:1025 (STARTTLS)
- **Bridge Password:** BlcMCKtNDfqv0cq1LmGR9g
- **Keychain:** `pass` (no gnome-keyring needed)
- **Config:** `~/.config/protonmail/bridge-v3/prefs.json` → `{"preferred_keychain": "pass"}`

### Message Bridge (WhatsApp backend) - whatsmeow
- **Service:** `systemctl --user status message-bridge`
- **Port:** 8030
- **Source:** `/home/johan/dev/message-bridge/`
- **Data:** `~/.message-bridge/`
- **Linked Number:** +1 727 225 2475 (Johan's ThinkPhone)
- **Note:** MC wraps this — use MC API for WhatsApp, not this directly

**Direct API (for debugging):**
- `GET /status` - connection status
- `GET /messages` - list messages
- `GET /qr?format=png` - QR code for linking (if disconnected)
- `POST /send` - send message

### Message Center (MC) - Unified Messaging API
- **Service:** `systemctl --user status mail-bridge`
- **Port:** 8025
- **Source:** `/home/johan/dev/mail-bridge/` (branch: mc-unified)
- **Data:** `~/.message-center/` (cursors.json, orchestration.db)
- **Health:** `curl http://localhost:8025/health`

**Connectors:**
- `tj_jongsma_me` — IMAP (tj@jongsma.me via Proton Bridge)
- `johan_jongsma_me` — IMAP (johan@jongsma.me via Proton Bridge)
- `whatsapp` — HTTP wrapper for message-bridge on port 8030

**Unified API:**
- `GET /messages/new` — unseen messages from all sources
- `GET /messages?since=24h` — replay window
- `GET /messages/{id}` — single message
- `POST /messages/ack` — advance consumer cursor

**Actions:**
- `POST /messages/{id}/archive` — mark seen/archive
- `POST /messages/{id}/delete` — delete message
- `POST /messages/{id}/reply` — send reply `{"body": "..."}`
- `POST /messages/{id}/to-docs` — forward attachments to ~/documents/inbox/

**Orchestration DB:** `~/.message-center/orchestration.db`
- Tracks: first_seen, last_action, acked_by per message
- Actions persist across restarts

**Webhook:** POSTs `{"event": "new"}` to `http://localhost:18789/hooks/messages`

### Commands
- `/screenshot` → Pull latest screenshot from Mac desktop (uses screenshot skill)

## Why Separate?

Skills are shared. Your setup is yours. Keeping them apart means you can update skills without losing your notes, and share skills without leaking your infrastructure.

---

Add whatever helps you do your job. This is your cheat sheet.

### Govee H5122 Buttons
- **Button 1:** `event.gv5122775b_button_1` (MAC: D2:2D:83:86:77:5B)
  - **Automation:** `automation.govee_button_mbed_pendants_toggle` → toggles `switch.mbed_pendants`
- **Button 2:** `event.gv51222839_button_1` (MAC: D2:2D:80:C6:28:39) — Office
  - **Automation:** `automation.govee_button_2_suction_machine` → toggles suction machine
- **Pairing:** Hold 5 sec (LED flashes), press once to broadcast, add from HA UI quickly
- **Note:** BLE proxy must be enabled on nearby Athom sensor (Office1 b372f4 has it now)
