Documentation

Build, run, and architecture

Everything needed to run the engine scaffold locally and understand how the pieces fit. The API section is rendered from a service-produced config — the site does not author it.

Building, testing, running

The engine is a Poetry package at services/engine, targeting Python 3.14, with code under src/. A scaffold exists: structure, interfaces, and the API are in place, but each engine’s run method raises NotImplementedError (surfaced as HTTP 501) until that engine is built.

From services/engine:

  • Install dependencies: poetry install
  • Run the API and MCP server: poetry run optival-engine — serves http://localhost:8000; OpenAPI docs at /docs; MCP at /mcp
  • Run the full test suite: poetry run pytest
  • Run a single test: poetry run pytest tests/test_smoke.py::test_health
  • Lint and type-check: poetry run ruff check . and poetry run mypy src

To run in containers, services/docker-compose.yml is the single entry point for the platform: from services, docker compose up --build builds and starts the engine on a shared optival network.

Architecture

The code lives in services/engine/src as four modules: core plus one per engine — audit, diagnosis, generation.

The core module provides everything the engines share. Its library part — contracts (typed models engines exchange), meta (the YAML meta schema), providers (the provider interface), and config — holds no business logic; it provides capability. Its shell part (core/app.py, core/schemas.py) is the composition root: it assembles each engine’s HTTP router into one FastAPI app, defines the end-to-end /pipeline, and mounts the MCP server.

The LLM layer composes three libraries: DSPy for typed signatures and modules, LiteLLM beneath it for unified multi-provider access, and Pydantic for the type system and YAML meta schema. Each engine owns one domain responsibility and depends only on the core’s library — never on another engine’s internals.

The provider interface

The provider interface abstracts over two heterogeneous access modes. Most providers are LLM APIs reached through DSPy/LiteLLM. But Google AI Overviews has no LLM API — it appears inside Google Search results and is captured by SERP scraping or browser automation. The interface hides which a provider is, and the audit engine treats both uniformly. The active provider set is configurable per run.

ChatGPTLLM API PerplexityLLM API Google AI Overviewssearch-surface capture Ollamalocal — plumbing only LM Studiolocal — plumbing only

Local providers exercise the pipeline without paid API calls; their answers have no relationship to how real consumer engines cite brands, so local runs validate plumbing, never measurement.

The YAML meta

The generation engine emits the meta as a schema-governed YAML document — an engine-neutral optimization spec, not the on-page format. The artifacts it describes have canonical web formats (llms.txt is markdown, schema markup is JSON-LD, titles and descriptions are HTML tags); serializing each field into its canonical form happens at render time, which is the v1 content engine’s job. In v0 the deliverable is the YAML meta itself.

API & MCP

Awaiting service config The API reference is not authored by this website. Each service exports its own API/MCP configuration, and the site renders it from _data/api.yml. Once a service populates that file, this section fills in automatically — no website change required.