Metadata-Version: 2.4
Name: glimpse-applet-sdk
Version: 0.5.0
Summary: Typed async framework for Glimpse exec applets
Keywords: glimpse,applet,panel,desktop,sdk
Author: Alex Oleshkevich
Author-email: Alex Oleshkevich <alex.oleshkevich@gmail.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Desktop Environment
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.14
Project-URL: Homepage, https://alex-oleshkevich.github.io/glimpse/
Project-URL: Documentation, https://alex-oleshkevich.github.io/glimpse/applets/exec-sdk
Project-URL: Repository, https://github.com/alex-oleshkevich/glimpse
Project-URL: Issues, https://github.com/alex-oleshkevich/glimpse/issues
Description-Content-Type: text/markdown

# Glimpse Applet Python SDK

Small async framework for building Glimpse `exec` applets without touching stdio or raw JSON.

Requires Python 3.14+.

## Install

```sh
pip install glimpse-applet-sdk
# or with uv:
uv add glimpse-applet-sdk
```

The distribution is named `glimpse-applet-sdk` on PyPI; the import name is `glimpse_sdk`.

## Develop

Create and live-run a Python applet project with the Glimpse tooling:

```sh
glimpse-applet new counter --lang python
cd counter
glimpse-applet dev
```

Read `docs/custom-applets/tooling.md` for project layout, `applet.toml`, dev applets, linking, and diagnostics.

## Goals

- typed protocol models
- typed widget builders
- async runtime
- decorator-based callbacks (`@click`, `@scroll`, `@input`, `@change`, `@toggle`)
- separate `status(state)` and `popover(state)` methods; state mutation via `await self.set_state(...)`

## Example

```python
from dataclasses import dataclass

from glimpse_sdk import (
    Applet,
    AppletState,
    Box,
    Button,
    ButtonVariant,
    Hero,
    Icon,
    Label,
    StatusItem,
    click,
)


@dataclass
class DeployState(AppletState):
    version: str = "2026.04.07"
    status: str = "Ready"


class DeployApplet(Applet[DeployState]):
    def initial_state(self) -> DeployState:
        return DeployState()

    async def status(self, state: DeployState):
        return [
            StatusItem(
                id="deploy",
                icon=Icon.name("software-update-available-symbolic"),
                label=state.status,
            )
        ]

    async def popover(self, state: DeployState):
        return Box.vertical(
            [
                Hero(
                    icon=Icon.name("software-update-available-symbolic"),
                    title="Deploy",
                    subtitle=state.version,
                ),
                Label(text="Version"),
                Button(
                    id="deploy_now",
                    label="Deploy now",
                    icon="media-playback-start-symbolic",
                    variant=ButtonVariant.PRIMARY,
                ),
            ]
        )

    @click("deploy_now")
    async def on_deploy(self, _event) -> None:
        await self.set_state(status="Deploying")


if __name__ == "__main__":
    DeployApplet().run()
```

## IPC client

Talk to a running Glimpse daemon: subscribe to event channels and dispatch
actions. `ipc(service)` only resolves the socket path — the connection is
opened lazily.

```python
import glimpse_sdk

sub = glimpse_sdk.ipc(service="shell")  # "shell" | "wallpaper" | "idle" | "lock"

# Fire an action; awaits the ack, raises IpcError if the server rejects it.
ack = await sub.dispatch("open_uri", {"uri": "https://example.com"})

# Stream events until the socket closes.
async for ev in sub.listen("audio.*"):
    print(ev.name, ev.fields)
```
