Skip to main content

Getting started

This page takes you from a fresh clone to a first verified tick. Every command works at any clone path — nothing here depends on a specific machine layout.

Prerequisites

You install these yourself — muyan-pilot setup only checks them (it verifies git, gh, python3, uv and the systemd user session on the machine); it never installs system packages, never installs gh, and never runs gh auth login (you log in first, setup only verifies the login). Install uv with the official installer (verified against the uv docs):
Pi must be configured with a provider that can serve a coding agent stably (system prompt + tool schemas + long sessions). Verify the endpoint with one real call before dispatching work — do not assume the key or the model service works:
If this fails, fix the model endpoint first; the Runner will fail fast on every task otherwise.
The local-llm-kv-cache proxy is an optional enhancement (faster prefix reuse for local llama.cpp models), not a core prerequisite — see Optional components.

1. Clone the repository

2. Install the CLI

The official usage is the installed muyan-pilot console script (the PEP 621 packaging in pyproject.toml maps muyan-pilot = muyan_pilot:main), installed as an editable uv tool install — the official local deployment (Issue #152). From the clone directory, --python pins the production interpreter (3.14):
uv tool keeps the CLI in an isolated tool environment; the executable lands in ~/.local/bin (on the PATH of the systemd unit). Why --editable matters: a non-editable install copies the source into the tool environment’s site-packages. The service’s ExecStartPre fast-forwards the checkout to the latest main before every start — with a copied source the CLI would keep executing the stale copy (bootstrap deadlock: Issue #152). With the editable install the tool env imports muyan_pilot directly from the clone directory, so the next CLI process (the next timer-triggered Runner) picks up the merged code automatically: ordinary Python source and systemd template/migration changes need NO reinstall and no upgrade command. When the PACKAGING inputs change (a new runtime module in py-modules, a dependency, the entry point, the package name, the build backend or the Python version), the editable finder’s module mapping is stale and the next CLI process dies with ModuleNotFoundError before the Runner can start (Issue #158) — the Runner now refreshes this automatically: at every start (before any slot or claim) it compares the sha256 of the checkout’s pyproject.toml with the fingerprint of the last successful install (recorded in the shared state dir, .muyan-pilot/cli-install.json): unchanged → no uv call at all (no per-tick reinstall); changed or first install → ONE lock-protected run of the exact force editable reinstall command above (the same base-sync flock the service ExecStartPre uses, so two instances starting in the same tick serialize and the second reuses the first’s result); a failing install fails the start fast with the structured cli_install_failed line (reason + the exact fix command). muyan-pilot doctor reports the consistency (cli_source: clean or cli_source: DRIFT with the structured cli_source_drift line), and muyan-pilot setup verifies or reinstalls it idempotently. The release package carries no third-party runtime dependency, no token and no user directory — the config file and the user systemd dir stay machine-local. The direct-execution entry of muyan_pilot.py (running the file with the interpreter) stays a development/compatibility path.

3. Create the configuration

The repository ships a committed example; the real config is local state (gitignored). Copy it and edit it:
All fields (TOML, relative paths resolve against the config file’s directory): Minimal example:

4. Run the one-time setup

The setup entry does the whole initialization in one command: it verifies the prerequisites you installed (git, gh, python3, uv, the systemd user session — a missing one fails fast with the actionable install guidance), verifies or reinstalls the editable CLI install (Issue #152 — the running CLI must import from the deployment checkout), verifies gh auth status and the repo permissions, aligns the platform labels from the repo-managed labels.toml (the single source of truth for label name, color and description — a commit never creates labels, and a missing label makes the scan silently skip that state), installs the systemd user units and enables the timer, checks the checkout, and reports the optional model proxy:
It is idempotent (re-running it never creates duplicate labels, units or timers) and fail-fast (a wrong repo, insufficient permission, a dirty checkout or a missing systemd user bus stops it with the concrete reason). See One-time setup for the full output contract, success and failure examples.

5. Run one tick manually

The manual command is for first verification and troubleshooting only — normal operation is scheduled by the timer (step 7):
One tick does at most one thing: resume an opened PR (review/fix/merge) or claim one ai-ready Issue (p0-labeled Issues are picked first, then bug-labeled Issues, then plain features; with active_milestone set, only Issues of that Milestone are claimable — Issue #139), then it exits. With an empty ready queue it exits cleanly without claiming anything.

6. Smoke walkthrough (from zero)

The smallest end-to-end proof that your setup works. Run it in the clone directory from step 1; every command is relative to that directory.
You are done when: the Issue moves ai-ready → ai-in-progress → ai-pr-opened → ai-merged, a PR exists with Fixes #<issue> in its body, and the journal shows run_end ... result=pr_opened. If any step fails, the Issue is marked ai-blocked with the scene — see Operations for recovery.

7. Verify the timers

The setup step already installed the unit templates and enabled the two timer instances ([email protected] and [email protected], each triggering its own service instance — see Operations); verify them:
The setup output carries one line per instance ([email protected] enabled active=true next=..., [email protected] ...) with the next trigger time. Each timer fires every 5 minutes, 24 hours a day (00:00–23:55). While one service instance is active, systemd ignores further starts of THAT instance; the next real start picks up the latest code (the service fast-forwards main before starting — see Operations). Two instances may run concurrently; the capacity is the Runner’s flock slots (max_concurrency), not the instance count.
The committed unit templates reference the author’s clone layout via %h specifiers (%h/Documents/muyan/muyan-pilot). If your clone lives elsewhere, install the CLI from your clone path (step 2) and edit the installed units in your user unit directory (~/.config/systemd/user/) to point WorkingDirectory and MUYAN_PILOT_CONFIG at your clone path, then systemctl --user daemon-reload. ExecStart is the installed muyan-pilot CLI and stays relative. The repo templates stay the single source of truth for everything else — see Operations on drift detection.