> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbi.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Getting started

# 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).

| Requirement                                    | What it is used for                                                                                                  | Check                              |
| ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
| Python 3.14                                    | The Runner and the test contract (CI pins the same minor version)                                                    | `python3 --version`                |
| [uv](https://docs.astral.sh/uv/)               | Installs the `muyan-pilot` CLI into an isolated tool environment (setup's CLI editable step calls `uv tool install`) | `uv --version`                     |
| [Pi](https://github.com/earendil-works/pi) CLI | The development agent; one full session per task                                                                     | `pi --version`                     |
| Git                                            | Worktrees, branches, base freshness                                                                                  | `git --version`                    |
| GitHub CLI (`gh`)                              | Issues, labels, PRs, merge                                                                                           | `gh auth status`                   |
| systemd (user session)                         | The timer that triggers one tick every 5 minutes                                                                     | `systemctl --user status`          |
| A working OpenAI-compatible model endpoint     | Pi's model provider — a local llama.cpp server or any OpenAI-compatible API                                          | one real `pi --print` call (below) |

Install `uv` with the official installer (verified against the [uv
docs](https://docs.astral.sh/uv/getting-started/installation/)):

```bash theme={null}
curl -LsSf https://astral.sh/uv/install.sh | sh
```

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:

```bash theme={null}
pi --print "reply with the single word: ok"
```

If this fails, fix the model endpoint first; the Runner will fail fast on
every task otherwise.

<Note>
  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](/optional-kv-cache).
</Note>

## 1. Clone the repository

```bash theme={null}
git clone https://github.com/xqliu/muyan-pilot.git
cd muyan-pilot
```

## 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):

```bash theme={null}
uv tool install --force --reinstall --editable --python /usr/bin/python3 .
muyan-pilot --help
```

`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:

```bash theme={null}
cp .muyan-pilot.example.toml muyan-pilot.toml
```

All fields (TOML, relative paths resolve against the config file's
directory):

| Field              | Required | Default            | Meaning                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| ------------------ | -------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `source_repos`     | yes      | —                  | Ordered list of `owner/repo` task pools scanned each tick (e.g. your pilot repo first, then your backlog repo)                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `repo_dir`         | no       | `.`                | The Runner checkout the service starts from (where `bootstrap_runner.py` lives)                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `workspace_root`   | no       | `..`               | Directory that contains the task worktrees and the repositories the agent may modify                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `prompt`           | no       | `prompt.md`        | Implementer prompt template (placeholders like `{{SOURCE_REPO}}` are rendered by the Runner)                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `prompt_review`    | no       | `prompt_review.md` | Review prompt template for the independent post-PR review session                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `base_branch`      | no       | `main`             | Delivery base branch; every task worktree is created from the frozen `origin/<base_branch>` SHA                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `active_milestone` | no       | unset              | Claim scope for the fresh-claim scans (Issue #139): the active GitHub Milestone title (e.g. `v0.2.0`). Set it to restrict the p0/bug/plain ready scans to that Milestone (the `milestone:"<title>"` qualifier is part of the gh search query — an Issue of another or no Milestone never enters the queue); `ai-ready` stays the execution switch, the pickup order is unchanged, P0 does not cross milestones, and resume states (opened PRs, in-flight restarts) are never gated by it. Unset = every `ai-ready` Issue is claimable (pre-#139 behavior) |
| `max_concurrency`  | no       | `1`                | Concurrent Pilot tasks on this machine (positive integer; a local model/GPU usually serves one stable task)                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `skills`           | no       | `[]`               | Optional Pi skill paths (absolute, `~`, or relative to the config file)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `context_files`    | no       | `[]`               | Optional Markdown context files injected into the prompt as paths                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |

Minimal example:

```toml theme={null}
source_repos = [
  "OWNER/PILOT-REPO",
  "OWNER/BACKLOG-REPO",
]

repo_dir = "."
workspace_root = ".."
prompt = "prompt.md"
prompt_review = "prompt_review.md"
base_branch = "main"
max_concurrency = 1
skills = []
context_files = []
```

## 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:

```bash theme={null}
muyan-pilot setup --config muyan-pilot.toml
```

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](/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):

```bash theme={null}
python3 bootstrap_runner.py --config muyan-pilot.toml
```

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.

```bash theme={null}
# a. Dispatch a tiny task into the first configured source repo.
#    `add` creates the Issue and labels it ai-ready in one step.
muyan-pilot add "Docs: verify smoke walkthrough" \
  --body "Read README.md and confirm the smoke walkthrough commands exist." \
  --config muyan-pilot.toml

# b. Watch the queue: the new Issue is ready.
muyan-pilot status --config muyan-pilot.toml

# c. Run one tick: the Runner claims the Issue, starts Pi in a fresh
#    worktree, and works toward a PR.
python3 bootstrap_runner.py --config muyan-pilot.toml

# d. Follow the live activity while the tick runs (second terminal):
journalctl --user -u muyan-pilot@1.service -u muyan-pilot@2.service -f
# or, for a manual tick, follow the session JSONL directly:
muyan-pilot session --follow --config muyan-pilot.toml

# e. After the PR is opened, the Issue carries ai-pr-opened and the
#    delivery continues (independent review, in-session fix, merge) on
#    later ticks. Watch the Issue and the PR on GitHub.
gh issue list --repo OWNER/PILOT-REPO --label ai-pr-opened
```

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](/operations) for recovery.

## 7. Verify the timers

The setup step already installed the unit templates and enabled the two
timer instances (`muyan-pilot@1.timer` and `muyan-pilot@2.timer`, each
triggering its own service instance — see [Operations](/operations));
verify them:

```bash theme={null}
systemctl --user list-timers 'muyan-pilot@*.timer'
```

The setup output carries one line per instance (`timer=muyan-pilot@1.timer
enabled active=true next=...`, `timer=muyan-pilot@2.timer ...`) 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](/operations)). Two instances may run concurrently; the
capacity is the Runner's flock slots (`max_concurrency`), not the
instance count.

<Note>
  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](/operations) on
  drift detection.
</Note>


## Related topics

- [Index](/index.md)
- [Workflow](/workflow.md)
- [Operations](/operations.md)
- [Setup](/setup.md)
