Skip to content

Edge Agents

The 30 MB open-source edge AI agent runtime. Run AI agents offline, on Linux.

CI Go Reference License: AGPL v3

Edge Agents demo

Build an edge agent visually, deploy it to a Raspberry Pi, and let it talk to GPIO, MQTT and local SLMs — no cloud required.

Offline by default. GPIO, UART, MQTT as first-class nodes. Local SLMs alongside cloud LLMs in the same workflow. Industrial protocols (OPC-UA, Modbus) are on the roadmap.

Runs on Linux edge devices: Raspberry Pi 5 · Jetson Orin Nano · STM32MP25 · Bosch Rexroth ctrlX CORE.

Star the repo if you think AI agents belong beyond the cloud.

Today's AI agents live in datacenters. The interesting workloads — sensors, machines, vehicles, gateways — live everywhere else. Edge Agents brings the agent paradigm to the devices that interact with the real world: small enough to run on a Pi 5, capable enough to drive an industrial controller, with hardware I/O as native primitives instead of REST shims.

What you can build

  • Voice assistant on a Pi with a local SLM — wake-word → STT → agent → TTS, no internet required
  • Predictive maintenance on industrial gear — live vibration stream over MQTT → LLM decides → MQTT alert
  • Local RAG on a Jetson (on the roadmap) — answers grounded in live sensor and machine state instead of the public web (today the retriever runs against an external backend; a fully on-device RAG path is in progress)

Edge Agents vs other agent frameworks

Edge Agents n8n LangGraph Dify OpenClaw
Runtime size ~30 MB container ~500 MB Docker Python library ~500 MB Docker ~1 GB Docker
Offline by default depends on host ❌ datacenter-only
Hardware I/O (GPIO, UART, ADC) as nodes ✅ first-class
On-device SLM provider ✅ typed multi-endpoint partial via libs
MQTT as workflow transport ✅ first-class community node
Visual builder ❌ code-only
Industrial protocols (OPC-UA, Modbus) on roadmap community nodes

Using Edge Agents

Two pieces: the engine (a small container that runs your workflows) and the fh-workflow CLI (authors, validates, and visually edits workflow files). You can run the engine without ever cloning this repo, and author workflows with a single npm i -g @foresthubai/workflow-cli.

Quickstart

The lightest path needs no clone and no Docker — just the CLI and the visual builder:

npm i -g @foresthubai/workflow-cli
fh-workflow open my.workflow.json      # opens the visual builder; Save writes back to the file

Don't have a workflow yet? Let Claude Code write one from a single sentence — see Generate workflows with Claude Code. Ready to run it on real hardware? Run the engine on the device.

Run the engine

The engine ships as a small container you build from go/Dockerfile.engine (multi-arch, distroless, nonroot). Most edge targets are arm64 (Pi, Jetson, STM32MP2, ctrlX), so the common flow is to cross-build on an amd64 workstation and ship the result to the device:

cd go

# Cross-build for an arm64 edge device (use --platform linux/amd64 for x86 targets)
docker buildx build -f Dockerfile.engine --platform linux/arm64 -t engine:latest --load .

# Ship to an offline device: save to a tar, copy it across, load it there
docker save engine:latest -o engine.tar
#   scp engine.tar device:/tmp/   ← then, on the device:
docker load -i engine.tar

# The engine boots exactly one workflow, read once from ENGINE_CONFIG_FILE.
# A `fh-workflow deploy` bundle wires this up for you (see "Deploy a workflow").
docker run --rm \
  -v "$PWD/engine-config.json:/etc/foresthub/engine-config.json:ro" \
  -e ENGINE_CONFIG_FILE=/etc/foresthub/engine-config.json \
  engine:latest

Building for the same architecture you're already on? A plain docker build -f Dockerfile.engine -t engine:latest . works too — the Dockerfile cross-compiles via TARGETARCH, so QEMU only emulates the trivial copy into the final layer.

The engine:latest tag is the one a fh-workflow deploy bundle expects (its docker-compose.yml loads the image with pull_policy: never), so an image built here drops straight into a generated bundle.

The engine is a headless, immutable runner — it serves no inbound HTTP. It reads its single boot config (workflow + bindings + device manifest) once from ENGINE_CONFIG_FILE, runs that one workflow, and exits when the workflow does; a boot failure exits the process. It runs standalone by default — no control plane, no account, no inbound port, no outbound calls beyond LLM provider APIs. Setting FH_BACKEND_URL (with ENGINE_SECRET) opts into memory sync only; logs always go to stdout (the container runtime captures them — docker logs or your collector), and liveness is observed externally from the container's exit, not self-reported. Configure via ENGINE_* env vars; see go/cmd/engine/config.go.

Hardware access: the image runs as a nonroot distroless user, so reaching real GPIO, serial or analog devices needs them passed into the container with the right group — e.g. --device /dev/gpiochip0 --group-add "$(stat -c '%g' /dev/gpiochip0)" (or run with --privileged on a throwaway dev box). Pure-software workflows need none of this.

Author workflows

A workflow is a *.workflow.json file you author, validate, and open in the visual builder. Install the fh-workflow CLI from npm — no clone required:

npm i -g @foresthubai/workflow-cli
# or run it without installing:
npx @foresthubai/workflow-cli <command>
fh-workflow open my.workflow.json          # open the visual builder; Save writes back to the file
fh-workflow validate my.workflow.json      # semantic: wiring, references, types
fh-workflow check-schema my.workflow.json  # structural: types, required fields, enums
fh-workflow update my.workflow.json        # migrate a workflow to the current schema version
fh-workflow deploy my.workflow.json        # generate a self-contained deployment bundle
fh-workflow help                           # list all commands

fh-workflow open is the visual builder — the same React Flow canvas, served locally; hit Save and it writes straight back to your file. See ts/workflow-cli for the full command reference and the --static / --dev open modes.

Generate workflows with Claude Code

Describe a workflow in plain language and the workflow-generate skill writes the *.workflow.json and runs the validators for you. Install it into any project with the skills CLI — no clone required:

npx skills add ForestHubAI/edge-agents --skill workflow-generate

The skill validates by shelling out to the fh-workflow CLI, so install that too (npm i -g @foresthubai/workflow-cli). Then just describe a workflow — e.g. "read a sensor every 10s and toggle a relay" — and the skill generates and validates the file for you.

Deploy a workflow to a device

The quick path is fh-workflow deploy my.workflow.json — it inspects the workflow, asks for the values it can't infer (device paths, broker URLs, model files, API keys), and writes a self-contained bundle: docker-compose.yml, .env, the workflow, and any config files the workflow needs — plus a README.md with the build/transfer/run steps. For an on-device SLM it even drops in a llama component wired to the engine over the compose network. Without a terminal (CI, a Claude Code skill) feed the answers with --values <file.json>. The rest of this section explains what ends up in that bundle — and how to assemble it by hand if you'd rather.

Prefer to drive it from Claude Code? The workflow-deploy skill runs this same flow — reading the workflow, gathering the values, and writing the bundle while keeping secrets as placeholders. Install it the same way:

npx skills add ForestHubAI/edge-agents --skill workflow-deploy

A workflow is binding-free: it declares what it needs — channels (GPIO, MQTT, …) and custom models — but not where those live on a given device. You supply the where in a single boot config mounted into the engine container. See go/docs/workflow-deployment-layers.md for the schemas and deploy-time validation rules.

The engine reads exactly one file at a fixed path — /etc/foresthub/config.json, the EngineConfig blob — plus an out-of-band secret document. There are no per-file env vars:

Mounted file Holds When it matters
/etc/foresthub/config.json EngineConfig: { workflow, mapping, resources } — the graph, the logical-id→resource bindings, and every resolved resource (device families + MQTT / LLM / ML endpoints), all in one blob always — it is the engine's whole input
/etc/foresthub/secrets.json resolved credentials keyed by resource id (broker passwords, provider API keys / bearers) only when a resource needs a secret; absent otherwise (an anonymous broker is valid)

Within config.json, the parts you actually author per deployment are mapping (binds each logical id to a resource ref, plus a sub-address for hardware/endpoints) and the environment-supplied families of resources (mqttBrokers / llmProviders / mlProviders). The device families of resources (gpios..cameras) are device ground truth; the workflow is the binding-free graph as authored.

Rule of thumb: a workflow with no channels and only built-in catalog models (e.g. claude-haiku-4-5) needs almost none of this — a workflow and the provider's API key in secrets.json. A mapping entry and a resources entry appear the moment a channel or a custom/self-hosted model does; hardware adds device families, MQTT and self-hosted models add the matching endpoint families.

To assemble this by hand instead of with fh-workflow deploy: ship the image with the docker save / docker load flow from Run the engine and start it with docker run, mounting the two files above read-only at those exact paths. The repo ships no static compose.yaml; fh-workflow deploy generates one per workflow, or write your own.

Features

  • Workflow engine — typed graph runtime; nodes for LLM calls, hardware I/O, MQTT, web search, memory, control flow.
  • Multi-provider LLMs — Anthropic, OpenAI, Google Gemini, Mistral, plus a local SLM provider for llama.cpp / vLLM / Ollama / any OpenAI-compatible endpoint.
  • Visual React Flow builder — embeddable component or runnable as bundled SPA, with typed parameters and live validation.
  • Contract-typed wire format — every API generated from contract/*.yaml for both Go and TypeScript; CI fails on schema drift.

Local models (self-hosted SLMs)

Models run on the device through llama.cpp, in their own container, separate from the engine. Reference the model in the workflow as a custom LLMModel; the engine talks to its endpoint over HTTP.

The easy way is to mark that model as on-device and let fh-workflow deploy add the llama component to the generated docker-compose.yml for you — reached by service name over the compose network, no host networking, no hand-written compose (see Deploy a workflow to a device).

That component is built from components/llama/, the same way as the engine image above. It wraps llama-swap, so one container serves several models and renders its own server config from the boot config the bundle writes:

docker build -t llama:latest components/llama

# Ship to an offline device: save to a tar, copy it across, load it there
docker save llama:latest -o llama.tar

llama:latest is the tag a generated bundle expects (pull_policy: never). Put the .gguf weights in the bundle's workspaces/llama/ directory, and docker compose up does the rest.

A model marked on the network instead points at an inference server you run yourself — any OpenAI-compatible endpoint (llama.cpp, vLLM, Ollama). The bundle does not start that one for you.

Hardware and transports

  • GPIO via go-gpiocdev (digital in/out, edge triggers)
  • ADC / DAC / PWM via Linux character-device interfaces
  • UART / serial via go.bug.st/serial
  • MQTT via Eclipse Paho — topic-scoped channels for device-to-device messaging
  • Web search as a pluggable node

Digital and analog signal types are first-class in the workflow contract.

Target hardware

✅ = brought up and exercised on our own bench. We don't yet publish a per-device CI matrix, so treat these as known-good targets rather than a continuously tested guarantee.

Target Status
Raspberry Pi 5 (8 GB)
NVIDIA Jetson Orin Nano (8 GB)
x86 NUC (16 GB)
STM32MP25 (1 GB, Linux MCU)
Bosch Rexroth ctrlX CORE
Other Linux amd64 / arm64 Works, untested
macOS arm64 / amd64 Supported (development)
Bare-metal MCU (Cortex-M) Not supported by the Go engine. Contract is portable; dedicated MCU runtime is on the roadmap.

Developing Edge Agents

Want to hack on the engine, the builder, or the contract? Clone the repo — go/ and ts/ are independently buildable and releasable; only contract/ edits touch both.

git clone https://github.com/ForestHubAI/edge-agents
cd edge-agents

Build from source

Go engine (requires the Go version pinned in go/go.mod):

cd go
go build ./cmd/engine
ENGINE_CONFIG_FILE=engine-config.json ./engine   # boots the one workflow it's given
go test ./...                                     # testify-based tests

TypeScript packages (Node ≥ 20):

cd ts
npm ci
npm run dev              # Vite dev server with the visual builder → http://localhost:5173
npm run build            # build all three packages
npm run typecheck && npm run lint && npm test

The CLI from your working tree — the root package.json delegates to ts/workflow-cli, so a single root npm install (its postinstall builds the ts/ toolchain) runs the validators against your local changes instead of the published package:

npm install
npm run check-schema -- my.workflow.json   # the -- passes the path to the CLI, not to npm
npm run validate    -- my.workflow.json
npm run open        -- my.workflow.json
npm run deploy      -- my.workflow.json     # generate a deployment bundle (--values <file.json> for scripted runs)

After a git pull that changed dependencies, just run npm install again. If a stale node_modules bites you after switching branches, do a clean reinstall:

rm -rf node_modules ts/node_modules && npm install

Contract is the source of truth

Every API type is generated from contract/*.yaml for both Go and TypeScript — CI fails on drift. Never hand-edit generated bindings; edit the contract, then regenerate both sides:

cd go && go generate ./...     # → go/api/*/types.gen.go, server.gen.go
cd ts && npm run generate      # → ts/workflow-core/src/api/workflow.ts

See go/CLAUDE.md and ts/CLAUDE.md for the full contributor guide, conventions, and the domain-layer reconciliation each side needs.

Architecture

A workflow is a directed graph of typed nodes — LLM call, hardware I/O, MQTT, memory, control flow, expressions — connected by edges with one of five types: control, tool, agentTask, agentChoice, agentDelegate. The engine interprets the graph as a state machine: wait for event → execute node → transition. The contract (contract/*.yaml) is the single source of truth — Go and TypeScript both regenerate from it, CI fails on drift.

See go/CLAUDE.md and ts/CLAUDE.md for deeper architecture notes.

Repository layout

Path What it contains
contract/ OpenAPI 3.0.3 schemas — single source of truth for Go, TS and Python.
go/ Engine binary, camera capture component, LLM proxy, hardware drivers, MQTT transport. Module github.com/ForestHubAI/edge-agents/go.
ts/workflow-core @foresthubai/workflow-core — headless workflow model, validation, (de)serialization. No React.
ts/workflow-builder @foresthubai/workflow-builder — React canvas component.
ts/workflow-cli @foresthubai/workflow-cli — the fh-workflow CLI + the reference SPA it serves.
py/onnx onnx — generic ONNX inference component (model repository), FastAPI + onnxruntime. Build-yourself image, pull_policy: never.

Releases

  • Go runtime — tagged go/vX.Y.Z; consume with go get github.com/ForestHubAI/edge-agents/go@vX.Y.Z.
  • TypeScript packages@foresthubai/workflow-core, @foresthubai/workflow-builder, and @foresthubai/workflow-cli ship in lockstep at the same version, published to public npm.
  • Container image — built from go/Dockerfile.engine: multi-arch (linux/amd64, linux/arm64), distroless, nonroot. Build it yourself (see Run the engine).

See RELEASING.md.

Contributing

See CONTRIBUTING and the Code of Conduct. Open an issue before any non-trivial change. Every contribution is accepted under a Contributor License Agreement that preserves the dual-licensing model.

Security

Do not open public issues for security vulnerabilities. Use GitHub private vulnerability reporting or email root@foresthub.ai. See SECURITY.md for scope and process.


Learn more

New to edge AI? These guides on foresthub.ai define the concepts Edge Agents builds on:


Talk to the team

Using Edge Agents in a product, need a license that isn't AGPL-compatible, or want help getting an agent onto your hardware? Talk to the people who build it at ForestHub:


License

Edge Agents uses a two-tier license model designed to make the wire format and the headless workflow model maximally reusable while keeping the engine and the visual builder protected under copyleft.

Component License Why
contract/ (OpenAPI schemas) Apache-2.0 Wire format. Third-party Python, Rust, or Java clients should be free to implement against it.
ts/workflow-core (headless model) Apache-2.0 Workflow model and validation. Same reasoning — should be embeddable into any TypeScript/JavaScript project without copyleft friction.
go/ (engine, LLM proxy, drivers) AGPL-3.0-only or commercial Keeps hosted "Edge Agents as a service" offerings honest. For commercial use cases incompatible with AGPL, book a call or contact root@foresthub.ai.
ts/workflow-builder (React canvas) AGPL-3.0-only or commercial Same dual-license terms as the engine.
ts/workflow-cli (@foresthubai/workflow-cli + reference SPA) AGPL-3.0-only or commercial Bundles the AGPL builder; same dual-license terms.
py/onnx (onnx inference component) AGPL-3.0-only or commercial A service shipped alongside the engine; same dual-license terms.

For the AGPL components, the AGPL network clause applies — providing a modified version over a network requires making the corresponding source available to users of that service.

Third-party components retain their own licenses; see THIRD_PARTY_NOTICES and NOTICE.


Built by ForestHub — the platform for embedded and edge AI agents. Questions or a commercial use case? Book a call.

About

The 30 MB open-source edge AI agent runtime. Run AI agents offline on Linux (Raspberry Pi, Jetson). GPIO, UART, MQTT as first-class nodes. Industrial protocols (OPC-UA, Modbus) on the roadmap.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages