No description
  • Nix 51.1%
  • Rust 48.6%
  • Just 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
JMARyA 73a013c0aa
docs(display): where screens are heading
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>
2026-10-10 20:56:31 +02:00
bin feat(appliance): units sandboxed, a firewall, named logs, an aarch64 boot 2026-10-05 18:40:17 +02:00
crates feat(display): screens as Things — display, kiosk and sign on Hyprland 2026-10-10 20:56:31 +02:00
docs docs(display): where screens are heading 2026-10-10 20:56:31 +02:00
examples feat(host): the computer itself as a Thing 2026-10-07 15:31:38 +02:00
nix feat(display): screens as Things — display, kiosk and sign on Hyprland 2026-10-10 20:56:31 +02:00
.gitignore refactor: the flake in parts, every Nix file formatted, the docs a site 2026-10-05 18:40:18 +02:00
Cargo.lock feat(display): screens as Things — display, kiosk and sign on Hyprland 2026-10-10 20:56:31 +02:00
Cargo.toml feat: appliance images with ecinit as PID 1 2026-09-22 23:51:51 +02:00
flake.lock refactor: the flake in parts, every Nix file formatted, the docs a site 2026-10-05 18:40:18 +02:00
flake.nix refactor: the flake in parts, every Nix file formatted, the docs a site 2026-10-05 18:40:18 +02:00
justfile refactor: the flake in parts, every Nix file formatted, the docs a site 2026-10-05 18:40:18 +02:00
README.md feat(display): screens as Things — display, kiosk and sign on Hyprland 2026-10-10 20:56:31 +02:00
renovate.json Add renovate.json 2026-07-25 02:00:33 +00:00
rust-toolchain.toml initial commit 2026-06-19 23:52:00 +02:00
zensical.toml feat(display): screens as Things — display, kiosk and sign on Hyprland 2026-10-10 20:56:31 +02:00

💠 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.