Перейти к содержанию

Member node onboarding (phase 1)

Goal: add a member node to an AdaOS hub using a short one-time join-code (no long-lived tokens in CLI args), then start python -m adaos api serve via OS autostart/service when possible.

For the target-state architecture beyond this phase-1 flow, including supervisor-owned member-hub lifecycle, restart-aware connectivity semantics, QR-based onboarding, and unified device access policy for members and browsers, see Member-Hub Connectivity, Device Access and Browsers, and Device Access Roadmap.

Prereqs

  • Python 3.11
  • adaos installed (or run via repo bootstraps)
  • Hub node is running python -m adaos api serve (or bootstrap-installed autostart) and has role hub

1) On the hub: create a join-code (Root session)

Run on the hub machine:

python -m adaos hub join-code create

This prints a short code like ABCD-EFGH (one-time, TTL). The code is stored on Root and can be consumed by the member via Root.

Notes:

  • Root mode does not require a public hub URL: members connect via the Root proxy path /hubs/<subnet_id>/....
  • Hub must be bootstrapped on Root (mTLS hub cert/key + Root CA). If missing, run: python -m adaos dev root init (requires ROOT_TOKEN).

1b) Offline/LAN-only join-code (no Root)

If the subnet has no Internet access / no Root connectivity, create a local join-code on the hub:

python -m adaos hub join-code create --local

2) On the member: bootstrap + join + autostart

RootUrl/--root-url is the join entrypoint:

  • Online mode: Root (default: https://api.inimatic.com)
  • Offline mode: Hub URL (the hub node accepts join directly)

Zone-aware bootstrap is supported too:

  • Repo bootstrap scripts accept --zone <id> on Bash or -ZoneId <id> on PowerShell.
  • Use only a two-letter country or region code such as ru.
  • With the default public Root URL, national zones follow the [zone].api.inimatic.com rule.
  • Right now this is active for ru, which resolves to https://ru.api.inimatic.com; the other zones still use https://api.inimatic.com.
  • This zone selection affects hub bootstrap, owner login, member join via join-code, and hub join-code creation.

For offline/LAN-only setups you can still override the hub address explicitly via adaos node join --hub-url http://<HUB_LAN_IP>:8777 (advanced).

Windows (PowerShell, pip bootstrap)

powershell -ExecutionPolicy Bypass -File tools/bootstrap.ps1 -JoinCode <CODE>
# example for RU Root:
# powershell -ExecutionPolicy Bypass -File tools/bootstrap.ps1 -JoinCode <CODE> -ZoneId ru -Dev

Linux/macOS (pip bootstrap)

bash tools/bootstrap.sh --join-code <CODE>
# example for RU Root:
# bash tools/bootstrap.sh --join-code <CODE> --zone ru --dev

Windows/Linux/macOS (uv bootstrap)

powershell -ExecutionPolicy Bypass -File tools/bootstrap_uv.ps1 -JoinCode <CODE>
# example for RU Root:
# powershell -ExecutionPolicy Bypass -File tools/bootstrap_uv.ps1 -JoinCode <CODE> -ZoneId ru -Dev
bash tools/bootstrap_uv.sh --join-code <CODE>
# example for RU Root:
# bash tools/bootstrap_uv.sh --join-code <CODE> --zone ru --dev

Offline/LAN member bootstrap (using --local join-code)

When using a local hub join-code, you must point join to the hub URL explicitly:

powershell -ExecutionPolicy Bypass -File tools/bootstrap.ps1 -JoinCode <CODE> -RootUrl http://<HUB_HOST>:8777
bash tools/bootstrap.sh --join-code <CODE> --root-url http://<HUB_HOST>:8777

Note: joining on the same machine as the hub

If the hub is already running on 127.0.0.1:8777, the member node must use a different local API port.

Bootstraps now auto-pick 8778+ when --join-code/-JoinCode is provided, but you can override explicitly:

powershell -ExecutionPolicy Bypass -File tools/bootstrap.ps1 -JoinCode <CODE> -RootUrl http://127.0.0.1:8777 -ServePort 8778 -ControlPort 8778

3) Verify status

On the member machine:

python -m adaos node status --control http://127.0.0.1:8777 --json

Expected (example):

  • role is member
  • ready is true
  • route_mode is ws when connected to hub via /ws/subnet

Current phase-1 note:

  • adaos node join persists the membership contract immediately
  • live member -> hub activation may still depend on the running runtime picking up the new configuration
  • the target design is to make join self-activating in dev and supervisor-managed in production; see the roadmap in Member-Hub Connectivity

Where config is stored

  • Bootstrap identity: $ADAOS_BASE_DIR/node.yaml (default in bootstraps: <repo>/.adaos/node.yaml). This file is intentionally minimal and keeps only bootstrap/static identity such as zone_id, node_id, subnet_id, role, root.base_url, and key/cert paths.
  • Runtime connection state: $ADAOS_BASE_DIR/state/node_runtime.json. Dynamic fields such as the current hub_url, local control token, and runtime NATS credentials are stored here, not in node.yaml.
  • Durable structured state: local SQLite durable state. Long-lived structured data such as root auth cache, subnet alias metadata, and capacity projections are persisted there instead of node.yaml.
  • Join-code store: Root server (Root mode) or $ADAOS_BASE_DIR/join_codes.json (hub local mode)

Idempotency

  • Re-running bootstrap without --join-code should keep existing node_id and config.
  • Join-codes are one-time; reusing the same code fails.

Default role behavior

  • If --join-code/-JoinCode is provided, bootstrap defaults role to member.
  • If no join-code is provided, bootstrap defaults role to hub.

Windows note: prefer python -m adaos (or wrapper script)

If adaos console-script wrapper is broken (e.g. ModuleNotFoundError: No module named 'adaos'), run via:

.\.venv\Scripts\python.exe -m adaos --help
.\tools\adaos.ps1 hub join-code create

For the hub API on Windows, prefer:

.\.venv\Scripts\python.exe -m adaos api serve --host 127.0.0.1 --port 8777