App definition can describe the runtime, the chat handler, the queue page, the background jobs, the mounted storage, and the channels the app shows up in. capsule serve and capsule deploy both read from that same source of truth.
Deploying the app also gives you a hosted product surface with its own authenticated users. The app definition is not just “the backend.” It is the thing Capsule uses to run the actual product.
The idea is that each app user gets an isolated sandboxed runtime. Your code runs with its declared image, packages, secrets, integrations, and mounted filesystems, so an agent can read and write files, run background work, call tools, and serve pages as part of one application.
How a real app is split
Most non-trivial Capsule apps settle into four layers:- the app shell, which declares runtime, integrations, collections, settings, and pages
- workflow surfaces, where users review queues, data, or task state
- assistant logic, which routes requests and answers questions
- background work, which keeps the product moving without blocking chat
One app definition, many product surfaces
Unlike a split stack where chat, background jobs, file storage, and UI all live in different systems, Capsule lets one app expose multiple surfaces at once:- built-in web chat
- named external channels
- API endpoints
- Python DSL pages
- React pages
- scheduled jobs
- background tasks
App definition. In practice, this means you can read one file and understand the shape of the product.
Runtime per app user
Capsule runs the app inside a managed runtime per app user. You do not have to invent your own execution layer for sessions, channel traffic, tasks, page-backed interactions, or user-specific filesystem work. That runtime is sandboxed and container-like: it has the environment specified inImage(...), access to declared secrets and integrations, and any filesystems you mount. This is what lets Capsule apps do more than answer a prompt. They can keep working across chat, pages, tasks, schedules, generated files, uploads, and review flows.
The same runtime model powers local iteration with capsule serve, hosted deploys with capsule deploy, and the channel-facing versions of the app. The main thing that changes is where the requests come from, not what kind of app you are writing.
App-scoped users
When you deploy a Capsule app, users sign into that app. They do not land in one shared global user pool across every Capsule project. That distinction matters becauseaccess="authenticated" pages, data handlers, and session context are all scoped to the deployed app. Two Capsule apps can have different user pools, different access policies, and different user-scoped data even if the same email signs into both.
Runtime flow
What capsule serve and capsule deploy read
When you run capsule serve app.py:app or capsule deploy app.py:app, Capsule resolves the app entry point and serializes the app configuration. That includes:
imageand package installs- declared pages
- data handler names
- collection declarations
- settings metadata
- integrations
- schedule specs
- filesystems and secrets
Handler types
Most apps end up with a small mix of handler types:- message handlers for chat or API conversations
- lifecycle hooks like
boot,shutdown,enter, andexit - tasks for asynchronous background work
- schedules for cron-triggered jobs
- endpoints and ASGI mounts for HTTP surfaces
Where should a new feature live?
This is the design question people hit most often. As a rule of thumb:- put conversational interpretation in
@app.message() - put durable records in collections
- put operator controls in settings and pages
- put external side effects and long work in tasks
- put recurring maintenance in schedules
State layers
There are three main kinds of state in Capsule:session.datafor per-conversation key-value state- collections for durable document storage
- settings for scoped configuration values that can be edited through the UI
session.datafor ephemeral conversation context- collections for real data models
- settings for configuration, not records
UI layers
Capsule has two page models:- the Python DSL, where a page returns
cpsl.ui.Page([...]) - React pages registered with
app.add_page(...)
Product and deploy knobs live in code
Operational concerns are part of the app definition, not an afterthought. The same code can describe things like:Image(...)controls Python packages, apt packages, and setup commandspriceandpricing_typedescribe how the app is soldkeep_warm_secondsaffects runtime readinessfilesystemsandsecretsconnect external statechannelsdecide where the app can talk to users