Skip to content

Instantly share code, notes, and snippets.

@fuzzy
Created March 8, 2026 08:52
Show Gist options
  • Select an option

  • Save fuzzy/cc664775e55b4b45125dc67920ee898b to your computer and use it in GitHub Desktop.

Select an option

Save fuzzy/cc664775e55b4b45125dc67920ee898b to your computer and use it in GitHub Desktop.
9p based home automation plan

Capabilities File Format Specification v1

Format Versioning

The first line of every /capabilities file MUST specify the format version:

# capabilities-format: v1

This enables future evolution of the format while maintaining backward compatibility.

Version 1 Format Specification

After the version line, each subsequent line defines a single file or directory:

# <path> | <help text> | <ui label> | <type> | <access> | [options]

Field Definitions

  • path : Full path to the file relative to node root
  • help text : Human-readable description
  • ui label : Short label for UI generation
  • type : Data type (see *Data Types)
  • access : read, write, read/write
  • options : Optional comma-separated key=value pairs (see *Options)

Data Types

TypeDescriptionExample Values
integerWhole number72, -5, 1000
booleanTrue/false0/1, on/off, true/false
stringText“living room”, “fan”
enumSet of allowed valueslow,medium,high
floatDecimal number23.5, -1.2, 98.6
directoryContainer for other files(no value)
timestampTime in ISO 8601 or Unix epoch2024-01-15T14:30:00Z
colorRGB or named color#FF0000, red

Options

Optional key=value pairs that provide additional metadata:

OptionDescriptionExample
unitUnit of measurementunit=F, unit=C, unit=%
minMinimum allowed valuemin=0
maxMaximum allowed valuemax=100
stepIncrement step for UI controlsstep=0.5
enumComma-separated allowed valuesenum=off,low,medium,high
defaultDefault valuedefault=72
patternRegex pattern for string validationpattern=^[A-Za-z ]+$
deprecatedMark as deprecateddeprecated=use /new/path
requiresDependency on another filerequires=/config/mode
writableWhen file is only writable under conditionswritable=when state=off

Complete Version 1 Example

# capabilities-format: v1

# Sensor readings
/current/temperature_f | Temperature in Fahrenheit | Temp F | float | read | unit=F, min=-40, max=250
/current/temperature_c | Temperature in Celsius | Temp C | float | read | unit=C, min=-40, max=120
/current/humidity | Relative humidity percentage | Humidity | integer | read | unit=%, min=0, max=100
/current/pressure | Barometric pressure in hPa | Pressure | float | read | unit=hPa, min=300, max=1100

# Control endpoints
/sockets/01/control | Fan control | Fan | enum | read/write | enum=off,on,auto, default=off
/sockets/01/state | Current fan state | Fan State | enum | read | enum=off,on
/sockets/02/control | Light control | Light | boolean | read/write | default=0
/sockets/02/state | Current light state | Light State | boolean | read

# Configuration
/config/name | Friendly name | Device Name | string | read/write | pattern=^[a-z0-9-]{1,32}$
/config/report_interval | Seconds between reports | Report Interval | integer | read/write | unit=s, min=1, max=3600, default=30
/config/thresholds/high_temp | Alert when temp exceeds | High Temp Alert | float | read/write | unit=F, min=50, max=120, default=85

# Node metadata
/node/info | Node information | Info | string | read
/node/version | Firmware version | Version | string | read | pattern=^\d+\.\d+\.\d+$
/node/status | Current health status | Status | enum | read | enum=ok,warning,error,unknown
/node/uptime | Seconds since boot | Uptime | integer | read | unit=s

# Cache and state (read-only views)
/cache/last_reported/temperature_f | Last reported temperature | Last Temp | float | read | unit=F
/cache/stats/temperature_f/min | Minimum temperature today | Min Today | float | read | unit=F
/cache/stats/temperature_f/max | Maximum temperature today | Max Today | float | read | unit=F
/cache/stats/temperature_f/avg | Average temperature today | Avg Today | float | read | unit=F

# Directories (implied by paths, can be explicit)
/config/ | Configuration directory | Config | directory | read
/config/thresholds/ | Threshold values | Thresholds | directory | read
/cache/ | Local state cache | Cache | directory | read
/cache/stats/ | Statistical data | Statistics | directory | read
/cache/stats/temperature_f/ | Temperature statistics | Temp Stats | directory | read

Capabilities File Location and Access

  • Every node MUST provide /capabilities at its root
  • The file MUST be readable by anyone (no authentication required)
  • The file SHOULD be static (changes only with firmware updates)
  • Control panels MAY cache this file and check for updates periodically

Version Negotiation (Future)

Control panels can check the version and adapt:

version=$(head -1 /capabilities | cut -d: -f2 | tr -d ' ')
case $version in
  v1)   parse_v1_capabilities ;;
  v2)   parse_v2_capabilities ;;
  *)    log_error "Unsupported capabilities format: $version" ;;
esac

Extended Example: Desk Clock Capabilities

# capabilities-format: v1

# Display interface
/display/message | Write text to display | Message | string | write | pattern=^.{1,64}$
/display/markup | List available markup codes | Markup | directory | read
/display/brightness | Display brightness | Brightness | integer | read/write | min=0, max=100, step=5, default=80
/display/clear | Clear the display | Clear | boolean | write

# Markup definitions (files under /display/markup)
/display/markup/red | Red text markup | Red | string | read | default=[red]:
/display/markup/yellow | Yellow text markup | Yellow | string | read | default=[yellow]:
/display/markup/green | Green text markup | Green | string | read | default=[green]:
/display/markup/blue | Blue text markup | Blue | string | read | default=[blue]:
/display/markup/white | White text markup | White | string | read | default=[white]:

# Syslog interface
/syslog/messages | Recent log messages | Logs | directory | read
/syslog/priority/info | Info priority | Info | boolean | write
/syslog/priority/warn | Warning priority | Warn | boolean | write
/syslog/priority/error | Error priority | Error | boolean | write

# Time (if clock has RTC)
/time/current | Current time | Time | timestamp | read
/time/set | Set the time | Set Time | timestamp | write
/time/timezone | Timezone setting | Timezone | string | read/write | pattern=^[A-Za-z/]+$

# Node metadata
/node/info | Clock node | Info | string | read | default="9P Desk Clock"
/node/version | Firmware version | Version | string | read | pattern=^\d+\.\d+\.\d+$
/node/status | Node health | Status | enum | read | enum=ok,warning,error

Extended Example: Power Strip with Energy Monitoring

# capabilities-format: v1

# Overall device info
/device/model | Device model | Model | string | read | default="4-Outlet Smart Strip"
/device/mac | MAC address | MAC | string | read | pattern=^([0-9A-F]{2}:){5}[0-9A-F]{2}$

# Individual outlets
/socket/1/control | Outlet 1 control | Outlet 1 | boolean | read/write | default=0
/socket/1/state | Outlet 1 state | State | boolean | read
/socket/1/name | Outlet 1 name | Name | string | read/write | pattern=^.{1,32}$, default="Outlet 1"
/socket/1/power | Current power draw | Power | float | read | unit=W, min=0, max=1800

/socket/2/control | Outlet 2 control | Outlet 2 | boolean | read/write | default=0
/socket/2/state | Outlet 2 state | State | boolean | read
/socket/2/name | Outlet 2 name | Name | string | read/write | pattern=^.{1,32}$, default="Outlet 2"
/socket/2/power | Current power draw | Power | float | read | unit=W, min=0, max=1800

/socket/3/control | Outlet 3 control | Outlet 3 | boolean | read/write | default=0
/socket/3/state | Outlet 3 state | State | boolean | read
/socket/3/name | Outlet 3 name | Name | string | read/write | pattern=^.{1,32}$, default="Outlet 3"
/socket/3/power | Current power draw | Power | float | read | unit=W, min=0, max=1800

/socket/4/control | Outlet 4 control | Outlet 4 | boolean | read/write | default=0
/socket/4/state | Outlet 4 state | State | boolean | read
/socket/4/name | Outlet 4 name | Name | string | read/write | pattern=^.{1,32}$, default="Outlet 4"
/socket/4/power | Current power draw | Power | float | read | unit=W, min=0, max=1800

# Total system monitoring
/power/total | Total power draw | Total Power | float | read | unit=W, min=0, max=3600
/power/voltage | Line voltage | Voltage | float | read | unit=V, min=100, max=240
/power/frequency | Line frequency | Frequency | float | read | unit=Hz, min=50, max=60

# Energy tracking (cumulative)
/energy/total_kwh | Total energy used | Total Energy | float | read | unit=kWh, min=0
/energy/reset | Reset energy counters | Reset | boolean | write

# Configuration
/config/auto_off_timer | Auto-off minutes | Auto Off | integer | read/write | unit=min, min=0, max=1440, default=0
/config/startup_state | State on power-up | Startup | enum | read/write | enum=off,on,last, default=off

# Node metadata
/node/info | Power strip node | Info | string | read
/node/version | Firmware version | Version | string | read | pattern=^\d+\.\d+\.\d+$
/node/status | Health status | Status | enum | read | enum=ok,warning,error

Control Panel Capabilities Example

# capabilities-format: v1

# Node management
/nodes/ | Discovered nodes | Nodes | directory | read
/nodes/_discover | Trigger discovery | Discover | boolean | write

# Rule management
/rules/ | User rules | Rules | directory | read
/rules/_create | Create new rule | New Rule | string | write
/rules/_validate | Validate rule syntax | Validate | string | write | returns validation result

# System state
/state/current | Current system state | Current | directory | read
/state/history | Historical data | History | directory | read
/state/summary | System summary | Summary | string | read

# AI integration
/ai/prompt | Send prompt to AI | Prompt | string | write
/ai/response | Last AI response | Response | string | read
/ai/context | Current context for AI | Context | string | read
/ai/tools/ | Available AI tools | Tools | directory | read

# Control panel configuration
/config/poll_interval | Node poll interval | Poll Interval | integer | read/write | unit=s, min=5, max=3600, default=30
/config/llm_endpoint | LLM API endpoint | LLM URL | string | read/write
/config/llm_model | LLM model name | Model | string | read/write

# Control panel metadata
/node/info | Control panel node | Info | string | read | default="9P Home Control Panel"
/node/version | Software version | Version | string | read | pattern=^\d+\.\d+\.\d+$
/node/status | System health | Status | enum | read | enum=ok,warning,error
/node/uptime | Uptime in seconds | Uptime | integer | read | unit=s

Version History

  • **v1** (2024-01-15): Initial format specification
    • Basic path|help|label|type|access format
    • Support for key=value options
    • Standard data types defined
    • Directory support

Future Version Considerations (v2 ideas)

  • JSON schema support for complex validation
  • Internationalization (multiple help text languages)
  • Capability groups/profiles
  • Event subscriptions
  • Unit conversion hints
  • Security capabilities (auth requirements)
  • Rate limiting specifications
  • Dependency graphs between files
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment