Agent Cluster

Arona's deployment story splits into two halves. The panel (the arona server binary) owns routing, billing, auth and the management plane. Each GPU node runs one _agent process that owns the model weights and the local serving processes. Agents open a long-lived WebSocket back to the panel's agent control plane (/ws/agent); the panel pushes deploy / stop commands down that socket and the agent streams download progress, heartbeats and command results back up. Once a model is running on an agent, the panel registers it as a routable backend so /v1/* and RPC traffic reach it — the control plane is WebSocket, the data plane is plain HTTP to the agent's local engine port.

Downloading model weights (CLI)

The _cli binary downloads model weights from HuggingFace, ModelScope or GitHub releases:

bash
1
arona download <repo> [--filter <glob|prefix>]... [--out <dir>] [--revision <rev>] [--yes]
bash
1
  HF_ENDPOINT=https://hf-mirror.com arona download hf:owner/repo --filter "*.safetensors"

The other CLI commands (packages/cli/src/main.rs:28-53):

CommandPurpose
installOne-click environment setup: detects the hardware profile and prints backend / quantization recommendations.
statusPrints the hardware profile.
deploy <model>Resolves a model locally and reports whether it is already cached.
downloadDownload model weights (above).
serveStarts the API server (panel).
connect <url>Connects to a management panel.
migrateRuns database migrations.

The _agent binary

_agent runs on each GPU node and is configured purely by environment variables (packages/core/src/config.rs:37-40):

VariableDefaultMeaning
ARONA_AGENT_NAMEarona-agentUnique node id; the panel uses it as the agent_id.
ARONA_PANEL_URLlocalhost:8080Panel host:port; the agent connects to ws://{ARONA_PANEL_URL}/ws/agent.

See Configuration for the full environment-variable reference (panel-side variables, database, secrets).

bash
1
2
3
4
# On each GPU node:
export ARONA_AGENT_NAME="gpu-node-01"
export ARONA_PANEL_URL="192.0.2.10:8420"   # the panel's host:port
_agent

Behaviour:

Run _agent under a service supervisor (systemd, malkuth, ...) so it reconnects automatically; the panel tolerates restarts on either side (see node persistence below).

Agent control plane RPC

The whole agent surface is admin-gated: every method requires a valid JWT and an admin account (validate_admin_jwt checks is_admin_email; packages/core/src/gateway/rpc.rs:106-118,301-337).

MethodParamsReturns
agents.listCluster topology: id, name, host, status (online/offline), GPU summary, models, last_heartbeat, version, connected_at.
agents.registermachine_name, versionagent_id, token.
agents.deregisteragent_id{ "ok": true } — removes the node.
agents.statusagent_idonline, GPU summary, gpu_utilization, models, host, connected_at, last_heartbeat.
agents.deploymodel_id, agent_id?{ "ok": true, "stream_id" } — empty agent_id auto-targets the least-loaded node.
agents.stopagent_id, model_id{ "ok": true } — halts the deployment.

agents.deploy returns a stream_id; subscribe to /api/rpc/events?session=<stream_id> before or immediately after the call to receive models.progress download notifications (see Events & Notifications). See JSON-RPC API for the transport and auth details.

Deployed-model auto-registration

When a deploy_result frame reports success, the panel registers an ExternalApiBackend named agent-{model_id} into the gateway router, with base URL http://{agent-host}:{port} — the agent's recorded host plus the engine port it reported (packages/core/src/gateway/server.rs:310-366, packages/core/src/gateway/mod.rs:253-270). The deployed model becomes a normal routable backend: /v1/chat/completions, embeddings and RPC chat all reach it, aliases apply, and the health checker probes it (see Backends for backend types and probing semantics).

Placement

Deployments without an explicit agent_id go through least-loaded placement (packages/core/src/gateway/tunnel.rs:214-229): candidates are agents whose last heartbeat is under 30 seconds, and the one with the lowest average GPU utilization is picked. Agents without telemetry sort last but remain selectable. If no agent is online the RPC fails with No online agents available for deployment.

On the routing side, conversations are pinned to one backend (session affinity): the first backend that serves a conversation is recorded and reused for subsequent turns, so per-conversation state such as a runtime KV cache stays warm (packages/core/src/routing/mod.rs:31-34,110-138). If the pinned backend becomes unhealthy, routing degrades to a fresh selection and re-pins.

Node persistence

Agent nodes persist in the agent_nodes table (agent_id, machine_name, version, host, gpu_info, models, connected_at, last_heartbeat; packages/core/src/gateway/tunnel.rs:8-12). At panel startup the persisted rows are restored so previously registered nodes stay visible across restarts; restored entries are sender-less until each agent reconnects over WebSocket (packages/core/src/gateway/run.rs:74-85). Deploying to a restored but disconnected node therefore fails until its _agent reconnects.