{host?.name ?? 'Host'} · Electric Cherry
{#snippet crumbs()}{/snippet} {#snippet actions()}{#if canManage && host && (!cleaning || host.decommission?.retryable)}
More actions
{/if}{/snippet}
{#if error}{/if}{#if notice}

{notice}

{/if} {#if loading}

Loading host…

{:else if host} {#if host.decommission}

Host cleanup

{hostDeletionMessage(host)}

{#if host.decommission.error}

{host.decommission.error}

{/if}

Requested . This page closes only after the cleanup worker confirms removal.

{#if host.decommission.stage === 'cleaned'}

The agent is expected to go offline during uninstall. If final confirmation never arrives, inspect the machine; loss of contact alone does not prove completion.

{/if}
{/if}

{host.connectionState} · {hostReadinessLabel(host.readiness)}

Last heartbeat:
{#if host.readinessReasons.length}{:else}

Connected and ready. Each deployment also checks its latest game files, runtime, and ports.

{/if} {#if host.readiness !== 'ready' && tab !== 'setup'}{/if}
{#if tab === 'overview'}

Agent workers

{#if host.inventory.agentLanes?.length}
{#each host.inventory.agentLanes as lane (lane.name)}
{hostAgentLaneLabel(lane.name)}
{hostAgentLaneState(lane)}{#if !host.connected} (last reported){/if}
Last successful poll:
{/each}
{:else}

This agent has not reported worker status yet.

{/if}

Inventory

Hostname
{host.hostname || 'Pending'}
Agent
{host.inventory.agentVersion ?? 'Unknown'}
Platform
{host.inventory.os ?? 'Unknown'} · {host.inventory.architecture ?? 'Unknown'}
CPU
{host.inventory.cpu ?? 'Unknown'} ({host.inventory.cpuCount ?? '?'} cores)
CPU usage
{host.inventory.cpuUsagePercent === undefined ? 'Not reported' : `${host.inventory.cpuUsagePercent.toFixed(1)}%`}{#if !host.connected && host.inventory.cpuUsagePercent !== undefined} (last reported){/if}
CPU temperature
Memory available / total
{bytes(host.inventory.memoryAvailable)} / {bytes( host.inventory.memoryTotal )}
Game storage available / total
{bytes(host.inventory.storageAvailable)} / {bytes( host.inventory.storageTotal )}
Docker
{host.inventory.dockerVersion ?? 'Unknown'} · {host.inventory .dockerRunning ? 'Running' : 'Unavailable'}
Current operation
{host.inventory.currentOperation ?? 'None reported'}
{#if calibration}

Learned server capacity

Allowances update from observed container usage. Hosts reserve 5% CPU and 500 MB of memory. Startup and running usage are tracked separately.

{#each ['startup', 'running'] as phase}{@const allowance = calibration[phase as keyof CapacityCalibration]}
{phase === 'startup' ? 'Starting a server' : 'Running a server'}
{allowance.cpuCores.toFixed(2)} CPU cores · {bytes( allowance.memoryBytes )} · {allowance.source === 'host' ? 'Learned on this host' : allowance.source === 'fleet' ? 'Learned from the fleet' : 'Calibrating; temporary allowance'} ({countLabel( allowance.samples, 'sample' )})
{/each}
{#if host.inventory.instanceResourcesError}

{host.inventory.instanceResourcesError}

{/if} {#if calibration.startup.source === 'bootstrap' || calibration.running.source === 'bootstrap'}

{hostCalibrationHint(host.inventory.agentVersion)} Measurements arrive with agent heartbeats and are combined into one peak sample per container per minute. The first five minutes after a container starts count toward startup; later measurements count toward running.

{/if} {#key host.id}{/key}
{/if} {:else if tab === 'servers'}

Running servers · {instances.length}

Current instances on this host, including any that are starting or unavailable.

{#if !host.connected && instances.length}

The host is offline. Instance details reflect the latest reports.

{/if} {#if instances.length}
{#each instances as instance (instance.name)} {/each}
{:else}

No instances are currently deployed on this host.

{/if}
{:else if tab === 'setup'} {#if !cleaning}

Automatic host setup

{/if}

Automatic agent updates · {host.enrolled ? hostAgentUpdateLabel(host.inventory) : 'Awaiting installation'}

Running version
{host.inventory.agentVersion ?? host.inventory.agentUpdate?.currentVersion ?? 'Not reported'}
Target version
{host.inventory.agentUpdate?.targetVersion ?? 'None reported'}
Last update check
{#if !host.connected && host.enrolled}

This is the last reported update status. The host is offline.

{/if} {#if host.inventory.agentUpdate?.error}

{host.inventory.agentUpdate.error}

{/if} {#if host.enrolled}

{hostAgentUpdateMessage(host.inventory)}

{:else}

The installer enables automatic updates when this host first enrolls.

{/if} {#if host.enrolled && !hostAgentUpdatesEnabled(host.inventory)}

{canManage ? 'Generate an installer under Agent access in Settings, run it on this host, and wait for a fresh heartbeat. The installer preserves the existing host identity and game data.' : 'An administrator can generate an installer under Agent access and run it on this host.'}

{:else if hostAgentUpdatesEnabled(host.inventory)}

The host checks this controller about every five minutes. Updates replace agent code between operations; running game containers continue.

{/if}

Cached game files and runtimes

{#if host.inventory.libraries?.length}
    {#each host.inventory.libraries as library}
  • {library.id}: {library.state}{library.progress !== undefined ? ` (${library.progress}%)` : ''}
  • {/each}
{:else}

No cached game libraries reported yet.

{/if}

Prepared runtimes: {host.inventory.preparedRuntimeImages?.join(', ') || 'None reported yet'}

{#if canManage}
Advanced: custom runtime or manual retry

The configured default runtime is prepared automatically. Use this to prepare another image or retry a pull now.

{ event.preventDefault(); void action( '/operations', 'POST', { kind: 'runtime.pull', image: runtimeImage }, 'Runtime download queued.' ); }} >
{/if}
{:else if tab === 'settings'}

Host availability

{#if canManage && !cleaning}
{/if}

Draining blocks new deployments and migrates empty instances to other hosts with capacity. The host disables when migration is complete and it is empty. Enabling refreshes the runtime and verifies BO1 and BO2 game files before returning the host to the capacity pool.

Host configuration

{#if canManage}
{:else}
Friendly name
{host.name}
Game ports
{host.portMin}–{host.portMax}
Local bind address
{host.bindAddress}
Public / NAT address
{host.publicAddress || 'Not configured'}
Minimum free storage
{bytes(host.minimumFreeBytes)}

Host configuration is managed by administrators.

{/if}

Public addressing is separate from local port reservations. Configure your firewall and NAT for the game-port range.

Agent access

Credentials: {host.credentialActive ? 'Active' : 'Not active'}. Enrollment links expire after 15 minutes and work once.

{#if canManage}
{#if enrollment}

Expires {$timeFormat.dateTime(enrollment.expiresAt)}

This command downloads the installer from the public Electric Cherry repository. The host fetches its public signing key from that repository during installation and before every update check.

{enrollment.command}
{/if}{:else}

Administrators manage enrollment and agent credentials.

{/if}
{/if}
{/if}
{ if (result.deleted) await goto('/hosts'); else { enrollment = null; await load(); } }} />

New deployments will stop on this host. Each instance will wait until its lobby is empty and another host has capacity, then be destroyed here and rebuilt there with the same server identity and map. Its address or port may change.

If capacity is unavailable, instances stay here until space becomes available. After all migrations finish, this host will be disabled.

{#if error}{/if} {#snippet actions()}{/snippet}