$npx -y skills add tikoci/routeros-skills --skill routeros-quickchrGround RouterOS config/scripts/API code against a REAL router using quickchr (@tikoci/quickchr) — a CLI + Bun/TS library that downloads, boots, and manages MikroTik CHR VMs on QEMU. Use when: validating generated RouterOS config or scripts against real RouterOS before trusting th
| 1 | # Grounding RouterOS with quickchr |
| 2 | |
| 3 | ## What this is for |
| 4 | |
| 5 | The reliable way to know whether a RouterOS config, script, or API call actually |
| 6 | works is to run it against **real RouterOS** — not to guess from docs. quickchr |
| 7 | ([`@tikoci/quickchr`](https://github.com/tikoci/quickchr), npm, MIT, public) makes |
| 8 | that a few lines: it downloads a MikroTik **CHR** (Cloud Hosted Router) image, |
| 9 | boots it under QEMU, provisions it, and hands you a REST/SSH/exec handle. The free |
| 10 | CHR license (1 Mbps, no signup) is enough for config validation, API iteration, and |
| 11 | test grounding. |
| 12 | |
| 13 | **Reach for quickchr when** you want to apply config and read it back, iterate on |
| 14 | REST/scripting against a live box, or run integration tests against CHR. |
| 15 | |
| 16 | **Don't reach for it** when you only need documentation (use the `rosetta` MCP / |
| 17 | the `routeros-fundamentals` skill), or you're flashing physical hardware (use the |
| 18 | `routeros-netinstall` skill). For raw QEMU boot internals without the quickchr |
| 19 | wrapper, see the `routeros-qemu-chr` skill. |
| 20 | |
| 21 | ## The grounding loop (core pattern) |
| 22 | |
| 23 | ```ts |
| 24 | import { QuickCHR } from "@tikoci/quickchr"; |
| 25 | |
| 26 | const chr = await QuickCHR.start({ name: "lab", channel: "stable" }); |
| 27 | // start() resolves REST-READY — provisioning is already done. No second wait needed |
| 28 | // in normal background/library use; waitForBoot() is only a belt-and-suspenders check. |
| 29 | |
| 30 | await chr.exec("/ip/firewall/address-list/add list=blocked address=10.9.9.9"); |
| 31 | const list = await chr.rest("/ip/firewall/address-list"); // structured read-back |
| 32 | // assert the entry is there → your config is grounded against real RouterOS |
| 33 | |
| 34 | await chr.remove(); // tear down |
| 35 | ``` |
| 36 | |
| 37 | `exec()` runs a CLI command (config writes, scripts) and returns `{ output, via }`; |
| 38 | `rest()` does a REST call and returns parsed JSON. Worked, runnable version: |
| 39 | [`examples/grounding/`](https://github.com/tikoci/quickchr/tree/main/examples/grounding). |
| 40 | Minimal boot-and-read smoke test: |
| 41 | [`examples/quickstart/`](https://github.com/tikoci/quickchr/tree/main/examples/quickstart). |
| 42 | All examples are runnable `bun run` scripts (`grounding/` is the one `bun:test`); the |
| 43 | full set + coverage map is in |
| 44 | [`examples/COVERAGE.md`](https://github.com/tikoci/quickchr/tree/main/examples/COVERAGE.md). |
| 45 | |
| 46 | > **Tip — re-run safety.** Give each run a unique machine name and assert on |
| 47 | > values carrying a per-run nonce, so a stale machine from an interrupted run can't |
| 48 | > make a later run pass falsely. |
| 49 | |
| 50 | ## Key entry points |
| 51 | |
| 52 | Pointers, not duplicated signatures — the authoritative, versioned reference is the |
| 53 | quickchr [`MANUAL.md`](https://github.com/tikoci/quickchr/blob/main/MANUAL.md) and |
| 54 | the JSDoc in |
| 55 | [`src/lib/types.ts`](https://github.com/tikoci/quickchr/blob/main/src/lib/types.ts). |
| 56 | See also [`references/quickchr-api.md`](./references/quickchr-api.md) in this skill. |
| 57 | |
| 58 | | Need | Surface | |
| 59 | |---|---| |
| 60 | | Boot / create a machine | `QuickCHR.start(opts)` → REST-ready `ChrInstance` | |
| 61 | | Pick RouterOS | `channel` (`stable`/`long-term`/`testing`/`development`) **or** `version` (`"7.23.1"`) | |
| 62 | | Architecture | `arch:` — `"x86"` or `"arm64"` | |
| 63 | | Managed login vs open admin | `secureLogin: true` (managed user, real password) / `false` | |
| 64 | | Run a CLI command | `instance.exec(cmd, opts?)` | |
| 65 | | REST call | `instance.rest(path, init?)` | |
| 66 | | Move files | `instance.upload(local, remote?)` / `instance.download(remote, local)` | |
| 67 | | Add a package | `instance.installPackage(name)` (downloads + reboots; returns installed names) | |
| 68 | | Custom port-forwards | `extraPorts` / CLI `--forward` (see Networking) | |
| 69 | | Extra NICs | `networks` / CLI `--add-network` (see Networking) | |
| 70 | | Connection surface for a child process | `instance.subprocessEnv()` / `instance.descriptor()` | |
| 71 | | Snapshots | `instance.snapshot(...)` | |
| 72 | | Tear down | `instance.remove()` / `instance.stop()` / `instance.destroy()` | |
| 73 | |
| 74 | The same two knobs exist on the CLI and the library: |
| 75 | |
| 76 | | CLI | Library (`StartOptions`) | |
| 77 | |---|---| |
| 78 | | `--forward <spec>` (repeatable) | `extraPorts: PortMapping[]` | |
| 79 | | `--add-network <spec>` (repeatable) | `networks: NetworkSpecifier[]` | |
| 80 | |
| 81 | CLI without installing: `bunx @tikoci/quickchr <cmd>` (e.g. `add`, `start`, `exec`, |
| 82 | `list`, `inspect`, `env`, `networks`, `logs`). Library dependency patterns (npm / |
| 83 | `file:` / `bun link`): |
| 84 | [`examples/README.md`](https://github.com/tikoci/quickchr/blob/main/examples/README.md). |
| 85 | |
| 86 | ## Ne |