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 a typed API: its procedures become tools your agent — and any MCP client connected to mcp.clawnify.com — can call 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
# Edit src/api.ts to add procedures
clawnify deploy
See CLI → Install for the full setup.
How procedures surface to the agent
Once your app deploys, its procedures become tools the agent (and any connected MCP client) can call. Two shapes, depending on procedure count.
Small apps (≤ 5 procedures) — direct tools
Every procedure shows up as <app_slug>.<procedure_name> in the gateway’s tools/list. The agent calls them like first-class tools.
quotes.createQuote
quotes.listQuotes
quotes.markPaid
Larger apps (> 5 procedures) — via clawnify_execute
The agent finds them via clawnify_docs_search and calls them as code through clawnify_execute:
import { client } from "@clawnify/sdk";
const result = await client.quotes.createQuote({ customer_id: "...", items: [...] });
This keeps the agent’s tool list small and lets it chain multiple procedure calls in one round trip.
You can override per-app in your clawnify.json manifest:
{
"api": {
"exposure_mode": "auto" | "code-only" | "direct-only"
}
}
| Mode | Behavior |
|---|---|
auto (default) | Direct tools if ≤ 5 procedures, otherwise code-mode-only. |
code-only | Always reached via clawnify_execute, regardless of count. |
direct-only | Every procedure projects as a direct tool, regardless of count. |
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.
Per-app README
Each app gets an auto-generated README that the agent reads on demand via clawnify_docs_search to learn what the app does and how to call its procedures.
The README is derived from your clawnify.json + JSDoc on your procedures. You control it by writing good descriptions; no separate doc files needed.