LapEE bundler quickstart
This guide gets a laptop online as a PermawebOS paid bundler node.
It uses the signed LapEE runtime image and the bundler profile.
What You Need
- A target x86_64 UEFI laptop.
- TPM 2.0.
- The release-provided LapEE runtime image, hash, and signature material.
- The release-provided LapEE provisioner image and instructions.
- A local LapEE source checkout for the Makefile image helpers.
- Docker Desktop or another Docker runtime.
jqfor command-line JSON checks.- A USB stick for the runtime image.
- The bundler profile.
- Optional WiFi credentials if the laptop will not use Ethernet.
Use lapee-usb.img by default. Use the no-TME image only for hardware that
cannot satisfy the memory-encryption gate.
1. Provision The Laptop
Run the LapEE provisioner on the target laptop before booting the runtime image. The provisioner prepares the firmware Secure Boot policy for the release key or exact UKI hash.
This is a firmware-owner action. Know how to recover the laptop firmware before changing Secure Boot policy.
2. Download and Verify The Runtime Image
Download a LapEE image here.
To verify, use the hash and signature material published with the release. For a SHA-256 file:
sha256sum -c lapee-usb.img.sha256
On macOS:
shasum -a 256 -c lapee-usb.img.sha256
Do not write an image whose release hash does not match.
3. Stage The Image
Run the remaining image commands from the LapEE source repo root. Put the verified image at the default path used by the Makefile helpers:
mkdir -p build/images
cp /path/to/lapee-usb.img build/images/lapee-usb.img
4. Prepare config.json
Copy the bundler profile to a local config.json beside the Makefile:
cp /path/to/lapee-bundler-devices/profile/lapee.json config.json
That profile enables remote device loading, pins the trusted device signer, maps the published Forge package IDs, and installs the paid-bundler startup hook.
Set bundler-beneficiary to your own address to receive AO tokens for bundling
data.
If you have release-provided operator config to preserve, merge it first and the paid-bundler profile second:
jq -S -s '.[0] * .[1]' \
/path/to/release-config.json \
/path/to/lapee-bundler-devices/profile/lapee.json \
> config.json
Put release-image config first and the paid-bundler profile second. The profile wins when both define the same role key.
Do not put secrets in config.json. It is public operator config and appears in
the measured node message.
5. Optional WiFi
If Ethernet is available, prefer Ethernet. If WiFi is needed, create
wifi.conf beside the Makefile as exactly two lines:
SSID
WPA2-PSK
wifi.conf is plaintext secret material. Do not commit it.
6. Apply Operator Inputs
With Docker running, inject config.json and optional wifi.conf into the
staged image:
make operator-config-apply IMAGE=build/images/lapee-usb.img
This uses the tooling container to edit the FAT ESP. It does not rebuild LapEE,
and it does not rebuild or re-sign EFI/Boot/BootX64.efi.
After this step, build/images/lapee-usb.img contains any staged WiFi password.
Do not share the modified image if it contains wifi.conf.
7. Write The USB
make write-image DEV=/dev/diskN IMAGE=build/images/lapee-usb.img
Use the whole removable disk, not a partition. On Linux this is usually
/dev/sdX; on macOS it is usually /dev/diskN. The target device is erased.
8. Boot
Boot the target laptop from the prepared USB stick.
Expected behavior:
- The splash appears.
- Networking comes up.
- PermawebOS starts on port
8734. - The splash shows a node URL and QR code.
If the splash appears stuck at Starting HyperBEAM, probe the node from another
machine before assuming boot failed:
curl -fsS -H 'accept: application/json' \
http://<node-ip>:8734/~measurement@1.0/info
9. Smoke Check
Set the node URL from the splash:
export NODE_URL=http://<node-ip>:8734
Check the measured node and the paid-bundler profile:
curl -fsS -H 'accept: text/plain' "$NODE_URL/~meta@1.0/info/address"
curl -fsS -H 'accept: text/plain' "$NODE_URL/~meta@1.0/info/lapee-profile"
curl -fsS -H 'accept: text/plain' "$NODE_URL/~meta@1.0/info/load-remote-devices"
curl -fsS \
-H 'accept: application/json' \
-H 'accept-bundle: true' \
"$NODE_URL/~meta@1.0/info/trusted-device-signers" \
| jq '[to_entries[] | select(.key | test("^[0-9]+$")) | .value]'
curl -fsS \
-H 'accept: application/json' \
-H 'accept-bundle: true' \
"$NODE_URL/~measurement@1.0/boot" > boot-measurement.json
curl -fsS -H 'accept: application/json' "$NODE_URL/~tpm@2.0a/info"
curl -fsS -H 'accept: application/json' "$NODE_URL/~ao-payment@1.0/info"
curl -fsS -H 'accept: application/json' "$NODE_URL/~bundler-settlement@1.0/info"
curl -fsS -H 'accept: application/json' "$NODE_URL/~arweave-byte-pricing@1.0/quote?resource=arweave-bytes&amount=1"
curl -fsS -H 'accept: text/html' "$NODE_URL/~hyperbuddy@1.0/index" >/dev/null
Expected profile value:
aopayment-bundler
Use explicit accept headers for machine-readable checks. Browser requests may
open HyperBuddy or HTML views.
trusted-device-signers is an AO json@1.0 list, encoded as numeric object
keys such as "1", "2", and so on. The jq filter above renders the plain
JSON signer array.
Public Reachability
Public reachability is external routing, not config.json: DNS, a tunnel,
router port forwarding, or a reverse proxy must point at the node HTTP port.
Clients and dashboards still need to health-check the public URL.