Docs

Generator

hlpd_generator reads an app's source, drives its UI and builds a help bundle: topics, Show me and Guide me walkthroughs with narration, captioned videos and an on-device search index.

Set up

Shell
cd generator
uv venv -p 3.12 .venv && VIRTUAL_ENV=.venv uv pip install -r requirements.txt

Settings come from the environment, .env or ~/.env:

VariablePurpose
LLM_BASE_URL, LLM_API_KEY, LLM_MODELThe language model gateway that writes topics and scripts
OPENROUTER_API_KEYNarration audio. Or set GEMINI_API_KEY with HLPD_TTS_PROVIDER=gemini
HLPD_IOS_SIMULATORThe simulator used to record iOS walkthroughs
HLPD_EMBEDDING_MODELThe search embedding model, minishlab/potion-retrieval-32M by default
HLPD_API_URLThe hlpd API used by publish, https://api.hlpd.uk by default

The other HLPD_* settings are in hlpd_generator/config.py.

Generate

Shell
.venv/bin/python -m hlpd_generator generate ~/Code/drink_ios --platform ios --out /tmp/hlpd/drink

Stages run in order, and each skips work whose outputs already exist:

StageWhat it does
analyzeBuilds a product model of the app from its source
outlinePlans categories and topics, and which topics can have an in-app walkthrough
docsWrites each topic in Markdown
enrichGives each topic more ways to be found, and held-out queries that measure search
scriptsWrites a step script for each topic with a feasible walkthrough
translateLocalises the help into the app's own locales
narrateSpeaks each step's narration and converts it to AAC
walkthroughCompiles the steps into bounded, declarative in-app walkthroughs
recordRuns each script through the platform driver and records the screen
reviewChecks narration against the recorded screen and corrects it
renderTurns recordings into captioned videos with poster frames
bundleAssembles the bundle and checks it
  • --stage <name> --force redoes one stage.
  • --only id,... limits per-topic work to the listed topics.
  • --languages es,fr overrides the translated locales.
  • --gaps queries.json assigns unanswered user queries to topics.

Recording uses the iOS simulator and the HlpdDriver UI-test runner from the iOS SDK. The finished bundle is in <out>/bundle.

Edit and reindex

After editing topics by hand, rebuild search, embeddings, suggestion thresholds and the manifest's files inventory:

Shell
.venv/bin/python -m hlpd_generator reindex /tmp/hlpd/drink/bundle

Publish

Shell
HLPD_EMAIL=me@example.com HLPD_PASSWORD=... \
  .venv/bin/python -m hlpd_generator publish /tmp/hlpd/drink/bundle --project brp_...

publish validates the bundle, uploads it as a gzipped tar to POST /admin/api/projects/<project>/bundles and prints the result. It uses the owner session in HLPD_TOKEN, or opens one with HLPD_EMAIL and HLPD_PASSWORD and closes it afterwards. --api URL overrides HLPD_API_URL, and --draft uploads without making the bundle live.

Bundle layout

Text
HlpdBundle/
  manifest.json
  topics/<topic-id>.md
  walkthroughs/<topic-id>.json    declarative in-app walkthrough
  audio/<topic-id>/<step-id>.m4a  pre-generated AAC narration
  videos/<topic-id>.mp4           rendered walkthrough video
  videos/<topic-id>.vtt           captions, one cue per step
  images/<topic-id>/1.png         video poster frame
  search.json                     precomputed inverted index
  embeddings/                     static embedding model and chunk vectors

manifest.json describes the product, categories and topics, and ends with a files inventory holding the SHA-256 and size of every other file. Validation requires the inventory to match the directory exactly, and over-the-air updates use it to fetch only the changed files. An abridged manifest:

JSON
{
  "schema": 1,
  "bundleId": "drink-ios",
  "version": "2026.10.12-1",
  "product": { "name": "Drink", "platform": "ios", "appBundleId": "uk.ph1l.drink", "appVersion": "1.4.0" },
  "categories": [{ "id": "getting-started", "title": "Getting started", "order": 1 }],
  "topics": [{
    "id": "log-a-drink",
    "title": "Log a drink",
    "summary": "Record a glass of water from the home screen.",
    "category": "getting-started",
    "doc": "topics/log-a-drink.md",
    "walkthrough": "walkthroughs/log-a-drink.json"
  }],
  "files": { "topics/log-a-drink.md": { "sha256": "9f2c…", "bytes": 812 } }
}