cli/cmd/core-app/CODEX_PROMPT.md
Snider 1e2e8e9c11 chore: migrate forge.lthn.ai → forge.lthn.io
Update Forgejo domain references in CI pipeline, vanity import
tool, and core-app codex prompt.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-16 05:53:52 +00:00

5 KiB

Codex Task: Core App — FrankenPHP Native Desktop App

Context

You are working on cmd/core-app/ inside the host-uk/core Go monorepo. This is a working native desktop application that embeds the PHP runtime (FrankenPHP) inside a Wails v3 window. A single 53MB binary runs Laravel 12 with Livewire 4, Octane worker mode, and SQLite — no Docker, no php-fpm, no nginx, no external dependencies.

It already builds and runs. Your job is to refine, not rebuild.

Architecture

Wails v3 WebView (native window)
    |
    | AssetOptions.Handler → http.Handler
    v
FrankenPHP (CGO, PHP 8.4 ZTS runtime)
    |
    | ServeHTTP() → Laravel public/index.php
    v
Laravel 12 (Octane worker mode, 2 workers)
    ├── Livewire 4 (server-rendered reactivity)
    ├── SQLite (~/Library/Application Support/core-app/)
    └── Native Bridge (localhost HTTP API for PHP→Go calls)

Key Files

File Purpose
main.go Wails app entry, system tray, window config
handler.go PHPHandler — FrankenPHP init, Octane worker mode, try_files URL resolution
embed.go //go:embed all:laravel + extraction to temp dir
env.go Persistent data dir, .env generation, APP_KEY management
app_service.go Wails service bindings (version, data dir, window management)
native_bridge.go PHP→Go HTTP bridge on localhost (random port)
laravel/ Full Laravel 12 skeleton (vendor excluded from git, built via composer install)

Build Requirements

  • PHP 8.4 ZTS: brew install shivammathur/php/php@8.4-zts
  • Go 1.25+ with CGO enabled
  • Build tags: -tags nowatcher (FrankenPHP's watcher needs libwatcher-c, skip it)
  • ZTS php-config: Must use /opt/homebrew/opt/php@8.4-zts/bin/php-config (NOT the default php-config which may point to non-ZTS PHP)
# Install Laravel deps (one-time)
cd laravel && composer install --no-dev --optimize-autoloader

# Build
ZTS_PHP_CONFIG=/opt/homebrew/opt/php@8.4-zts/bin/php-config
CGO_ENABLED=1 \
CGO_CFLAGS="$($ZTS_PHP_CONFIG --includes)" \
CGO_LDFLAGS="-L/opt/homebrew/opt/php@8.4-zts/lib $($ZTS_PHP_CONFIG --ldflags) $($ZTS_PHP_CONFIG --libs)" \
go build -tags nowatcher -o ../../bin/core-app .

Known Patterns & Gotchas

  1. FrankenPHP can't serve from embed.FS — must extract to temp dir, symlink storage/ to persistent data dir
  2. WithWorkers API (v1.5.0): WithWorkers(name, fileName string, num int, env map[string]string, watch []string) — 5 positional args, NOT variadic
  3. Worker mode needs Octane: Workers point at vendor/laravel/octane/bin/frankenphp-worker.php with APP_BASE_PATH and FRANKENPHP_WORKER=1 env vars
  4. Paths with spaces: macOS ~/Library/Application Support/ has a space — ALL .env values with paths MUST be quoted
  5. URL resolution: FrankenPHP doesn't auto-resolve //index.php — the Go handler implements try_files logic
  6. Auto-migration: AppServiceProvider::boot() runs migrate --force wrapped in try/catch (must not fail during composer operations)
  7. Vendor dir: Excluded from git (.gitignore), built at dev time via composer install, embedded by //go:embed all:laravel at build time

Coding Standards

  • UK English: colour, organisation, centre
  • PHP: declare(strict_types=1) in every file, full type hints, PSR-12 via Pint
  • Go: Standard Go conventions, error wrapping with fmt.Errorf("context: %w", err)
  • License: EUPL-1.2
  • Testing: Pest syntax for PHP (not PHPUnit)

Tasks for Codex

Priority 1: Code Quality

  • Review all Go files for error handling consistency
  • Ensure handler.go's try_files logic handles edge cases (double slashes, encoded paths, path traversal)
  • Add Go tests for PHPHandler URL resolution (unit tests, no FrankenPHP needed)
  • Add Go tests for env.go (resolveDataDir, writeEnvFile, loadOrGenerateAppKey)

Priority 2: Laravel Polish

  • Add config/octane.php with FrankenPHP server config
  • Update welcome view to show migration status (table count from SQLite)
  • Add a second Livewire component (e.g., todo list) to prove full CRUD with SQLite
  • Add proper error page views (404, 500) styled to match the dark theme

Priority 3: Build Hardening

  • Verify the Taskfile.yml tasks work end-to-end (task app:setup && task app:composer && task app:build)
  • Add .gitignore entries for build artifacts (bin/core-app, temp dirs)
  • Ensure go.work and go.mod are consistent

CRITICAL WARNINGS

  • DO NOT push to GitHub — GitHub remotes have been removed deliberately. The host-uk org is flagged.
  • DO NOT add GitHub as a remote — Forge (forge.lthn.io / git.lthn.ai) is the source of truth.
  • DO NOT modify files outside cmd/core-app/ — This is a workspace module, keep changes scoped.
  • DO NOT remove the -tags nowatcher build flag — It will fail without libwatcher-c.
  • DO NOT change the PHP-ZTS path — It must be the ZTS variant, not the default Homebrew PHP.