Skip to main content

Image

cpsl.Image defines the runtime environment for your app. If the app needs Python packages, system packages, or setup commands, this is where they go.

Worked example

This is a realistic app-level deployment config:
app = cpsl.App(
    name="support-ops",
    image=cpsl.Image(
        python_packages=["openai", "pypdf"],
        apt_packages=["poppler-utils"],
    ),
    secrets=["OPENAI_API_KEY"],
    filesystems={"/data": cpsl.FileSystem("support-ops")},
    keep_warm_seconds=30,
    price=1500,
    pricing_type="monthly",
)

app.theme(
    preset="light",
    accent="#1565C0",
    font_sans="DM Sans, sans-serif",
    tagline="Mailbox triage and support operations",
)
This is what makes Capsule feel like an application platform instead of a model wrapper: runtime dependencies, branding, storage, warm behavior, and pricing all live next to the app code.

Constructor

image = cpsl.Image(
    python_packages=["openai", "numpy"],
    apt_packages=["ffmpeg"],
    commands=["python -m spacy download en_core_web_sm"],
)
You can also build it up incrementally:
image = (
    cpsl.Image()
    .add_python_packages(["openai", "numpy"])
    .add_apt_packages(["ffmpeg"])
    .add_commands(["python -m spacy download en_core_web_sm"])
)

Methods

MethodPurpose
add_python_packages(packages)Add Python packages or load from a requirements file
add_apt_packages(packages)Add apt packages
add_commands(commands)Add shell commands to run during setup
python_packages can be a list or a path to requirements.txt.

Theme

Configure app branding with app.theme(...). Most apps do not need a fully custom theme. A preset plus a few overrides is usually enough:
app.theme(
    preset="midnight",
    accent="#A78BFA",
    font_sans="DM Sans, sans-serif",
    font_mono="DM Mono, monospace",
)

Presets

Built-in presets:
  • dark
  • light
  • midnight
  • warm

Common theme fields

FieldMeaning
presetStarting palette
logoPath or URL to a logo
logo_backgroundBackground behind the logo
taglineSidebar subtitle
primaryMain interactive color
accentAccent color
backgroundPage background
foregroundMain text color
sidebarSidebar background
surfaceCards and panels
borderBorders and dividers
mutedSecondary text
dangerError/destructive color
successSuccess color
font_sansBody font family
font_monoCode/data font family
radiussm, md, or lg

FileSystem

Use cpsl.FileSystem("name") to mount named durable storage into the runtime:
app = cpsl.App(
    name="reports",
    image=cpsl.Image(),
    filesystems={"/data": cpsl.FileSystem("reports")},
)
The key is the mount path inside the runtime. The value is the named filesystem resource in the workspace. Once mounted, you can use it like a normal path:
with open("/data/summary.txt", "w") as f:
    f.write("hello from capsule\n")

Pricing

Capsule uses cents for pricing:
app = cpsl.App(
    name="infra-analyst",
    image=cpsl.Image(),
    price=500,
    pricing_type="monthly",
)
Valid pricing types:
  • one_time
  • monthly

Warm runtimes

app = cpsl.App(
    name="fast-agent",
    image=cpsl.Image(),
    keep_warm_seconds=30,
)
This asks Capsule to keep the runtime warm for a short period after activity.

Secrets and filesystems

These are deployment config, not runtime afterthoughts:
app = cpsl.App(
    name="secure-agent",
    image=cpsl.Image(),
    secrets=["OPENAI_API_KEY"],
    filesystems={"/data": cpsl.FileSystem("reports")},
)
That same app could also set a theme, pages, tasks, and integrations. There is no separate deployment manifest hiding elsewhere.

Class-based deploy config

For class-based apps, the deploy-specific knobs live on @app.cls(...) instead of the App(...) constructor:
@app.cls(
    image=cpsl.Image(),
    price=500,
    pricing_type="monthly",
    keep_warm_seconds=30,
    secrets=["OPENAI_API_KEY"],
    filesystems={"/data": cpsl.FileSystem("reports")},
)
class MyApp:
    ...

See also