Spec-driven ML on the factory floor. Drop signed agents into legacy PLCs with a single firmware call—treat intelligence like any other function block, not a science project.
Grid and plant operators still depend on ladder logic and fixed hardware long after software-defined systems took over the data center. EdgePlug closes that gap: a tiny on-device runtime, a marketplace and API for agents, and a pipeline from training to quantized binaries—so you can ship something like VoltageEventAgent v1.0 with the same discipline as shipping firmware.
The repository is a polyglot monorepo: embedded C, Go services, React/TypeScript UI, Python ML tooling, and an Electron desktop client. Everything is wired for reproducible installs (lockfiles, uv, CI per component) and honest automation (root GitHub Actions, Dependabot).
| Layer | Role | Tech | Docs |
|---|---|---|---|
| Runtime | Load, verify, run, and hot-swap agents under flash/SRAM budgets | C11, CMake | runtime/docs |
| Marketplace | REST API, auth, storage, metrics | Go, PostgreSQL, Docker | marketplace/README.md |
| UI | Design system, demos, a11y-tested flows | React 18, TypeScript, Vite | ui/README.md |
| Models | Train, quantize, stress-test models for deployment | Python 3.11, uv | models/README.md |
| Desktop | Native marketplace client | Electron | marketplace/desktop/ |
flowchart TB
subgraph device [Device]
RT[Runtime C ≤32KB]
end
subgraph platform [Platform]
API[Marketplace API Go]
WEB[Design system UI]
DESK[Electron desktop]
end
subgraph ml [ML workflow]
PY[Python pipeline]
end
PY -->|"agents / binaries"| RT
WEB --> API
DESK --> API
API --> RT
Contract between worlds: manifest.proto describes the agent manifest; tooling under tools/ helps sign and publish artifacts.
Repository tree (expand)
EdgePlug/
├── .github/ CI workflows, Dependabot
├── runtime/ Firmware runtime, CTest, CMakePresets (ci-native)
├── marketplace/ Go API, compose stack, desktop/, k6, SBOM, monitoring
├── ui/ @edgeplug/ui — components, Storybook, Playwright
├── models/ pyproject.toml, uv.lock, Dockerfile, pipeline stages
├── tools/ Manifest signing, flash helpers
├── tests/ Cross-cutting integration / security tests
├── Makefile make test-ui, test-go, test-runtime, …
├── CONTRIBUTING.md · SECURITY.md · RELEASING.md
└── manifest.proto
cd marketplace
docker compose up -d
curl -s http://localhost:8080/health| Endpoint | Purpose |
|---|---|
| localhost:8080 | API |
| localhost:3000 | Grafana (admin / admin by default) |
| localhost:9001 | MinIO console |
| localhost:9091 | Prometheus (host port in compose) |
The Vite design-system demo is separate: run it from ui/ (npm run demo). Compose does not start it.
cd runtime
cmake --preset ci-native
cmake --build --preset ci-native
ctest --preset ci-native --output-on-failureCross-compile for ARM targets uses your toolchain file (see runtime/toolchain/).
cd ui
npm ci
npm run dev # tsc --watch
npm run demo # Vite demo
npm test && npm run lint && npm run buildcd models
uv sync --python 3.11 --extra full # full stack; omit --extra full for lighter dev
uv run python pipeline.py --helpMore detail: models/TOOLCHAIN.md for QEMU, ARM GCC, and CMake outside PyPI.
Load a signed agent, run inference on sensor data, hot-swap without rebooting:
edgeplug_status_t status = edgeplug_load_agent(
agent_cbor_data, agent_size, &manifest);
edgeplug_sensor_data_t sensor_data = {
.voltage = 230.0f, .current = 10.5f,
.timestamp = get_timestamp(), .quality = 95
};
edgeplug_actuation_cmd_t actuation_cmd;
status = edgeplug_process_sensors(&sensor_data, &actuation_cmd);
status = edgeplug_hotswap_agent(new_agent_cbor, new_agent_size, &new_manifest);Public headers and memory layout: runtime/include/, runtime/docs/memory_map.md.
| Theme | Examples |
|---|---|
| Integrity | Ed25519 signing, SHA-512 content binding, manifest verification |
| Platform | JWT-backed API, TLS-ready deployment patterns, SBOM generation |
| Runtime | Bounds checks, NaN guards, output limits, fail-closed paths |
| Process | SECURITY.md for disclosure, govulncheck and Dependabot in CI |
Compliance targets (IEC 62443, OWASP ASVS, CycloneDX, SOC 2) are design goals—map them to your audit scope and deployment, not as a substitute for your own assessment.
Numbers below are engineering targets for the embedded profile and representative API/UI work—not a substitute for measurement on your silicon and network.
| Metric | Target | Reference |
|---|---|---|
| Runtime image | ≤ 32 KB Flash | ~28 KB class |
| RAM | ≤ 4 KB SRAM | ~3.2 KB class |
| Inference | ≤ 500 µs | ~420 µs class |
| Agent binary budget | ≤ 16 KB | ~14 KB class |
| API latency | P95 under 300 ms | ~245 ms class |
| UI quality | Lighthouse ≥ 90 | ~94 class |
| You are working on… | Useful commands | Workflow |
|---|---|---|
| Go API | cd marketplace && go test ./... -race |
marketplace.yml |
| UI | cd ui && npm ci && npm test |
ui.yml |
| Runtime | make test-runtime (needs Ninja) |
runtime.yml |
| Models | cd models && uv sync && uv run pytest tests/ |
models.yml |
| Desktop | cd marketplace/desktop && npm ci && npm run build |
desktop.yml |
Repo-wide conventions: CONTRIBUTING.md. Releases and branch protection: RELEASING.md.
Compose (lab or staging):
docker compose -f marketplace/docker-compose.yml up -d
docker compose -f marketplace/docker-compose.yml logs -fEmbedded: build edgeplug_runtime with your cross-build directory, then flash with your tool of choice (see tools/ for helpers such as edgeplug-push).
We welcome focused PRs—see CONTRIBUTING.md. Report security issues privately per SECURITY.md.
Licensed under the Apache License 2.0 — LICENSE. SPDX: Apache-2.0 where packages declare a license field.