Infrastructure · Offloading · Workload Assignment Platform
The Distributed Node Capability Framework
I only want a picture. I built a capability-based execution fabric.
The origin is embarrassingly simple. I wanted to generate an AI image on my Mac Mini — it has the GPU, it runs MLX/mflux. But my AI agent doesn't live on the Mac. It runs in a VM on my Proxmox server. So every time I asked for a picture, the agent had to reach across the network to a machine that wasn't its own.
That gap — the thing that thinks and the thing that does living on different boxes — is the whole reason IOWAP exists. Not a grand architecture. Just: the Mac can generate images, the VM can't, and I wanted the VM to be able to ask the Mac to do it.
So I built a minimal coordinator. Nodes claim what they can do, the relay connects them, and workloads get routed to whatever node actually has the capability. No orchestration, no micro-managing — just matching capability to task.
For a picture. I built a whole platform and never stopped.
iowap-org/
├── iowap ← this repo (meta: story + architecture)
├── iowap-server ← relay server: API, scheduler, auth, DB, dashboard
├── iowap-node ← node framework: daemon, CLI, handlers
├── iowap-storage ← reference storage node (docker)
├── iowap-ha ← Home Assistant: HAOS app (node container) + thin integration
├── iowap-federation ← federation node: bridge capabilities between relays (E2EE)
├── iowap-hermes-integration ← Hermes desktop: fleet control surface (plugin)
├── iowap-client-mcp ← MCP toolkit: curated node-cli toolset for MCP-speaking agents
├── iowap-docker ← docker images: base, server, storage, flow
└── iowap-docs ← documentation: setup, concepts, API reference
| Repo | Description |
|---|---|
| iowap | Meta-repo — story, architecture, links (this repo) |
| iowap-server | Relay server — purpose-agnostic scheduler, API, auth, database, dashboard |
| iowap-node | Node framework — daemon, CLI, capability management, handler runner. Build and register your own node |
| Repo | Description |
|---|---|
| iowap-storage | Storage node — file storage, retrieval, and bridging for the IOWAP ecosystem |
| iowap-flow | Flow runner — plan/fan-out/join orchestrator node (minimal Kanban) for the relay cluster |
| iowap-ha | Home Assistant — HAOS app (node container) + thin custom integration for submissions |
| Repo | Description |
|---|---|
| iowap-hermes-integration | Hermes desktop plugin — fleet status, task submission & tracking from the desktop app |
| iowap-client-mcp | MCP stdio server — curated node-cli toolset (relay status, fleet, capabilities, task submit/result, artifact download, docs) so agents don't relearn the node CLI's pitfalls |
| Repo | Description |
|---|---|
| iowap-federation | Federation node — bridge capabilities between relays. Inbox/Outbox, transport-agnostic, E2EE. V1 forward path implemented; result return leg open |
| Repo | Description |
|---|---|
| iowap-docker | Docker images — packaging layer: base, server, storage & flow |
| iowap-docs | Documentation — setup, concepts, API reference, node guides |
# 1. Start the relay server
docker run -d --name iowap-server -p 8788:8788 \
ghcr.io/iowap-org/iowap-server:latest
# 2. Run a node (example: storage)
# keep the state volume — it holds the node identity
docker run -d --name iowap-storage \
-e RELAY_URL=http://host.docker.internal:8788 \
-v iowap-storage-state:/home/appuser/.relay \
ghcr.io/iowap-org/iowap-storage:latest
# 3. Submit a task
curl -X POST http://localhost:8788/relay/v2/scheduler/task-simple \
-H "Authorization: Bearer <node-token>" \
-H "Content-Type: application/json" \
-d '{"capability": "storage.archive", "payload": {"path": "/data"}}'Full setup, API reference and node guides live in iowap-docs.
Relay routes. Nodes execute. Flows compose. Federation extends.
The relay server is a purpose-agnostic scheduler — it answers WHERE can this task run? Nodes execute handlers — they answer HOW is one capability executed? Flow runner composes capabilities into sequences — it answers WHAT sequence of tasks should happen? These are three distinct layers, and none of them orchestrates the others.
┌──────────┐ heartbeat/capabilities ┌──────────┐
│ NODE A │ ◄───────────────────────────► │ RELAY │
│ (GPU) │ │ SERVER │
└──────────┘ claim/submit tasks └────┬─────┘
┌──────────┐ │
│ NODE B │ ◄─────────────────────────────────┤
│ (STORAGE)│ │
└──────────┘ │
┌──────────┐ │
│ NODE C │ ◄─────────────────────────────────┤
│ (CUSTOM) │ │
└──────────┘ │
┌──────────┴──────────┐
│ DASHBOARD (iFrame) │
└─────────────────────┘
IOWAP is not an agent-communication protocol, a tool gateway, a workflow engine, or a task queue — and it does not compete with them. The closest neighbors, and where IOWAP differs:
- A2A (Agent2Agent) — a standard for agent↔agent communication (agent cards, task delegation). IOWAP routes between machines via capability claims; agents are one client among several. A2A could ride on IOWAP as a capability adapter node — not the other way round.
- MCP / MCP gateways — centralized tool and MCP-server distribution for agent processes. IOWAP operates below that layer: independent node daemons on real devices, with heartbeat, load, and claim-based scheduling. An MCP gateway would run as a node.
- Task queues (Celery, Asynq, taskiq) — same mechanical layer, but workers are deployed instead of advertising themselves. No capability discovery, no heterogeneous device fleet.
- Multi-agent frameworks (Autogen, agent-framework, swarms) — they orchestrate agents inside one runtime. IOWAP is the device fabric below the agents.
- Workflow tools (n8n, Activepieces) — their "node" is a graph step in one engine. IOWAP nodes are independently running machines, and the flow runner composes across them.
The one-liner: the relay answers WHERE a task can run, nodes answer HOW, flows answer WHAT — no layer orchestrates the others.
MIT — see LICENSE.
