npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tikoci/quickchr

v0.4.3

Published

CLI and library to download, launch, and manage MikroTik CHR virtual machines via QEMU

Readme

quickchr

Experimental — quickchr is under active development. Most testing has been on macOS (Apple Silicon + Intel), with CI on Linux (x86_64 + aarch64). Windows support is early-stage: unit tests pass on windows-latest CI, but integration tests (running a real CHR via QEMU for Windows) are not yet automated. Expect rough edges on Windows — bug reports welcome.

CLI and library to download, launch, and manage MikroTik CHR virtual machines via QEMU.

Quick Start

Prerequisites

  • Bun runtime
  • QEMU with qemu-system-x86_64 and/or qemu-system-aarch64
  • qemu-img for disk resize and extra-disk features (--boot-size, --add-disk, quickchr disk)
  • UEFI firmware (edk2) for arm64 CHR

Install QEMU:

# macOS
brew install qemu

# Ubuntu/Debian
sudo apt install qemu-system-x86 qemu-system-arm qemu-efi-aarch64 qemu-utils

# Fedora/RHEL
sudo dnf install qemu-kvm qemu-system-aarch64 edk2-aarch64 qemu-img

# Arch
sudo pacman -S qemu-full
# Windows — install QEMU (qemu-img is included)
winget install SoftwareFreedomConservancy.QEMU

# Install Bun (PowerShell — matches bun.sh official install docs)
powershell -c "irm bun.sh/install.ps1 | iex"
# Alternative: winget install Oven-sh.Bun

Install

CLI:

bun install -g @tikoci/quickchr
quickchr doctor

Library:

bun add @tikoci/quickchr

CLI Usage

The easiest way to start is the interactive wizard — it walks through every option and starts the CHR for you:

quickchr setup

quickchr setup wizard walkthrough

Or run quickchr with no arguments on a TTY to get the same wizard automatically. See MANUAL.md §3 setup for a step-by-step breakdown of every wizard prompt.

All wizard options are also available as flags for scripting:

# Create a machine without starting it
quickchr add --name my-chr --channel stable --arch arm64

# Create with a resized boot disk and extra blank disks
quickchr add --name lab --boot-size 1G --add-disk 512M --add-disk 2G

# Start an existing machine
quickchr start my-chr

# Create and start in one step
quickchr start --name throwaway --version 7.22.1 --boot-size 2G

# List instances (table view)
quickchr list

# Detailed status for one instance
quickchr status my-chr

# Stable connection descriptor/env for a running instance
quickchr inspect my-chr
quickchr env my-chr
quickchr env my-chr --json

# Stop an instance
quickchr stop my-chr

# Stop all instances
quickchr stop --all

# Run a RouterOS CLI command on a running instance
quickchr exec my-chr /system/resource/print
quickchr exec my-chr ":put [/system/routerboard/get serial-number]"

# Attach to serial console of a running instance (exit: Ctrl-A X)
quickchr console my-chr

# Tail QEMU log
quickchr logs my-chr
quickchr logs my-chr --follow

# Query live machine config (license, device-mode, admin users)
quickchr get my-chr
quickchr get my-chr license
quickchr get my-chr device-mode --json

# Manage snapshots (requires qcow2 boot disk)
quickchr snapshot my-chr list
quickchr snapshot my-chr save before-upgrade
quickchr snapshot my-chr load before-upgrade
quickchr snapshot my-chr delete before-upgrade

# Apply or renew a trial license
quickchr license my-chr

# Network discovery and virtual socket management
quickchr networks
quickchr networks sockets

# Set up shell completions (bash/zsh/fish)
quickchr completions

# Persist a default so you stop repeating a flag on every add/start
quickchr settings set default-channel long-term
quickchr settings set secure-login true
quickchr settings print

# Reset disk to fresh image
quickchr clean my-chr

# Inspect disk layout
quickchr disk lab

# Remove instance entirely
quickchr remove my-chr

# Check prerequisites
quickchr doctor

Create / Start Options

| Flag | Description | Default | |------|-------------|---------| | --version <ver> | RouterOS version (e.g., 7.22.1) | Latest stable | | --channel <ch> | stable, long-term, testing, development | stable | | --arch <arch> | arm64, x86, or auto | Host native | | --name <name> | Instance name | Auto-generated | | --cpu <n> | vCPU count | 1 | | --mem <mb> | Memory in MB | 512 | | --boot-disk-format <f> | Boot disk format: qcow2|raw | qcow2 | | --boot-size <size> | Resize boot disk (e.g., 512M, 2G). Requires qemu-img. | | | --add-disk <size> | Attach an extra blank qcow2 disk. Repeatable. Requires qemu-img. | | | --forward <spec> | Add or pin a QEMU SLiRP hostfwd mapping. Repeatable. | | | --bg / --background | Run in background (default) | true | | --fg / --foreground | Run in foreground — serial console on stdio | | | --add-package <pkg> | Extra package to install (repeatable) | | | --install-all-packages | Install all packages from all_packages.zip | | | --add-user <user:pass> | Create a user after boot | | | --disable-admin | Disable the default admin account | | | --no-secure-login | Keep admin with no password (skip managed account creation) | | | --add-network <spec> | Add a network NIC (repeatable). Specs: user, shared, bridged:<iface>, socket::<name>, tap:<iface>. Default: single user NIC. | | | --no-network | Start with no NICs (headless) | | | --no-winbox | Exclude WinBox port mapping | | | --no-api-ssl | Exclude API-SSL port mapping | | | --license-level <l> | Apply trial license: p1, p10, unlimited | | | --license-account <a> | MikroTik account email | env MIKROTIK_WEB_ACCOUNT | | --license-password <p> | MikroTik account password | env MIKROTIK_WEB_PASSWORD | | --device-mode <m> | Configure device-mode: rose|advanced|basic|home|auto|skip | | | --device-mode-enable <f> | Set one or more device-mode flags to yes | | | --device-mode-disable <f> | Set one or more device-mode flags to no | | | --port-base <port> | Starting port number | Auto (9100+) | | --timeout-extra <s> | Add extra seconds to the auto-computed boot timeout | | | --dry-run | Print what would run without executing | |

RouterOS Provisioning Support Policy

quickchr separates boot-only machine management from post-boot provisioning.

  • Boot-only / QEMU-local features work on older RouterOS 7.x builds: image download, boot/start, disk resize, extra disks, network attachment, and port mappings.
  • Post-boot provisioning is validated/tested on RouterOS 7.20.8+ only: package install, managed login or custom user creation, disabling admin, CHR license operations, and device-mode changes.
  • This is a quickchr support policy, not a RouterOS claim that older versions can never work. We intentionally stop at the first long-term baseline to avoid version-specific provisioning traps that are not covered by tests.
  • If you plan to provision, prefer --channel long-term or an explicit version >= 7.20.8.

| Feature | Minimum RouterOS | Notes | |---------|------------------|-------| | Boot / start / stop | Any RouterOS 7.x | Boot-only path; no post-boot RouterOS mutations | | Disk resize / extra disks / disk inspection | Any RouterOS 7.x | Requires host qemu-img; QEMU-local only | | Network attachment / port mappings | Any RouterOS 7.x | QEMU networking setup; not provisioning | | Managed login / custom user / disable-admin | 7.20.8+ | Post-boot provisioning | | Package install / install-all-packages | 7.20.8+ | Post-boot provisioning | | License apply / renew | 7.20.8+ | Post-boot provisioning | | Device-mode changes | 7.20.8+ | Post-boot provisioning; intentionally unsupported below the baseline |

Background vs Foreground Mode

By default quickchr start runs QEMU in the background: QEMU is spawned as a detached process and the command returns once CHR has booted. Use quickchr list, quickchr status, and quickchr stop to manage it.

# Background (default) — returns after CHR finishes booting
quickchr start --channel stable

# Foreground — serial console attached to your terminal
quickchr start --channel stable --fg

In foreground mode, your terminal becomes the CHR serial console. Use these key sequences:

| Key | Action | |-----|--------| | Ctrl-A X | Exit QEMU and return to shell | | Ctrl-A C | Toggle QEMU monitor (quit to force-stop) | | Ctrl-A H | List all key shortcuts |

Note: Background QEMU processes are true OS-level orphans — quickchr does not use shell job control (&). After the command returns you can close the terminal and QEMU keeps running. Use quickchr stop <name> to shut it down cleanly.

Disk Support

  • The CHR boot image starts as raw. Using --boot-size converts it to qcow2 and resizes it before first boot.
  • Extra disks from --add-disk are always created as blank qcow2 images.
  • quickchr clean <name> removes any resized boot disk and extra disks, then recreates them from the saved machine config.
  • quickchr disk <name> shows the stored disk layout. If qemu-img is installed, it also shows virtual and actual sizes.
  • quickchr snapshot manages qcow2 internal snapshots (requires a qcow2 boot disk).

Multi-NIC Networking

By default each CHR gets a single user-mode NIC (SLIRP). Use --add-network to add more NICs or replace the default:

# Two CHRs on a shared L2 segment via socket_vmnet (macOS) or bridge (Linux)
quickchr start --name router1 --add-network user --add-network shared
quickchr start --name router2 --add-network user --add-network shared

# Named virtual socket (L2 tunnel between CHRs)
quickchr networks sockets create lab-switch
quickchr start --name r1 --add-network socket::lab-switch
quickchr start --name r2 --add-network socket::lab-switch

# Bridge to a physical interface
quickchr start --name gw --add-network user --add-network bridged:en0

Not sure which mechanism fits your traffic (host→guest service, host receiving guest-originated UDP, L2 broadcasts, VM↔VM links, real LAN)? See the networking recipes guide — a "traffic shape → mechanism" decision table. The CLI flags map 1:1 to the library: --add-networkStartOptions.networks, --forwardStartOptions.extraPorts.

Port Layout

Each instance gets a block of 10 ports. With the default base of 9100, the first instance maps:

| Offset | Service | Default port | |--------|---------|-------------| | +0 | HTTP / REST / WebFig | 9100 | | +1 | HTTPS | 9101 | | +2 | SSH | 9102 | | +3 | RouterOS API | 9103 | | +4 | RouterOS API-SSL | 9104 | | +5 | WinBox | 9105 | | +6–+9 | Reserved (spare) | 9106–9109 |

The second instance gets 9110–9119, and so on.

Custom Port Forwards and Fixed WinBox

Use --forward <spec> on add or create-and-start start commands to add extra QEMU SLiRP hostfwd mappings. The shorthand uses the built-in service registry when it knows the guest port:

quickchr add lab --forward smb                  # auto host port → guest 445/tcp
quickchr add dude-lab --forward winbox:8291     # host 8291 → guest WinBox 8291/tcp
quickchr add app-lab --forward myapp:9200:7777/udp
quickchr add btest-lab --forward btest:9200-9210:2000-2010/udp  # UDP port range

A port range (name:hostStart-hostEnd[:guestStart-guestEnd][/proto]) expands to one hostfwd per port — handy for L3 peers with dynamic data ports. To receive UDP a guest sends (no forward at all), see the gateway path in the networking recipes guide.

Reusing a built-in service name such as winbox pins/replaces that service's host port for the machine. Existing machines keep the mapping stored in machine.json; recreate the machine to change fixed service ports cleanly.

Machine Descriptors and Subprocess Environments

quickchr inspect <name> [--json] emits a stable JSON descriptor for a running machine: status, ports, URLs, auth, env vars, and the machine directory. --json is accepted for parity; inspect output is always JSON.

quickchr env <name> [--json] prints the same subprocess environment as ChrInstance.subprocessEnv(): shell KEY=value lines by default, or a JSON map with --json.

Credential caveat: descriptor/env output includes connection secrets (auth.password, auth.basic, auth.header, QUICKCHR_AUTH, BASICAUTH) so child processes can connect without reading quickchr's secret store. Treat it like a password: do not commit it, paste it into public issues, or leave it in CI logs. Stopped machines fail with MACHINE_STOPPED; start the machine before requesting a descriptor or env map.

Library Usage

import { QuickCHR } from "@tikoci/quickchr";

// Start a CHR instance
const chr = await QuickCHR.start({
  name: "disk-lab",
  channel: "stable",
  arch: "arm64",
  mem: 512,
  bootSize: "1G",
  extraDisks: ["512M", "2G"],
});

// Use REST API
const info = await chr.rest("/system/resource");
console.log(info);

// Run a RouterOS CLI command
const result = await chr.exec("/system/resource/print");
console.log(result);

// Stop (or remove)
await chr.stop();
await chr.remove();

console.log(chr.state.bootDiskFormat); // "qcow2"
console.log(chr.state.extraDisks);     // ["512M", "2G"]

Version & channel API

Pick which CHRs are worth booting (handy for CI matrices) without scraping CLI text:

import { resolveActiveChannels, resolveAllVersions } from "@tikoci/quickchr";

await resolveAllVersions();
// { stable: "7.23.1", "long-term": "7.21.4", testing: "7.23rc4", development: "7.24beta2" }

await resolveActiveChannels();
// ["stable", "long-term", "development"]
//   released channels always, plus any pre-release at/ahead of stable

compareRouterOsVersion orders pre-release suffixes (7.24beta2 < 7.24rc1 < 7.24 < 7.24.1). The same map is available from the CLI via quickchr version --json. See MANUAL.mdVersion & channel helpers.

Use in Tests

import { describe, test, afterAll, expect } from "bun:test";
import { QuickCHR } from "@tikoci/quickchr";

let chr: Awaited<ReturnType<typeof QuickCHR.start>>;

test("boot CHR and check version", async () => {
  chr = await QuickCHR.start({ channel: "stable" });

  const resource = await chr.rest("/system/resource");
  expect(resource["board-name"]).toContain("CHR");
}, 120_000);

afterAll(async () => {
  if (chr) await chr.remove();
});

Environment Variables

| Variable | Description | |----------|-------------| | MIKROTIK_WEB_ACCOUNT | MikroTik.com account email (for license renewal) | | MIKROTIK_WEB_PASSWORD | MikroTik.com password (for license renewal) | | QUICKCHR_DEFAULT_CHANNEL, QUICKCHR_DEFAULT_ARCH, QUICKCHR_CACHE_MAX_SIZE, QUICKCHR_TIMEOUT_EXTRA, QUICKCHR_SECURE_LOGIN | Env-tier overrides for the 5 quickchr settings keys — see MANUAL.md §3 settings | | QUICKCHR_INTEGRATION | Set to 1 to run integration tests | | QUICKCHR_TEST_TARGET | Integration tests only: RouterOS channel (stable/long-term/testing/development) or pinned version (e.g. 7.22.1) to boot. Empty = stable. The Integration workflow (integration.yml) sets this from its routeros-target dispatch input to test a release across platforms |

The full list (including QUICKCHR_DATA_DIR, QUICKCHR_NO_PROMPT, QUICKCHR_DEBUG, NO_COLOR) is in MANUAL.md §11.

Documentation

  • MANUAL.md — complete reference: every CLI command, every library API, provisioning, channels, networking, storage, errors. Source-checked.
  • examples/ — runnable scripts (bun run): quickstart/ (boot + query), grounding/ (apply config → read back — the one bun:test), dude/ (install a package), harness/ (drive an external tool), rollback/, service-forward/, file-transfer/, device-mode/, plus mndp/udp-gateway/ version-matrix. See examples/COVERAGE.md.
  • docs/networking-recipes.md — which networking mechanism for which traffic shape.
  • DESIGN.md — architecture, layers, design principles.
  • CONTRIBUTING.md — dev setup and bun run check.
  • CHANGELOG.md — release history.

Using quickchr with an AI agent? The routeros-quickchr skill (in tikoci/routeros-skills) teaches agents the grounding workflow — boot a CHR, apply config, read it back — plus the networking recipes and harness patterns.

License

MIT