One-time setup
muyan-pilot setup is the one-time, config-driven initialization
entry for a new machine or a new task-pool repository. It verifies or
reinstalls the editable CLI install, 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.
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.- Commands —
git,gh,python3,uvand the installedmuyan-pilotCLI on the PATH (you install these yourself — setup only checks them; a missing one fails fast with the actionable install guidance, e.g.required command missing: uv (not on PATH) — install uv first: curl -LsSf https://astral.sh/uv/install.sh | sh), and a reachablesystemctl --useruser bus (a container or headless session without a user bus fails with the bus error). - CLI editable install (Issue #152) — the official local
deployment is the EDITABLE
uv toolinstall: the tool env importsmuyan_pilotfrom the deployment checkout, so theExecStartPrecheckout sync is picked up by the next CLI process automatically. When the running process already imports from the configuredrepo_dirthe step verifies it (no uv call,cli=verified); otherwise it runs the exact force editable reinstall (uv tool install --force --reinstall --editable --python /usr/bin/python3 <repo_dir>,cli=installed). A failing install fails fast — no unit install, no half-initialized state. The step never touches a running Runner process (the new source is loaded by the next CLI start). - Auth —
gh auth status(logged in with a usable token). - Per target repository (every configured
source_reposentry by default; exactly one with--repo OWNER/REPO):- the repo exists and the viewer has write permission
(
gh repo view→viewerPermissionmust beWRITE,MAINTAINorADMIN); - the eight 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.
- the repo exists and the viewer has write permission
(
- Systemd units — the repo templates
(
systemd/[email protected],systemd/[email protected]) are installed idempotently into the user unit directory (the same installinstall-unitsperforms: copy, migrate the pre-#149 non-templated units away once,daemon-reload, enable the two timer instances[email protected]/[email protected]— the service is never started, stopped or restarted), then each timer instance’s enabled/active state and next trigger time are reported. - Checkout + git transport — check of the configured
repo_dir: theoriginremote’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 HTTPSoriginis migrated here with the plaingit 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 withsetup_failed reason=... origin remote repo mismatch ...— andgit ls-remote <ssh-url>must exit 0 (SSH reachable and authenticated — a failure issetup_failed reason=... ssh_unreachable ..., no HTTPS fallback). Then the read-only parts: current branch, clean worktree (a dirty checkout fails: the timer’sExecStartPrefast-forward refuses a dirty worktree, so the Runner could never start), and base freshness (localHEADvs freshly fetchedorigin/<base_branch>— reported, not a failure: the timer fast-forwards a clean checkout at each start). - Optional model proxy — the
local-llm-kv-cacheproxy 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.
Options
Output
The default output is stablekey=value lines (one per concern; values
containing spaces are quoted), so agents and scripts can parse it:
cli=verified means the running CLI already imports muyan_pilot
from the deployment checkout (the editable install is in place);
cli=installed means the force editable reinstall ran. labels=8/8
means all eight platform labels match labels.toml;
there is one timer= line per timer instance and its next is that
instance’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 code0):
optional_proxy=unhealthy —
but the core setup still succeeds with exit code 0.)
Failures (non-zero exit code, setup_failed reason=... on stderr):
uv), 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 theorigin remote is SSH
and re-runs only re-verify it (migrated=false).