Most apps won't implement SLOP natively from day one. Adapters bridge existing applications to the SLOP protocol by translating their existing state representations into SLOP state trees.
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ App │────>│ Adapter │────>│ Consumer │
│ (existing) │ │ (bridge) │ │ (AI) │
└──────────────┘ └──────────────┘ └──────────────┘
│ │
App's native SLOP state tree
state/API + affordances
An adapter:
- Reads state from the app through whatever interface the app already exposes
- Maps it to a SLOP state tree
- Runs a SLOP provider (socket, stdio, etc.)
- Detects changes and emits patches
- Translates affordance invocations back into app-native actions
Web integration is covered in detail in Web Integration. It defines three tiers:
- SLOP-native — the app implements SLOP directly (server-side via WebSocket, or client-side via postMessage)
- Framework adapter — an extension hooks into React/Vue/Svelte state
- Accessibility adapter — an extension reads the browser's accessibility tree
The remaining sections of this document cover non-web adapters.
Terminal applications render to a character grid. An adapter can parse this into structure.
- Screen buffer — the current character grid (via
tmux capture-pane, PTY interception, or terminal emulator API) - Cursor position — maps to
meta.focus - ANSI colors/styles — can indicate semantic roles (red = error, bold = heading)
For well-known TUI frameworks (ncurses, blessed, ink, bubbletea), the adapter can recognize common patterns:
| Pattern | SLOP mapping |
|---|---|
| Bordered box | type: "group" |
| Menu with highlighted item | type: "collection" with selected property |
| Text input with cursor | type: "field" |
| Status bar | type: "status" |
| Tab bar | type: "group" with children |
TUI frameworks could export SLOP state directly. For example, a Bubbletea middleware:
// Go — Bubbletea SLOP middleware
func SLOPMiddleware(model tea.Model) SLOPProvider {
return &slopBubbletea{
model: model,
// Expose Model state as SLOP tree
// Map Msg handling to affordances
}
}Desktop apps on macOS, Windows, and Linux expose accessibility trees through OS APIs.
AXUIElement → SLOP node
──────────────────────────────────
AXWindow → type: "view"
AXTable → type: "collection"
AXRow → type: "item"
AXTextField → type: "field"
AXButton → type: "control"
AXStaticText → properties.label
AXValue → properties.value
AXFocused → meta.focus
Same concept with IUIAutomationElement → SLOP nodes.
Same concept with Atspi.Accessible → SLOP nodes.
A standalone adapter process that:
- Enumerates accessible windows
- Registers as a SLOP provider for each
- Polls or subscribes to AX change notifications
- Translates to SLOP patches
The simplest case. CLI tools that want to be SLOP-aware just print structured state to stdout.
A generic wrapper that captures stdout and maps it:
# Wrapper: run a command, capture output, expose as SLOP
slop-wrap -- git statusThe wrapper:
- Runs the command
- Parses output (plain text, JSON, or known formats)
- Exposes it as a SLOP tree on stdout (NDJSON)
CLI tools can add a --slop flag that outputs SLOP state instead of human-readable text:
$ my-tool --slop
{"type":"snapshot","version":1,"tree":{"id":"root","type":"root","children":[...]}}This is the lightest possible integration — a few extra lines of code in the tool.
-
Semantic mapping over literal translation. Don't create a SLOP node for every DOM element. Group, summarize, and create meaningful nodes.
-
Stable IDs are critical. Use the app's own IDs where possible (database IDs, element IDs). Fall back to content hashes or path-based IDs. Avoid index-based IDs (they break on reorder).
-
Compute salience. The adapter is in the best position to judge what matters — focused element gets high salience, off-screen elements get low salience, errors get critical salience.
-
Debounce aggressively. UI updates happen at 60fps. SLOP patches should happen at 1–10/second max. Batch changes.
-
Respect depth requests. Don't send the full tree when the consumer asked for depth 1. This is the primary mechanism for managing token cost.
-
Map native actions to affordances. Every clickable button, every submittable form, every keyboard shortcut — these are affordances. Expose them.