MCPcopy Create free account
hub / github.com/ForestHubAI/edge-agents

github.com/ForestHubAI/edge-agents @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
3,395 symbols 7,194 edges 373 files ⚖ custom 2,153 documented · 63% updated 27d ago★ 98

Browse by type

Functions 2,454 Types & classes 941
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

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 Linu

Extension points exported contracts — how you extend this code

browse all types & interfaces →

Core symbols most depended-on inside this repo

browse all functions →

Shape

Method 1,619
Function 835
Struct 555
TypeAlias 199
Interface 170
Class 8
FuncType 7
Enum 2

Languages

Go82%
TypeScript18%

Modules by API surface

go/llmproxy/provider/mistral/types.gen.go1,203 symbols
go/api/workflow/types.gen.go248 symbols
go/llmproxy/mocks_test.go132 symbols
go/engine/mocks_test.go128 symbols
go/api/llmapi/types.gen.go54 symbols
go/engine/node.go34 symbols
go/api/engineapi/server.gen.go32 symbols
go/api/engineapi/types.gen.go31 symbols
go/api/debugapi/types.gen.go27 symbols
go/llmproxy/tools.go23 symbols
ts/workflow-core/src/parameter/Parameter.ts22 symbols
go/engine/driver/driver.go20 symbols

Datastores touched

fh_testDatabase · 1 repos

For agents

$ claude mcp add edge-agents \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page