ops-dashboard, a web app on your agent. It has a page that lists tickets and opens new ones, and two routes that read and write a Data collection as the person using the page. At the end, the app is live and open in Lua Workspace in your browser. Allow 20 minutes. You need a project created with lua init and a user session from lua auth configure (Install the CLI and sign in), and Node.js 20 or later.
Verified against lua-cli 3.44.0.
The complete project is in the examples repository: lua-apps-ops-dashboard. It adds a third route that closes a ticket.
What you’ll build
- A web app listed on your agent, with a page project in
src/apps/ops-dashboard/web. - A
GET /ticketsroute and aPOST /ticketsroute with a Zod body schema. - A React page that calls both routes with
lua.api()and follows the shell’s theme. - A local run with hot reload, a route test from the terminal, and a pushed version.
- An agent version that makes the app live, opened by its URL.
1
Scaffold the app
Run this in the root of your agent project, where The command writes two things.
lua.skill.yaml is:Output
app.ts holds the routes, which run on Lua. web/ is a Vite + React project with the @lua-ai-global/ui components and Tailwind; it runs in the browser. The command also lists the app under webApps on your LuaAgent and keeps the page project out of the agent’s TypeScript build. It never overwrites an existing app.2
Install the page project
The page project has its own dependencies:
@lua-ai-global/app-client is the page side of the app. It opens the session that the shell hands over, talks to the shell, and calls your routes.lua-cli 3.42 to 3.45 copy the client into
web/src/lua/client.ts instead of adding the package. To switch, install the package as above, change from './lua/client' to from '@lua-ai-global/app-client' in web/src/main.tsx and web/src/App.tsx, and delete web/src/lua/client.ts.3
Write the routes
Replace A route key is a method and a path. The handler gets the request already checked against the route’s schemas: a body without a
src/apps/ops-dashboard/app.ts:src/apps/ops-dashboard/app.ts
title is answered with 400 before your code runs. auth is the person using the page, never an API key. A handler that returns a value answers 200 with it as JSON; json(value, status) sets another status.Run lua compile --ci. The summary counts the app:Output
4
Call the routes from the page
Replace Then make
src/apps/ops-dashboard/web/src/App.tsx:src/apps/ops-dashboard/web/src/App.tsx
src/apps/ops-dashboard/web/src/main.tsx start the client and follow the shell’s light or dark theme:src/apps/ops-dashboard/web/src/main.tsx
lua.api(method, path, body?) calls a route of this app as the signed-in person and resolves the JSON it answers. In web/, npx tsc --noEmit reports no errors.5
Run it locally
Data, so the ticket is a real entry in the tickets collection. Edit App.tsx and the page reloads; edit app.ts and the routes recompile. Press Ctrl+C to stop.6
Test a route from the terminal
lua test webapp calls one route the way the platform would, with you as auth:201 with the new ticket; the second lists it. A body that fails the schema answers 400. Add --json to get the result as JSON for a script.7
Push a version
--force picks the next version number without asking. The version is staged, not live: the command ends with Staged but NOT live yet and the two commands of the next step.8
Go live
A web app has no deploy of its own. It goes live with the agent version that pins it:
lua version create prints ✓ Created v<n> (staged); pass that number to promote. To roll back, promote the previous agent version.9
Open the app
Open it by URL in your browser. The app opens full page in Lua Workspace, signed in as you, and lists the tickets you added locally. The admin console lists the agent’s apps at
<agentId> is agent.agentId in lua.skill.yaml:https://admin.heylua.ai/admin/agents/<agentId>/apps. Neither has a menu entry for apps yet.The app opens at its Workspace URL, a ticket you add there shows your name, and
lua test webapp --name ops-dashboard --route 'GET /tickets' lists it.What you learned
- A web app is part of an agent:
defineWebAppinsrc/apps/<name>/app.ts, listed underwebApps. About web apps explains where it opens and who can open it. - Routes are typed handlers that run on Lua as the person using the page, with
Dataandenv(). The page calls them withlua.api(). Write routes and pages covers params, query, errors, and limits. lua apps devandlua test webapprun the routes locally against live data.lua push webappstages a version; an agent version makes it live, and promoting an earlier one rolls it back.
Next steps
Write routes and pages
The full
defineWebApp shape, the page client, and limits.lua apps reference
lua apps new and lua apps dev.Store and search data
More on the
Data collections your routes use.lua-apps-ops-dashboard example
The full project, ready to clone and run.

