DEVELOPER DOCS

Build plugins for Dofek

Extend the dashboard with custom data sources. Plugins are standalone executables that communicate via JSON-over-stdio — write one in any language, in under 50 lines.

⚠️ Plugin API — experimental. The JSON protocol is versioned (schema_version: 1) but subject to breaking changes until further notice. Pin your plugin to a specific Dofek version if stability matters. Once the contract stabilizes, the API will follow semver.
ARCHITECTURE

How plugins work

Dofek spawns your plugin as a child process. Every refresh cycle, it writes a poll request to stdin and reads your JSON response from stdout. That's the entire contract.

Dofek (parent) plugin (child process) │ │ │── spawns process ───────────────>│ │ │ │ [every refresh cycle] │ │── {"type":"poll",...}\n ────────>│ │<── {"type":"poll_response"}\n ──│ │ │ │ [on exit] │ │── {"type":"shutdown"}\n ───────>│ │── kills after 2s ──────────────>│

Pull Model

Dofek owns the tick rate. No backpressure, no buffering, no message floods. Your plugin just responds when asked.

Stdio Pipes

No ports, no sockets, no service discovery. stdin/stdout pipes are inherited at spawn. Use stderr for your debug logs.

Auto Recovery

If your plugin crashes, Dofek restarts it with exponential backoff: 1s → 2s → 4s → 8s → 16s → 30s cap.

PROTOCOL

Request & response

Newline-delimited JSON. One object per line, terminated by \n. Your plugin receives poll requests on stdin and writes responses to stdout.

Poll Request Dofek → plugin

JSON{ "type": "poll", "timestamp_ms": 1713020400000, "processes": [ { "pid": 1234, "name": "ollama_llama_server.exe", "vram_bytes": 4294967296 } ] }
FIELDTYPEDESCRIPTION
type"poll"Always "poll"
timestamp_msu64Unix timestamp in milliseconds
processesarrayCurrent system processes — ignore if not needed

Poll Response plugin → Dofek

JSON{ "status": "ok", "panels": [...], "process_annotations": [...], "metrics": [...] }

All three arrays are optional — include only what your plugin provides. On the first response, include a manifest field to identify your plugin.

RESPONSE FIELDS

Three ways to inject data

Each response can include panels (dock UI), process annotations (watchlist labels), and metrics (ticker pills). Mix and match as needed.

panels — Plugin Dock UI

JSON"panels": [{ "id": "ollama-status", "label": "OLLAMA", "content": [ { "key": "Model", "value": "llama3:8b", "style": "accent" }, { "key": "Status", "value": "idle", "style": "dim" } ] }]

Panel content is rendered in the plugin dock at the bottom of the watchlist. The first panel's values appear inline next to the plugin name.

Style values

normal
accent
dim
warn
error

process_annotations — Enrich Process Rows

JSON"process_annotations": [{ "pid": 1234, "label": "llama3:8b", "category": "ai", "ai_state": "inferring" }]
FIELDREQUIREDVALUES
pidyesMust match a running process
labelnoAny string — shown on the process row
categoryno"ai" "dev" "watch"
ai_stateno"idle" "loading" "inferring"

metrics — Ticker Bar Pills

JSON"metrics": [{ "id": "ollama.requests_per_min", "label": "Req/min", "value": 12.5, "unit": "req/m" }]
FIELDTYPEDESCRIPTION
idstringUnique, namespaced (e.g., "ollama.running")
labelstringShort label for the ticker pill
valuef64Numeric value
unitstringSuffix (empty string for no unit)
LIFECYCLE

Plugin states

Dofek tracks each plugin's health and displays a colored indicator in the dock.

Starting
Just spawned, no successful poll yet
Healthy
Last poll succeeded
Unhealthy
5+ consecutive errors or timeouts
Crashed
Process exited — respawns with backoff

Configuration

TOML# dofek.toml [[plugins]] name = "my-plugin" # Display name (overridden by manifest) command = "dofek-my-plugin" # Binary name (PATH) or absolute path args = ["--flag", "value"] # Optional arguments enabled = true # Default: true timeout_ms = 2000 # Per-poll timeout (default: 2000)
INTERACTIVE

Protocol playground

Edit a plugin response and see how it renders in the Dofek dock. Validates your JSON in real-time.

PLUGIN RESPONSE EDITOR
DOCK PREVIEW
PLUGINS
TICKER PREVIEW
GENERATOR

Plugin scaffolder

Generate a starter template for your plugin. Fill in the details, pick a language, and copy the code.

← Click GENERATE to create a plugin template
BEST PRACTICES

Tips for plugin authors

  • Always flush stdout after writing a response — buffered output causes timeouts
  • Use stderr for logging — Dofek captures it, stdout is reserved for the protocol
  • Respond quickly — you have timeout_ms (default 2s) to respond to each poll
  • Namespace metric IDs — use plugin_name.metric_name to avoid collisions
  • Ignore unknown fields — Dofek may add new fields to poll requests in the future
  • Handle malformed input — skip lines you can't parse, don't crash
  • Include a manifest in your first response so Dofek can identify your plugin
  • Test standalone before connecting to Dofek:
# Quick test — pipe a poll request to your plugin echo '{"type":"poll","timestamp_ms":0,"processes":[]}' | python my_plugin.py