AI CLI Integration

How Claude Code CLI and Gemini CLI are invoked for site generation.

Design Philosophy

Hippopotamoose does not call the Claude or Gemini APIs directly. Instead, it spawns the official CLI tools in separate, visible terminal windows. This design has several advantages:

The Launcher Chain

ai_launcher.py → reads USE_GEMINI_CLI from registry → calls claude_launcher.py or gemini_launcher.py

Claude Launcher

File: core/claude_launcher.py

Why a Temp File for the Prompt?

Windows has a maximum command-line length of ~32,000 characters. Demo prompts routinely exceed this (they include full site file listings). Passing the prompt via a temporary file avoids this limit entirely.

Process

  1. Prompt string is written to data/temp/tmpXXXXXX.txt (unique filename per invocation).
  2. A PowerShell command is assembled:
    Set-Location '<working_dir>';
    $task = Get-Content -Path '<prompt_file>' -Raw;
    claude --dangerously-skip-permissions --model <model> --effort <effort> $task
  3. subprocess.Popen is called with creationflags=subprocess.CREATE_NEW_CONSOLE and shell=True. This opens a new, independent terminal window.
  4. The flag -NoExit is NOT used — the terminal closes when Claude exits, which is how ProcessMonitor detects completion.
  5. A ProcessMonitor thread is started to watch the process. When it emits finished, the temp file is deleted.

Return Value

Returns a tuple (proc, monitor) where proc is the subprocess.Popen object and monitor is the ProcessMonitor thread. The caller connects to monitor.finished to know when the AI session ends. (The monitor exposes both a finished signal and an on_finished callback, so the PyQt UI and the TUI can both consume it.)

Gemini Launcher

File: core/gemini_launcher.py

Identical structure to claude_launcher but runs:

gemini --yolo $task

The --yolo flag grants the Gemini CLI permission to run tool calls without confirmation prompts, mirroring the behavior of --dangerously-skip-permissions for Claude.

AI Model & Effort Parameters

Both launchers accept use_case and model parameters. ai_launcher.py reads the per-use-case model and effort from the registry before calling the launcher:

Use CaseRegistry Keys
scratchAI_MODEL_SCRATCH, AI_EFFORT_SCRATCH
demoAI_MODEL_DEMO, AI_EFFORT_DEMO
formAI_MODEL_FORM, AI_EFFORT_FORM
reiterateAI_MODEL_REITERATE, AI_EFFORT_REITERATE
seonot user-configurable — always Opus 4.7, max effort

The seo use case powers the SEO window's Enhance to 100% (loop) button (SeoEnhanceWorker). It runs an automated loop: audit the site with the app's own four-category auditors, launch Claude to fix the failing categories, re-audit, and repeat until all four (Technical, Local, AI/GEO, Performance) score 100%. The loop stops at the SEO_MAX_ITERATIONS cap (default 5, configurable in Settings) or early if a pass makes no progress. The deterministic audit — not the model's self-assessment — is the success check. Model and effort come from the registry seo use case (default Opus 4.7, max).

Cold Call — Silent Invocation

The Cold Call step does not open a terminal window. Instead, ColdCallWorker runs Claude with the -p (print) flag for a single-shot, non-interactive response:

claude -p "<contact_extraction_prompt>" \
       --model claude-sonnet-4-6 \
       --effort low

The worker captures stdout directly and parses the JSON response. This is appropriate for cold call because the task is mechanical (extract contacts) and doesn't benefit from the interactive AI tool loop.

Demo Prompt Structure

The Demo prompt instructs the AI to work autonomously through a site rebuild. It includes:

Monitoring Terminal Exit

The pipeline row widget connects to ProcessMonitor.finished(exit_code):

💡

If an AI session fails or produces incorrect output, you can re-run the step by clicking the step cell again. The working directory persists, so the AI can read what was already built and correct it.