Extensions
What an Imperal Cloud extension is — its files, lifecycle, and capabilities; the Webbee superpower you build, publish, and ship to users as a Python package.
An extension is a Python package that gives Webbee new things it can do for the user. This page explains what's actually inside one and what each piece is for.
The mental model
Identity
Every extension has a unique name (e.g. tasks-mini), a display name, a description, and an icon. This is what users see in the marketplace.
Capabilities
Four types: chat functions, panels, skeletons, and background jobs. An extension can have any combination.
Manifest
A JSON file (imperal.json) that declares everything machine-readably. Auto-generated from your code.
Handlers
Plain Python functions, decorated. The SDK wires them to the [web-kernel](/en/reference/glossary/) at install time.
The minimal extension
That's the floor. app.py declares your Extension and at least one capability. imperal.json is auto-generated from app.py by imperal build.
A typical real-world extension grows into:
Plain Python — no framework structure imposed. Whatever module split makes sense is fine.
The four capability types
@chat.function
The big one. A tool the LLM can call when users speak. Typed parameters, structured return, automatic audit.
@ext.panel
A UI block rendered in the Imperal Panel. `slot=` selects left / right / center; the handler returns a `ui.*` UINode tree.
@ext.skeleton
A live data probe. Web-kernel queries it on a schedule and feeds the result into Webbee's awareness.
@ext.schedule
A background job — cron-like. Runs on a [ICNLI Worker](/en/reference/glossary/) on a schedule. Useful for backfills, sync jobs, periodic cleanup.
You'll learn each one in depth in its own concept page. For now: an extension can mix and match. A mail extension typically has all four.
The Extension class
The first thing in app.py is always:
from imperal_sdk import Extension
ext = Extension(
display_name="Tasks (Mini)", # human-readable, shown in marketplace
description="A tiny task manager", # short — one paragraph max
icon="check-square", # Lucide icon name OR url to PNG
actions_explicit=True, # federal default — see below
)Prop
Type
actions_explicit=True is the federal default
When True, Webbee won't fire your tools unless the intent classifier is confident enough that the user explicitly asked. This is the right default for anything that touches user data. Set False only if your extension is purely informational (e.g. a glossary lookup).
The lifecycle
Develop locally
You write app.py, run imperal build, smoke-test with imperal_sdk.cli test --tool .... No web-kernel needed.
Validate
imperal validate runs all 11 federal validators (V14-V22 + V24 + V31). Every one is ERROR-severity — failing any blocks publishing.
The validators check:
| Validator | What |
|---|---|
| V14 | Manifest schema v3 conformance |
| V15 | Display name + description not empty/placeholder |
| V16 | Icon resolves |
| V17 | Pydantic params model is module-scope (not function-local) |
| V18 | Every @chat.function declares a typed return annotation (-> ActionResult or subclass / Pydantic model) |
| V19 | All @chat.function descriptions ≥ 10 chars and not boilerplate |
| V20 | write/destructive @chat.function should declare effects (WARN-only) |
| V21 | icon.svg declared + valid (XML-validated, viewBox, ≤100KB, no embedded raster) |
| V22 | Lifecycle hook signatures match the SDK contract (on_refresh(message=), on_upgrade(from_version=)) |
| V24 | Handlers use ctx.http, never ctx.skeleton.* (AST scan) |
| V31 | Extension(system=True) reserved for first-party Imperal authors |
Only @chat.function is gated for -> ActionResult
The -> ActionResult requirement (V18) applies only to @chat.function
handlers. Panel handlers (@ext.panel), tool handlers (@ext.tool), and
lifecycle hooks (@ext.on_install / on_uninstall / on_refresh /
on_upgrade) are exempt — they are never run through the return-type
validator and may return whatever their contract specifies (e.g. a panel
handler returns a UI node tree).
Publish to the Developer Portal
Upload your packaged extension at panel.imperal.io/developer (drag-and-drop). The portal re-runs every validator server-side, then a reviewer (or auto-review for trusted publishers) checks your manifest matches your code and approves.
Install
End users install your extension from the marketplace. Behind the scenes:
- Registry stores
(user_id, ext_id, version, scopes_granted, status='installed') - The next chat turn for that user includes your tools in the intent classifier's tool list
- Skeletons start firing on schedule
- Panel slots become available
Run
Your handlers run on the platform's worker fleet on demand. You don't manage processes, deployments, or scaling.
Update
Bump the version in your manifest, publish again. Existing installs migrate on the next turn (no downtime). The Developer Portal lets you stage a release to a percentage of users for canary.
The federal-blocking rule
Don't edit shipped extensions in the deployed-extension directory directly
Imperal-Cloud-deployed extensions live in the deployed-extension directory. They have inner-git managed by the Developer Portal — direct edits cause replay drift. Always work from your local source and re-publish.
What an extension isn't
Not a web service
No HTTP server. No port to expose. The web-kernel calls your handlers in-process via [ICNLI](/en/reference/glossary/) Worker.
Not a daemon
No long-running event loop in your code. The web-kernel triggers handlers; they return; that's the loop.
Not a UI framework
Panels return JSON layouts. The Imperal Panel React app does the rendering. You don't ship React/HTML.
Not a job queue
Use @ext.schedule — ICNLI Worker handles cron, retries, timeouts. Don't roll your own.
Where to go next
@chat.function in depth
Parameters, return shapes, action types, chain hints, [Pydantic feedback loop](/en/reference/glossary/).
Skeletons
How Webbee always knows your state without prompting.
Panels
UI surfaces — sidebars, editors, settings panes, dashboards.
Web-kernel context (ctx)
The single object every handler gets. user, tenant, api, secrets, history.
Architecture
Imperal Cloud architecture — gateway, web-kernel, workers, SDK: the full path a chat message travels to reach your extension handler, with gates on the way.
@chat.function
@chat.function — the typed decorator that turns a Python coroutine into an LLM-callable Webbee tool, with auto-validated params, action types, and multi-step turns.