Skip to content

Latest commit

 

History

History
85 lines (65 loc) · 1.62 KB

File metadata and controls

85 lines (65 loc) · 1.62 KB

Plugin authoring guide

A plugin is any executable that follows the JSON protocol:

  1. Read the request from stdin.
  2. Write the response to stdout.
  3. Exit with a non-zero status on failure.

Request

{
  "version": 1,
  "kind": "widget",
  "plugin": "timezone",
  "args": { "zones": [{ "label": "Tokyo", "utc_offset": 9 }] },
  "context": { "now": "2026-09-10T18:22:01+02:00", "width": 0, "height": 0 }
}

Response

Static lines:

{ "version": 1, "lines": ["Tokyo  01:22"] }

Animation frames:

{
  "version": 1,
  "lines": [],
  "frames": [
    { "delay_ms": 80, "lines": ["frame 1"] },
    { "delay_ms": 80, "lines": ["frame 2"] }
  ]
}

Error:

{ "version": 1, "lines": [], "error": "network unavailable" }

Rules

  • Declare a runtime budget and return a fallback response when it elapses.
  • Never block forever: the kernel kills plugins that exceed its timeout.
  • Keep responses small: the kernel renders them inside a widget.
  • Handle missing or invalid args with sensible defaults.

Rust template

[package]
name = "xclock-plugin-example"
version = "0.1.0"
edition = "2024"
license = "MIT"

[[bin]]
name = "example"
path = "src/main.rs"

[dependencies]
xclock-plugin-api = { git = "https://github.com/xclock-cli/api" }
use xclock_plugin_api::{read_request, write_response, Response};

fn main() -> std::io::Result<()> {
    let request = read_request()?;
    let label = request
        .args
        .get("label")
        .and_then(|value| value.as_str())
        .unwrap_or("example");

    write_response(&Response::lines(vec![format!("hello from {label}")]))
}