{"id":50594951,"url":"https://github.com/tikoci/quickchr","last_synced_at":"2026-06-05T13:30:47.635Z","repository":{"id":352731452,"uuid":"1216363690","full_name":"tikoci/quickchr","owner":"tikoci","description":"`quickchr` - Fastest path to MikroTik RouterOS CHR instance for testing and scripts","archived":false,"fork":false,"pushed_at":"2026-04-20T22:41:15.000Z","size":1476,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-20T23:26:24.175Z","etag":null,"topics":["ai","automation","bun","chr","claude-ai","cli","copilot-enabled","mikrotik","routeros","testing-library","testing-tools","tikoci","wizard"],"latest_commit_sha":null,"homepage":"https://tikoci.github.io/p/quickchr","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tikoci.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-20T20:39:49.000Z","updated_at":"2026-04-20T22:48:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tikoci/quickchr","commit_stats":null,"previous_names":["tikoci/quickchr"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/tikoci/quickchr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tikoci%2Fquickchr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tikoci%2Fquickchr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tikoci%2Fquickchr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tikoci%2Fquickchr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tikoci","download_url":"https://codeload.github.com/tikoci/quickchr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tikoci%2Fquickchr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33944671,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-05T02:00:06.157Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","automation","bun","chr","claude-ai","cli","copilot-enabled","mikrotik","routeros","testing-library","testing-tools","tikoci","wizard"],"created_at":"2026-06-05T13:30:47.568Z","updated_at":"2026-06-05T13:30:47.629Z","avatar_url":"https://github.com/tikoci.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# quickchr\n\n\u003e **Experimental** — quickchr is under active development. Most testing has been on\n\u003e macOS (Apple Silicon + Intel), with CI on Linux (x86_64 + aarch64). Windows support\n\u003e is early-stage: unit tests pass on `windows-latest` CI, but integration tests\n\u003e (running a real CHR via QEMU for Windows) are not yet automated. Expect rough edges\n\u003e on Windows — bug reports welcome.\n\nCLI and library to download, launch, and manage MikroTik CHR virtual machines via QEMU.\n\n## Quick Start\n\n### Prerequisites\n\n- [Bun](https://bun.sh) runtime\n- [QEMU](https://www.qemu.org) with `qemu-system-x86_64` and/or `qemu-system-aarch64`\n- `qemu-img` for disk resize and extra-disk features (`--boot-size`, `--add-disk`, `quickchr disk`)\n- UEFI firmware (edk2) for arm64 CHR\n\nInstall QEMU:\n\n```bash\n# macOS\nbrew install qemu\n\n# Ubuntu/Debian\nsudo apt install qemu-system-x86 qemu-system-arm qemu-efi-aarch64 qemu-utils\n\n# Fedora/RHEL\nsudo dnf install qemu-kvm qemu-system-aarch64 edk2-aarch64 qemu-img\n\n# Arch\nsudo pacman -S qemu-full\n```\n\n```powershell\n# Windows — install QEMU (qemu-img is included)\nwinget install SoftwareFreedomConservancy.QEMU\n\n# Install Bun (PowerShell — matches bun.sh official install docs)\npowershell -c \"irm bun.sh/install.ps1 | iex\"\n# Alternative: winget install Oven-sh.Bun\n```\n\n### Install\n\nCLI:\n\n```bash\nbun install -g @tikoci/quickchr\nquickchr doctor\n```\n\nLibrary:\n\n```bash\nbun add @tikoci/quickchr\n```\n\n### CLI Usage\n\nThe easiest way to start is the interactive wizard — it walks through\nevery option and starts the CHR for you:\n\n```bash\nquickchr setup\n```\n\n![quickchr setup wizard walkthrough](./docs/images/wizard-demo.gif)\n\nOr run `quickchr` with no arguments on a TTY to get the same wizard\nautomatically. See [MANUAL.md §3 setup](./MANUAL.md#setup) for a\nstep-by-step breakdown of every wizard prompt.\n\nAll wizard options are also available as flags for scripting:\n\n```bash\n# Create a machine without starting it\nquickchr add --name my-chr --channel stable --arch arm64\n\n# Create with a resized boot disk and extra blank disks\nquickchr add --name lab --boot-size 1G --add-disk 512M --add-disk 2G\n\n# Start an existing machine\nquickchr start my-chr\n\n# Create and start in one step\nquickchr start --name throwaway --version 7.22.1 --boot-size 2G\n\n# List instances (table view)\nquickchr list\n\n# Detailed status for one instance\nquickchr status my-chr\n\n# Stable connection descriptor/env for a running instance\nquickchr inspect my-chr\nquickchr env my-chr\nquickchr env my-chr --json\n\n# Stop an instance\nquickchr stop my-chr\n\n# Stop all instances\nquickchr stop --all\n\n# Run a RouterOS CLI command on a running instance\nquickchr exec my-chr /system/resource/print\nquickchr exec my-chr \":put [/system/routerboard/get serial-number]\"\n\n# Attach to serial console of a running instance (exit: Ctrl-A X)\nquickchr console my-chr\n\n# Tail QEMU log\nquickchr logs my-chr\nquickchr logs my-chr --follow\n\n# Query live machine config (license, device-mode, admin users)\nquickchr get my-chr\nquickchr get my-chr license\nquickchr get my-chr device-mode --json\n\n# Manage snapshots (requires qcow2 boot disk)\nquickchr snapshot my-chr list\nquickchr snapshot my-chr save before-upgrade\nquickchr snapshot my-chr load before-upgrade\nquickchr snapshot my-chr delete before-upgrade\n\n# Apply or renew a trial license\nquickchr license my-chr\n\n# Network discovery and virtual socket management\nquickchr networks\nquickchr networks sockets\n\n# Set up shell completions (bash/zsh/fish)\nquickchr completions\n\n# Reset disk to fresh image\nquickchr clean my-chr\n\n# Inspect disk layout\nquickchr disk lab\n\n# Remove instance entirely\nquickchr remove my-chr\n\n# Check prerequisites\nquickchr doctor\n```\n\n### Create / Start Options\n\n| Flag | Description | Default |\n|------|-------------|---------|\n| `--version \u003cver\u003e` | RouterOS version (e.g., 7.22.1) | Latest stable |\n| `--channel \u003cch\u003e` | stable, long-term, testing, development | stable |\n| `--arch \u003carch\u003e` | arm64, x86, or auto | Host native |\n| `--name \u003cname\u003e` | Instance name | Auto-generated |\n| `--cpu \u003cn\u003e` | vCPU count | 1 |\n| `--mem \u003cmb\u003e` | Memory in MB | 512 |\n| `--boot-disk-format \u003cf\u003e` | Boot disk format: qcow2\\|raw | qcow2 |\n| `--boot-size \u003csize\u003e` | Resize boot disk (e.g., 512M, 2G). Requires `qemu-img`. | |\n| `--add-disk \u003csize\u003e` | Attach an extra blank qcow2 disk. Repeatable. Requires `qemu-img`. | |\n| `--forward \u003cspec\u003e` | Add or pin a QEMU SLiRP hostfwd mapping. Repeatable. | |\n| `--bg` / `--background` | Run in background (default) | true |\n| `--fg` / `--foreground` | Run in foreground — serial console on stdio | |\n| `--add-package \u003cpkg\u003e` | Extra package to install (repeatable) | |\n| `--install-all-packages` | Install all packages from `all_packages.zip` | |\n| `--add-user \u003cuser:pass\u003e` | Create a user after boot | |\n| `--disable-admin` | Disable the default admin account | |\n| `--no-secure-login` | Keep admin with no password (skip managed account creation) | |\n| `--add-network \u003cspec\u003e` | Add a network NIC (repeatable). Specs: `user`, `shared`, `bridged:\u003ciface\u003e`, `socket::\u003cname\u003e`, `tap:\u003ciface\u003e`. Default: single user NIC. | |\n| `--no-network` | Start with no NICs (headless) | |\n| `--no-winbox` | Exclude WinBox port mapping | |\n| `--no-api-ssl` | Exclude API-SSL port mapping | |\n| `--license-level \u003cl\u003e` | Apply trial license: p1, p10, unlimited | |\n| `--license-account \u003ca\u003e` | MikroTik account email | env `MIKROTIK_WEB_ACCOUNT` |\n| `--license-password \u003cp\u003e` | MikroTik account password | env `MIKROTIK_WEB_PASSWORD` |\n| `--device-mode \u003cm\u003e` | Configure device-mode: rose\\|advanced\\|basic\\|home\\|auto\\|skip | |\n| `--device-mode-enable \u003cf\u003e` | Set one or more device-mode flags to yes | |\n| `--device-mode-disable \u003cf\u003e` | Set one or more device-mode flags to no | |\n| `--port-base \u003cport\u003e` | Starting port number | Auto (9100+) |\n| `--timeout-extra \u003cs\u003e` | Add extra seconds to the auto-computed boot timeout | |\n| `--dry-run` | Print what would run without executing | |\n\n### RouterOS Provisioning Support Policy\n\nquickchr separates **boot-only** machine management from **post-boot provisioning**.\n\n- **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.\n- **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.\n- 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.\n- If you plan to provision, prefer **`--channel long-term`** or an explicit version **`\u003e= 7.20.8`**.\n\n| Feature | Minimum RouterOS | Notes |\n|---------|------------------|-------|\n| Boot / start / stop | Any RouterOS 7.x | Boot-only path; no post-boot RouterOS mutations |\n| Disk resize / extra disks / disk inspection | Any RouterOS 7.x | Requires host `qemu-img`; QEMU-local only |\n| Network attachment / port mappings | Any RouterOS 7.x | QEMU networking setup; not provisioning |\n| Managed login / custom user / disable-admin | 7.20.8+ | Post-boot provisioning |\n| Package install / install-all-packages | 7.20.8+ | Post-boot provisioning |\n| License apply / renew | 7.20.8+ | Post-boot provisioning |\n| Device-mode changes | 7.20.8+ | Post-boot provisioning; intentionally unsupported below the baseline |\n\n### Background vs Foreground Mode\n\nBy 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.\n\n```bash\n# Background (default) — returns after CHR finishes booting\nquickchr start --channel stable\n\n# Foreground — serial console attached to your terminal\nquickchr start --channel stable --fg\n```\n\nIn **foreground** mode, your terminal becomes the CHR serial console. Use these key sequences:\n\n| Key | Action |\n|-----|--------|\n| `Ctrl-A X` | Exit QEMU and return to shell |\n| `Ctrl-A C` | Toggle QEMU monitor (`quit` to force-stop) |\n| `Ctrl-A H` | List all key shortcuts |\n\n\u003e **Note:** Background QEMU processes are true OS-level orphans — `quickchr` does not use shell job control (`\u0026`). After the command returns you can close the terminal and QEMU keeps running. Use `quickchr stop \u003cname\u003e` to shut it down cleanly.\n\n### Disk Support\n\n- The CHR boot image starts as raw. Using `--boot-size` converts it to qcow2 and resizes it before first boot.\n- Extra disks from `--add-disk` are always created as blank qcow2 images.\n- `quickchr clean \u003cname\u003e` removes any resized boot disk and extra disks, then recreates them from the saved machine config.\n- `quickchr disk \u003cname\u003e` shows the stored disk layout. If `qemu-img` is installed, it also shows virtual and actual sizes.\n- `quickchr snapshot` manages qcow2 internal snapshots (requires a qcow2 boot disk).\n\n### Multi-NIC Networking\n\nBy default each CHR gets a single user-mode NIC (SLIRP). Use `--add-network` to add more NICs or replace the default:\n\n```bash\n# Two CHRs on a shared L2 segment via socket_vmnet (macOS) or bridge (Linux)\nquickchr start --name router1 --add-network user --add-network shared\nquickchr start --name router2 --add-network user --add-network shared\n\n# Named virtual socket (L2 tunnel between CHRs)\nquickchr networks sockets create lab-switch\nquickchr start --name r1 --add-network socket::lab-switch\nquickchr start --name r2 --add-network socket::lab-switch\n\n# Bridge to a physical interface\nquickchr start --name gw --add-network user --add-network bridged:en0\n```\n\n### Port Layout\n\nEach instance gets a block of 10 ports. With the default base of 9100, the first instance maps:\n\n| Offset | Service | Default port |\n|--------|---------|-------------|\n| +0 | HTTP / REST / WebFig | 9100 |\n| +1 | HTTPS | 9101 |\n| +2 | SSH | 9102 |\n| +3 | RouterOS API | 9103 |\n| +4 | RouterOS API-SSL | 9104 |\n| +5 | WinBox | 9105 |\n| +6–+9 | Reserved (spare) | 9106–9109 |\n\nThe second instance gets 9110–9119, and so on.\n\n### Custom Port Forwards and Fixed WinBox\n\nUse `--forward \u003cspec\u003e` on `add` or create-and-start `start` commands to add\nextra QEMU SLiRP `hostfwd` mappings. The shorthand uses the built-in service\nregistry when it knows the guest port:\n\n```bash\nquickchr add lab --forward smb                  # auto host port → guest 445/tcp\nquickchr add dude-lab --forward winbox:8291     # host 8291 → guest WinBox 8291/tcp\nquickchr add app-lab --forward myapp:9200:7777/udp\n```\n\nReusing a built-in service name such as `winbox` pins/replaces that service's\nhost port for the machine. Existing machines keep the mapping stored in\n`machine.json`; recreate the machine to change fixed service ports cleanly.\n\n### Machine Descriptors and Subprocess Environments\n\n`quickchr inspect \u003cname\u003e [--json]` emits a stable JSON descriptor for a\n**running** machine: status, ports, URLs, auth, env vars, and the machine\ndirectory. `--json` is accepted for parity; inspect output is always JSON.\n\n`quickchr env \u003cname\u003e [--json]` prints the same subprocess environment as\n`ChrInstance.subprocessEnv()`: shell `KEY=value` lines by default, or a JSON\nmap with `--json`.\n\n\u003e **Credential caveat:** descriptor/env output includes connection secrets\n\u003e (`auth.password`, `auth.basic`, `auth.header`, `QUICKCHR_AUTH`, `BASICAUTH`)\n\u003e so child processes can connect without reading quickchr's secret store. Treat\n\u003e it like a password: do not commit it, paste it into public issues, or leave it\n\u003e in CI logs. Stopped machines fail with `MACHINE_STOPPED`; start the machine\n\u003e before requesting a descriptor or env map.\n\n### Library Usage\n\n```typescript\nimport { QuickCHR } from \"@tikoci/quickchr\";\n\n// Start a CHR instance\nconst chr = await QuickCHR.start({\n  name: \"disk-lab\",\n  channel: \"stable\",\n  arch: \"arm64\",\n  mem: 512,\n  bootSize: \"1G\",\n  extraDisks: [\"512M\", \"2G\"],\n});\n\n// Use REST API\nconst info = await chr.rest(\"/system/resource\");\nconsole.log(info);\n\n// Run a RouterOS CLI command\nconst result = await chr.exec(\"/system/resource/print\");\nconsole.log(result);\n\n// Stop (or remove)\nawait chr.stop();\nawait chr.remove();\n\nconsole.log(chr.state.bootDiskFormat); // \"qcow2\"\nconsole.log(chr.state.extraDisks);     // [\"512M\", \"2G\"]\n```\n\n### Use in Tests\n\n```typescript\nimport { describe, test, afterAll, expect } from \"bun:test\";\nimport { QuickCHR } from \"@tikoci/quickchr\";\n\nlet chr: Awaited\u003cReturnType\u003ctypeof QuickCHR.start\u003e\u003e;\n\ntest(\"boot CHR and check version\", async () =\u003e {\n  chr = await QuickCHR.start({ channel: \"stable\" });\n\n  const resource = await chr.rest(\"/system/resource\");\n  expect(resource[\"board-name\"]).toBe(\"CHR\");\n}, 120_000);\n\nafterAll(async () =\u003e {\n  if (chr) await chr.remove();\n});\n```\n\n## Environment Variables\n\n| Variable | Description |\n|----------|-------------|\n| `MIKROTIK_WEB_ACCOUNT` | MikroTik.com account email (for license renewal) |\n| `MIKROTIK_WEB_PASSWORD` | MikroTik.com password (for license renewal) |\n| `QUICKCHR_INTEGRATION` | Set to `1` to run integration tests |\n\n## Documentation\n\n- **[MANUAL.md](./MANUAL.md)** — complete reference: every CLI command,\n  every library API, provisioning, channels, networking, storage,\n  errors. Source-checked.\n- **[DESIGN.md](./DESIGN.md)** — architecture, layers, design principles.\n- **[CONTRIBUTING.md](./CONTRIBUTING.md)** — dev setup and `bun run check`.\n- **[CHANGELOG.md](./CHANGELOG.md)** — release history.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftikoci%2Fquickchr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftikoci%2Fquickchr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftikoci%2Fquickchr/lists"}