Skip to content

Releases: HexaEightTeam/hbia-agent

HBIA r6 — fetch returns a Response, binary bodies preserved, workspace bundle

Choose a tag to compare

@hexaeight hexaeight released this 13 Aug 13:08

The leaf runtime's fetch now behaves like fetch, and binary responses survive it. Adds the
workspace UI as a downloadable bundle.

Agent source only — Bridge 1.9.21 / ASK 1.9.161 / JWT 1.9.292 are unchanged from r5, and the
runtime stays pinned at 8.0.28. --probe returns 0 on Windows and Linux with no new integrity
registration, because the rows registered for r5 still describe these builds.

heia.fetch returns a Response

const r = heia.fetch(url);        // quickjs: synchronous, Asyncify suspends the stack
const data = r.json();
r = await heia.fetch(url)         # pyodide: async, as it has always been
data = await r.json()

ok, status, headers, and text() / json() / bytes() to choose a form — the same shape
fetch gives you, for the same reason: the bytes are what arrived, and any decode is the caller's
decision.

Binary responses are no longer destroyed. The body used to be decoded as UTF-8 before a unit saw
it, which replaced every invalid sequence with U+FFFD, irreversibly. A unit fetching a PDF received
something that was still a string and no longer a PDF, and nothing downstream could tell. The body
now crosses as real bytes — an ArrayBuffer in QuickJS, a bytes object in Python — so
PdfReader(io.BytesIO(r["body"])) works.

heia is available in Python without an import, because it is the runtime rather than a package the
author chose. import heia still works.

Egress

  • allowed_hosts: ["*"] for units that fetch URLs discovered at run time — search results, links
    inside a page. Must be keyless ("name": ""): injecting a secret into a request bound for a host
    the runtime picked would hand that secret to whatever URL was discovered, so it is refused at build
    and again at run time.
  • Hostnames reached through * are put to a resolver that declines to answer for known-malicious
    domains. It fails open — a resolver that cannot be reached must not read as a host that was blocked.
  • Loopback and link-local are refused regardless of declaration. Loopback is the machine's own
    control plane; 169.254.0.0/16 is where every cloud puts instance metadata, which hands out
    credentials to anything that can make an HTTP request. An ordinary LAN address (10.x, 172.16-31.x,
    192.168.x) is reachable — a skill that publishes a site and fetches from another internal host
    is a real case, and it is separated from the two above precisely so allowing it does not allow them.
  • A public IP literal is refused under *, since it skips the DNS check that is the whole protection.

Build refuses what used to ship broken

A pyodide unit that calls heia.fetch from a synchronous def, or with async def but no await,
is now a build failure. Pyodide has no synchronous fetch: the call returned a coroutine, indexing it
raised, and units written that way wrap the call in a bare except — so every fetch silently
returned nothing while the unit reported success.

Ingest

Goal 6 is now shown an audit of units.json against what was actually built — a unit planned as
pyodide and built as quickjs, a planned library that no unit declares. It is reported, not
enforced
: a gate can be satisfied by deleting the requirement, which is exactly how a capability
went missing three runs running. Goal 6 decides whether to send the run back or record, and owns
that decision.

The leaf-building contract is 14 sections, down from 29. Everything describing Node-RED JSON that
build_leaf generates is gone, along with the worked examples — a model does not need to be taught
Python, and every example it was given came back copied complete with the example's own quirks.

The workspace

hexaeight-workspace-dist.zip is the built UI, the Bootsharp browser-auth runtime, and a
dependency-free static server.

hexaeight-activate install-workspace --serve

Downloaded and verified the same way as the agent, extracted under the runtime root, and served by
an ordinary express app — so it sits behind nginx or a load balancer without argument
(--behind-proxy, --base /path).

Installing and updating

dotnet tool install --global HexaEight.Activate
hexaeight-activate install-agent       # agent + the pinned Node toolchain + MCP config
hexaeight-activate install-workspace
hexaeight-activate newtoken            # interactive: licence code + Authenticator approval

install-agent now also provisions Node-RED, the QuickJS and Pyodide leaf runtimes, and Claude
Code, pinned by a lockfile shipped inside the package and installed with npm ci — so two machines
provisioned a month apart run identical code.

hexaeight-activate update installs only the components whose version moved, and restarts only
what that implies: the agent restart brings Node-RED with it; a router update restarts the agent
too; a workspace update restarts nothing and just wants a browser refresh. whats-new lists what
each component changed.

Platform coverage

win-x64, linux-x64 and osx-arm64 are published. osx-x64 (Intel Mac) and linux-arm64 are
not: the attestation hash can only be produced by building and running on the target architecture,
and we have no such machine. install-agent exits 2 there and points at support@hexaeight.com
rather than installing a near-match the platform would refuse.

See HASHES.md for SHA-256 per download and the PROTECTION HASH per platform, and for why those are
two different things.

HBIA r5 — Bridge 1.9.21 / ASK 1.9.161

Choose a tag to compare

@hexaeight hexaeight released this 05 Aug 10:05

First release with the approved-build gate working end to end — an agent can now be told which
builds may call it, and both halves are proven: an unlisted build is refused, and approving it
admits the same binary without a restart.

Built on Bridge 1.9.21 / ASK 1.9.161 / JWT 1.9.292, .NET 8 self-contained, runtime pinned to
8.0.28, single-file with IncludeAllContentForSelfExtract=true. Nothing needs to be installed
to run these.

Downloads

platform file SHA-256
Windows x64 hexaeight-agent-win-x64.exe 4FC727D15F6E46152ED5B4DBE56C7FF004901D5514F667680E7E348CA358681D
Linux x64 hexaeight-agent-linux-x64 384BFA57A6D7216C63EA135C6C1B86D1F43D6DDDC60C7CFD750D409478BBDF78
macOS arm64 hexaeight-agent-osx-arm64 1DBC782B90CDC910D70556256BBBAC824D5B81D26B78C8EDD718CA14D996E70A

PROTECTION HASHES

What a peer's approved-build gate matches on — the hash of the extracted entry dll, not of the
file you downloaded. All three verified blessed against the live platform (--probe returns 0).

win-x64    6230A870E4825659E3A011E7C4FD6ABD80D1BDEC966BBEBC076C519398F4E57F5DD7A54B6B4C0E70967713DDF0A417CCA877A24539E76D1330D5F2D9B9064CEB
linux-x64  51652F55027CBB41779BA78317E28CBBC92D0ECFFEA049F3C8FB395E2B26EC48A5C3591453B14298D0E4789995C6C238B710D5C51B6AF6B586EB32523EF7ECD7
osx-arm64  8FD1377D7A7A535FD1174F05084B28E81650A52FCFCE210245D3E97C4DCE8A6C12D48432B2E4F2A9E3CF21D961EB685C63433E9FD94CC29C93CD0A251A7F5343

All three ship inside HexaEight.Activate 1.0.11 (approved-build list v5), so verify-env approves
them automatically and nobody copies a hash by hand.

What's new

The gate is enforced by the agent. Earlier builds never read the allowlist: the Bridge does not
auto-load it, and the agent never asked it to, so every agent ran permissive while the policy on
disk said otherwise. It now loads the list at startup and prints which state it is in —
ENFORCING or NOT enforcing — because a gate that is quietly open is worse than no gate.

Live reload. approve-builds runs in a separate process, so the agent watches the file.
Approving a peer takes effect immediately; restarting an agent to admit a caller was exactly the
outage this feature exists to prevent.

--init-policy gates on origin. It measures the running build's own PROTECTION HASH by sealing
to itself, approves that, and drops the wildcard. Measured, not guessed — what a build attests
depends on how it was published. If it cannot measure, it leaves the gate open and says so, rather
than tightening on a value it is unsure of and locking you out of your own agent.

Refusals say what they are. A blocked build used to surface as a JSON parse error, which reads
as a broken envelope and points nowhere near the allowlist. Both envelope routes now check the
decision first: the operator's log names the sender and the reason, while the caller gets only
denied — a prober cannot tell an unapproved build from an unauthorised sender.

Runtime pinned to 8.0.28. The platform validates an IL hash computed per (assembly, runtime,
OS)
, so the bundled .NET patch level is part of a build's identity. Left floating, a publish on a
machine with a different runtime pack silently produces different hashes and every agent from that
build is refused, with no source change to explain it.

Verifying

sha256sum hexaeight-agent-linux-x64     # 1. the file is ours
./hexaeight-agent --probe               # 2. run once; 0 = platform trusts this build
hexaeight-activate verify-libs          # 3. libraries match nuget.org

verify-libs finding nothing is itself a red flag: official releases place their assemblies on disk
so they can be checked.

Notes

  • macOS is Apple Silicon only. Intel needs its own build — the IL hash is per-OS and
    cross-publishing cannot produce it.
  • Self-published agents remain first class: approve-builds --add-hash <PROTECTIONHASH> admits your
    own build alongside the official ones. Prefer --add-hash over --add-file, which has to infer
    which file your publish shape attests and refuses the peer silently when it guesses wrong.