Apps
Declare the bespoke Surface people use to work with your Swirls system.
What it is. An App is the hosted interface for the people who use a Swirls system. It can be an internal operations desk, a branded client portal, or a review workspace. You declare the shell, navigation, and pages beside the workflows, data, access, and agents that power them; Swirls validates and deploys the whole project together.
Use it when your team or your client needs an exact-fit workspace—not the builder dashboard. Use a page shortcut when the job is a shared agent room or review inbox. Use render: @openui { … } when the job needs a bespoke dashboard, data browser, or workflow-launching surface.
Where Apps fit
An App is the ongoing interface to the system: the place people return to see operational state, start workflows, work with agents, and make reviewed decisions. It brings the primitives behind a Swirls project into one exact-fit piece of software.
Not every interaction needs an App. Use a form for a focused human submission, a webhook when another system sends an event, and a schedule when work starts at a particular time. Those resources initiate workflows. An App gives the people responsible for the operation a place to keep using what you built.
Apps are optional. A workflow-only or agent-only project is complete when that is all the job requires; add an App when people need a durable interface around the work.
Start with an app block
An app needs a bare identifier, a label, and at least one page. Pages have exactly one body: an OpenUI render tree, a shared portal room, a thread directory, or a workflow review inbox.
app support_desk {
label: "Support Desk"
description: "Triage, approvals, and the support room in one place."
icon: "headset"
shell {
preset: sidebar
topbar {
right: [widget.user_menu]
}
}
nav {
section "Work" {
page: queue
page: approvals
page: room
}
}
page queue {
label: "Ticket queue"
render: @openui {
root = ViewBrowser("open_tickets", { title: "Open tickets" })
}
}
page approvals {
label: "Approvals"
icon: "inbox"
reviews: [refund_request]
}
page room {
label: "Support room"
icon: "hash"
channel: support_room
}
}The support_room channel must declare platform: portal. The refund_request workflow and open_tickets view must exist somewhere in the same Swirls workspace.
Choose the right page body
| Body | Use it for | What people get |
|---|---|---|
render: @openui { … } | A dashboard, launcher, browser, or custom operational page | A compile-time validated composition of OpenUI components bound to Swirls primitives |
channel: <channel> | Shared work with an agent | A full-viewport room for a platform: portal channel |
threads: [<channel>, …] | Find and resume conversations | A full-viewport directory for one or more platform: portal channels |
reviews: [<workflow>, …] | Human decisions that pause workflows | A full-viewport inbox for pending, approved, and rejected reviews |
OpenUI is authored when you write the app, not generated at deploy or run time. The layout in Git is the layout people receive. Use components such as ViewBrowser, StreamBrowser, TableEditor, WorkflowLauncher, RunTimeline, Chat, and StatCard to compose the page your operation needs.
page launch_refund {
label: "Start a refund"
render: @openui {
root = WorkflowLauncher("refund_request", [
{
name: "ticketId",
label: "Ticket",
required: true,
input: Select({ view: "open_tickets" })
}
], "Request refund", "Refund request")
}
}Set viewport: full on an OpenUI page when the artifact should own the main pane. Channel, thread-directory, and review pages are always full viewport.
Make it feel like the business that uses it
Use brand to set a logo, accent, avatar treatment, and a sparse light/dark token overlay. Apps inherit the Swirls palette for any token you do not set.
app client_portal {
label: "Acme Client Portal"
brand {
logo: "https://acme.example/logo.svg"
accent: "#B33A2B"
tokens {
light {
canvas: "#f7f5f1"
viewport: "#ffffff"
brand: "#B33A2B"
brand_foreground: "#ffffff"
}
}
}
page home {
render: @openui {
root = Stack([StatCard("Open requests", "12")])
}
}
}An optional landing block customizes the sign-in experience for deep links. Its discover sub-block can opt the landing page into search indexing and publish safe app metadata for people and agents.
Control who can use it
Without audience, an App is for organization members. Add an audience block to declare an external client or partner admission policy; Swirls hosts audience-enabled apps on a stable *.swirls.cloud URL while Cloud manages invitations, sessions, and identity-provider credentials.
audience {
admission: invite_or_domain
auth: email_otp
allow_domains: ["acme.com"]
}The DSL owns the versioned policy. Cloud owns operational access such as invitations, user sessions, and IdP client secrets.
The page is also the permission boundary
An App can reach only the primitives it names. When Swirls resolves the app, it derives an expose set from the agents, channels, workflows, views, streams, databases, and queries referenced by its OpenUI pages, room pages, thread directories, and review pages. Surface uses that server-enforced set to scope data and execution access.
Naming a workflow in a reviews: page additionally grants review authority for that workflow in that exact app. Referencing a workflow from an OpenUI component alone does not grant review authority.
Next steps
- Read the primitives overview to choose the rest of your system.
- Read channels to create a shared portal room.
- Read reviews to add human approval to a workflow.
- See Apps in action for examples of the operational software you can declare.