Skip to content

srcfl/hugin-agent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hugin-agent

Thin local helper for the Hugin web app — scans your LAN, talks Modbus, runs Lua drivers. Open. Stateless. Auditable.

Why this exists

Hugin's web app at hugin.sourceful-labs.net lets you write Lua drivers for energy devices with the help of an AI. To actually test a draft against the real hardware on your network, the browser needs a way out — it can't speak Modbus TCP, it can't sweep ARP, it can't talk to your inverter.

This binary is that way out. It listens on localhost:19090, exposes five JSON endpoints, and does exactly the things the browser can't:

  • Sweep your LAN for devices (TCP probe + ARP)
  • Read Modbus holding-registers from an IP
  • Execute a forty-two-watts-style Lua driver in a sandbox and stream the emissions back

Nothing else. No state stored on disk. No telemetry. No auto-update. No hidden background work. The whole binary is auditable in 30 minutes.

If you already run forty-two-watts, you don't need this — 42w can play the agent role itself (same protocol).

Install

macOS / Linux — Homebrew

brew install srcfl/tap/hugin-agent
hugin-agent

(Homebrew strips macOS quarantine automatically — no Gatekeeper warning.)

Windows — Scoop

scoop bucket add srcfl https://github.com/srcfl/scoop-bucket
scoop install hugin-agent
hugin-agent

From source (any platform with Go 1.25+)

go install github.com/srcfl/hugin-agent/cmd/hugin-agent@latest
hugin-agent

Pre-built tarball

Direct downloads at github.com/srcfl/hugin-agent/releases. On macOS, you'll need to run xattr -d com.apple.quarantine /path/to/hugin-agent to bypass Gatekeeper for the unsigned binary — this is exactly what Homebrew does for you.

Audit before you run

git clone https://github.com/srcfl/hugin-agent
cd hugin-agent
# read everything in cmd/ and internal/ — it's small
go build ./cmd/hugin-agent
./hugin-agent

Pair with Hugin

When you start the agent it prints something like:

  Hugin agent v0.1.0
  Listening on http://127.0.0.1:19090
  Pairing token: a3f9c2d8e7b1f0a4c5d6e8f7a1b2c3d4

  Pair this agent with the web app:
    1. Open https://hugin.sourceful-labs.net/settings.html
    2. Paste the URL above + this token
    3. Click 'Test connection' then 'Save pairing'

Open the URL, paste both fields, save. The web app stores the pair in your browser's localStorage (never sent to Sourceful's servers). After that, the chat page at hugin.sourceful-labs.net/chat.html shows a green "agent" pill in the header and unlocks "Scan my LAN" + "Test latest driver" buttons.

Flags

Flag Default Notes
--host 127.0.0.1 Use 0.0.0.0 only if you're running this on a Pi and want LAN access.
--port 19090
--token (random) Persistent token if you want to skip re-pairing on restart

Same values via env: HUGIN_AGENT_HOST, HUGIN_AGENT_PORT, HUGIN_AGENT_TOKEN.

Protocol (v1)

All endpoints return JSON. Auth: every protected endpoint expects Authorization: Bearer <token> matching the pairing token.

GET /v1/info (no auth)

{
  "name": "hugin-agent",
  "version": "0.1.0",
  "protocol_version": 1,
  "capabilities": ["scan", "probe", "run-lua"]
}

GET /v1/health (no auth)

{ "status": "ok", "ts": "2026-05-02T08:30:00Z" }

POST /v1/scan (auth)

Sweeps the local subnet for devices.

Request:

{ "cidr": "192.168.1.0/24", "ports": [502, 80, 1883], "deep_probe": false }

Response:

{
  "devices": [
    {
      "ip": "192.168.1.50",
      "mac": "AA:BB:CC:DD:EE:FF",
      "vendor_oui": "Sungrow",
      "open_ports": [502, 80],
      "modbus": { "fc43_make": "Sungrow", "fc43_model": "SH10RT" },
      "http_banner": "..."
    }
  ],
  "errors": []
}

If deep_probe: true, devices on TCP-502 also get a Modbus FC43 device-identification probe.

POST /v1/probe (auth)

Reads holding-registers from a specific Modbus device.

Request:

{
  "ip": "192.168.1.50",
  "protocol": "modbus",
  "modbus": {
    "port": 502,
    "slave_id": 1,
    "registers": [
      { "addr": 16384, "count": 2, "kind": "i32_be" },
      { "addr": 16386, "count": 1, "kind": "u16" }
    ]
  }
}

kind is one of: u16, i16, u32_be, u32_le, i32_be, i32_le, f32_be, f32_le.

POST /v1/run-lua (auth)

Executes a forty-two-watts Lua driver and returns whatever it emits.

Request:

{
  "lua_source": "DRIVER = {...} function driver_init(c) ... end function driver_poll() ... end",
  "config": { "host": "192.168.1.50", "port": 502, "slave_id": 1 },
  "actions": ["init", "poll"],
  "duration_ms": 30000
}

actions is run in order; defaults to ["init", "poll"]. The Lua VM is sandboxed (no os/io/debug, no require/load/dofile); the only way out is the host.* table.

Response:

{
  "ok": true,
  "emissions": [
    { "ts": "...", "channel": "meter", "data": { "power_w": -2500 } }
  ],
  "metrics": {},
  "logs": ["[info] driver_init done"],
  "errors": []
}

Security model

What the agent CAN do with the token someone has stolen from your machine:

  • Read your Modbus / HTTP-discoverable devices on the LAN it's bound to
  • Send Modbus reads (no writes — /v1/probe is read-only; Lua can write but only to the host you give it)
  • Execute Lua source you POST it (sandboxed)

What the agent CAN'T do:

  • Reach the public internet (we never make outbound calls except the ones drivers explicitly issue via host.http_get / host.http_post)
  • Persist anything to disk
  • Auto-update itself
  • Phone home with telemetry
  • Run arbitrary Go code (only sandboxed Lua)

Recommendations:

  • Default bind is 127.0.0.1 (only the same machine). Don't change it unless you understand the trade-off.
  • Don't share your pairing token. Generate a new random one with each restart by leaving --token empty.
  • The web app at hugin.sourceful-labs.net stores the token in browser localStorage — clear it from settings if you stop using Hugin.

License

MIT. See LICENSE.

Issues, questions

github.com/srcfl/hugin-agent/issues

About

Thin local agent for Hugin (https://hugin.sourceful-labs.net) — scans LAN, talks Modbus, runs Lua drivers. Open + auditable.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages