Skip to main content

Updates & Logs

Every Intern runs bootstrap-server, a small Go worker that polls a metadata JSON every five minutes and applies updates to the other binaries. You rarely need to update by hand, but you sometimes need to inspect logs or force a version.

Where things live

ComponentPath
intern-server binary/usr/local/bin/intern-server
bootstrap-server binary/usr/local/bin/bootstrap-server
OpenClaw (npm global)managed by intern-server openclaw …
Web SPA/usr/share/nginx/html/setup
Device config/root/config/config.json
Bootstrap config/root/config/bootstrap.json
OpenClaw config/root/.openclaw/openclaw.json
OpenClaw credentials/root/openclaw/credentials/
Intern log/var/log/intern.log (slog DEBUG)

Bootstrap loop

bootstrap.service polls a metadata JSON every poll_interval (default 5 minutes). Override by editing /root/config/bootstrap.json:

{
"metadata_url": "https://cdn.autonomous.ai/intern-v2/ota/metadata.json",
"poll_interval": "5m"
}

The metadata JSON looks like this:

{
"intern": { "version": "v1.2.3", "url": "https://.../intern-server-v1.2.3.zip" },
"bootstrap": { "version": "v1.0.0", "url": "https://.../bootstrap-server-v1.0.0.zip" },
"web": { "version": "v1.5.0", "url": "https://.../web-bundle.zip" }
}

Only three zipped components are listed in metadata.json: intern, bootstrap, and web. OpenClaw is intentionally absent — it ships as an npm package and is installed/upgraded via intern-server openclaw install (npm install openclaw@<version>), not through the bootstrap zip-swap path. To pin a specific OpenClaw release, set OPENCLAW_VERSION (defaults to latest) when running the install command. On version mismatch for the listed components, the worker downloads the zip, atomically replaces the binary, and restarts the corresponding systemd unit.

Manual updates

Force a specific version (or latest) from the CLI:

sudo software-update intern # latest
sudo software-update intern v1.2.3
sudo software-update bootstrap
sudo software-update web
sudo software-update openclaw

The helper script calls into bootstrap-server so the install path is identical to the OTA path.

Reading logs

systemd units:

journalctl -u intern -f
journalctl -u bootstrap -f
journalctl -u openclaw -f
journalctl -u nginx -f

Verbose intern-server log:

tail -f /var/log/intern.log

slog levels: DEBUG, INFO, WARN, ERROR. To raise verbosity, edit the systemd unit override and re-export LOG_LEVEL:

sudo systemctl edit intern
[Service]
Environment="LOG_LEVEL=DEBUG"

Then:

sudo systemctl daemon-reload
sudo systemctl restart intern

Heartbeat

intern-server pings the backend periodically (POST <llm_base_url>/ping with the Anthropic key as Bearer token). The payload reports:

  • Firmware versions (intern / bootstrap / openclaw / web)
  • supermemory_installed (boolean — does openclaw.json have the plugin block?)
  • Network state (AP vs STA, SSID)
  • Uptime, error counts

The backend uses these to flip the device from "pending" to "ready" in the setup UI. If /ping fails repeatedly, check llm_base_url and the device's outbound connectivity.

Factory reset

Factory reset is hardware-only — there is no HTTP endpoint for it. Hold the GPIO 23 reset button on the back of the device for at least 10 seconds. The LED ring transitions to the factoryreset state while you're holding it. Releasing after the 10-second threshold clears /root/config/config.json (LLM key, channel tokens, Wi-Fi credentials, Supermemory keys) and reboots the device into AP mode for re-pairing.

If you have SSH access (Developer Edition) and the device is responsive enough to accept commands, you can do the equivalent by hand:

sudo systemctl stop openclaw intern
sudo rm -f /root/config/config.json
sudo /usr/local/bin/device-ap-mode
sudo systemctl start intern

This is a "soft" reset — it doesn't touch OpenClaw plugins, credentials under /root/openclaw/credentials/, or the user's SSH keys. For a clean slate, re-flash the SD card from the factory image.