Skip to content

Fleet onboarding handoff

This is the standalone runbook for adding the next Jones-Gaffney fleet computer. It records the failure signatures learned during FLT-218 and the Windows ARM64 policy delivered by FLT-222. A person or agent should be able to follow it without access to either ticket conversation.

Who is who

Teammate System Usual role
Clahadore Jones-Gaffney Claude planning, orchestration, review, and hard calls
Cedric "Cody" Jones-Gaffney Codex / ChatGPT implementation and second-opinion review
Jenny Jones-Gaffney Gemini implementation, research, and review
Gronktayvius "Gronk" Jones-Gaffney Grok adversarial review and red-teaming

Terms used below are expanded here once. ARM64 means the 64-bit Arm architecture. x64 means the 64-bit x86 architecture. Secure Shell (SSH) is the remote-login protocol; Secure Copy (SCP) is its file-copy tool. Continuous integration (CI) is automated build and test work. A software development kit (SDK) supplies compilers and build tools. A command-line interface (CLI) is a terminal tool. A network interface controller (NIC) is a wired or wireless network adapter. An Internet Protocol (IP) address identifies a host on a network. Hypertext Transfer Protocol (HTTP) carries the listener traffic, and a Uniform Resource Locator (URL) identifies each address reserved for that listener. A personal computer (PC) is one fleet computer; PC-Bootstrap is the established deployment-folder name. JavaScript Object Notation (JSON) is the structured text used by manifests and probes. Secure Hash Algorithm 256-bit (SHA-256) is the artifact-digest algorithm. HKEY_LOCAL_MACHINE (HKLM) is the Windows machine registry hive. Domain Name System (DNS) names identify hosts, and Transmission Control Protocol (TCP) carries the Secure Shell connection.

Physical first step: Tailscale

After Windows or macOS out-of-box setup, physically install Tailscale and sign in through its browser flow before attempting remote onboarding. Confirm that the new computer appears in the Jones-Gaffney tailnet and that Tailscale reports a connected backend.

This step cannot be safely automated. It grants a device access to a private network and can require account choice, user consent, multi-factor authentication, and device approval. A script must not embed those credentials, approve a device on Andrew's behalf, or pretend that installing the application proves identity enrollment.

Do not begin repository cloning, publishing, model downloads, or any other long operation until portable power policy and unattended Tailscale are also proven as described below.

Platform matrix

Platform Entry artifact Intended work Native policy Deliberate omissions
Windows x64 Existing per-computer setup.ps1; give every new computer a self-elevating .cmd wrapper Role-specific main, gaming, streaming, or generic work x64 Windows packages and publishes Determined by its assigned role
Windows ARM64 Double-click WIN-ARM64/Fleet-Setup.cmd, which selects Invoke-Bootstrap -Role arm -UserOnly User-scope preparation for a light Fleet Dispatch worker on the Microsoft SQ1 Surface Pro X with about 8 gigabytes of memory Native ARM64 only; an x64 executable under emulation fails the probe Administrator-owned OpenSSH, firewall, power, unattended Tailscale, URL reservation, private-key delivery, and listener activation are deferred; no runner, Docker, Semgrep, audio loop, Guidepup, Ollama, local models, council hosting, or x64-only governor
macOS ARM64 Double-click fleet-mac-bootstrap/Fleet-Setup.command Apple-silicon fleet worker described by that repository Native Apple-silicon tools; Windows binary pools are not reused Follow fleet-mac-bootstrap/README.md for its current exclusions and manual steps

The Windows ARM64 role is separate from generic on purpose. A distinct role makes heavy work explicitly report SKIP and prevents a future expansion of the generic role from silently turning an 8-gigabyte tablet into a CI runner or model host.

Windows ARM64 availability evidence

All eight tools named in FLT-222 had native Windows ARM64 artifacts when rechecked on 2026-08-08. These versions and digests are evidence, not bootstrap pins: WinGet resolves the current native package, and the bootstrap independently probes the installed binary. Recheck the vendor release and WinGet manifest before changing package or skip policy.

Tool Native Windows ARM64 evidence checked on 2026-08-08 Published SHA-256 digest FLT-222 action
Git for Windows 2.55.0(3) ARM64 installer e3d7f5a2214f214f0a93cf0d8915dab236a0e91c7de6de70a7dbde9a61c794db Install through WinGet with --architecture arm64; parse git --version and require an ARM64 executable. There is no invented minimum version.
GitHub CLI 2.97.0 Windows ARM64 installer 5389e1baf84383470f3b1a5e61377fbb2e529483a38261ce0e4d83fe70c36ca0 Install native; parse gh version and require an ARM64 executable. There is no invented minimum version.
Node.js long-term support 24.19.0 ARM64 installer and signed checksums 47b16e1b1012b1b9ad62169b3a466adb6bc758b2cb8bd8224683c086836484f8 Require version 22 or newer because Claude Code requires that floor; require process.arch to equal arm64.
.NET SDK 10 10.0 release metadata with Windows ARM64 builds and the WinGet ARM64 manifest bedf0d3ae61284252db8012dab3809879fb6d9721335414b68992d32a6da20bb in the checked WinGet manifest Require a 10.* SDK and require dotnet --info to report ARM64.
PowerShell 7 7.6.4 Windows ARM64 release and Microsoft's Surface Pro X guidance 9b441d52176befd22b3aadf34f2f43f3a6f692c8d0181815169a397236b33d1f for the checked ARM64 Microsoft Installer package Require major version 7 or newer and an ARM64 process. Native Windows support requires Windows 11 build 22000 or newer.
ripgrep 15.2.0 ARM64 release archive e4abca10c3a64ebea742667dd7009449d49403db5460dd6873e389fa2945360f Install native; parse rg --version and require an ARM64 executable. There is no invented minimum version.
GitHub Actions runner 2.336.0 Windows ARM64 release archive; Windows ARM64 support remains public preview b3799e9cf754fe4dfcb3d220c9701c924829737ee815dbeb674f8bd076794504 SKIP: a native build exists, but this light role is not a CI runner. No token is fetched and no archive is downloaded. The existing x64 pin and checksum remain untouched for x64 roles.
Docker Desktop 4.85.0 Windows ARM Early Access release and Windows ARM requirements a73ed41477691ea0eb186d7cb362bec2cab3bd4e3c5af9c743aa372da1c5cc69 SKIP: the native build is Early Access, Docker's documented minimum is 8 gigabytes of memory, and containers are outside the light role. Semgrep is skipped with it.

Never interpret “a native build exists” as “this role should install it.” Availability and role fitness are separate decisions.

Exact order of operations

1. Enroll Tailscale in person

Install Tailscale, complete browser sign-in, approve the device if required, and confirm the backend is connected. Do not send Andrew a terminal command for this step.

2. Put the double-click artifact on the new computer

For the Surface, copy the deployed PC-Bootstrap/WIN-ARM64 folder from OneDrive or copy this repository's WIN-ARM64 folder. The folder contains Fleet-Setup.cmd and setup.ps1; the shared library must be either one directory above it in a repository checkout or at PC-Bootstrap/_shared/lib/bootstrap-lib.ps1 in the deployed layout.

The Fleet Dispatch private key is not part of this copy. It must never be stored in OneDrive.

3. Double-click the launcher

Double-click Fleet-Setup.cmd normally. Do not choose Run as administrator. The launcher and setup.ps1 both refuse an Administrator token, so OneDrive scripts, repository build inputs, npm JavaScript, and transcript writes never cross the User Account Control boundary. The transcript is stored at %LOCALAPPDATA%\Jones-Gaffney\FleetBootstrap\Fleet-Setup-ARM64.log; it is never appended inside the OneDrive package. The launcher preserves the bootstrap exit code and ends with pause. The arm role itself also fails closed unless -UserOnly is present; a modified caller cannot reactivate the legacy self-elevation path. The PowerShell child remains visible so errors and the final paused summary cannot disappear in a hidden console.

The reusable WIN-ARM64 folder does not guess the final computer name. setup.ps1 reads the real name and refuses to run the arm role on a non-ARM64 operating system.

4. Let the early safety sections finish before any long work

The bootstrap performs these actions in this order:

  1. It proves the process has a standard-user token and refuses to self-elevate.
  2. It writes a managed SSH alias block at the top of ~/.ssh/config before any SSH or SCP call. It also writes a dedicated ~/.ssh/fleet_known_hosts containing greatroom's Ed25519 host key, verified on the greatroom console on 2026-08-08 as SHA256:1CNhArjMmEIbkHKkfLLy6nQFnRabw7OFVwSd0hxhF5c. Accept-on-first-use is disabled for the private dispatch-key transfer.
  3. It explicitly defers administrator-owned sleep, hibernate, lid, NIC, Tailscale unattended, OpenSSH capability/service, firewall, and HKLM shell changes. It does not silently attempt them.
  4. It validates every imported public key as one Ed25519 key and updates only the current user's authorized_keys; the administrator key store remains deferred.
  5. It installs native prerequisites through WinGet with --architecture arm64 and probes each resolved binary, version, and architecture.
  6. It checks GitHub authentication, then consumes the canonical 39-repository flat manifest from fleet-repo-sync/manifest.json under ~/source/repos.
  7. It installs Claude Code only through the exact native Node.js path. The ARM role reports SKIP for the current usage-governor installer because that installer publishes win-x64 and registers console-backed tasks before an ARM postcondition could be checked.
  8. It explicitly skips the runner, Docker Desktop, Semgrep, model-host, audio, and screen-reader workloads for the arm role.
  9. As the standard user, it publishes the ARM64 Fleet Dispatch engine and its no-console C# launcher into a new publish-win-arm64/build-* directory, requires both publish commands to succeed, and probes the fresh files before using them. Before publishing, it ends and removes the three known listener tasks, stops any remaining FleetDispatch.exe process, and refuses to claim a known-offline host if either a registration or process remains.
  10. As the standard user, it retrieves and validates the private Dispatch key over the pinned greatroom SSH alias. It never moves that key through OneDrive. It does not execute listener repository scripts, change URL reservations, or register tasks; those operations remain blocked until the separately reviewed administrator-owned activation path runs.
  11. It writes the summary and an expected ARM administrator activation warning. The launcher returns nonzero until that second stage is completed and independently proven.

5. Complete the browser authorization opened by the launcher

After the first pass proves the ARM64 operating system and native authorization executables, Fleet-Setup.cmd starts GitHub and Claude browser authorization when either account is unauthenticated. It configures and probes the GitHub Git credential helper, invokes Claude through the exact native Node.js executable, and automatically runs the user-scope dependent sections again after authorization changes. Andrew receives a click-through flow rather than a command to transcribe.

6. Activate the reviewed administrator stage, then rerun normally

The user-scope package imports public keys already present in the OneDrive mesh, builds the native ARM64 listener, and retrieves the private Dispatch bearer key over the pinned greatroom SSH alias. It does not activate an inbound listener. Do not bypass that boundary, elevate either OneDrive script, or move the private key through OneDrive.

The FLT-222 task supplies one out-of-band command containing the immutable Git commit plus SHA-256 values for Activate-Administrator.ps1, bootstrap-lib.ps1, and both reviewed ARM64 release binaries. Paste that command into Windows Terminal opened as Administrator. The command creates a locked ProgramData staging directory, downloads exactly the two scripts through authenticated gh api, verifies both script hashes, and only then runs the activation script. The activation script refuses every other location or hash. OneDrive transports the two release binaries but does not establish trust: the activation script copies them to a locked ProgramData install directory and requires the two out-of-band hashes on the locked destinations.

That stage configures power, unattended Tailscale, OpenSSH, the Tailscale-only SSH and Dispatch firewalls, public administrator keys pinned in the reviewed artifact, exact URL reservations, machine environment, and a DACL-hardened hidden Limited scheduled-task definition. It starts the hash-pinned, administrator-owned ARM64 wrapper and engine only through the task's independently proven interactive-user Limited principal. The Administrator process never directly executes either binary and checks only the private key's non-reparse path, bounded file size, and owner/System-only ACL metadata; the Administrator process never reads or decodes the bearer secret. It never executes a user repository script, MSBuild project, or npm payload. It requires two health responses from the same limited engine process 35 seconds apart. On any failure it removes the task and protected activation marker so the listener remains offline.

After it succeeds, close the Administrator window and double-click Fleet-Setup.cmd normally a second time. The standard-user pass validates the protected marker and every readable system postcondition, revalidates the private Dispatch key transferred by the preparation pass, and independently requires two health responses from the same native engine process 35 seconds apart. Only that final pass may report onboarding complete.

7. Add the new computer's inbound alias before the first remote connection

On every managing computer, add the new host to ~/.ssh/config with its actual Windows username and Tailscale MagicDNS name or stable address. Obtain its public SSH host key and fingerprint from the new computer's physical console, then install that trusted key before the first connection. Never use ssh-keyscan output by itself as proof. Put the specific host block before wildcard blocks. Connect by alias only. Never construct user@host at a call site.

The existing username map is:

Alias Windows username
greatroom fives
gaming AndrewJonesDev
streaming fives
bedroom fives
gamelaptop fives
streamlaptop Andrew

Record the new computer's real account; do not infer it from another fleet member.

Verification by probe

The launcher is the normal interface. The commands below document what the automation proves and are diagnostic references for an agent or operator; do not make Andrew retype the runbook.

Stage Required probe and passing condition
Platform Operating-system architecture resolves to arm64; Windows build is 22000 or newer for native PowerShell 7.
SSH aliases ssh -G greatroom and each other alias report the exact configured user and hostname; greatroom reports strict host checking, Ed25519-only negotiation, and fleet_known_hosts. ssh-keygen -F finds the pinned greatroom key in that dedicated file.
Portable power Current alternating-current and battery indexes for sleep, hibernate timeout, and lid close equal zero; HibernateEnabled in HKLM:\SYSTEM\CurrentControlSet\Control\Power equals zero. Tailscale debug prefs reports ForceDaemon=true, its service is Automatic and Running, and its backend is Running.
NIC power Get-NetAdapterPowerManagement no longer reports that Windows may turn off each active physical adapter.
Tailscale tailscale set --unattended succeeds, tailscale debug prefs reports ForceDaemon=true, the service is Automatic and Running, and tailscale status --json reports backend state Running.
OpenSSH Server Before the service starts, the reviewed controller key set is installed and sshd_config is proven public-key-only for both the interactive user and a non-match user. Active Include directives and Match-scoped authentication overrides are rejected or removed. The sshd service is Automatic and Running; a full TCP/22 rule inventory, including ranges and multi-port filters, finds exactly one allow rule bound to the adapter owning the proven Tailscale address and 100.64.0.0/10.
Git git --version yields a parseable version and the resolved executable has ARM64 Portable Executable machine value 0xAA64.
GitHub CLI gh version yields a parseable version, the executable is ARM64, and gh api user --hostname github.com succeeds after interactive authorization. Bare gh auth status is not used as the probe: it aggregates every configured account and exits nonzero if any one fails, so a stale account reports failure on a box whose auth is fine. --hostname is required, or the probe follows GH_HOST and an enterprise credential could satisfy a github.com gate. Note that this probe requires connectivity — it does not distinguish a missing credential from a GitHub outage.
Node.js The parsed version is 22 or newer and node -p process.arch returns arm64. A found node.exe alone does not pass.
.NET SDK dotnet --list-sdks contains a line beginning 10. and dotnet --info reports architecture arm64.
PowerShell 7 $PSVersionTable.PSVersion is major version 7 or newer and .NET runtime process architecture is Arm64.
ripgrep rg --version yields a parseable version and the executable has ARM64 Portable Executable machine value 0xAA64.
Repository set Parsing fleet-repo-sync/manifest.json yields 39 entries; every entry resolves below the flat ~/source/repos root, git rev-parse --is-inside-work-tree returns true, and git remote get-url origin equals that entry's exact approved GitHub origin before and after pull. The manifest repository itself must equal its one canonical origin before its data is read.
GitHub Actions runner The section says SKIP with the light-role reason; no runner service or archive is created by the arm role.
Docker Desktop The section says SKIP with the Early Access, memory-floor, and role reason; Docker presence is never reported as an ARM onboarding success.
Usage governor The section says SKIP because its current installer publishes win-x64 and registers console-backed tasks. No usage-governor installer is invoked on ARM64.
Fleet Dispatch publish User preparation produces native ARM64 output. Deployment transports a reviewed release copy through OneDrive; the administrator stage copies it into ProgramData\Jones-Gaffney\FleetDispatch\FLT-222-v1, verifies out-of-band hashes on the locked destinations, and registers only that administrator-owned wrapper. Both files have ARM64 Portable Executable machine value 0xAA64; the wrapper subsystem is windows-gui.
Dispatch key ~/.claude/fleet-dispatch.key was freshly transferred by SCP from alias greatroom, parses as Base64, contains at least 32 decoded bytes, is not a reparse point, and grants access only to the current user and LocalSystem; no copy exists in the OneDrive bootstrap tree.
HTTP URL reservations A full netsh http show urlacl inventory finds exactly the Tailscale and loopback reservations on port 47600, with no wildcard or competing prefix; both name the exact [Security.Principal.WindowsIdentity]::GetCurrent().Name account. The limited listener health probe then proves the reservations are usable without administrative rights.
Listener account Executable syntax in the canonical installer assigns [Security.Principal.WindowsIdentity]::GetCurrent().Name; after registration, the scheduled task principal resolves to the same security identifier and its run level is Limited.
Listener service The canonical installer performs two settled health checks against the same serving process. The task has exactly one action, uses interactive logon, starts and stays running on battery, is hidden, has the exact expected arguments and working directory, uses the C# Windows executable rather than a console executable, and produces no visible console. The engine starts suspended, joins the kill-on-close Job Object, then resumes.
Listener failure posture Before initial ARM publishing and before administrator activation, FleetDispatchServe, legacy FleetDispatchListen, and FleetDispatchServeFallback are ended, deleted, and absence-probed. Administrator-stage failure absence-probes task/process and firewall removal, verifies URLACL and OpenSSH rollback, and if restoration is uncertain disables every effective inbound TCP/22 allow rule plus the OpenSSH service. Final standard-user health failure stops the task and processes.
User-preparation result %LOCALAPPDATA%\Jones-Gaffney\FleetBootstrap\Fleet-Setup-ARM64.log contains the current section summary. Before activation, the only expected unresolved warning is ARM administrator activation; investigate every other WARN. After activation, every section must be OK or an intentional light-worker SKIP.
Administrator activation A locked ProgramData stage verifies out-of-band SHA-256 values before execution. OpenSSH, power/NIC policy, unattended Tailscale, pinned administrator public keys, Tailscale-only firewalls, exact URL reservations, machine environment, and the hidden Limited task definition pass exact probes. The fleet executable starts only through the proven Limited task principal and passes stable health; it never runs elevated. The standard-user rerun independently revalidates the prepared key without replacing it underneath the running process, then proves stable health.

An exit code or success-looking output is supporting evidence only. It never replaces the postcondition probe in this table.

Failure signatures learned on FLT-218

Symptom Actual cause to check first Required response
SSH completes key exchange and then resets at user authentication; it looks like a dead server, firewall block, or antivirus termination Wrong Windows username. Windows sshd may reset instead of returning “permission denied.” Inspect ssh -G <alias>, correct the alias's User, and retry the alias. Do not debug the daemon first and do not switch to user@host.
SCP reports an unknown or changed greatroom host key during private-key delivery The dedicated pinned key is missing, greatroom's host key changed, or the connection is being intercepted Stop. Verify the current Ed25519 fingerprint at the physical greatroom console. Update the shipped pin through a reviewed ticket only when that console value proves an intentional rotation. Never switch to accept-on-first-use.
Portable computer disappears in the middle of cloning, publishing, or a listener probe Sleep, hibernate, lid-close, NIC power saving, or Tailscale not running unattended Apply and probe alternating-current plus battery policy before the long step. A Surface is a tablet, so this is more important, not less.
Register-ScheduledTask fails with 0x80070534, or a headless repair appears to hang Over SSH, USERDOMAIN can equal WORKGROUP; WORKGROUP\username is not a resolvable principal Use [Security.Principal.WindowsIdentity]::GetCurrent().Name. The fix belongs in fleet-dispatch/repair-fleet-listener.ps1 under FLT-218; home-bootstrap must not duplicate it. Until that fix is present, the ARM bootstrap refuses listener installation.
Bootstrap skips Node.js and Claude Code reports an unsupported engine A presence-only check found Fast Node Manager (fnm) Node.js 20.13.1; Claude Code needs version 22 or newer Parse the resolved Node.js version and process architecture. Install native long-term support only if that probe fails.
WinGet prints “Successfully installed,” but the next package is absent; later calls can say “Access is denied” The Windows App Execution Alias worked once in the SSH session, then failed while stale buffered text remained visible Resolve the concrete App Installer winget.exe; after every install, newly resolve and run the target binary. Trust neither WinGet stdout nor its exit code by itself.
A human receives a PowerShell command and no durable record of what happened No double-click handoff artifact Ship a user-scope .cmd that refuses Administrator execution, writes its log below %LOCALAPPDATA%, preserves status, and ends with pause. Keep administrator activation separate and administrator-owned.
Fleet Dispatch task registers and starts but never serves; a probe waits for many minutes ~/.claude/fleet-dispatch.key was not delivered; prior bootstrap behavior treated the failed copy as a warning and continued Copy only by SCP from alias greatroom, prove its Base64 format and minimum 32-byte decoded length, and block listener registration otherwise. On ARM, end and delete all current, legacy, and fallback listener tasks before the attempt so a failed refresh leaves none running. Never use OneDrive for this private key.
Limited-rights Fleet Dispatch task starts but cannot bind, while an elevated manual launch works One or both HTTP URL reservations are missing or owned by the wrong principal; an elevated bind is a false-positive probe Use canonical setup-urlacl.ps1 logic for both the Tailscale and loopback URLs, verify each reservation names the exact Windows identity, then prove the limited scheduled listener through its health endpoint. Do not solve this by elevating the network-facing listener.
A console window flashes at logon or task restart Task Scheduler's Hidden setting hides the task in its user interface but does not suppress a console executable Use the ARM64 C# WinExe launcher, CreateNoWindow, a kill-on-close Job Object, and a hidden non-interactive scheduled task. Probe the task settings and observe no console.

What FLT-222 does not do

  • It does not automate Tailscale identity enrollment or the human consent and account selection required by GitHub and Claude authorization. The launcher starts the two browser flows only after its ARM64 safety and native-executable gate passes; Andrew completes or cancels them interactively.
  • It does not install the Windows ARM64 GitHub Actions runner, even though a verified native archive and checksum exist.
  • It does not install Docker Desktop, Semgrep, local models, audio automation, or screen-reader automation on the Surface.
  • It does not run the current x64-only usage-governor installer or its console-backed scheduled tasks on the Surface.
  • It does not copy any private key through OneDrive. The standard-user stage retrieves the Dispatch bearer key only over the pinned greatroom SSH alias and protects it owner/System-only.
  • It does not elevate OneDrive scripts, npm JavaScript, repository scripts, or MSBuild inputs.
  • It does not duplicate or land the FLT-218 listener-account fix. It detects the corrected [Security.Principal.WindowsIdentity]::GetCurrent().Name implementation and refuses to run the stale installer.
  • It does not claim physical Surface validation from an x64 development computer. The final acceptance run must use the Surface and preserve Fleet-Setup.log.

Handoff acceptance checklist

  • Tailscale sign-in was completed physically and unattended service state is proven.
  • The managing hosts contain a tested alias with the new computer's exact username.
  • The new computer completed the user-scope double-click preparation with no unresolved WARN results except the expected ARM administrator activation boundary.
  • Every installed Windows ARM64 prerequisite passed both version and native-architecture probes.
  • The manifest count is 39 and all repositories occupy the flat ~/source/repos root.
  • Greatroom imported the new public SSH key; the Surface then received the private Fleet Dispatch key directly by strict SCP using the reviewed greatroom Ed25519 pin.
  • The FLT-218 Windows identity fix is present in the canonical listener installer.
  • Fleet Dispatch passed two same-process health probes through a limited-rights, hidden, interactive-logon, battery-safe task with no visible console flash.
  • Runner, Docker Desktop, model-host, and heavy-tool omissions are visible as reasoned SKIP results.
  • %LOCALAPPDATA%\Jones-Gaffney\FleetBootstrap\Fleet-Setup-ARM64.log is attached to the ticket or handed to the next operator, with secrets removed if any diagnostic command accidentally printed them.