Skip to content

Exec Line Protocol

The exec line protocol is the raw interface between the panel and an exec applet process. Glimpse starts the child process, writes setup and event lines to stdin, and reads applet output from stdout. Diagnostics belong on stderr.

Use an SDK when possible. Use this page when you are writing a small script, debugging SDK output, or implementing the protocol directly.

Line Format

Each line starts with a command name. Commands with JSON payloads use one space followed by a JSON object:

text
command {"field":"value"}

The raw protocol is line-oriented. Every message must end with a newline. The child process should flush stdout after writing a line.

Commands

DirectionCommandPayloadMeaning
Child to GlimpsestatusJSON objectReplaces this applet panel status.
Child to GlimpsepopoverJSON objectReplaces this applet popover tree.
Child to Glimpseclassraw text after the spaceSets one applet CSS class suffix.
Child to Glimpseclose-popovernoneCloses this applet popover.
Glimpse to childinitJSON objectSends instance id and [exec.options].
Glimpse to childeventJSON objectSends user interaction and popover lifecycle events.

Unknown commands and invalid JSON are ignored and logged. Unknown component types are rejected when Glimpse parses the popover tree.

Example child output:

text
status {"items":[{"id":"cpu","label":"42%","icon":"cpu-symbolic","tooltip":"CPU usage"}]}
popover {"root":{"type":"popover_shell","data":{"children":[{"type":"hero","data":{"title":"System","subtitle":"CPU 42%"}}]}}}
class sysinfo
close-popover

Example input from Glimpse:

text
init {"instance":"sysinfo","options":{"interval":5,"unit":"celsius"}}
event {"id":"cpu","type":"click","source":"status","button":"left"}

Init Messages

init is sent by Glimpse after the child process starts.

FieldMeaning
instanceRuntime instance id for this applet.
optionsObject from [exec.options] in the applet package.

Use options for applet-specific settings instead of hardcoding values in the script.

Status Messages

A status message replaces the full list of status items shown in the panel.

text
status {"items":[
  {"id":"cpu","icon":"cpu-symbolic","label":"12%","tooltip":"CPU","css_classes":["threshold-ok"]},
  {"id":"mem","icon":"memory-symbolic","label":"51%","tooltip":"Memory"}
]}
FieldDefaultMeaning
idunsetEvent id. Add it when the item should receive clicks or scrolls.
iconunsetSymbolic icon name.
labelunsetText shown in the panel.
tooltipunsetHover text.
css_classes[]Extra CSS classes for this status item.

Left-click opens the popover when the applet has popover content. Right-click opens the context menu if one is available. Status items with id also receive click and scroll events.

Popover Messages

A popover message replaces the full popover tree. The payload has a root field containing a component node, or null to clear popover content.

text
popover {"root":{"type":"popover_shell","data":{"size":"medium","children":[{"type":"hero","data":{"title":"System","subtitle":"Live status","icon":"utilities-system-monitor-symbolic"}},{"type":"tile","data":{"id":"refresh","primary":"Refresh","secondary":"Run now","left_icon":"view-refresh-symbolic"}},{"type":"meter","data":{"label":"Memory","value":0.51,"text":"51%"}}]}}}

Clear the popover:

text
popover {"root":null}

Component nodes use this structure:

FieldMeaning
typeComponent name, such as popover_shell, column, tile, or meter.
dataComponent fields. The expected fields depend on type.

Send a complete popover update whenever the content changes. Read Components for valid component types and fields.

Class Messages

class sets one applet-specific class suffix on the panel item and popover. It is not JSON.

text
class build-status

That class is applied as applet-specific styling by the shell. Send it once after startup if the applet needs custom theme selectors.

Close Popover

close-popover closes this applet popover. It has no payload.

text
close-popover

Do not send close_popover {} or an action line from raw protocol applets; those are not accepted child commands by the shell protocol.

Events

Interactive status items and popover components send event lines back to the child process.

FieldValuesMeaning
idstringThe status item or component id. Popover lifecycle events use popover.
typeclick, toggle, change, scroll, open, closeEvent kind.
sourcestatus, popoverWhere the event came from.
buttonleft, middle, right, otherMouse button for click events when available.
activebooleanToggle state for toggle events.
valueJSON valueNew value for change events.
delta_ynumberScroll delta for scroll events.
SourceEventPayload
Status item with idclick, scrollbutton or delta_y.
tile, choice_tile, panel_indicator, pager_itemclickid identifies the component.
switch_tile, expander_tile, segmented_tiletoggleactive = true or false.
slider_tilechangeNumeric value.
meter with interactive = truechangeNumeric value.
choice_list, pager_strip, calendarchangeSelected id, item id, or date string in value.
Popover lifecycleopen, closeid = "popover".

Components without an id are display-only unless the component requires an id.

Example events:

text
event {"id":"volume","type":"change","source":"popover","value":0.72}
event {"id":"vpn","type":"toggle","source":"popover","active":true}
event {"id":"popover","type":"open","source":"popover"}

Shell Starter

sh
#!/bin/sh

printf "%s\n" "status {\"items\":[{\"id\":\"load\",\"label\":\"starting\",\"icon\":\"utilities-system-monitor-symbolic\"}]}"

while IFS= read -r line; do
  case "$line" in
    init\ *)
      printf "%s\n" "status {\"items\":[{\"id\":\"load\",\"label\":\"ready\",\"icon\":\"utilities-system-monitor-symbolic\"}]}"
      ;;
    event\ *)
      printf "%s\n" "popover {\"root\":{\"type\":\"popover_shell\",\"data\":{\"children\":[{\"type\":\"hero\",\"data\":{\"title\":\"System\",\"subtitle\":\"Last event seen\"}},{\"type\":\"badge\",\"data\":{\"label\":\"seen\",\"kind\":\"success\"}}]}}}"
      ;;
  esac
done

This shape is event-driven. For polling, run a background loop and keep reading events in the foreground.

How-To: Toggle A Command

Render a clickable tile:

text
popover {"root":{"type":"popover_shell","data":{"children":[{"type":"tile","data":{"id":"toggle-vpn","primary":"Toggle VPN","left_icon":"network-vpn-symbolic"}}]}}}

Handle the click:

text
event {"id":"toggle-vpn","type":"click","source":"popover","button":"left"}

Run your command, then print updated status and popover lines.

Best Practices

PracticeWhy
Print status immediatelyThe panel should not sit empty while your script warms up.
Write diagnostics to stderrStdout is reserved for protocol lines.
Send complete updatesTreat each status or popover line as the current truth.
Use stable idsEvents are easier to handle when ids do not change between updates.
Keep panel text shortThe panel is for glanceable state.
Put detail in the popoverPopovers are for explanations and controls.
Validate JSON before runningBad JSON is ignored and logged.

See Also

PageCovers
Exec AppletApplet package config and restart behavior.
ComponentsPopover component fields and component types.
Exec SDKSDK reference by language.