The rk command is the command-line interface (CLI) for the RSG 2.0 SDK. It provides developer tooling for building, deploying, and debugging Roku apps that use the RSG 2.0 SDK.

Installation

The rk CLI ships in the @roku-sdk/tooling package on npmjs.com, and each RSG 2.0 SDK app declares it in its package.json. Apps created with rk create already list it. To add it to an existing app:

pnpm add @roku-sdk/tooling

Inside a clone of the SDK repository, the example apps reference it as "workspace:*" instead; therefore, they run against the local source.

Once installed, the rk command becomes available through npx:

npx rk <command> [options]

Run rk directly (no npx)

Each call to npx rk or pnpm rk runs a wrapper self-bootstrap step that takes from approximately 350 to 550 ms. The first call in a fresh terminal takes several seconds. Both delays occur before rk starts. To skip that cost, install a one-time launcher:

npx rk setup --install-cli   # Writes ~/.local/bin/rk

After this you can call rk directly from any app directory:

rk <command> [options]

The launcher walks up from your current directory to find the nearest project-local rk and runs it directly. If ~/.local/bin is not on your PATH, the installer prints the line to add to your shell profile. You can use rk setup --check to see the launcher and PATH status, and rk setup --uninstall-cli to remove it. The launcher does not support Windows. On Windows, add your app's node_modules\.bin to PATH instead.

Available commands

  • mcp — Configure AI assistant integration via the Model Context Protocol (stdio and server mode).
    • Debugging with AI — Human-facing recipes: prompts to give your AI for common device debug tasks.
  • device — Manage and query Roku devices used by the SDK for sideloading, debugging, and opening the web UI.
    • Roku Cloud Emulator devices — Register, start, stop and drive cloud-hosted Roku devices; rk dev, rk ecp, rk logs and the MCP tools reach them like a Roku on your network.
    • device lease — acquire / release / reap a device lease through a configured pool (local or custom).
    • device pool — status of the configured pool's inventory + live state.
  • package — Sign, rekey, delete, convert, and list package artifacts on target Roku devices.
  • plugins — Add commands and server features to rk with installable plugin packages.
  • dcl — List and delete Downloadable Component Libraries installed on target Roku devices.
  • ecp — External Control Protocol commands for querying and controlling Roku devices.
  • keysequence — Send an ordered sequence of ECP keypresses from a single CLI call.
  • server — Run rk as a persistent HTTP server for improved performance.
  • server managed lifecycle (Phase 0) — API contract for managed vs unmanaged server lifecycle with window-based client leases.
  • build — Build RSG 2.0 SDK applications for deployment
  • dev — Side load your app in development mode, with or without debugging. Add --no-build to install an already-built app without rebuilding; it reads <out-dir>/pkg-dir, defaulting to dist-dev. Add --no-sideload for the inverse — build the dev artifacts and contact no device at all
  • start-dev — Deprecated alias for dev; still routes, prints the replacement on stderr
  • sideload — Deprecated; use rk dev --no-build. Still works with its existing options
  • create - Create a new RSG 2.0 SDK application (documentation TBD)
  • logs — Start, collect, search, and tail device logs through a server-side log session
  • decode-stack — Translate a raw Hermes or JS stack trace back to TypeScript source positions
  • gen-types — Generate .xml.d.ts for imported XML components without a full build (for fresh type-check)
  • perfetto — Record and manage Perfetto performance traces on a device
  • version — Print the @roku-sdk/tooling version (rk version, rk --version or rk -v); --where adds how it was installed (npm registry, npx/dlx temporary copy, or local build) and its path; --json prints {"version":"..."}

Extensibility

You can plug in a custom DeviceProvider (for example, a private device farm, a cloud Roku pool, or a custom continuous integration (CI) selection strategy) through the registry exposed by @roku-sdk/tooling. See Extending the device pool for more information.

Usage

Run the rk command with the following syntax:

npx rk <command> [options]

You can run npx rk --help to see the global usage and the command list.

You can also run npx rk help <command>, which is equivalent to npx rk <command> --help.

Global behavior:

  • The rk command automatically discovers the nearest running rk server by walking upward from the current working directory and validating /api/health.
  • You can use --local to skip discovery and force local mode for commands that support local execution fallback (build, dev, device, package, dcl, perfetto).
  • For commands that are server-only (for example, logs, ecp, server), rk rejects --local as an unknown option.

Startup performance model

The CLI applies several startup optimizations to reduce command latency:

  • Lazy command module loading: The CLI imports command modules only for the matched command, instead of eagerly loading all command implementations at startup.
  • Lazy fast-path executor loading: The CLI imports the server fast-path executor module (a relatively heavy module) only when it discovers a live rk server; therefore, non-fast-path invocations never pay its import cost.
  • Server fast-path (for build, dev, device, perfetto, package, dcl, cdp): When a live rk server is discovered and --local is not set, the CLI executes a direct server request before importing local command modules. rk dev --no-build and rk dev --no-sideload both decline the fast path, since the server always builds and always sideloads; they fall back to local execution.
  • Server endpoint for dev: The endpoint is POST /api/dev, with DELETE /api/dev/:sessionId to stop a watch session. The former names /api/start-dev and /api/start-dev/:sessionId still route to the same handlers so an older client reaches a newer server, but this repository does not post to them anymore. The internal command: "start-dev" discriminator is deliberately not renamed with the route.
  • Leaf filesystem helpers: Lightweight helpers such as pathIfExists live in a dependency-free module (tooling-utils/path-utils); therefore, commands that need only those helpers (for example, sideload and manifest and version updates) do not transitively pull in the build hub (esbuild, @babel, TypeScript, and sharp).

This design keeps lightweight commands fast and avoids unnecessary local initialization work when server mode is available.

The per-invocation cost described above comes from the npx or pnpm wrapper, not from rk itself. See Run rk directly (no npx) for more information. Only commands that run the build and image pipeline (build, dev, create, and server) load the native image library sharp. Lightweight commands (device, ecp, logs, decode-stack, sideload, and so on) never load it; therefore, it is not a factor in their startup latency.

You can run npx rk <command> --help to see command-specific help.


Did this page help you?