# How @motrix/cli Discovers and Pairs with Motrix Instances: A Technical Deep Dive

> Learn how @motrix/cli discovers local Motrix instances via ShellEnvironmentResolver and pairs securely using device-code flow. Understand the technical details of connection and token exchange.

- Repository: [Dr_rOot/Motrix](https://github.com/agalwood/Motrix)
- Tags: deep-dive
- Published: 2026-08-19

---

**The @motrix/cli tool uses a two‑stage process: first discovering the local Motrix executable via `ShellEnvironmentResolver` and version checks in `cli‑tool‑service.ts`, then establishing a secure connection through a device‑code pairing flow managed by `DeviceCodeService` that generates a user code, polls for UI approval, and exchanges a one‑time token.**

The `@motrix/cli` package provides a command‑line interface for controlling the Motrix download manager. When you execute CLI commands, the tool must first locate the Motrix binary on your system and then authenticate with the running instance. This article examines the source code in the `agalwood/Motrix` repository to explain exactly how discovery and pairing work under the hood.

## Stage 1: Executable Discovery via CliToolService

The discovery phase begins in `src/main/cli/cli‑tool‑service.ts` (lines 62–90), where the `CliToolService` class orchestrates the detection of the local Motrix installation. The service initializes a `ShellEnvironmentResolver` to build the correct shell context for the host platform.

To locate the binary, the service invokes `resolveExecutable` to find both the `node` runtime and the `motrix` command. Once located, the CLI validates the installation by executing `motrix --version` through the internal `#runVersion` method.

The service performs a critical version check: if the running Node version is 22 or higher, and the Motrix binary responds correctly, the CLI reports a **Ready** status and persists the executable path and version.

## Stage 2: Device‑Code Pairing Flow (Spec 7b)

Once the executable is discovered, pairing follows the Spec 7b device‑code flow. The `DeviceCodeService` class in `src/core/bridge/device‑code‑service.ts` manages the entire handshake, from request generation to token exchange.

### Initiating the Pairing Request

When you run `motrix pairing request`, the CLI instantiates `DeviceCodeService` and calls `request()`. This method (lines 48–66) generates a cryptographically random `requestId` and a human‑readable `userCode`, then stores a pending entry in memory.

The service arms a TTL (time‑to‑live) timer to prevent stale requests from accumulating. At this point, the CLI prints the user code (e.g., "ABCD‑EFGH") to the terminal.

### Polling for Approval

After displaying the code, the CLI enters a polling loop via `poll(requestId)`. Each iteration checks the entry's `effectiveStatus` property (lines 32–46). When you approve the request in the Motrix UI, the status flips to `approved` and the service returns a one‑time token to the CLI.

The polling mechanism handles the asynchronous nature of user interaction, waiting until the status change occurs or the TTL expires.

### Handling UI Approval

The bridge between the Motrix UI and the CLI pairing service is handled by `src/core/bridge/resolve‑cli‑pair.ts` (lines 20–33). This module provides a "resolve‑pair" helper used by both the desktop IPC bridge and the HTTP `/rpc` endpoint.

When the user clicks approve in the interface, the system calls `DeviceCodeService.approve()`, and the helper returns a standardized result object. Successful approvals return `{ok: true}`, while failures or unavailable states return `{ok: false, reason: 'unavailable'}`. This normalization ensures consistent behavior across transport layers.

## Practical Implementation Examples

You can interact with the discovery and pairing system via command‑line or programmatically through the Node.js API.

### Command‑Line Usage

```bash

# Check discovery status and version compatibility

npx @motrix/cli status

# Initiate device-code pairing

npx @motrix/cli pairing request

# → Outputs user code: ABCD-EFGH

# Approve in Motrix UI, then the CLI receives the token automatically

```

### Programmatic API

```javascript
import { CliToolService } from '@motrix/cli';

// Stage 1: Discovery
const cli = new CliToolService({
  directInstallSupported: true,
  platform: process.platform,
});
const status = await cli.getStatus();
console.log(`Found Motrix ${status.version} at ${status.executablePath}`);

// Stage 2: Pairing
const { requestId, userCode } = await cli.requestPair();
console.log(`Enter code ${userCode} in Motrix UI`);

let token;
while (!token) {
  const poll = await cli.pollPair(requestId);
  if (poll.status === 'approved') token = poll.token;
  await new Promise(r => setTimeout(r, 2000));
}
console.log('Paired successfully. Token:', token);

```

The public methods `requestPair()` and `pollPair()` are thin wrappers around the internal `DeviceCodeService` methods described above.

## Summary

- **Discovery** relies on `CliToolService` in `src/main/cli/cli‑tool‑service.ts` to resolve the Motrix executable using `ShellEnvironmentResolver` and validate it via `motrix --version`, requiring Node.js 22 or newer.
- **Pairing** utilizes `DeviceCodeService` in `src/core/bridge/device‑code‑service.ts` to implement a Spec 7b device‑code flow, generating unique request IDs and user codes stored with TTL timers.
- **Approval** is bridged through `src/core/bridge/resolve‑cli‑pair.ts`, which normalizes results for both IPC and HTTP transports.
- **Authentication** completes when the CLI receives a one‑time token after the user approves the request in the Motrix UI, enabling secure headless operation.

## Frequently Asked Questions

### What Node.js version does @motrix/cli require for discovery?

The CLI requires Node.js version 22 or higher to report a Ready status during the discovery phase. This check occurs in `src/main/cli/cli‑tool‑service.ts` after resolving the executable path and running `motrix --version`.

### How does the CLI locate the Motrix binary on the system?

The `CliToolService` uses `ShellEnvironmentResolver` to build the host environment, then calls `resolveExecutable` to find the `motrix` command in the system path. It verifies the binary by executing the `#runVersion` method, which runs `motrix --version` and parses the output.

### What happens if the user denies or ignores the pairing request?

If the user denies the request or the TTL timer expires, the `effectiveStatus` never transitions to `approved`. The polling loop in `DeviceCodeService.poll()` continues until timeout, and no one‑time token is issued, leaving the CLI unpaired and unable to authenticate.

### Can pairing requests be initiated programmatically without the CLI binary?

Yes, you can instantiate `CliToolService` and `DeviceCodeService` directly in Node.js code to trigger `request()` and `poll()` methods, as shown in the implementation examples. These classes are available when importing `@motrix/cli` as a dependency, allowing headless automation without shelling out to the CLI binary.