Apps
Clawnify apps are full web apps — internal tools, CRMs, dashboards, client portals — that your agent builds and deploys for you. Describe what you want in natural language and the agent generates the app, provisions its database and storage, and ships it to a live URL at <slug>.apps.clawnify.com.
Every app is also an API: your agent, and any MCP client connected to mcp.clawnify.com, can discover its endpoints and call them directly. So an app is both something people use in the browser and something agents drive programmatically.
Two ways to create an app
- Natural language (App Builder). Ask your agent — “build me a CRM for tracking deals” — and it scaffolds, deploys, and iterates on the app for you.
- From a project (CLI). Deploy an existing TypeScript project yourself with
clawnify deploy.
Deploying from the CLI
clawnify init my-app
cd my-app
# Add API routes in src/server/routes.ts
clawnify deploy
See CLI → Install for the full setup.
How agents call your app
Apps serve two descriptions of their own API, generated from the routes you define:
/llms.txt: a short index of every endpoint./api/openapi.json: the full request and response schemas.
An agent reads one of these to find the right endpoint, then calls it. From an MCP client connected to mcp.clawnify.com, reading goes through clawnify_app_api_read and changes through clawnify_app_api_write (or clawnify_app_api_delete), each taking the app’s id from clawnify_list_apps and a path:
clawnify_app_api_read({ app_id: "...", path: "/llms.txt" })
clawnify_app_api_write({ app_id: "...", method: "POST", path: "/api/quotes", body: { customer_id: "...", items: [...] } })
Because both descriptions come from the live routes, they can’t drift from your code. To make an endpoint easy for agents to use, give its route a clear summary and description, with typed request and response schemas. The build-a-clawnify-app agent skill shows how.
To find which app handles something in the first place, clawnify_docs_search searches your org’s apps by name and description.
Identity
Every call into your app arrives with an identity the platform has already
verified at its perimeter. Your app never authenticates anyone — no login, no
sessions, no token parsing. Read it with the helpers from @clawnify/app:
import { user, orgId, caller } from "@clawnify/app";
app.get("/api/notes", (c) => {
const org = orgId(c); // the tenant key — filter every query by it
const u = user(c); // null when the caller isn't a person
return c.json({ org, greeting: u ? `Hi, ${u.firstName}` : "Hi there" });
});
| Helper | Returns |
|---|---|
orgId(c) | The organization UUID. Null for agent-browser, public and bypass callers — treat null as no access, never as a wildcard. |
user(c) | { id, email, name, avatarUrl, firstName, lastName }, or null when the caller isn’t a person. |
caller(c) | user, api, agent, agent-browser, public, bypass, system, or app. |
Five of the eight caller kinds have no human behind them, so always handle
user(c) === null rather than assuming someone is signed in.
firstName / lastName are a convenience split of a single stored full name —
use them for a greeting, but store name.