Skip to main content

One-time setup

muyan_pilot.py setup is the one-time, config-driven initialization entry for a new machine or a new task-pool repository. It verifies the local prerequisites, aligns the platform labels, installs the systemd user units, checks the checkout, and reports the optional model proxy — in one command, with a stable machine-readable result.
Run it once per machine (and once per new task-pool repository). It is idempotent: re-running it never creates duplicate labels, units or timers, and never touches business Issues or business labels.

What it does, in order

Setup is fail-fast: a core prerequisite failure stops the run before any later mutation, with the concrete reason on stderr and a non-zero exit code.
  1. Commandsgit, gh, python3 on the PATH, and a reachable systemctl --user user bus (a container or headless session without a user bus fails with the bus error).
  2. Authgh auth status (logged in with a usable token).
  3. Per target repository (every configured source_repos entry by default; exactly one with --repo OWNER/REPO):
    • the repo exists and the viewer has write permission (gh repo viewviewerPermission must be WRITE, MAINTAIN or ADMIN);
    • the seven platform labels are aligned declaratively from the repo-managed labels.toml (repo root) — the single source of truth for label name, color and description: a missing label is created, a drifted label is updated, nothing is deleted, and business labels (bug, enhancement, …) are never touched.
  4. Systemd units — the repo templates (systemd/muyan-pilot.service, systemd/muyan-pilot.timer) are installed idempotently into the user unit directory (the same install install-units performs: copy, daemon-reload, enable the timer — the service is never started, stopped or restarted), then the timer’s enabled/active state and next trigger time are reported.
  5. Checkout + git transport — check of the configured repo_dir: the origin remote’s transport (Issue #114): git data operations (fetch, push — including .github/workflows/*.yml) must go over SSH ([email protected]:owner/repo.git), so an existing HTTPS origin is migrated here with the plain git remote set-url origin [email protected]:owner/repo.git (setup is the human-authorized migration path — the Runner itself never rewrites a remote), the SSH URL must match the first configured source repo — a remote pointing at a DIFFERENT repo is never migrated (the rewrite would re-target the checkout at another repository) and fails with setup_failed reason=... origin remote repo mismatch ... — and git ls-remote <ssh-url> must exit 0 (SSH reachable and authenticated — a failure is setup_failed reason=... ssh_unreachable ..., no HTTPS fallback). Then the read-only parts: current branch, clean worktree (a dirty checkout fails: the timer’s ExecStartPre fast-forward refuses a dirty worktree, so the Runner could never start), and base freshness (local HEAD vs freshly fetched origin/<base_branch> — reported, not a failure: the timer fast-forwards a clean checkout at each start).
  6. Optional model proxy — the local-llm-kv-cache proxy health endpoint (http://127.0.0.1:18082/health) is checked and reported as optional: its absence or unhealthiness is a warning in the output and never blocks the core GitHub/Pilot setup.
Setup never creates business Issues, never claims a task, never starts Pi, and never modifies a protected branch.

Options

Output

The default output is stable key=value lines (one per concern; values containing spaces are quoted), so agents and scripts can parse it:
labels=7/7 means all seven platform labels match labels.toml; next is the timer’s next trigger time (- when it has none); optional_proxy is healthy, unhealthy or unavailable and never changes the exit code. migrated=true means setup rewrote an HTTPS origin to the SSH URL (a re-run then reports migrated=false); ssh_reachable is the git ls-remote probe result. --json prints the equivalent JSON document:

Success and failure examples

Success (exit code 0):
(The optional proxy is down here — note optional_proxy=unhealthy — but the core setup still succeeds with exit code 0.) Failures (non-zero exit code, setup_failed reason=... on stderr):
A wrong repo, missing labels that cannot be created (permission), a dirty checkout, an unreachable SSH (no HTTPS fallback) or a missing systemd user bus all stop the setup with the concrete reason — nothing is half-initialized without a clear signal.

Idempotency

Re-running setup on an already-initialized machine is a no-op for the external state: labels that already match are not rewritten, the unit templates are re-copied from the repo (drift repair), the timer stays enabled, and no Issues or business data are created or modified. The reported hashes and states are stable across runs. The HTTPS→SSH migration is one-shot: after the first run the origin remote is SSH and re-runs only re-verify it (migrated=false).