🧠 omp Integration

This is the load-bearing page for Prompt Wizard. All text and image generation goes through the locally installed omp binary using the user’s configured omp model roles and settings. The app must not add provider SDKs, API keys, direct provider endpoints, or app-level model selection.

Non-negotiable invariants

  • binary:
    • default: resolve omp from the service PATH
    • override: OMP_BIN
    • never import the stale source checkout
  • model:
    • do not pass --model
    • omission is intentional
    • the configured default role in the user’s omp config selects provider and model
  • process context:
    • run in data/omp-scratch
    • pass --cwd data/omp-scratch
    • disable sessions, skills, rules, extensions, LSP, and title updates
    • text mode also disables tools
  • stdin:
    • must be ignored
    • inherited or piped-but-open stdin can hang print mode without a TTY
  • output parsing:
    • read stdout only for completion payloads
    • log stderr but do not parse it as data
    • stderr can contain routine status notes such as print-mode startup warnings and progress text
  • concurrency:
    • module semaphore: maximum two concurrent omp child processes
    • later requests wait in queue
  • timeout:
    • text: 240 seconds
    • image: 420 seconds
    • timeout kills the process tree and returns gateway timeout

Text command

ompText({ system, messages, json }) writes the system prompt to a temporary file, normalizes messages into one user prompt, and runs print mode.

omp -p \
  --no-session \
  --no-tools \
  --no-skills \
  --no-rules \
  --no-extensions \
  --no-lsp \
  --no-title \
  --cwd data/omp-scratch \
  --system-prompt data/omp-scratch/.omp-system-prompt-<uuid>.txt \
  '<user message>'
  • message flattening:
    • one turn: role: content
    • multiple turns:
      • ### Previous turns
      • prior role: content lines
      • ### Current request
      • final role: content
  • JSON mode:
    • system prompt appends: Respond with ONLY a single valid JSON object. No prose, no explanation, no markdown code fences.
    • leading JSON code fences are stripped defensively
    • response is parsed with JSON.parse
    • invalid JSON retries once with a stricter repair instruction
    • second parse failure returns a 502 and exposes raw text for debugging
  • non-JSON mode:
    • response content is trimmed stdout
  • measured contract from plan:
    • small text generation: approximately 18 to 21 seconds

Image command

ompImage({ subject, aspectRatio }) enables the generate_image tool for this run only. The user’s global omp config is not edited.

generate_image:
  enabled: true
omp --mode json \
  --no-session \
  --no-skills \
  --no-rules \
  --no-extensions \
  --no-lsp \
  --no-title \
  --auto-approve \
  --cwd data/omp-scratch \
  --config server/omp-image-overlay.yml \
  --tools generate_image \
  --system-prompt data/omp-scratch/.omp-system-prompt-<uuid>.txt \
  '<subject>'

System prompt:

You generate images. Call the generate_image tool exactly once, using the user message as the subject. Then reply with only DONE.
  • allowed aspect ratios:
    • 1:1
    • 3:4
    • 4:3
    • 9:16
    • 16:9
  • compatibility mapping:
    • archive square maps to 1:1
  • subject shaping:
    • append Aspect ratio: <value>. to the subject text
  • approval boundary:
    • --auto-approve is acceptable because --tools generate_image restricts the session to the one image tool
  • measured contract from plan:
    • verified image run: approximately 43 seconds
    • provider: openai-codex
    • model: gpt-5.6-sol
    • output: non-empty WebP copied into data/uploads/

JSONL image event contract

The image command emits JSONL on stdout. The bridge scans events until it finds the tool completion event.

{
  "type": "tool_execution_end",
  "toolName": "generate_image",
  "result": {
    "details": {
      "imagePaths": ["<temporary-webp-path>"],
      "provider": "openai-codex",
      "model": "gpt-5.6-sol"
    }
  }
}
  • required fields:
    • type === "tool_execution_end"
    • toolName === "generate_image"
    • result.details.imagePaths[0]
    • result.details.provider
    • result.details.model
  • file handling:
    • copy the temporary WebP to data/uploads/<uuid>.webp
    • return /uploads/<uuid>.webp
  • retry behavior:
    • if no usable image event exists, retry once
    • after the retry, return 502 with captured output context

API bridge

  • POST /api/ai/text:
    • body: { system, messages, json, kind, templateKey }
    • response: { content }
    • logs kind, template_key, system_prompt, user_message, and response_json
  • POST /api/ai/image:
    • body: { subject, aspectRatio, kind }
    • response: { url, provider, model }
    • logs outcome through the same server-side logging path

Fidelity gaps versus archive behavior

  • temperature and max tokens:
    • archive calls supplied temperature and max_tokens
    • installed omp CLI has no such flags
    • the port does not fake them
    • intent is encoded in the system prompt when needed:
      • enhancement: precise and conservative wording
      • idea generation: inventive and varied wording
      • Mermaid: strict syntax and no improvisation
  • wizard transparency:
    • archive requested transparent wizard avatars
    • generate_image exposes no transparency parameter
    • verified image output used a solid background
    • UI compensation is a circular mask with object-fit cover for wizard images

Failure policy

  • text generation failure:
    • non-zero omp exit returns 502
    • invalid JSON after retry returns 502
    • timeout returns 504
  • image generation failure:
    • invalid ratio returns 400
    • non-zero omp exit returns 502
    • missing image event after retry returns 502
    • timeout returns 504
  • no fabricated successes:
    • archive fallback behavior could invent a fake project on JSON failure
    • local bridge fails loudly instead

See api for route details and verification for live smoke checks.