EcoOS
EcoOS is a purpose-built Ubuntu-based operating system for EcoBridge kiosks and local device appliances. It boots into a fullscreen bundled EcoBridge Main App under Sway while the EcoOS daemon exposes a management UI and API on 0.0.0.0:3006.
Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.
Features
- Mainapp kiosk boot - Sway starts the bundled EcoBridge Main App from
/opt/eco/mainapp/current/ecobridge.xyz. - Management UI - Monitoring and control via HTTP on port
3006. - Signed mainapp updates - The daemon verifies a signed manifest before installing or switching mainapp releases.
- EcoOS daemon updates - The daemon installs signed EcoOS releases, checks the new executable before swapping it in, and restores the previous one when it does not come up.
- System monitoring - CPU, memory, disk, network, GPU, input, audio, logs, and service health.
- Display controls - Sway output discovery and display enable/disable/primary actions.
- Compatibility endpoint -
/api/restart-chromiumremains available as an alias for shipped clients, but the runtime app is now the mainapp.
Architecture
EcoOS ISO / installed system
├── eco-daemon (systemd)
│ ├── process manager: Sway + EcoBridge Main App
│ ├── system info collector
│ ├── EcoOS updater
│ ├── signed mainapp updater
│ └── UI server: REST API and dashboard on 0.0.0.0:3006
├── Sway compositor (Wayland)
│ └── EcoBridge Main App (fullscreen Electron app)
├── /opt/eco/mainapp/releases/<version>
├── /opt/eco/mainapp/current -> active release
└── Ubuntu 24.04 base with systemd, seatd, and PipeWire
Development
Prerequisites
- Docker for ISO building (the live-build step runs
docker run --privileged) - pnpm for package scripts, Node.js for daemon development
- qemu-user with
binfmt_miscand the arm64 cross libraries (/usr/aarch64-linux-gnu) for the emulated linux-arm64 smoke check ofpnpm run daemon:bundle - QEMU for ISO testing
Project Structure
eco_os/
├── ecoos_daemon/ # Daemon source (Node.js/TypeScript), its own pnpm package
│ ├── mod.ts # Entry point (`--version`, else start)
│ ├── .smartconfig.json # tsbundle (UI, daemon bundle) and tssea (executables) configuration
│ ├── test/ # Daemon tests (tstest)
│ ├── keys/ # Public keys used for update verification
│ ├── ts/daemon/ # Core daemon, process manager, updaters
│ ├── ts/ui/ # HTTP/WebSocket management server
│ ├── ts_interfaces/ # API contracts shared with the UI
│ └── ts_web/ # Management UI frontend
├── isobuild/ # ISO build configuration
│ ├── Dockerfile # Build container and ISO assembly
│ ├── mainapp-version.txt # Bundled mainapp release tag
│ ├── config/ # live-build configuration
│ └── scripts/ # Build scripts
├── isotest/ # QEMU test scripts
└── .nogit/ # Generated artifacts and local secrets
Commands
# Build the amd64 ISO. The build also builds the daemon executable for the target.
pnpm run build
# Explicit amd64 build.
pnpm run build:amd64
# Build the management UI and the daemon bundle (ecoos_daemon/dist_node/eco-daemon.mjs).
pnpm run daemon:ui
# Type-check daemon and UI code (after daemon:ui, which generates ts/daemon/bundledui.ts).
pnpm run daemon:typecheck
# Run the daemon tests.
pnpm run daemon:test
# Build the linux-x64 and linux-arm64 executables into ecoos_daemon/bundle/.
pnpm run daemon:bundle
# Build and run the daemon bundle on this machine.
pnpm run daemon:start
# Test ISO in QEMU.
pnpm run test
# Take a screenshot of the running VM.
pnpm run test:screenshot
# Stop the QEMU VM.
pnpm run test:stop
# Clean generated build artifacts.
pnpm run clean
Current bundled mainapp support is amd64 / Linux x64 only. The arm64 and rpi build scripts remain present but are intentionally blocked until matching signed mainapp release artifacts exist.
Management UI and API
The daemon serves the management UI at http://localhost:3006 and on the device IP at port 3006.
Dashboard Panels
| Panel | Description |
|---|---|
| Services | Sway and Main App status |
| CPU | Model, core count, and real-time usage |
| Memory | Used and total memory |
| Network | Interface names and IP addresses |
| Disks | Mount points, usage, and capacity |
| System | Hostname, uptime, and GPU information |
| Controls | Mainapp restart, display controls, and system reboot |
| Updates | EcoOS daemon update controls and signed mainapp update controls |
| Input Devices | Keyboards, mice, touchscreens, and related devices |
| Audio | Detected speakers and microphones |
| Logs | Daemon logs and system journal output |
API Endpoints
| Endpoint | Method | Description | Token |
|---|---|---|---|
/api/identity |
GET | { appId, version, hostname } for LAN discovery |
No |
/api/status |
GET | Full system status | Yes |
/api/logs |
GET | Daemon logs | Yes |
/api/displays |
GET | Sway display information | Yes |
/api/reboot |
POST | Reboot the system | Yes |
/api/restart-mainapp |
POST | Restart the EcoBridge Main App | Yes |
/api/restart-chromium |
POST | Compatibility alias for restarting the mainapp | Yes |
/api/updates |
GET | EcoOS update information | Yes |
/api/updates/check |
POST | Check for EcoOS updates | Yes |
/api/upgrade |
POST | Upgrade EcoOS to a specific version | Yes |
/api/mainapp-updates |
GET | Signed mainapp update information | Yes |
/api/mainapp-updates/check |
POST | Check for signed mainapp updates | Yes |
/api/mainapp-upgrade |
POST | Install and switch to a specific mainapp version | Yes |
/api/displays/{name}/enable |
POST | Enable a display output | Yes |
/api/displays/{name}/disable |
POST | Disable a display output | Yes |
/api/displays/{name}/primary |
POST | Set the primary kiosk display | Yes |
/ws |
WebSocket | Status stream | Yes, as ?token= |
Every endpoint except /api/identity requires the API token as Authorization: Bearer <token> or X-EcoOS-Api-Token: <token>; loopback requests are not trusted. The token is ECOOS_API_TOKEN when set, otherwise the one persisted in /etc/eco/api-token (0600), generated on first start; read it on the appliance with sudo cat /etc/eco/api-token. The UI asks for it once per browser session. No Access-Control-Allow-Origin header is sent, so cross-origin pages cannot call the API.
Update System
EcoOS has two update tracks.
EcoOS Daemon Updates
- The daemon polls EcoOS releases and tracks available versions.
- New EcoOS releases wait through a stability period before automatic upgrade.
- Manual checks and upgrades are available through the UI and API.
- Only releases with
ecoos-update-manifest.jsonand.sigare installed. The signature is verified with the pinned key (ecoos_daemon/keys/ecoos-update-manifest-public-key.pem), then the manifest must declare schema version 1, app idecoos-daemon, channelstable, the release's tag and version and the device's architecture (linux-x64/linux-arm64); the asset itsartifact.namenames must have the declared size and SHA-256. - The executable is streamed into a private directory beside
/opt/eco/bin/eco-daemonand must answer--versionwitheco-daemon <version>. The running executable is kept as/opt/eco/bin/eco-daemon.previous, the new one is renamed into place, and a transient systemd unit restartseco-daemon; when/api/identitydoes not report the new version within two minutes, it moves the previous executable back and restarts again. - The UI reloads when the daemon version changes.
Signed Mainapp Updates
- Mainapp releases are discovered from
ecobridge.xyz/mainappGitea releases. - EcoOS only accepts releases with
mainapp-update-manifest.jsonandmainapp-update-manifest.json.sig. - The manifest signature is verified with the pinned public key in
ecoos_daemon/keys/. - The manifest must match the expected app id, channel, architecture, version, asset size, and SHA256.
- The portable tarball is extracted safely into
/opt/eco/mainapp/releases/<version>. /opt/eco/mainapp/currentis switched only after verification.- The daemon restarts the mainapp, performs a health check, and rolls back on failure.
The bundled mainapp version for ISO builds is pinned in isobuild/mainapp-version.txt.
Testing
QEMU Virtual Machine
# Start VM.
pnpm run test
# Take screenshots to monitor progress.
pnpm run test:screenshot
# Screenshot loop.
pnpm run test:screenshot:loop
# Stop VM.
pnpm run test:stop
# Clean and restart fresh.
pnpm run test:clean && pnpm run test
Serial Console
socat - UNIX-CONNECT:.nogit/vm/serial.sock
Login is ecouser / ecouser. Use sudo -i for root.
Release Assets
A tag v<version> runs .gitea/workflows/release.yml in ht-docker-node, which publishes:
eco-daemon-v<version>: the linux-x64 daemon executable for in-place upgrades,ecoos-update-manifest.jsonandecoos-update-manifest.json.sig: the signed update manifest (the workflow fails without theECOOS_UPDATE_MANIFEST_PRIVATE_KEY_PEMsecret),ecoos-third-party-notices-v<version>.txtand.json: the executable's third-party notices,SHA256SUMS.txt.
The workflow does not build the ISO: live-build needs docker run --privileged, Docker access from the CI job container is not established, and jobs are limited to one hour. Build it with pnpm run build on a Docker host and attach .nogit/iso/ecoos.iso to the release. No linux-arm64 executable is published, because daemons released before the manifest-named asset selection install the first asset whose name contains eco-daemon.
The ISO build consumes a signed mainapp release from the mainapp repository. The expected portable asset name is EcoBridge-MainApp-vX.X.X-linux-x64.tar.gz, with the release tag read from isobuild/mainapp-version.txt.
Boot Menu Options
- Install EcoOS - Full installation to disk, auto-selected by default.
- EcoOS Live - Try without installing, running from RAM.
- EcoOS Live Safe Mode - Minimal boot for troubleshooting.
Technical Details
Daemon
- Runtime: a Node.js 26.11.1 single executable application (
@git.zone/tsbundlebundlesmod.tsand the base64-embedded management UI,@git.zone/tsseabuilds the executable). It needs glibc 2.28 or later,libstdc++6andlibatomic1(part of the ISO's package list); withoutlibatomic.so.1it exits 127. - Process management: Spawns and monitors Sway and the EcoBridge Main App.
- Backend fallback: Tries DRM first and falls back to headless or software-rendered modes when needed.
- Auto-recovery: Restarts crashed services.
- Logging: Integrates with the systemd journal and management UI.
Mainapp Runtime
- Executable:
/opt/eco/mainapp/current/ecobridge.xyz. - Environment:
RUNTIME_ENV=sway. - Electron flags:
--no-sandbox,--ozone-platform=wayland,--enable-features=UseOzonePlatform, and--disable-dev-shm-usage. - Active release link:
/opt/eco/mainapp/current. - Release storage:
/opt/eco/mainapp/releases/<version>.
System Stack
- Base: Ubuntu 24.04 LTS.
- Init: systemd.
- Display: Sway Wayland compositor.
- Seat manager: seatd.
- Audio: PipeWire.
License and Legal Information
No dedicated repository license file is currently present. Confirm the licensing terms before public redistribution.
Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
Company Information
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section and understand that these legal notices do not imply endorsement by Task Venture Capital GmbH of any derivative works.