Skip to content
Back to skills

Routeros Syntax Inspection

ASecurity

Inspecting and validating RouterOS command/script syntax against a live device via /console/inspect (highlight, completion, syntax, child) and :parse IL. Use when: validating RouterOS commands before execution, explaining or linting RouterOS scripts, building syntax-aware tooling (LSP servers, validators, agent explain/check commands), interpreting highlight token streams or :parse intermediate language, discovering enum values or argument schemas, or when the user mentions console/inspect, h...

  • 71 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added August 31, 2026
ai-agentsnodeexpressgitapi

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned September 22, 2026

npx -y skills add tikoci/routeros-skills --skill routeros-syntax-inspection --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Routeros Syntax Inspection?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Routeros Syntax Inspection
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tikoci-routeros-syntax-inspection/badge)](https://www.skillsdirectory.com/skills/tikoci-routeros-syntax-inspection)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: routeros-syntax-inspection
description: "Inspecting and validating RouterOS command/script syntax against a live device via /console/inspect (highlight, completion, syntax, child) and :parse IL. Use when: validating RouterOS commands before execution, explaining or linting RouterOS scripts, building syntax-aware tooling (LSP servers, validators, agent explain/check commands), interpreting highlight token streams or :parse intermediate language, discovering enum values or argument schemas, or when the user mentions console/inspect, highlight tokens, parseIL, or RouterOS script validation."
---

# RouterOS Syntax Inspection

## Overview

RouterOS exposes its **own parser** over the REST API: `/console/inspect`
classifies every byte of console input (`highlight`), proposes continuations
(`completion`), returns structured help (`syntax`), and enumerates the command
tree (`child`); the `:parse` scripting command returns the intermediate
language (IL) the engine actually executes. Together these are the ground
truth for "is this valid RouterOS?" — version-exact, package-exact, and even
runtime-state-exact, which no static grammar can be.

This skill is a **probe-selection and wire-format guide**: which surface
answers which question, how to read each response, and which claims the
responses do and do not support. It is grounded in full-corpus captures
(913 scripts × multiple RouterOS versions) published in
[tikoci/lsp-routeros-ts](https://github.com/tikoci/lsp-routeros-ts) — the
`docs/` references there carry the full evidence [^1].

**"Parse RouterOS" is not one operation.** Pick the probe for the question:

| Question | Probe | What it cannot establish |
|---|---|---|
| Which span is a command, argument, variable, comment, live-state marker? | `request=highlight` | Nested structure; value validity; anything after the first hard error |
| Is the script structurally valid; what blocks/expressions result? | `:parse` | Source ranges; partial IL on error; path/argument split without schema data |
| What is valid at this cursor position? Enum values? | `request=completion` | Requiredness; exhaustiveness of candidate lists; runtime acceptance |
| What paths, commands, arguments exist on this device? | `request=child` + `request=syntax` | Enum values (those come from `completion`); required arguments |
| Which arguments are required? | Execute-error probe (`add` with no args) | Conditional requirements past the first discriminator |

Details per surface: [references/highlight.md](references/highlight.md),
[references/parseil.md](references/parseil.md),
[references/command-schema.md](references/command-schema.md),
[references/validation.md](references/validation.md).

For crawling the full command hierarchy (`child` traversal, schema/RAML/OpenAPI
generation), see the **`routeros-command-tree`** skill — this skill covers the
*syntax/validity* surfaces of the same `/console/inspect` endpoint.

## Request shape

REST (basic auth, any RouterOS 7.x):

```text
POST /rest/console/inspect
{"request": "highlight" | "completion" | "syntax" | "child",
 "input": "<console input>",     // optional
 "path":  "ip,address,add"}      // optional comma-joined menu tokens
```

Native API — the same four modes as `=request=` / `=path=` words:

```text
/console/inspect
  =request=child
  =path=ip,address
```

**`path` takes comma-joined menu tokens, never a slash command.** Only the
comma form walks the menu: `system,license` returns that menu's nodes, while
`system/license` and `/system/license` return nothing on both transports, and
a JSON array body (`{"path":["system","license"]}`) silently returns the
**root** listing — a wrong answer that looks like a successful one. Measured
on 7.23.7; the comma form was independently confirmed on 7.23.1 [^5].

Every successful response is a JSON array of flat all-string objects (REST) or
one `!re` sentence per item (native). `highlight`, `completion` and `syntax`
rows carry a `type` field naming the request type; `request=child` instead
spends `type` on the row's role (`self`/`child`) and reports the node class in
`node-type`. Beyond that, the four response shapes share nothing — treat them
as four APIs behind one endpoint.

## Version baseline and safety

- **Baseline: RouterOS 7.20.8** — a long-term-channel release, used here as the
  recommended floor: the parseIL and crash-path behavior below was captured on
  it [^1][^3]. REST itself exists since 7.1beta4 (HTTPS-only at first [^2]);
  behavior below 7.20.8 is best-effort (7.9.2 was measured but harsher — see
  [references/highlight.md](references/highlight.md)), and RouterOS v6 has no
  REST API at all.
- **Always set a per-request timeout** (a few seconds). Old versions can hang
  the whole REST server on specific inspect calls; a hung server also makes
  *subsequent* unrelated probes appear broken.
- **Known hazards** (all measured, see [^1] and [^3]):

| Hazard | Versions | Rule |
|---|---|---|
| `request=syntax`/`completion` at bare path `do` deadlocks the REST server | ≤ 7.20.8 (fixed by 7.21.4) [^3] | Skip scripting-keyword paths (`where`, `do`, `else`, `rule`, `command`, `on-error`) on old/unknown versions; it is a conservative skip policy, not a timeless six-path crash rule |
| `request=syntax` with `input`, or command-level `syntax`, stalls ~60 s | observed on 7.9.2 | Query `syntax` by `path` only; feature-detect command-level lookups with a short timeout |
| `input` beyond 32,767 bytes rejected | all | Route oversized input to `:parse` (no cap) or reject it — never highlight a truncated copy and present it as validating the whole script |
| Highlight latency cliff near 28 KB | observed 7.23.x | Prefer a `:parse` pre-check for big scripts (no such cliff, no 32 KB cap) |

- **Distinguish `[]`, timeout, and transport failure.** An empty array is a
  real answer (nonexistent path); a timeout is not. Conflating them corrupts
  any cached conclusion.

## Reading results — rules that prevent wrong claims

These are the measured behaviors that most often get summarized wrongly:

1. **Offsets and tokens are byte-based.** RouterOS strings are single-byte
   data — the console has no Unicode awareness. Highlight emits exactly one
   token per input **byte**, and completion `offset` counts bytes as received
   on the wire (UTF-8 over REST, so non-ASCII characters occupy 2+ bytes and
   desynchronize byte offsets from UTF-16/JS string indexes). ASCII-normalize
   input first — replacing each char > 127 with one ASCII byte (`?`) keeps
   editor character positions aligned to RouterOS byte positions.
2. **One hard error, then silence.** Both highlight and `:parse` stop at the
   first hard error. Highlight marks exactly one `error` byte and leaves the
   rest unclassified (`none`); `:parse` returns a message with line/column
   and **no partial IL**. Neither gives multi-error diagnostics in one call.
   Soft markers (`obj-*`, `variable-undefined`, `syntax-obsolete`) do *not*
   stop classification.
3. **`none` means unclassified, not "valid literal."** Highlight accepts an
   obviously bad IP as `none`. Value validation is a different layer.
4. **`obj-inactive` / `obj-disabled` / `obj-dynamic` are live-state
   classifications, not grammar errors.** A disabled service or dynamic route
   table is a perfectly valid reference. Diagnostic severity is the
   consumer's policy decision — do not hard-code these as "invalid syntax."
5. **An undeclared `$name` is usually not an error.** It classifies as
   `variable-parameter` (it may be supplied at call time). The "probably a
   typo" signal is `variable-undefined` — a bare unresolvable identifier in
   expression position.
6. **Completion candidates are observed suggestions, not proven-closed
   enums.** Preserve "observed candidates" provenance unless independent
   evidence proves closure.
7. **Results are stateful.** Token classes and candidates depend on the
   RouterOS version, installed packages, and current object flags. Record
   version + package manifest with any captured result; a snapshot from one
   router is only approximately valid for another.

## Validating a command via completion

The grounded mechanics of "check before you run" (full detail:
[references/command-schema.md](references/command-schema.md)):

- Probe with the cursor **immediately after the word under test** — before
  `=`, whitespace, or the next token. Completion verdicts are cursor-local:
  advancing past an invalid word can hide its sentinel.
- Sentinel rows (`preference:"-20"`, empty `completion`,
  `text:"unknown command"`/`"unknown parameter"`) classify **the word at
  their `offset`** — and also appear *prospectively* at the end of valid
  input, so presence alone is not a verdict. Decision rule (7.21+):
  sentinel with no completing candidate → unknown name; sentinel plus
  candidates at the same offset → ambiguous prefix; candidates only → valid
  partial; a nonexistent *path* returns `[]` outright.
- Feature-detect on old versions: 7.9.2 emits the unknown-*command* sentinel
  but returns bare `[]` for an unknown typed *argument*.
- **Passing inspect validation is necessary, not sufficient.** There is a
  measured inspect-vs-runtime gap: `/console/inspect` accepts forms the
  device rejects at execution (e.g. `blackhole=yes` on a route, where the
  runtime wants the bare `blackhole` flag) [^4]. Only execution on an
  appropriate target proves runtime acceptance.

## Minimum pipeline for a syntax "explain"

1. **Segment** input statically (find command boundaries; preserve offsets).
2. **highlight** the ASCII-normalized input → lexical spans + first error.
3. **`:parse`** only when structure or an error message is needed → nested IL
   or line/column message. Align its error with highlight's error byte.
4. **`child`/`syntax`/`completion`** (or a same-version schema snapshot) →
   split IL's fused path/argument forms, enumerate arguments, fetch enums.
5. **Enrich** with docs/changelog prose — but the live device wins for what
   its inspect surface exposes; only execution proves runtime acceptance.

Steps 1–2 suffice for a lightweight explain; block/scope analysis needs 3;
rich command help needs 4–5. Execution probes (required-args discovery,
`/rest/execute`) mutate state — run them only on explicit request against an
appropriate target.

Whatever the depth, keep provenance with every derived fact: source probe,
RouterOS version + packages, path context, whether the claim is a direct
response or derived, normalization applied, truncation, and outcome
(`ok` / `empty` / `timeout` / `transport-error`).

## References

- [references/highlight.md](references/highlight.md) — per-byte token stream:
  vocabulary, error model, statefulness, drift.
- [references/parseil.md](references/parseil.md) — `:parse` IL: readout
  recipe, grammar, canonicalizations, error behavior.
- [references/command-schema.md](references/command-schema.md) —
  `child`/`syntax`/`completion` response shapes, enum discovery, sentinels.
- [references/validation.md](references/validation.md) — required-argument
  probing and layering live vs static evidence.

[^1]: Full format references with capture artifacts:
    [`highlight-format.md`](https://github.com/tikoci/lsp-routeros-ts/blob/main/docs/highlight-format.md),
    [`parseil-format.md`](https://github.com/tikoci/lsp-routeros-ts/blob/main/docs/parseil-format.md),
    [`inspect-shapes.md`](https://github.com/tikoci/lsp-routeros-ts/blob/main/docs/inspect-shapes.md)
    in tikoci/lsp-routeros-ts — 913-script corpus swept on 7.9.2/7.23.2/7.24rc2
    (highlight, inspect shapes) and 7.20.8/7.22.1/7.23rc1 (parseIL).
[^2]: MikroTik REST API introduction in 7.1beta4:
    <https://help.mikrotik.com/docs/spaces/ROS/pages/47579162/REST+API>.
[^3]: MikroTik support case SUP-127641; per-version probe data in
    [tikoci/restraml](https://github.com/tikoci/restraml) (`deep-inspect.ts`
    `CRASH_PATHS` notes and `docs/<version>/deep-inspect.json`
    `crashPathsCrashed`): bare `do` hangs `syntax`/`completion` on 7.20.8 at
    both 128 MB and 512 MB RAM; all six paths return instantly on 7.21.4+.
[^4]: [tikoci/bench-routeros-tools](https://github.com/tikoci/bench-routeros-tools)
    `REPORT.md` — the `blackhole=yes` inspect-vs-runtime case.
[^5]: [tikoci/centrs](https://github.com/tikoci/centrs)
    `commands/api/AGENTS.md` — CHR 7.23.1 grounding spikes for the comma `path`
    form and for `/execute` `as-string` on both transports.

Files in this skill

  • SKILL.md11.3 KB
  • references/command-schema.md5.5 KB
  • references/highlight.md5.5 KB
  • references/parseil.md4.7 KB
  • references/validation.md2.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.