Using AI to help configuring RouterOS and scripting

Clearly, you let it off the hook with an easy one :open_mouth:

Or the JIRA list of bugs…

Just even just showing colorized syntax in webfig/winbox to show the errors that /console/inspect “highlight” does in CLI and CLI “edit” command - so if you cut-and-paste some LLM code to /system/script, it show what was wrong. No AI or training needed to fix that at least.

Exactly. You can create training data in many different formats, like the annotated pseudo code snippets below to complement the AST. There are plenty of other ways to do it as well. The important part is to formalize those patterns and guide the model to prioritize them over other sources during training. Since LLMs are very capable of cross-references, it is pretty easy to update single patterns without having to start over every time.

{‘code’: ‘x = y + 42 ; if ( foo ) { x = 0 ; }’, ‘label’: ‘valid’}
{‘code’: ‘y == x + 1 if ( x + bar ) { foo = 123 ; }’, ‘label’: ‘invalid’}
{‘code’: ‘if ( 1 + 2 ) { bar = 0 ; }’, ‘label’: ‘valid’}

Currently it is hard to impossible - because formal syntax or grammar definitions do not exist. So LLM will deliver bull**t until forever.

Yep, they do. It’s pretty much standard practice and kind of an essential building block when constructing compilers or scripting languages. LLM coding models are trained using those formats like ANTLR/Yacc/Bison/etc or EBNF in combination with ASTs. And like I wrote, there are plenty of other ways too. Depending on the model you’re using, different strategies are used to apply these rules during training.

MikroTik could at least train their own model to understand RouterOS script language - without needing to publish any resources publicly, so the unique charm of RouterOS scripting isn’t lost when someone stumbles upon rextended’s script collection.

It would also be productive, I think, for them to publish a formal OpenAPI spec for the HTTP API. It wouldn’t be too hard to create a syntax def from that, I would think since:

Starting from RouterOS v7.1beta4, it is implemented as a JSON wrapper interface of the console API.

https://help.mikrotik.com/docs/spaces/ROS/pages/47579162/REST+API

Request for OpenAPI spec was made 4 years ago:

http://forum.mikrotik.com/t/feature-request-openapi-for-rest-api/149360/1

Third-party schema is downloadable here:
https://tikoci.github.io/restraml/#Schema+Downloads

Sorry, but in what sense, I don’t understand… :question:

As an experiment, I tried taking my JSON diff output between 7.18.2 and 7.19 (based on the RAML REST API schema at https://tikoci.github.io/restraml) , to get a more “RouterOS” style list of changed commands. [Free] ChatGPT didn’t like length, but Gemini did an okay job:

So from just one prompt, and “JSON diff” I got the below from the prompt:

"I have some JSON that reflect the difference in Mikrotik RouterOS commands between 7.18.2 and 7.19. I'd like to see the diffs represented in RouterOS CLI style"



# New commands and arguments added in RouterOS 7.19
/certificate builtin find where=
/certificate builtin get as-string= as-string-value= number= value-name=
/certificate builtin print append= as-value= brief= count-only= detail= file="string value" follow= follow-only= from= group-by= interval="00:00:00.200.." proplist= show-ids= terse= value-list= where= without-paging=
/certificate settings set builtin-trust-anchors=
/container add name="string value"
/container reset name="string value"
/container set name="string value"
/disk eject numbers=
/disk format as-value= duration= file-system= freeze-frame-interval="00:00:00.020..00:00:30" label="string value" mbr-partition-table= numbers= without-paging=
/disk btrfs filesystem reset-counters numbers=
/disk btrfs filesystem balance-start data-usage= metadata-usage= system-usage=
/disk btrfs filesystem replace-device device-to-remove-id=
/disk monitor-traffic proplist=
/dude export-db proplist=
/dude import-db proplist=
/dude vacuum-db proplist=
/file print show-hidden=
/file sync monitor proplist=
/for on-error=
/foreach on-error=
/interface bonding add lacp-mode=
/interface bonding monitor proplist=
/interface bonding reset lacp-mode=
/interface bonding set lacp-mode=
/interface bridge mdb add interface=
/interface bridge mdb reset interface=
/interface bridge mdb set interface=
/interface bridge monitor proplist=
/interface bridge msti monitor proplist=
/interface bridge port monitor proplist=
/interface bridge port mst-override monitor proplist=
/interface ethernet cable-test proplist=
/interface ethernet monitor proplist=
/interface l2tp-client monitor proplist=
/interface l2tp-ether monitor proplist=
/interface l2tp-server monitor proplist=
/interface lte esim provision proplist=
/interface lte firmware-upgrade proplist=
/interface lte monitor proplist=
/interface lte settings set link-recovery-timer=
/interface monitor-traffic proplist=
/interface ovpn-client monitor proplist=
/interface ovpn-server monitor proplist=
/interface ppp-client firmware-upgrade proplist=
/interface ppp-client info proplist=
/interface ppp-client monitor proplist=
/interface ppp-server monitor proplist=
/interface pppoe-client monitor proplist=
/interface pppoe-server monitor proplist=
/interface pptp-client monitor proplist=
/interface pptp-server monitor proplist=
/interface sstp-client monitor proplist=
/interface sstp-server monitor proplist=
/interface vpls monitor proplist=
/interface wifi add channel.reselect-time= datapath.traffic-processing=
/interface wifi add security.authentication-types="wpa-psk|wpa2-psk|wpa2-psk-sha2|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wifi channel add reselect-time=
/interface wifi channel reset reselect-time=
/interface wifi channel set reselect-time=
/interface wifi configuration add channel.reselect-time= datapath.traffic-processing=
/interface wifi configuration add security.authentication-types="wpa-psk|wpa2-psk|wpa2-psk-sha2|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wifi configuration reset channel.reselect-time= datapath.traffic-processing=
/interface wifi configuration reset security.authentication-types="wpa-psk|wpa2-psk|wpa2-psk-sha2|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wifi configuration set channel.reselect-time= datapath.traffic-processing=
/interface wifi configuration set security.authentication-types="wpa-psk|wpa2-psk|wpa2-psk-sha2|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wifi datapath add traffic-processing=
/interface wifi datapath reset traffic-processing=
/interface wifi datapath set traffic-processing=
/interface wifi monitor proplist=
/interface wifi reset channel.reselect-time= datapath.traffic-processing=
/interface wifi reset security.authentication-types="wpa-psk|wpa2-psk|wpa2-psk-sha2|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wifi security add authentication-types="wpa-psk|wpa2-psk|wpa2-psk-sha2|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,AuthenticationTypes*]"
/interface wifi security reset authentication-types="wpa-psk|wpa2-psk|wpa2-psk-sha2|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,AuthenticationTypes*]"
/interface wifi security set authentication-types="wpa-psk|wpa2-psk|wpa2-psk-sha2|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,AuthenticationTypes*]"
/interface wifi set channel.reselect-time= datapath.traffic-processing=
/interface wifi set security.authentication-types="wpa-psk|wpa2-psk|wpa2-psk-sha2|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wifi wps-client proplist=
/interface wireguard wg-import config-file= config-string="string value"
/interface wireless monitor proplist=
/interface wireless nstreme-dual monitor proplist=
/interface wireless setup-repeater proplist=
/interface wireless sniffer sniff proplist=
/interface wireless wds monitor proplist=
/interface wireless wps-client proplist=
/iot lora send bandwidth= device-id= frequency= inverted= modulation= payload="string value" power= preamble= spread-factor=
/iot lora joineui add type=
/iot lora joineui reset type=
/iot lora joineui set type=
/iot lora netid add type=
/iot lora netid reset type=
/iot lora netid set type=
/iot lora reset forward="crc-validation|dev-addr-validation|proprietary-traffic[,Forward*]"
/iot lora set forward="crc-validation|dev-addr-validation|proprietary-traffic[,Forward*]"
/iot lora traffic options set pckt-limit=
/modbus read-holding-registers proplist=
/ip dhcp-client add allow-reconfigure= check-gateway=
/ip dhcp-client reset allow-reconfigure= check-gateway=
/ip dhcp-client set allow-reconfigure= check-gateway=
/ip dhcp-relay monitor proplist=
/ip dhcp-server add use-reconfigure=
/ip dhcp-server lease send-reconfigure numbers=
/ip dhcp-server reset use-reconfigure=
/ip dhcp-server set use-reconfigure=
/ip neighbor unset numbers= value-name=
/ip proxy monitor proplist=
/ip route check proplist=
/ip traffic-flow monitor proplist=
/ipv6 dhcp-client add check-gateway= default-route-tables=
/ipv6 dhcp-client reset check-gateway= default-route-tables=
/ipv6 dhcp-client set check-gateway= default-route-tables=
/ipv6 dhcp-relay monitor proplist=
/ipv6 dhcp-server binding send-reconfigure numbers=
/log print with-extra-info=
/lora send bandwidth= device-id= frequency= inverted= modulation= payload="string value" power= preamble= spread-factor=
/lora joineui add type=
/lora joineui reset type=
/lora joineui set type=
/lora netid add type=
/lora netid reset type=
/lora netid set type=
/lora reset forward="crc-validation|dev-addr-validation|proprietary-traffic[,Forward*]"
/lora set forward="crc-validation|dev-addr-validation|proprietary-traffic[,Forward*]"
/lora traffic options set pckt-limit=
/queue monitor proplist=
/radius incoming monitor proplist=
/radius monitor proplist=
/routing bgp connection add afi="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,Afi*]" input.filter-communities= input.filter-ext-communities= input.filter-large-communities= input.filter-unknown=
/routing bgp connection reset afi="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,Afi*]" input.filter-communities= input.filter-ext-communities= input.filter-large-communities= input.filter-unknown=
/routing bgp connection set afi="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,Afi*]" input.filter-communities= input.filter-ext-communities= input.filter-large-communities= input.filter-unknown=
/routing bgp session refresh afi=
/routing bgp session resend afi=
/routing bgp template add afi="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,Afi*]" input.filter-communities= input.filter-ext-communities= input.filter-large-communities= input.filter-unknown=
/routing bgp template reset afi="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,Afi*]" input.filter-communities= input.filter-ext-communities= input.filter-large-communities= input.filter-unknown=
/routing bgp template set afi="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,Afi*]" input.filter-communities= input.filter-ext-communities= input.filter-large-communities= input.filter-unknown=
/routing settings set connected-in-chain= dynamic-in-chain=
/system gps monitor proplist=
/system package update check-for-updates proplist=
/system package update download proplist=
/system package update install proplist=
/system resource monitor proplist=
/system ups monitor proplist=
/tool bandwidth-test proplist=
/tool fetch proplist=
/tool flood-ping proplist=
/tool ping-speed proplist=
/tool sniffer set max-packet-size=
/tool speed-test proplist=
/tool traffic-generator inject-pcap proplist=
/user-manager monitor proplist=
/user-manager router monitor proplist=
/user-manager user monitor proplist=

# Commands and arguments removed in RouterOS 7.19
/certificate enable-ssl-certificate type=
/disk eject-drive numbers=
/disk format-drive as-value= duration="time interval" file-system= freeze-frame-interval="00:00:00.020..00:00:30 (time interval)" label="string value" mbr-partition-table= numbers= without-paging=
/interface amt add comment="string value" copy-from= disabled= discovery-ip="A.B.C.D (IP address)" dont-fragment= gateway-port= interface= local-ip="A.B.C.D (IP address)" mac-address="AB[:|-|.]CD[:|-|.]EF[:|-|.]GH[:|-|.]IJ[:|-|.]KL (MAC address)" max-tunnels= mode= name="string value" relay-port=
/interface amt comment comment="string value" numbers=
/interface amt disable numbers=
/interface amt edit number= value-name=
/interface amt enable numbers=
/interface amt export compact= file="string value" hide-sensitive= show-sensitive= terse= verbose= where=
/interface amt find where=
/interface amt get as-string= as-string-value= number= value-name=
/interface amt print append= as-value= count-only= detail= file="string value" follow= follow-only= from= group-by= interval="00:00:00.200.." proplist= show-ids= terse= value-list= where= without-paging=
/interface amt remove numbers=
/interface amt reset comment="string value" disabled= discovery-ip="A.B.C.D (IP address)" dont-fragment= gateway-port= interface= local-ip="A.B.C.D (IP address)" mac-address="AB[:|-|.]CD[:|-|.]EF[:|-|.]GH[:|-|.]IJ[:|-|.]KL (MAC address)" max-tunnels= mode= name="string value" numbers= relay-port=
/interface amt set comment="string value" disabled= discovery-ip="A.B.C.D (IP address)" dont-fragment= gateway-port= interface= local-ip="A.B.C.D (IP address)" mac-address="AB[:|-|.]CD[:|-|.]EF[:|-|.]GH[:|-|.]IJ[:|-|.]KL (MAC address)" max-tunnels= mode= name="string value" numbers= relay-port=
/interface bridge mdb add ports=
/interface bridge mdb reset ports=
/interface bridge mdb set ports=
/interface eoipv6 add remote-address="see documentation"
/interface eoipv6 reset remote-address="see documentation"
/interface eoipv6 set remote-address="see documentation"
/interface gre6 add remote-address="see documentation"
/interface gre6 reset remote-address="see documentation"
/interface gre6 set remote-address="see documentation"
/interface ipipv6 add remote-address="see documentation"
/interface ipipv6 reset remote-address="see documentation"
/interface ipipv6 set remote-address="see documentation"
/interface wifi add security.authentication-types="wpa-psk|wpa2-psk|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wifi cap set caps-man-addresses="see documentation"
/interface wifi configuration add security.authentication-types="wpa-psk|wpa2-psk|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wifi configuration reset security.authentication-types="wpa-psk|wpa2-psk|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wifi configuration set security.authentication-types="wpa-psk|wpa2-psk|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wifi reset security.authentication-types="wpa-psk|wpa2-psk|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wifi security add authentication-types="wpa-psk|wpa2-psk|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,AuthenticationTypes*]"
/interface wifi security reset authentication-types="wpa-psk|wpa2-psk|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,AuthenticationTypes*]"
/interface wifi security set authentication-types="wpa-psk|wpa2-psk|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,AuthenticationTypes*]"
/interface wifi set security.authentication-types="wpa-psk|wpa2-psk|wpa-eap|wpa2-eap|wpa3-psk|owe|wpa3-eap|wpa3-eap-192[,SecurityAuthenticationTypes*]"
/interface wireguard wg-import file=
/iot lora unset numbers= value-name=
/iot lora reset src-address="A.B.C.D (IP address)"
/iot lora reset forward="crc-validtaion|dev-addr-validtaion|proprietary-traffic[,Forward*]"
/iot lora set src-address="A.B.C.D (IP address)"
/iot lora set forward="crc-validtaion|dev-addr-validtaion|proprietary-traffic[,Forward*]"
/ipv6 route add gateway="see documentation"
/ipv6 route reset gateway="see documentation"
/ipv6 route set gateway="see documentation"
/lora unset numbers= value-name=
/lora reset src-address="A.B.C.D (IP address)"
/lora reset forward="crc-validtaion|dev-addr-validtaion|proprietary-traffic[,Forward*]"
/lora set src-address="A.B.C.D (IP address)"
/lora set forward="crc-validtaion|dev-addr-validtaion|proprietary-traffic[,Forward*]"
/mpls ldp neighbor add transport="see documentation"
/mpls ldp neighbor reset transport="see documentation"
/mpls ldp neighbor set transport="see documentation"
/mpls ldp remote-mapping add nexthop="see documentation"
/mpls ldp remote-mapping reset nexthop="see documentation"
/mpls ldp remote-mapping set nexthop="see documentation"
/routing bgp connection add address-families="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,AddressFamilies*]" input.accept-unknown=
/routing bgp connection add local.address="see documentation"
/routing bgp connection add remote.address="see documentation"
/routing bgp connection reset address-families="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,AddressFamilies*]" input.accept-unknown=
/routing bgp connection reset local.address="see documentation"
/routing bgp connection reset remote.address="see documentation"
/routing bgp connection set address-families="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,AddressFamilies*]" input.accept-unknown=
/routing bgp connection set local.address="see documentation"
/routing bgp connection set remote.address="see documentation"
/routing bgp session refresh address-family=
/routing bgp session resend address-family=
/routing bgp template add address-families="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,AddressFamilies*]" input.accept-unknown=
/routing bgp template reset address-families="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,AddressFamilies*]" input.accept-unknown=
/routing bgp template set address-families="ip|ipv6|l2vpn|l2vpn-cisco|vpnv4|vpnv6[,AddressFamilies*]" input.accept-unknown=
/routing fantasy add dst-address="see documentation" gateway="see documentation"
/routing fantasy reset dst-address="see documentation" gateway="see documentation"
/routing fantasy set dst-address="see documentation" gateway="see documentation"
/routing ospf static-neighbor add address="see documentation"
/routing ospf static-neighbor reset address="see documentation"
/routing ospf static-neighbor set address="see documentation"
/routing pimsm bsr candidate add address="see documentation"
/routing pimsm bsr candidate reset address="see documentation"
/routing pimsm bsr candidate set address="see documentation"
/routing pimsm bsr rp-candidate add address="see documentation"
/routing pimsm bsr rp-candidate reset address="see documentation"
/routing pimsm bsr rp-candidate set address="see documentation"
/routing rip static-neighbor add address="see documentation"
/routing rip static-neighbor reset address="see documentation"
/routing rip static-neighbor set address="see documentation"
/tool fetch address="see documentation"
/tool netwatch add host="see documentation"
/tool netwatch reset host="see documentation"
/tool netwatch set host="see documentation"

With same lesson… it these kinda transformation tasks that LLMs seem to do better at then writing RouterOS config/script. Now if MikroTik

/console/inspect

had a full types and “description” for ALL variables (and default value), the LLM would have been able to provide the defaults after = for new/removed attributes

The Dude is dead! The support site with the chatbot says:

Chatbot deactivated
This chatbot has been deactivated.

I’m not sure it will be missed. But it does popup pretty big when going to the help pages.

Somebody was too chatty with it, it went over the limits.

It wasn’t me. :slight_smile:
I’m not sure it’s actually all that useful FWIW & does clutter the help.mikrotik.com page since it shows opened hiding the link to support cases.

I’ve been playing around with short scripts to automate basic monitoring and backups, and ChatGPT helped me tweak some RouterOS syntax. Still needs a human check, but it's a decent starting point. For anyone curious about how far AI can really go with tasks like this, https://crowdo.net/blog/ai-search-where-are-we-what-can-we-do-about-it gives some good context on where things stand with AI and what we can actually trust it to do.

Laughing my hole out at the irony of this statement..........
Try our own AI bot. It’s not very good at scripting, because RouterOS is not as popular as generic programming languages, but it’s still pretty good if you can do your own sanity checks, and if you are able to formulate the problem in full sentences with a lot of details:

Ding ding, winner winner Turkey Dinner. Sounds like sandbox proposal for new poster to delineate their requirements in sufficient detail............. If its good enough for AI...... Straight from the bearded one with flowing latvian robes.

I've been using Grok extensively for writing Powershell scripts. It's scaringly good. Will give it a go with RouterOS scripts soon.

Can you provide some more info on what you trained The Dude chatbot on support page? Was it just help docs, or other things?

My question here is what use case do folk expect or want from a LLM connected to RouterOS?

For example, is it configuration generation, help to understand a particular syntax/configuration, orchestrating configuration, log analysis, etc... Ideally where someone things chat interface be better than using traditional tools.

Reason I ask is I'd like to expand my VSCode LSP+notebook to provide CoPilot more context internally.

There are a few different ways to help CoPilot perform better within my TikBook VSCode extension... but IDK what things actually be useful. But I do know CoPilot perform much better when providing more contextual data to CoPilot – like the export configuration and various "print"/status things from a connected RouterOS & interactively providing the help doc also help.

So kinda asking for input on what tasks folks might even want to use an LLM with as providing too much context data to CoPilot/LLM uses more tokens (and likely reduces accuracy if given context windows) & also guide agent prompting to CoPilot from the extension.

Hi everyone, You can find AI integration to Mikrotik at here, this is an open source project, integrating MCP and Mikrotik APIs.

MCP is a standard way of the integration between LLMs and any other tools or frameworks, I would love to know your feedback of how we can Improve the mikroik-mcp to be useful for the community!

CC: @robmaltsystems, @normis, @optio, @jaclaz, @mozerd, @Larsa, @Amm0, @rextended

Hi Jeff, how to help, not AI trained, so what is the process................

We'll see what happens...

Nice work. Few thoughts.

You might consider streamlining the packaging. Perhaps, you can compile the python into an EXE to make it more readily consumable. i.e. I think you'll lose @anav at docker and/or python+venv step.

In terms of the operations offered by your MCP, I'd be curious at your results so far? My high-level thought is an LLM isn't too bad at syntax... so mapping RouterOS's CLI/API directly into MCP tools may not offer much but IDK.

One tool you could add is some validate_syntax tool that use the /console/inspect request=completion input=<LLM_CMD_OUTPUT> which could be used check the results are valid syntax for the connected routed. This is what my LSP uses to check syntax. So in terms of an MCP, some some prompting to check its output against the a validate_syntax MCP tool might do much of the work your broken up mikrotik_get_vlan_interface etc etc., since LLM like can guess /interface/vlan/get without help.

It's the more complex cases, that may be a simple prompt that I worry about. For example, "I'm starting with a defconf, and want to add VLAN for guests, and make a ether5 trunk port for an AP". The MCP ideally know you need vlan-filtering=yes and all the various other parts of actually creating a vlan - beyond just adding /interface/vlan/add. And ideally the LLM be given the current configuration, and perhaps other print output from neighbors, DHCP leases, etc. Perhaps even loading the relevant doc pages and/or product specs so their in the current LLM window.

So I guess my 10,000 view - without much test however - is that an I think an LLM could be improved is by offering more context, than necessarily mapping CLI on a one-to-one basis. But IDK.