- Nix 51.1%
- Rust 48.6%
- Just 0.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Ideas for screens beyond a kiosk and a sign, each with what works today and what it would need: one picture across outputs and across devices, sharing a screen to one, interactive kiosks, e-ink and shelf labels. None is built; the roadmap gets a table pointing at the detail. Two framings are deliberate. Syncing screens is a display problem, so it belongs to a player daemon behind the Thing, the way go2rtc is behind a camera; ecd exposes its group and tile. And a shelf label runs no ecd *yet*: the aim is firmware built from the same declaration, with a gateway serving tags as Things only in the meantime. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
| bin | ||
| crates | ||
| docs | ||
| examples | ||
| nix | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| flake.lock | ||
| flake.nix | ||
| justfile | ||
| README.md | ||
| renovate.json | ||
| rust-toolchain.toml | ||
| zensical.toml | ||
💠 edgecore
A lean, declarative agent that turns a physical device into a discoverable,
composable capability surface — speaking W3C Web of Things.
edgecore is a framework for special devices and a control daemon, ecd,
that exposes a device's capabilities and values. You describe a device once, in a
single declarative TOML manifest; ecd then:
- generates a conformant WoT Thing Description (TD 1.1),
- serves a WoT HTTP API plus a small built-in web GUI,
- routes each interaction to its backing (a command, file, HTTP endpoint, …),
- announces the device on the LAN over DNS-SD/mDNS (
_wot._tcp).
Any WoT consumer can drive the device with zero edgecore-specific knowledge.
edgecore lives at git.hydrar.de/jmarya/edgecore. It is a sibling of
Shinra: Shinra declares what a computer should be, edgecore
exposes what a device provides. Neither requires the other.
Quick start
With Nix (flakes enabled):
nix develop # the pinned Rust toolchain, just, nixfmt, zensical
nix build .#ecd # build the daemon
nix flake check # build, clippy, rustfmt, tests, module evaluation, docs
just --list # the everyday recipes
Run the daemon against a manifest:
ecd path/to/device.toml # serve the device
ecd --check device.toml # validate the manifest and exit
ecd --td device.toml # print the generated Thing Description
One process can host several Things (a WoT Servient) — pass multiple manifests
or a directory of them. They share one port; each keeps its own base path, and
GET /things lists every hosted Thing Description:
ecd things.d/ # every *.toml in the directory
ecd lobby-01.toml door-02.toml # or an explicit list
Then visit http://<host>:<port><base> for the GUI, or fetch the TD at
<base>/.well-known/wot.
A minimal manifest
[device]
id = "urn:edgecore:kiosk:lobby-01"
title = "Lobby Kiosk"
class = "kiosk"
[property.brightness]
type = "integer"
unit = "percent"
minimum = 0
maximum = 100
source = { exec = "backlight-get" }
sink = { exec = "backlight-set {value}" }
[action.reload]
run = { exec = "kiosk-reload {hard}" }
[action.reload.input.properties.hard]
type = "boolean"
[expose]
bind = ["http"]
gui = true
[expose.http]
port = 9688
base = "/things/lobby-01"
[expose.discovery]
mdns = true
See the examples/ directory for full manifests:
lobby-01.toml (kiosk),
camera-01.toml (camera),
env-sensor-01.toml (sensor),
light-01.toml (smart light),
speaker-01.toml (speaker),
host-01.toml (the host itself — runnable as-is on any
Linux box).
See docs/manifest.md for the complete schema.
HTTP surface
| Route | WoT operation |
|---|---|
GET /.well-known/wot |
fetch the Thing Description |
GET /properties/{name} |
read a property (SSE observe with Accept: text/event-stream) |
PUT /properties/{name} |
write a property |
POST /actions/{name} |
invoke an action (JSON body → backing) |
GET /events/{name} |
subscribe to an event (SSE) |
ANY /stream/{*rest} |
authenticated reverse proxy to a local media server (when [stream] is set) |
GET / |
the web GUI (when expose.gui = true) |
All routes are mounted under the device's expose.http.base, and are served over
HTTPS when [expose.http.tls] is set.
Documentation
The documentation is a site built with Zensical, with an option reference
generated from the Nix modules:
nix build .#docs # the site, in result/
just docs-serve # preview locally
Start with what runs and what does not, then
the manifest, appliances,
the archetypes and the architecture.
Contributing covers the repository, the checks and the
commit style.
Repository layout
crates/manifest manifest types · parse · validate
crates/td Thing Description model · generation
crates/backing the Backing trait + exec/file/http/const/journal/lines
crates/server axum WoT HTTP surface + web GUI + auth + stream proxy
crates/discovery mDNS / DNS-SD advertise + browse
bin/ecd the daemon
bin/edgectl fleet CLI/TUI: discover and drive Things
bin/ecinit PID 1 for appliance images
nix/flake the flake's parts: modules, Rust build, checks, devshell
nix/modules NixOS modules: ecd, things
nix/things the Thing model: one directory per kind, one file per capability group
nix/appliance whole-device images on not-os
docs the documentation site and its reference generator
examples example manifests
edgectl — the fleet client
edgectl discovers Things on the LAN over mDNS and drives them by a short
handle — multi-Thing from the start, no per-command endpoint juggling.
edgectl discover # browse _wot._tcp → list the whole fleet
edgectl get webcam resolution # read a property (Thing addressed by handle)
edgectl set lobby brightness 70 # write a property
edgectl invoke webcam snapshot '{"output_dir":"/tmp"}'
edgectl watch door state # live SSE stream
edgectl tui # interactive fleet browser
Add --url <servient> to include hosts not on mDNS, --token/$ECD_TOKEN for
auth (applied per each Thing's advertised scheme), and -k to accept the
self-signed certs edge devices serve.
Status
Early. The daemon, its backings, TLS, discovery and edgectl work; the camera,
speaker, host, env-sensor, display, kiosk and sign archetypes produce working
Things; the other
archetypes' capabilities refuse to build until they are implemented. The roadmap is
the exact account.