Preview — /opt/jfmsrv01/scripts/HANDOVER.md

/opt/jfmsrv01/scripts/HANDOVER.md

# jfmsrv01 — Generic Web Hosting / AI / Transcription Server Handover

Last updated: 2026-05-30  
Server: jfmsrv01  
Internal IP: 192.168.100.197  
External IP: 103.138.201.66  
Timezone: Australia/Perth  

## Current workflow

Use the generic server workflow:

- /opt/jfmsrv01/scripts/HANDOVER.md
- /opt/jfmsrv01/scripts/CHANGELOG.md
- /opt/jfmsrv01/scripts/RULES.md
- /opt/jfmsrv01/scripts/publish_handoff.sh

Old /opt/legaltranscribe/scripts/ paths are stale historical references.

## Public handoff

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/server/HANDOVER.html

Internal legacy handoff:

- http://192.168.100.197:9002/vqngx6j8dc9q1lvt7g2a7a646q2t/

## Projects

### Mainsite

- URL: http://192.168.100.197/
- App path: /var/www/mainsite
- Stack: Statamic / Laravel 13 / PHP 8.3-FPM
- Nginx: /etc/nginx/sites-available/mainsite

### Admin

- URL: http://192.168.100.197:8080/admin
- App path: /var/www/admin
- Stack: Filament / Laravel 13 / PHP 8.3-FPM
- Nginx: /etc/nginx/sites-available/admin

### GoSeek AI Workbench

- URL: http://192.168.100.197:8090/admin
- Chat: http://192.168.100.197:8090/admin/chat
- AI Providers: http://192.168.100.197:8090/admin/ai-providers
- App path: /var/www/goseek
- Stack: Filament / Laravel 13 / PHP 8.3-FPM
- Nginx: /etc/nginx/sites-available/goseek

Important GoSeek files:

- app/Models/AiProvider.php
- app/Filament/Resources/AiProviderResource.php
- app/Services/GoSeek/ProviderRouter.php
- app/Services/GoSeek/ChatService.php
- app/Services/GoSeek/ToolEngine.php
- app/Http/Controllers/Api/ChatController.php
- resources/views/filament/pages/chat.blade.php
- resources/views/chat.blade.php

Provider rules:

- Ollama is the only local provider.
- OpenAI, Anthropic, Google, Deepseek, Kimi, Groq, Mistral, xAI and Cohere are cloud providers.
- API keys must be stored encrypted.
- API keys must never be printed in logs, handover files, source browsers, shell history, or chat.

## Handoff portal

- Path: /var/www/handoff
- Public root: /var/www/handoff/public
- Canonical folder: /var/www/handoff/public/vqngx6j8dc9q1lvt7g2a7a646q2t
- Nginx: /etc/nginx/sites-available/handoff and /etc/nginx/sites-available/handoff-public-ssl

## Rules

- Use heredoc-to-file scripts for patches.
- Back up files before editing.
- Repair broken patches in place by default.
- Roll back only for outage recovery or high-risk repair.
- Update HANDOVER.md and CHANGELOG.md after changes.
- Publish handoff after meaningful changes.
[REDACTED SECRET-LIKE LINE]

## Public source browser note

The public source browsers are enabled temporarily so ChatGPT can inspect first-party PHP code. Disable or restrict them when not actively needed.

---

## Update - 2026-05-30 - Fresh handoff run workflow

A cache-busting handoff publish wrapper now exists:

- /opt/jfmsrv01/scripts/publish_fresh_handoff_run.sh

Use this when files need to be re-read regularly by ChatGPT or browsers. It creates:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/<timestamp>/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/<timestamp>/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/<timestamp>/source/goseek/index.html

The non-slug alias /server/HANDOVER.html is now routed to the current canonical slug tree to avoid stale root-level files.

---

## Fresh handoff run - 20260530-160357

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260530-160357/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260530-160357/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260530-160357/source/goseek/index.html

---

## Update - 2026-06-02: AI Gateway + GoSeek Enhancements

### New: llmgateway — AI Gateway Server

- **VM:** llmgateway on ESXi (snapshot taken)
- **OS:** Ubuntu 24.04.4 LTS
- **IP:** 192.168.100.110
- **Purpose:** Centralised AI gateway — all model API traffic routes through here
- **App:** /var/www/gateway (Laravel, Filament admin)
- **DB:** gateway (PostgreSQL, on llmgateway)
- **Port:** 8095 (internal, ufw allows from 192.168.100.0/24)
- **Admin:** http://192.168.100.110:8095/admin
- **API:** POST http://192.168.100.110:8095/v1/chat/completions
- **Login:** see panel (user created via make:filament-user)

**What it does:**
[REDACTED SECRET-LIKE LINE]
- Resolves requested model → provider, decrypts stored API key
- Evaluates request against immutable rules then DB rules then default-allow
[REDACTED SECRET-LIKE LINE]
- Returns OpenAI-shaped response to client
- Fail-closed: any engine/DB error → deny

**Key files on llmgateway:**
| Path | Purpose |
|------|---------|
| /var/www/gateway/ | Laravel gateway application |
| /var/www/gateway/.env | App config (never share) |
| /etc/gateway/rules.immutable.php | Immutable rules (root-owned, gateway can read not write) |
[REDACTED SECRET-LIKE LINE]
| /etc/nginx/sites-available/gateway | Nginx vhost |

**Providers configured (keys via admin UI):**
- Ollama (local, disabled — shelved until GPU)
- DeepSeek (tier 3) — deepseek-v4-flash, deepseek-v4-pro, deepseek-chat, deepseek-reasoner
- OpenAI (tier 2) — gpt-4o, gpt-4o-mini
- Anthropic (tier 2) — claude-sonnet-4-6, claude-haiku-4-5, claude-opus-4-8 (adapter needed)
- Groq (tier 3) — llama-3.3-70b-versatile, llama-3.1-8b-instant
- Google (tier 2) — gemini-2.5-flash
- Kimi/Moonshot (tier 3) — kimi-k2.6, kimi-k2.5

**Admin panel sections:**
- Spend dashboard (cost by client/provider/model/day + recent requests)
- Providers (add/edit/delete, encrypted key storage)
[REDACTED SECRET-LIKE LINE]
[REDACTED SECRET-LIKE LINE]
- Rules (condition→action, priority-ordered, editable)
- Budgets (global or per-client, daily/monthly, deny or hold on exceed)

---

### Updated: GoSeek AI Workbench

**New tools added to ToolEngine (16+ total):**
- ssh_exec — run commands on llmgateway (locked to one host via /etc/goseek/build_target.php)
- clone_website — mirror a website (quick=wget, deep=httrack), browser UA
- scan_site — crawl local clone, report broken links and missing resources
- fix_site_links — bulk find-and-replace across HTML/CSS/JS in a cloned site
- serve_site — create nginx vhost for a cloned site on a domain/port

**New admin pages:**
- Tools — lists all tools with descriptions, call counts, success rates, last used
- Sites Manager — full site management UI:
  - Quick Clone (wget, fast)
  - Deep Clone (httrack, thorough)
  - AI Clone (clones then AI-fixes each page through the gateway)
  - Scan (broken link report)
  - Auto Fix (downloads missing resources)
  - Manual Fix (find-and-replace)
  - Serve (nginx vhost, go live)
  - Preview (opens on :9090)
  - Delete

**GoSeek → Gateway routing:**
- Gateway provider added in GoSeek AI Providers (slug: gateway)
- base_url: http://192.168.100.110:8095 (GoSeek adds /v1/chat/completions)
- API key: [REDACTED]
- All AI requests can now route through the gateway (metered + governed)

**Key files on jfmsrv01:**
| Path | Purpose |
|------|---------|
| /etc/goseek/build_target.php | SSH build target config (root-owned) |
| /etc/goseek/build_id_ed25519 | Build SSH key (www-data-owned, 600) |
| /etc/goseek/known_hosts | SSH known hosts for build target |
| /etc/sudoers.d/020-goseek-nginx | Narrow sudo for serve_site nginx ops |
| /var/www/sites/ | Cloned website storage |
| /etc/nginx/sites-available/sites-preview | Preview vhost on port 9090 |

---

### Cutover status (Phase 10 — partially complete)

- [x] Gateway built and tested end-to-end
- [x] GoSeek gateway provider configured and working
- [x] Requests route through gateway and appear on Spend dashboard
- [ ] GoSeek direct providers not yet disabled
- [ ] Untangle egress lock not yet configured
[REDACTED SECRET-LIKE LINE]
- [ ] Builder sudo on llmgateway to be tightened

---

### Next session priorities

1. Complete cutover: disable direct providers, lock Untangle egress
[REDACTED SECRET-LIKE LINE]
3. Tighten builder sudo on llmgateway
4. WordPress backup import feature
5. Hosting packages (domains, SSL, databases, email)
6. Anthropic adapter for gateway
7. Streaming support on gateway endpoint
8. Fix GoSeek models_json UI field
9. GoSeek ToolEngine input validation (arg-name normalization)
10. Budget daily-reset mechanism

---

## Fresh handoff run - 20260602-084132

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260602-084132/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260602-084132/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260602-084132/source/goseek/index.html

---

## Fresh handoff run - 20260602-144040

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260602-144040/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260602-144040/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260602-144040/source/goseek/index.html

---

## Update - 2026-06-02 (PM): GoSeek AI site editing + handover source fix

- Handover now self-updates GoSeek source: publish_goseek_source.sh regenerates
  source/goseek from the live app on every fresh run. Use the latest /runs/<id>/ URL.
- GoSeek can bulk-edit cloned sites via the gateway (ai_edit_site / restore_site_backup,
  plus the Sites Manager "AI Edit" panel). Gateway endpoint is /v1/chat/completions.
- OPEN: backups should move out of /var/www/sites; AI editing is single-shot and needs an
  agentic loop for structural changes. See CHANGELOG known-issues.

---

## Update - 2026-06-03: GoSeek is now an agentic system

GoSeek can run multi-step tasks autonomously and durably.

**How a chat task runs now**
1. UI posts to /chat-api/conversations/{id}/chat-async -> creates an AgentRun (queued).
2. RunAgentJob (on the 'agent' queue) runs the bounded agent loop in the worker.
3. UI polls /chat-api/runs/{id}; tool steps stream in, then the final answer.

**Pieces**
- app/Services/GoSeek/ChatService.php  -> runAgent() loop + runForAgentRun()
- app/Jobs/RunAgentJob.php             -> queued execution
- app/Models/AgentRun.php + agent_runs -> run state / progress
- config/queue.php 'agent' connection  -> retry_after 3600
- goseek-agent-worker.service          -> the worker (systemd)

**Runbook**
- Worker MUST be running for chat to work: systemctl status goseek-agent-worker
- After editing GoSeek PHP: systemctl restart goseek-agent-worker (else stale code).
- Logs: journalctl -u goseek-agent-worker -f
- Step cap: config goseek.agent_max_steps (env GOSEEK_AGENT_MAX_STEPS), default 8.

---

## Fresh handoff run - 20260603-125356

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-125356/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-125356/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-125356/source/goseek/index.html

## Update - 2026-06-03: step-cap env knob fixed
config/goseek.php was missing the 'agent_max_steps' key, so GOSEEK_AGENT_MAX_STEPS in .env
had no effect (cap always defaulted to 8). Added 'agent_max_steps' => (int) env('GOSEEK_AGENT_MAX_STEPS', 8).
The runbook line "raise the step budget via GOSEEK_AGENT_MAX_STEPS" is now accurate. Worker restarted.

---

## Fresh handoff run - 20260603-135253

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-135253/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-135253/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-135253/source/goseek/index.html

## Update - 2026-06-03 23:04 AWST: GoSeek chat full-width fix
GoSeek chat page now fills the viewport. Its full-screen styles zeroed padding and set
height but never overrode Filament's max content width, so the workbench rendered in a
centred column. Added a width override in resources/views/filament/pages/chat.blade.php
(marker: goseek-fullwidth-fix). Blade-only; view cache cleared; no worker restart needed.

---

## Fresh handoff run - 20260603-230421

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-230421/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-230421/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-230421/source/goseek/index.html

## Update - 2026-06-03 23:10 AWST: GoSeek full-screen launcher
Added a "Full screen" link in the Filament chat topbar that opens the standalone
full-browser chat at /chat (routes/web.php -> view('chat'), no admin shell).
OPEN: /chat's sendMessage() still calls the synchronous /chat endpoint, not the
/chat-async agent flow - long agentic tasks can time out there and step progress
is not shown. Next step: port /chat JS to gsSend/gsPollRun async flow.

---

## Fresh handoff run - 20260603-231049

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-231049/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-231049/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-231049/source/goseek/index.html

## Update - 2026-06-03 23:33 AWST: GoSeek /chat now uses the async agent flow
The standalone full-screen chat (/chat) now drives the durable agent loop like the
Filament page: POST /chat-async -> poll /runs/{id}, with live step labels. This closes
the earlier gap where /chat used the synchronous endpoint and could time out on long tasks.

---

## Fresh handoff run - 20260603-233326

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-233326/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-233326/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-233326/source/goseek/index.html

## Update - 2026-06-03 23:33 AWST: Internal quick-links dashboard
Added http://192.168.100.197:8090/links (GoSeek route /links -> view('links')) as a
LAN service launcher. Edit the cards in resources/views/links.blade.php. It is open
(no auth) and lists internal URLs + the handoff slug, so keep it LAN-only.

---

## Fresh handoff run - 20260603-233345

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-233345/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-233345/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260603-233345/source/goseek/index.html

## Update - 2026-06-04 01:37 AWST: GoSeek delete chats
The /chat sidebar now has a hover delete (x) per conversation, calling the existing
soft-delete endpoint. Deleted chats leave the list but remain in the DB (deleted_at set),
so they can be restored with a query if needed. The Filament chat page can get the same
treatment on request.

---

## Fresh handoff run - 20260604-013743

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-013743/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-013743/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-013743/source/goseek/index.html

## Update - 2026-06-04 01:50 AWST: GoSeek website orchestration
GoSeek can now build sites from scratch on the isolated build VM and publish them.
New tools: vm_write_file, publish_build. The agent scaffolds/builds via ssh_exec in
/srv/goseek-builds/<slug>, then publish_build rsyncs the static output to
/var/www/sites/<slug> and serves it (existing nginx sudo path). Note: full builds can
exceed GOSEEK_AGENT_MAX_STEPS - raise it in .env if multi-step builds get truncated.
Assumes the build VM has the needed toolchain (node/composer/git/rsync) - the agent
probes first. Untangle egress lock still pending (handover open item).

---

## Fresh handoff run - 20260604-015013

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-015013/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-015013/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-015013/source/goseek/index.html

## Update - 2026-06-04 01:51 AWST: GoSeek Projects backend
Projects are now a real table; conversations.project_id links them (legacy 'project'
string retained). API: GET/POST/PATCH/DELETE /chat-api/projects. Website projects carry
a workspace_path on the build VM, which the orchestration tools use. NEXT: project
switcher UI in resources/views/chat.blade.php.

---

## Fresh handoff run - 20260604-015132

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-015132/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-015132/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-015132/source/goseek/index.html

## Update - 2026-06-04 01:51 AWST: GoSeek website orchestration
GoSeek can now build sites from scratch on the isolated build VM and publish them.
New tools: vm_write_file, publish_build. The agent scaffolds/builds via ssh_exec in
/srv/goseek-builds/<slug>, then publish_build rsyncs the static output to
/var/www/sites/<slug> and serves it (existing nginx sudo path). Note: full builds can
exceed GOSEEK_AGENT_MAX_STEPS - raise it in .env if multi-step builds get truncated.
Assumes the build VM has the needed toolchain (node/composer/git/rsync) - the agent
probes first. Untangle egress lock still pending (handover open item).

---

## Fresh handoff run - 20260604-015159

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-015159/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-015159/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-015159/source/goseek/index.html

## Update - 2026-06-04 02:00 AWST: GoSeek Projects UI
The /chat sidebar now has a project switcher. Select a project to scope its conversations;
the "+" creates a project (chat or website). Website projects mark with a diamond and, on
creation, open a chat with a build prompt prefilled. Completes the Projects feature
(backend + orchestration + UI).

---

## Fresh handoff run - 20260604-020027

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-020027/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-020027/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-020027/source/goseek/index.html

## Update - 2026-06-04 11:31 AWST: GoSeek login redirect fix
Fixed the dead /login redirect in /chat loadProviders() (now /admin/login).

---

## Fresh handoff run - 20260604-113130

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-113130/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-113130/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-113130/source/goseek/index.html

---

## Fresh handoff run - 20260604-121407

Use this unique run URL for ChatGPT/browser inspection to avoid stale cache:

- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-121407/
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-121407/server/HANDOVER.html
- https://vqngx6j8dc9q1lvt7g2a7a646q2t.jfmcommunications.com.au/vqngx6j8dc9q1lvt7g2a7a646q2t/runs/20260604-121407/source/goseek/index.html


<!-- SPLICEVPN-HANDOVER-START -->

## 2026-06-09 — SpliceVPN relay MVP handover

Dedicated SpliceVPN handover has been added.

Source of truth:

- `/opt/splicevpn/HANDOVER.md`
- `/opt/jfmsrv01/scripts/SPLICEVPN_HANDOVER.md`
- Public copy: `server/SPLICEVPN_HANDOVER.html`

Current architecture:

- Hub-and-spoke WireGuard relay MVP.
- Coordinator/control plane, agent/client, and WireGuard hub run on jfmsrv01.
- This is not true peer-to-peer yet.
- Public site wording must say traffic is relayed through the user's own SpliceVPN hub.
- Two-machine overlay ping test is still outstanding.
- Windows ZIP and Linux tarball still need refreshing because they may contain the older agent.
[REDACTED SECRET-LIKE LINE]
- Public handoff site still needs authentication.
<!-- SPLICEVPN-HANDOVER-END -->

## 2026-06-09 — SpliceVPN handoff pack

SpliceVPN has been added as its own handoff pack and public portal section.

Source of truth:

- `/opt/splicevpn/HANDOVER.md`

Published HTML pack:

- `splicevpn/HANDOVER.html`
- `splicevpn/file-tree.html`
- `splicevpn/source-browser.html`
- `splicevpn/downloads.html`
- `splicevpn/service-status.html`

Important note:

- Current MVP is hub-and-spoke WireGuard relay through the user's own SpliceVPN hub.
- It is not full peer-to-peer yet.
- Public wording must not claim traffic never detours or that direct peer-to-peer is already complete.


## 20260609-124454 — Complete fresh handoff V2

Generated controlled complete handoff pack:

- `complete-handoff-v2-20260609-124454/index.html`
- `complete-handoff-v2-20260609-124454/all-links.html`
- `complete-handoff-v2-20260609-124454/new-chat-start.html`
- `complete-handoff-v2-20260609-124454/recent-work-since-20260604.html`

[REDACTED SECRET-LIKE LINE]