Skip to content

Generalize fleet: configurable topology + "Go Standalone" mode #338

Closed

Description

@jeonghun-jj-lee

Generalize fleet: configurable topology + "Go Standalone" mode

Important

Problem

The fleet implementation hardcodes Aaron's Mac Mini hostname (Aarons-Mac-mini) across
18+ locations in a public repo. "Local Fallback" is a temporary escape hatch with
rejoin pressure, but users need a clean way to run purely-local Amicode — the way it
worked before the fleet existed. A fleet client currently sees ONLY canonical sessions
(via tunnel) or ONLY local sessions (via fallback) — there is no unified view, and
fallback feels punitive rather than sovereign.

Approach

Forward-fix on main. Replace all hardcoded fleet topology with a config-file-driven
approach (~/.amico/ops/fleet/fleet.json). Change "Local Fallback" from a temporary
escape hatch into a permanent "Go Standalone" mode switch. No file = standalone
(the safe zero-config default for fresh installs).

Approaches Considered

  1. Config file at ~/.amico/ops/fleet/fleet.json (chosen) — readable by the shell
    guard, the extension, the installer, and CI. No file = standalone.
  2. VS Code settings only — the guard is a shell script and can't read VS Code
    settings without a sidecar. Rejected.
  3. Remove fleet entirely — loses the multi-machine capability for users who want it.
    Rejected.

Scope

Phase 1 (this issue): generalize fleet + Go Standalone command. Sessions are local-only
in standalone mode.

Deferred:

  • "Enroll" command (join a fleet from command palette)
  • Canonical session pull (merge server sessions into local DB with remote icon in UI)
  • Tunnel plist templating from fleet.json fields

Assumptions

  • No actual secrets were committed (verified: only hostnames, paths, SSH aliases)
  • Git history rewrite is unnecessary — forward-fix is sufficient
  • Aaron's specific fleet.json lives on his machine, not in the repo

Acceptance Criteria

  • No hardcoded Aarons-Mac-mini, /Users/aaron/, amico-mini, vault-aaron, or
    the-feynmachine in any file on HEAD
  • ~/.amico/ops/fleet/fleet.json is the single source of truth for fleet role
    (standalone | server | client) and canonical server coordinates
    (host, port, sshAlias)
  • No file = standalone: a fresh clone with no fleet.json spawns a local server
    (vendored binary, ephemeral port) — the pre-fleet behavior
  • Amicode: Fleet — Go Standalone command: writes fleet.json role=standalone, clears
    opencodeBinary/opencodePort settings (machine-scope), unloads tunnel plist, restarts
    server locally
  • Old commands removed: "Enter Local Fallback", "Exit Local Fallback", "Rejoin"
  • Guard script reads fleet.json role + canonical.host instead of scutil hostname
    comparison
  • fleet_health.ts reads fleet.json; health checks skip entirely when role = standalone
  • install.sh reads fleet.json for host/port; skips install when no file or
    role = standalone
  • CI gate (assert_fleet_guard.sh) verifies guard references fleet.json (replaces
    hostname grep)
  • Packaged copies (packages/extension/tools/fleet/*) stay in sync with tools/fleet/*
  • CONTEXT.md glossary updated: "Local fallback" → "Go Standalone"; "Rejoin" removed
  • Existing tests pass; new unit tests for fleet.json reading in guard + extension

Key Decisions

Fleet config shape

{
  "role": "client",
  "canonical": {
    "host": "<hostname>",
    "port": 4096,
    "sshAlias": "<ssh-host-alias>"
  }
}

No file on disk = role: "standalone" (implicit). The guard, extension, and installer all
resolve role the same way: read file → parse → fall back to standalone on any error.

"Go Standalone" semantics

Permanent mode switch, not a temporary escape hatch. The machine leaves the fleet and
serves itself. There is no "Rejoin" — re-enrollment in a fleet would be a separate
"Enroll" flow (deferred). Sessions created locally stay local. No migration or merge.

Session visibility

In standalone mode, the user sees their local sessions (whatever DB the opencode channel
logic resolves to). Canonical server sessions are not pulled or merged — that is a
separate follow-up feature (canonical session pull + remote icon in UI).

Constraints & Invariants

  • The guard must still exit 1 on a client that is NOT in standalone and NOT on the
    canonical host — the never-silently-fork invariant is preserved for fleet clients
  • Machine-scoped settings only — never synced via Settings Sync
  • The tunnel plist is unloaded on Go Standalone but NOT deleted (the file stays for
    potential re-enrollment)
  • Forward-fix only — no git history rewrite

Prior Art

  • ADR 0005 (docs/adr/0005-managed-fleet.md) — the fleet architecture decision
  • The 2026-08-07 silent-fork incident that motivated the fleet
  • tools/fleet/README.md — operational playbook

Source

Brainstorming session 2026-08-11. Motivated by: user cannot see local sessions after
fleet fallback was introduced; fleet code is Aaron-specific in a public repo.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions