Lua AI Documentation Audit
The docs are a Mintlify-built developer site for an agent platform with CLI, SDKs, devices, and a chat widget — but the canonical machine-readable surfaces (OpenAPI spec) and several authoritative pages contradict each other or point to placeholder content, which is exactly the failure mode that breaks AI coding agents trying to integrate.
1. Official OpenAPI spec is a Mintlify plant store sample served over plain HTTP (critical)
Location: https://docs.heylua.ai/api-reference/openapi.json (linked from /llms.txt under "OpenAPI Specs")
Problem: The OpenAPI spec advertised on llms.txt as the canonical machine-readable API contract is the unmodified Mintlify starter:
"title": "OpenAPI Plant Store",
"description": "A sample API that uses a plant store as an example...",
"servers": [ { "url": "http://sandbox.mintlify.com" } ],
"paths": { "/plants": ..., "/plants/{id}": ... }
There are no Lua endpoints. The server URL is http://sandbox.mintlify.com — plain HTTP, not HTTPS.
Consequence: This is the worst possible failure mode for agent ingestion. An AI coding agent (Cursor, Claude Code, Copilot) reading llms.txt will follow the "OpenAPI Specs" link, ingest a plant-store sample, and confidently generate code calling GET /plants against sandbox.mintlify.com — none of which exists in Lua. The http:// scheme also means autogenerated clients will emit insecure URLs by default. Humans notice; agents will silently produce wrong, insecure client code.
The fix: Replace openapi.json with a real spec generated from the Lua API (Agents, AI, Baskets, CDN, Data, etc., which are listed in llms.txt). Set servers[0].url to https://api.heylua.ai (note the scheme). Until that exists, remove the OpenAPI Specs block from llms.txt so agents don't cache the placeholder.
2. llms.txt promises a programmatic API surface that the spec doesn't deliver (critical)
Location: https://docs.heylua.ai/llms.txt
Problem: llms.txt enumerates a rich API surface — Agents, AI, Baskets, CDN, Data, plus CLI commands — and points agents at api-reference/openapi.json for machine-readable access. But the only OpenAPI artifact is the plant store sample (Issue 1), so for every API in llms.txt (e.g. api/agents.md, api/ai.md, api/baskets.md, api/cdn.md, api/data.md) there is no schema, no parameter typing, no auth scheme definition, and no error model that an agent can parse.
Consequence: The whole point of llms.txt is to give agents a manifest of structured docs. Lua's manifest is solid, but the structured payload behind it is prose-only Markdown. Agents must guess request shapes from English descriptions, which is exactly what llms.txt was designed to avoid.
The fix: Either generate per-resource OpenAPI fragments (api/agents.openapi.json, etc.) and link them from llms.txt, or publish a single combined spec covering every resource the docs document. Don't ship the manifest until the schemas exist.
3. Localhost guidance instructs developers to set environment: "production" (critical)
Location: https://docs.heylua.ai/chat-widget/installation
Problem: The widget refuses to load on un-whitelisted domains, and localhost cannot be whitelisted. The documented workaround is:
"Testing on localhost?
localhostcannot be whitelisted. You must pass your config inline and setenvironment: "production"explicitly — this bypasses the domain whitelist check so the widget loads during local development"
window.LuaPop.init({
agentId: "your-agent-id",
environment: "production"
});
Consequence: The docs are telling developers to label local dev traffic as production to bypass a security control. Anyone copying this snippet into a real app risks shipping it as-is — the literal string production is now in their initialization code, the whitelist is bypassed, and there's no instruction to remove it before deploy. It also means analytics, billing, or rate limits keyed on environment will be polluted by dev traffic.
The fix: Add a real development or localhost mode to LuaPop that bypasses whitelisting only when an explicit dev flag is set, then update the docs. If the workaround must remain, document the exact code path to remove before production deployment, and call out the security/billing implications in a Warning, not as a casual instruction.
4. No canonical API base URL reference; base URLs disagree across pages (significant)
Location: https://docs.heylua.ai/api-reference/openapi.json vs https://docs.heylua.ai/devices/how-it-works vs marketing surface
Problem: There is no single "API base URL" page anywhere in the docs. Different surfaces imply different bases:
- The OpenAPI spec on
api-reference/openapi.json:http://sandbox.mintlify.com - The devices reference:
https://api.heylua.ai(Socket.IO) andwss://mqtt.heylua.ai/mqtt(MQTT) - The marketing/admin surface:
heylua.ai,admin.heylua.ai,docs.heylua.ai,blog.heylua.ai
llms.txt does not list a base-URL reference page either.
Consequence: A developer (or agent) trying to call any Lua REST API has no authoritative answer for "what hostname do I hit?" They will either trust the OpenAPI placeholder (sandbox.mintlify.com), guess api.heylua.ai from the devices doc, or invent something based on the marketing domain. Each path produces different broken behavior.
The fix: Publish a single "API base URLs" reference page enumerating every public endpoint (api.heylua.ai, mqtt.heylua.ai, admin.heylua.ai, etc.), what each is for, and which transports/protocols they speak. Link it from llms.txt and from every API resource page.
5. npm package names are unreconciled across docs (significant)
Location: https://docs.heylua.ai/llms.txt vs https://docs.heylua.ai/chat-widget/installation
Problem: llms.txt's "Optional" block lists the npm package as lua-cli (https://www.npmjs.com/package/lua-cli). The chat widget install page tells developers to:
npm install @lua/pop
There is no single page that disambiguates which artifacts ship under which names: is @lua/* a real npm scope, what else lives in it, and how does it relate to the unscoped lua-cli package? The "Optional" links in llms.txt only mention lua-cli; @lua/pop is not listed there.
Consequence: A developer (or an agent) doing npm install lua or npm install @lua/cli based on inferred conventions will hit the wrong package or a 404. Agents extracting install commands from the chat-widget page won't know that @lua/pop is widget-only, and won't know whether other @lua/* packages exist.
The fix: Add a single "Packages" reference page enumerating every published artifact (npm scope, package name, what it's for, current version) and link it from llms.txt. Make sure both lua-cli and @lua/pop are listed, and clarify whether @lua/* is a published scope or only contains the widget.
6. Persona example contradicts itself within the same page (significant)
Location: https://docs.heylua.ai/overview/persona
Problem: The same AcmeCorp example shows different business facts in the Context block versus the "Good Persona" tab on the same page:
Context block:
AcmeCorp serves 50,000+ customers.
2-day shipping standard.
30-day return policy.
"Good Persona" tab on the same page:
Process returns within our 45-day policy
...
AcmeCorp is an online retailer since 2010.
10,000+ products.
Free shipping over $50.
45-day return policy.
Business hours: 9 AM - 6 PM EST.
Return window changes (30 days → 45 days), shipping policy changes (2-day standard → free over $50), and the Good Persona introduces unrelated facts not present in the Context block ("online retailer since 2010", "10,000+ products", "9 AM – 6 PM EST hours").
Consequence: This is a docs page about how to write a persona that won't hallucinate. The page itself models inconsistency. A developer copying either block as a template internalizes contradictions, and an agent training on this page learns that the same persona may legitimately disagree with itself.
The fix: Use one consistent set of AcmeCorp facts across every example on the page. If the intent is to contrast "bad" and "good" personas, label which fields changed and why — don't quietly mutate unrelated business facts.
7. lsk_ API key prefix is undocumented (significant)
Location: https://docs.heylua.ai/getting-started/installation and https://docs.heylua.ai/llms.txt
Problem: The "API Key" tab on the install page shows:
$ lua auth configure
? Choose authentication method: API Key
? Enter your API key: lsk_abc123def456...
The lsk_ prefix is never defined anywhere in the indexed pages. llms.txt lists no "API Keys" or "Authentication" reference page that would explain how to generate one, what lsk_ means, key scopes, expiration, or rotation. The MQTT auth flow (Issue 8) also expects an API key as the password but never says whether it's the same lsk_ key.
Consequence: A developer who picked "API Key" because they assumed they had one is stuck — there's no answer to where to generate it, what lsk_ stands for, or whether it can be rotated. Agents can't validate the prefix client-side or recognize keys in logs/errors. Agents helping a user onboard tend to invent a path (e.g. fake https://heylua.ai/settings/api-keys URLs).
The fix: Publish a dedicated "API Keys" reference page that documents: where in admin.heylua.ai to create one, the meaning of the lsk_ prefix, key scopes, expiration, rotation, and which subsystems (CLI, devices/MQTT, Socket.IO) accept which keys. Link it from llms.txt and from every place a key is required.
8. MQTT auth scheme is buried inside a code block, never explained in the security section (significant)
Location: https://docs.heylua.ai/devices/how-it-works
Problem: The MQTT connection lifecycle tab specifies:
1. Client connects to wss://mqtt.heylua.ai/mqtt
- username: {agentId}:{deviceName}
- password: {apiKey}
- LWT: offline status (retained)
This is the only place the docs say the API key is sent as the MQTT password and that the username is the colon-joined agentId:deviceName. The "Security Model" section on the same page talks about TLS and "API Key Authentication" generically but never explains the MQTT-specific credential mapping, never says whether {apiKey} is the same lsk_ key from the CLI flow, and never says how to rotate it without dropping device sessions.
Consequence: A developer building a device client has to reverse-engineer the auth scheme from a single bullet inside a tabbed example. Agents writing IoT integrations will likely produce code that puts the API key in a header instead of the MQTT password field, or will fail to construct the colon-joined username correctly.
The fix: Promote the MQTT credential mapping to the "Security Model" section: explicitly state username = "{agentId}:{deviceName}", password = <API key>, link to the API Keys reference (Issue 7), and document rotation behavior under live MQTT sessions.
9. Devices transport docs mix port and protocol claims (minor)
Location: https://docs.heylua.ai/devices/how-it-works
Problem: The Transport Comparison table says MQTT's default URL is wss://mqtt.heylua.ai/mqtt (i.e. MQTT-over-WebSocket). The Security Model section then states: "MQTT connects over port 443 (WebSocket) with TLS." The transport row labels the protocol as "MQTT 3.1.1 over TLS" with no mention of WebSocket framing. Three places, three subtly different framings of the same transport.
Consequence: A developer wiring up a device client has to decide between an MQTT-over-TCP-on-8883 client (what "MQTT 3.1.1 over TLS" usually implies) and an MQTT-over-WebSocket client (what wss:// and "port 443 (WebSocket)" imply). Picking the wrong client library is a several-hour debugging session. Agents writing IoT integrations will often default to TCP/8883.
The fix: Standardize on a single phrase across the page — e.g. "MQTT 3.1.1 over WebSocket Secure (WSS) on port 443" — and update the table, security model, and connection lifecycle blocks together.
10. llms.txt does not advertise llms-full.txt (minor)
Location: https://docs.heylua.ai/llms.txt
Problem: llms.txt is published as the agent index and links to per-page .md files. Mintlify also exposes an llms-full.txt (the consolidated full-text variant), but llms.txt itself does not link to it, so agents that respect only the manifest will miss the consolidated file.
Consequence: Agents that fetch llms.txt and stop there will issue N round-trips for N pages instead of one fetch for the full corpus. This makes Lua's docs more expensive and slower to ingest than they need to be, even though the consolidated file already exists.
The fix: Add an llms-full.txt entry to the top of llms.txt so agents discover it. Mintlify generates this automatically; just link it.
What they do well
llms.txtis comprehensive and uses descriptive titles for every page — the manifest layer is in good shape, even if the OpenAPI link behind it isn't.- Devices section provides a clear side-by-side transport comparison (Socket.IO vs MQTT) with concrete URLs, which is rare for agent-platform device docs.
- Credential storage is documented per-OS (macOS Keychain, Windows Credential Vault, Linux libsecret) — that level of specificity is unusual and helpful.
Top 3 recommendations
- Replace the placeholder
openapi.jsonwith a real Lua API spec served over HTTPS, or remove the OpenAPI link fromllms.txt. This is the single biggest agent-ingestion bug on the site. - Publish authoritative reference pages for the things developers and agents most need to look up but currently can't find: API base URLs, API keys (
lsk_prefix), and published packages. - Fix the localhost workaround for the chat widget so developers don't have to hardcode
environment: "production"in dev — and document a real dev mode.