中文

Three lanes,
one local proxy.

rowt runs a personal VPN, your corporate VPN, and a plain direct connection at the same time on macOS — by not being a VPN at all.

Per-connection routing · a live TUI · nothing in the routing table.

rowt1 / 25
Why it exists

Two tunnels, one default route.

You want Google through a personal VLESS server, the intranet through the corporate VPN, and Baidu straight out — simultaneously.

You can't. Shadowrocket and the corp client are both packet tunnels: each creates a utun interface and each wants to own the default route. macOS lets exactly one win.

So the usual day is manual: connect corp, lose Google. Connect the personal VPN, lose the intranet. Toggle, repeat.

The fight

Two utun devices, one routing table. Whoever connected last takes the default route — the other silently stops working.

What you actually want

A decision per connection, not per machine. google.com one way, jira.corp another, baidu.com a third.

rowt2 / 25
What it is

Not a tunnel. A proxy.

rowt runs sing-box as a plain userspace proxy on 127.0.0.1:7890. A proxy never touches the routing table, so it cannot fight the corp client. Apps hand it a connection; it picks an exit.

A typical VPN approwt
MechanismPacket tunnel (utun)Local proxy on a port
Routing tableClaims the default routeNever writes to it
Runs beside corp VPNNo — one winsYes, by construction
GranularityAll traffic, or a split you don't controlPer connection, per domain
Needs rootYesNo
Decides usingThe destination IPThe sniffed hostname, before DNS

The trade: it only catches what respects the proxy. Raw ping, ssh, and anything ignoring system proxy settings go around it — by design, and documented rather than hidden.

rowt3 / 25
What it is

Four lanes.

escape

Personal tunnel

VLESS / VMess / AnyTLS / hysteria2 / Shadowsocks / Trojan / TUIC to your own VPS. The socket is bound to the physical NIC, so it leaves via your home router even while the corp VPN holds the default route.

google.com · youtube.com · geosite:github

corp

Into the corporate VPN

An unbound socket resolved by the system resolver — so it follows the OS routing table straight into utunN. Fills itself; see corp sync.

*.intranet.example.com · 10.0.0.0/8

direct

Straight out

Bound to the physical NIC, bypassing both tunnels. The default for everything unlisted — local sites stay fast and un-tunnelled.

baidu.com · mirrors.debian.org · everything else

block

Sinkhole

Refused instantly — no DNS, no dial. Kills the ad/telemetry retry storm that otherwise spins CPU on the direct lane.

doubleclick.net · google-analytics.com

rowt4 / 25
How it works

Architecture

How traffic reaches rowt, how it is classified, and where it leaves.

ON YOUR MAC Browsers & GUI apps Safari · Chrome · Slack CLI tools git · npm · curl · claude Raw sockets ping · ssh · overlay peers macOS system proxy http_proxy env vars never sees the proxy rowt proxy on rowt-proxy-on · rowt run rowt sing-box · mixed HTTP+SOCKS · 127.0.0.1:7890 sniff the hostname → lane classification escape corp direct block your VPS bound to en0 utunN corp VPN en0 physical NIC refused no DNS, no dial OS routing table corp VPN · Tailscale · en0 the corp lane is UNBOUND — it follows this table into the tunnel watch reload on network change collector bytes per domain → SQLite
rowt5 / 25
How it works

Lane classification

Top to bottom, first match wins.

One connection arrives. sing-box sniffs the destination hostname — before any DNS — and walks the rules top to bottom.

# route.rules, in order sniff domain exact host → --domain entries domain_suffix longest match → the three lane files rule_set geosite:… → whole services ip_cidr corp ranges → from corp sync ip_cidr private/CGNAT → overlay peers rule_set ads → the broad blocklist final direct

Longest suffix wins across all lanes, so an explicit api.foo.com in escape beats foo.com in block — lane order never decides it.

Why hostname, not IP

A CDN address tells you nothing — the same IP serves a blocked site and a fine one. The name is the only thing that identifies the destination, and sniffing gets it before a resolver can be poisoned.

Ask it anything

rowt explain www.google.com www.google.com → ESCAPE matched: longest-match escape suffix 'google.com'

It mirrors the real rules, then adds a live HTTP check when the router is up.

rowt6 / 25
How it works

Three planes — and rowt owns two.

PlaneQuestionOwner
LaneWhich exit a proxied connection takesrowt
DNSWhich resolver answers a namerowt
OS routesWhich interface unbound traffic leaves bydeliberately not rowt

DNS follows the lane

  • corp names → the system resolver, so they get intranet answers
  • escape names → resolved VPS-side, so the exit sees what you see
  • everything else → DoH over the physical NIC

Why it refuses the third

Writing the route table needs a persistent root daemon — and a root daemon must never run user-writable code. rowt is brew-installed and updated constantly: exactly the wrong shape for root. It consumes the table; it never writes it.

rowt7 / 25
Getting started

Onboarding, step by step.

Do all of it with an existing VPN on — rowt up downloads sing-box for you. Only switch to the corp VPN once it works. rowt onboard prints this list with your progress at any time.

01

Install

brew install tanghong123/tap/rowt
02

Bring your servers in

Import from the clients you already use — Shadowrocket, Clash Verge, V2Box, FlClash. Run it once per client: entries accumulate into one review file, each tagged with where it came from. Prune, then apply.

rowt server import --from shadowrocket rowt server import --from clash-verge # accumulates $EDITOR ~/.config/rowt/import-review.json rowt server import --apply

Or add a share link directly: rowt server add '<vless://…>'

03

Start it

Fetches sing-box if missing, probes the right mode, renders the config, starts the router, turns the proxy on.

rowt up
04

Pick a server

rowt ping # rank by latency rowt use JP # or: rowt use auto
05

Switch networks, then verify

Quit the old VPN, connect corp, and check a destination from each lane.

rowt explain www.google.com rowt status
06

Fill the lanes

escape ships pre-seeded (Google, GitHub, Wikipedia, X…). corp fills itself from the VPN's routes. Add what you need:

rowt escape add youtube.com googlevideo.com rowt escape add geosite:google # a whole service rowt corp add '*.intranet.example.com' 10.0.0.0/8 rowt block add ads.example.com

geosite:<name> pulls a maintained rule-set — every Google domain and ccTLD — instead of you enumerating suffixes. A specific entry always beats it.

rowt corp suggest # from DHCP search domains rowt corp sync # with the corp VPN UP — mirror its routes

Run corp sync once while connected; after that the watchdog repeats it every tick.

07

Let it manage itself

Install the watchdog: auto-reload on network change, recovery from a wedged or crashed tunnel, and a stale proxy cleared at login.

rowt watch install rowt watch status
rowt8 / 25
Getting started

Getting your terminal to use it.

The macOS system proxy covers browsers and GUI apps. CLI tools ignore it entirely — they only read http_proxy / https_proxy / all_proxy. rowt gives you three ways to bridge that.

Per shell
eval "$(rowt shell-init)" # in ~/.zshrc, once rowt-proxy-on rowt-proxy-off

Both aliases come from rowt shell-init, which sets and clears the variables in this shell and installs tab-completion.

Per command
rowt run claude rowt run git pull

Probes which path actually reaches the internet right now — your shell's setting, the system proxy, rowt's port, then direct — and runs the command with the first that works. Refuses to run if none do.

Inspect
rowt proxy status rowt proxy env

What the system proxy is set to, whether it points at rowt, and the exact exports to paste somewhere else.

Why rowt run exists: with several proxy apps around and networks changing all day, the right value keeps moving. Guessing wrong fails in confusing ways — so it measures instead of assuming.

rowt9 / 25
Every day

The commands you actually use.

Constantly
rowt status
mode, server, proxy, reachability, config validity
rowt monitor
the live full-screen view
rowt escape add <d>
send a site through the tunnel
rowt reload
after switching Wi-Fi ↔ wired ↔ hotspot
Often
rowt explain <d>
which lane, and which rule matched
rowt direct errors
what failed direct — your escape candidates
rowt ping / use
rank servers, pin one or go auto
rowt connections
what's flowing right now, per lane
When something is odd
rowt audit
who changed what — you or the watchdog
rowt report
full diagnostic, secrets masked, shareable
rowt corp sync
re-mirror the corp VPN's live routes
rowt metrics top
heaviest domains over a window

The loop that matters: rowt direct errors 10m shows what just failed on the pass-through lane — timeouts and resets are usually blocked sites. Add the real ones to escape and move on.

rowt10 / 25
The monitor

One screen, the whole picture.

rowt monitor — demo fixture
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│   _ __ _____      __| |_   MONITOR                                                                            uptime  3h 15m │
│  | '__/ _ \ \ /\ / /| __|  ● LIVE  mode      host · en0     server  JP-Tokyo 42 ms                                           │
│  | | | (_) \ V  V / | |_           sys proxy on             router  running · 3%                                             │
│  |_|  \___/ \_/\_/   \__|          collector on             watch   on                                                       │
│                                                                                                                              │
├─┤ live connections ├───────────────────────────────────────────────────────┬─┤ errors & blocked ├────────────────────────────┤
│ all    ↑ 2.9 MB/s   ↓ 3.5 MB/s      27     426.4M      1.9G                │ aggregated over                 5m [10m] 1h 24h │
│ escape ↑ 2.7 MB/s   ↓ 3.5 MB/s      18     417.1M      1.3G                │ transient    12 · 1 dom                         │
│ corp   ↑ 144 KB/s   ↓ 44 KB/s        5       8.1M    414.6M                │ persistent   50 · 5 dom                         │
│ direct ↑ 5 KB/s     ↓ 2 KB/s         4       1.2M    176.9M                │ blocked      57 · 5 dom                         │
├────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────┤
│ LANE   HOST:PORT                     #         UP      DOWN  RULE          │ COUNT   TYPE        DOMAIN                      │
│ escape i.ytimg.com:443               5       8.0M    352.2M  domain_suffix │    15   timeout     vpn.corp.example.com        │
│ escape raw.githubusercontent.com:443 2       915K     96.8M  domain_suffix │    13   blocked     googlesyndication.com       │
│ escape fonts.gstatic.com:443         3      12.5M     43.1M  domain_suffix │    13   blocked     doubleclick.net             │
│ escape www.youtube.com:443           5      18.2M    427.7M  domain_suffix │    12   dns         gateway.icloud.com          │
│ escape api.anthropic.com:443         2     376.1M    414.4M  domain_suffix │    11   timeout     dl.google.com               │
│ escape en.wikipedia.org:443          1       1.4M      1.8M  domain_suffix │    11   blocked     criteo.com                  │
│ corp   jira.corp.example.com:443     5       8.1M    414.6M  domain_suffix │    10   blocked     adnxs.com                   │
│ direct mirrors.debian.org:443        1       509K    128.6M  final         │    10   blocked     google-analytics.com        │
│ direct dl.google.com:443             1       104K     47.8M  final         │    10   reset       x.com                       │
│ direct gateway.icloud.com:443        2       610K      519K  final         │     8   timeout     rr5.googlevideo.com         │
│ escape netflix.com                   0         0B        0B                │                                                 │
│ corp   backups.corp.example.com      0         0B        0B                │                                                 │
│ escape mail.google.com               0         0B        0B                │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
├────────────────────────────────────────────────────────────────────────────┴─┤ server health ├───────────────────────────────┤
│ auto off   10 servers · 9 up · 1 down                                                                                        │
│ ▶ JP-Tokyo  42 ms   JP-Osaka 175 ms   KR-Seoul  72 ms   DE-Frankfurt 195 ms   HK-1  82 ms   SG-1  81 ms   TW-Taipei 110 ms   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
1
2
3
4

Four regions, each covered next.

1 · identity band mode, active server, proxy, router health, sidecars — is it working?
2 · live connections what is flowing, per lane, and which rule sent it there
3 · errors & blocked what is failing over a rolling window — your escape candidates
4 · server health the pool, measured latency, and the active outbound

Everything derives from a 2-second tick, and nothing is mutated unless you press a control key.

rowt11 / 25
The monitor · region 1 of 4

Identity band — is it working?

rowt monitor — demo fixture
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│   _ __ _____      __| |_   MONITOR                                                                            uptime  3h 15m │
│  | '__/ _ \ \ /\ / /| __|  ● LIVE  mode      host · en0     server  JP-Tokyo 42 ms                                           │
│  | | | (_) \ V  V / | |_           sys proxy on             router  running · 3%                                             │
│  |_|  \___/ \_/\_/   \__|          collector on             watch   on                                                       │
│                                                                                                                              │
├─┤ live connections ├───────────────────────────────────────────────────────┬─┤ errors & blocked ├────────────────────────────┤
│ all    ↑ 2.9 MB/s   ↓ 3.5 MB/s      27     426.4M      1.9G                │ aggregated over                 5m [10m] 1h 24h │
│ escape ↑ 2.7 MB/s   ↓ 3.5 MB/s      18     417.1M      1.3G                │ transient    12 · 1 dom                         │
│ corp   ↑ 144 KB/s   ↓ 44 KB/s        5       8.1M    414.6M                │ persistent   50 · 5 dom                         │
│ direct ↑ 5 KB/s     ↓ 2 KB/s         4       1.2M    176.9M                │ blocked      57 · 5 dom                         │
├────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────┤
│ LANE   HOST:PORT                     #         UP      DOWN  RULE          │ COUNT   TYPE        DOMAIN                      │
│ escape i.ytimg.com:443               5       8.0M    352.2M  domain_suffix │    15   timeout     vpn.corp.example.com        │
│ escape raw.githubusercontent.com:443 2       915K     96.8M  domain_suffix │    13   blocked     googlesyndication.com       │
│ escape fonts.gstatic.com:443         3      12.5M     43.1M  domain_suffix │    13   blocked     doubleclick.net             │
│ escape www.youtube.com:443           5      18.2M    427.7M  domain_suffix │    12   dns         gateway.icloud.com          │
│ escape api.anthropic.com:443         2     376.1M    414.4M  domain_suffix │    11   timeout     dl.google.com               │
│ escape en.wikipedia.org:443          1       1.4M      1.8M  domain_suffix │    11   blocked     criteo.com                  │
│ corp   jira.corp.example.com:443     5       8.1M    414.6M  domain_suffix │    10   blocked     adnxs.com                   │
│ direct mirrors.debian.org:443        1       509K    128.6M  final         │    10   blocked     google-analytics.com        │
│ direct dl.google.com:443             1       104K     47.8M  final         │    10   reset       x.com                       │
│ direct gateway.icloud.com:443        2       610K      519K  final         │     8   timeout     rr5.googlevideo.com         │
│ escape netflix.com                   0         0B        0B                │                                                 │
│ corp   backups.corp.example.com      0         0B        0B                │                                                 │
│ escape mail.google.com               0         0B        0B                │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
├────────────────────────────────────────────────────────────────────────────┴─┤ server health ├───────────────────────────────┤
│ auto off   10 servers · 9 up · 1 down                                                                                        │
│ ▶ JP-Tokyo  42 ms   JP-Osaka 175 ms   KR-Seoul  72 ms   DE-Frankfurt 195 ms   HK-1  82 ms   SG-1  81 ms   TW-Taipei 110 ms   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
identity band

The answer to "is anything wrong?" without reading any further.

● LIVE
breathing heartbeat — if it stops, the data is stale. Also reads DOWN, ERROR or PAUSED
mode
host / vm / local, and the interface in use
server
the active outbound and its measured latency
sys proxy
whether macOS is actually pointing at rowt
router
running state and CPU — a spinning router shows here first
collector · watch
whether history recording and the auto-reload watchdog are up

What you can do here

  • o toggles the system proxy — or click the sys proxy cell
  • p pauses sampling, so the screen holds still while you read
  • r re-probes every server now instead of waiting for the timer
rowt12 / 25
The monitor · region 2 of 4

Live connections — what is flowing.

rowt monitor — demo fixture
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│   _ __ _____      __| |_   MONITOR                                                                            uptime  3h 15m │
│  | '__/ _ \ \ /\ / /| __|  ● LIVE  mode      host · en0     server  JP-Tokyo 42 ms                                           │
│  | | | (_) \ V  V / | |_           sys proxy on             router  running · 3%                                             │
│  |_|  \___/ \_/\_/   \__|          collector on             watch   on                                                       │
│                                                                                                                              │
├─┤ live connections ├───────────────────────────────────────────────────────┬─┤ errors & blocked ├────────────────────────────┤
│ all    ↑ 2.9 MB/s   ↓ 3.5 MB/s      27     426.4M      1.9G                │ aggregated over                 5m [10m] 1h 24h │
│ escape ↑ 2.7 MB/s   ↓ 3.5 MB/s      18     417.1M      1.3G                │ transient    12 · 1 dom                         │
│ corp   ↑ 144 KB/s   ↓ 44 KB/s        5       8.1M    414.6M                │ persistent   50 · 5 dom                         │
│ direct ↑ 5 KB/s     ↓ 2 KB/s         4       1.2M    176.9M                │ blocked      57 · 5 dom                         │
├────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────┤
│ LANE   HOST:PORT                     #         UP      DOWN  RULE          │ COUNT   TYPE        DOMAIN                      │
│ escape i.ytimg.com:443               5       8.0M    352.2M  domain_suffix │    15   timeout     vpn.corp.example.com        │
│ escape raw.githubusercontent.com:443 2       915K     96.8M  domain_suffix │    13   blocked     googlesyndication.com       │
│ escape fonts.gstatic.com:443         3      12.5M     43.1M  domain_suffix │    13   blocked     doubleclick.net             │
│ escape www.youtube.com:443           5      18.2M    427.7M  domain_suffix │    12   dns         gateway.icloud.com          │
│ escape api.anthropic.com:443         2     376.1M    414.4M  domain_suffix │    11   timeout     dl.google.com               │
│ escape en.wikipedia.org:443          1       1.4M      1.8M  domain_suffix │    11   blocked     criteo.com                  │
│ corp   jira.corp.example.com:443     5       8.1M    414.6M  domain_suffix │    10   blocked     adnxs.com                   │
│ direct mirrors.debian.org:443        1       509K    128.6M  final         │    10   blocked     google-analytics.com        │
│ direct dl.google.com:443             1       104K     47.8M  final         │    10   reset       x.com                       │
│ direct gateway.icloud.com:443        2       610K      519K  final         │     8   timeout     rr5.googlevideo.com         │
│ escape netflix.com                   0         0B        0B                │                                                 │
│ corp   backups.corp.example.com      0         0B        0B                │                                                 │
│ escape mail.google.com               0         0B        0B                │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
├────────────────────────────────────────────────────────────────────────────┴─┤ server health ├───────────────────────────────┤
│ auto off   10 servers · 9 up · 1 down                                                                                        │
│ ▶ JP-Tokyo  42 ms   JP-Osaka 175 ms   KR-Seoul  72 ms   DE-Frankfurt 195 ms   HK-1  82 ms   SG-1  81 ms   TW-Taipei 110 ms   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
live connections

A per-lane rate summary, then one row per host.

LANE
which exit this connection took
HOST:PORT
the sniffed destination
#
concurrent connections to it
UP · DOWN
bytes each way
RULE
why it went there — domain_suffix, domain, rule_set or final

That last column answers "why is this going through the tunnel?" without leaving the screen.

Rows greyed with 0B are dormant — seen recently, idle now. They keep their place so a host you are watching does not vanish the moment it goes quiet.

rowt13 / 25
The monitor · region 3 of 4

Errors & blocked — what is failing.

rowt monitor — demo fixture
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│   _ __ _____      __| |_   MONITOR                                                                            uptime  3h 15m │
│  | '__/ _ \ \ /\ / /| __|  ● LIVE  mode      host · en0     server  JP-Tokyo 42 ms                                           │
│  | | | (_) \ V  V / | |_           sys proxy on             router  running · 3%                                             │
│  |_|  \___/ \_/\_/   \__|          collector on             watch   on                                                       │
│                                                                                                                              │
├─┤ live connections ├───────────────────────────────────────────────────────┬─┤ errors & blocked ├────────────────────────────┤
│ all    ↑ 2.9 MB/s   ↓ 3.5 MB/s      27     426.4M      1.9G                │ aggregated over                 5m [10m] 1h 24h │
│ escape ↑ 2.7 MB/s   ↓ 3.5 MB/s      18     417.1M      1.3G                │ transient    12 · 1 dom                         │
│ corp   ↑ 144 KB/s   ↓ 44 KB/s        5       8.1M    414.6M                │ persistent   50 · 5 dom                         │
│ direct ↑ 5 KB/s     ↓ 2 KB/s         4       1.2M    176.9M                │ blocked      57 · 5 dom                         │
├────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────┤
│ LANE   HOST:PORT                     #         UP      DOWN  RULE          │ COUNT   TYPE        DOMAIN                      │
│ escape i.ytimg.com:443               5       8.0M    352.2M  domain_suffix │    15   timeout     vpn.corp.example.com        │
│ escape raw.githubusercontent.com:443 2       915K     96.8M  domain_suffix │    13   blocked     googlesyndication.com       │
│ escape fonts.gstatic.com:443         3      12.5M     43.1M  domain_suffix │    13   blocked     doubleclick.net             │
│ escape www.youtube.com:443           5      18.2M    427.7M  domain_suffix │    12   dns         gateway.icloud.com          │
│ escape api.anthropic.com:443         2     376.1M    414.4M  domain_suffix │    11   timeout     dl.google.com               │
│ escape en.wikipedia.org:443          1       1.4M      1.8M  domain_suffix │    11   blocked     criteo.com                  │
│ corp   jira.corp.example.com:443     5       8.1M    414.6M  domain_suffix │    10   blocked     adnxs.com                   │
│ direct mirrors.debian.org:443        1       509K    128.6M  final         │    10   blocked     google-analytics.com        │
│ direct dl.google.com:443             1       104K     47.8M  final         │    10   reset       x.com                       │
│ direct gateway.icloud.com:443        2       610K      519K  final         │     8   timeout     rr5.googlevideo.com         │
│ escape netflix.com                   0         0B        0B                │                                                 │
│ corp   backups.corp.example.com      0         0B        0B                │                                                 │
│ escape mail.google.com               0         0B        0B                │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
├────────────────────────────────────────────────────────────────────────────┴─┤ server health ├───────────────────────────────┤
│ auto off   10 servers · 9 up · 1 down                                                                                        │
│ ▶ JP-Tokyo  42 ms   JP-Osaka 175 ms   KR-Seoul  72 ms   DE-Frankfurt 195 ms   HK-1  82 ms   SG-1  81 ms   TW-Taipei 110 ms   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
errors & blocked

Aggregated over a rolling window — w or [ ] cycles 5m → 10m → 1h → 24h → all.

transient
DNS failures — usually resolve themselves
persistent
timeout, reset, refused — these are your escape candidates
blocked
what the block lane and the ad rule-set sank

The workflow: filter to the direct lane, look at persistent failures, and route the real ones to escape — without leaving the monitor.

Only failed connections are logged. An empty pane means no errors — not no traffic.

rowt14 / 25
The monitor · region 4 of 4

Server health — where you go out.

rowt monitor — demo fixture
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│   _ __ _____      __| |_   MONITOR                                                                            uptime  3h 15m │
│  | '__/ _ \ \ /\ / /| __|  ● LIVE  mode      host · en0     server  JP-Tokyo 42 ms                                           │
│  | | | (_) \ V  V / | |_           sys proxy on             router  running · 3%                                             │
│  |_|  \___/ \_/\_/   \__|          collector on             watch   on                                                       │
│                                                                                                                              │
├─┤ live connections ├───────────────────────────────────────────────────────┬─┤ errors & blocked ├────────────────────────────┤
│ all    ↑ 2.9 MB/s   ↓ 3.5 MB/s      27     426.4M      1.9G                │ aggregated over                 5m [10m] 1h 24h │
│ escape ↑ 2.7 MB/s   ↓ 3.5 MB/s      18     417.1M      1.3G                │ transient    12 · 1 dom                         │
│ corp   ↑ 144 KB/s   ↓ 44 KB/s        5       8.1M    414.6M                │ persistent   50 · 5 dom                         │
│ direct ↑ 5 KB/s     ↓ 2 KB/s         4       1.2M    176.9M                │ blocked      57 · 5 dom                         │
├────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────┤
│ LANE   HOST:PORT                     #         UP      DOWN  RULE          │ COUNT   TYPE        DOMAIN                      │
│ escape i.ytimg.com:443               5       8.0M    352.2M  domain_suffix │    15   timeout     vpn.corp.example.com        │
│ escape raw.githubusercontent.com:443 2       915K     96.8M  domain_suffix │    13   blocked     googlesyndication.com       │
│ escape fonts.gstatic.com:443         3      12.5M     43.1M  domain_suffix │    13   blocked     doubleclick.net             │
│ escape www.youtube.com:443           5      18.2M    427.7M  domain_suffix │    12   dns         gateway.icloud.com          │
│ escape api.anthropic.com:443         2     376.1M    414.4M  domain_suffix │    11   timeout     dl.google.com               │
│ escape en.wikipedia.org:443          1       1.4M      1.8M  domain_suffix │    11   blocked     criteo.com                  │
│ corp   jira.corp.example.com:443     5       8.1M    414.6M  domain_suffix │    10   blocked     adnxs.com                   │
│ direct mirrors.debian.org:443        1       509K    128.6M  final         │    10   blocked     google-analytics.com        │
│ direct dl.google.com:443             1       104K     47.8M  final         │    10   reset       x.com                       │
│ direct gateway.icloud.com:443        2       610K      519K  final         │     8   timeout     rr5.googlevideo.com         │
│ escape netflix.com                   0         0B        0B                │                                                 │
│ corp   backups.corp.example.com      0         0B        0B                │                                                 │
│ escape mail.google.com               0         0B        0B                │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
├────────────────────────────────────────────────────────────────────────────┴─┤ server health ├───────────────────────────────┤
│ auto off   10 servers · 9 up · 1 down                                                                                        │
│ ▶ JP-Tokyo  42 ms   JP-Osaka 175 ms   KR-Seoul  72 ms   DE-Frankfurt 195 ms   HK-1  82 ms   SG-1  81 ms   TW-Taipei 110 ms   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
server health

Every server in the pool with its probe latency, measured through the tunnel on a gentle cadence — real network work, done off the UI thread so it never stutters.

▶
the active server, pinned at the left edge so it never scrolls out of view
marquee
when the pool overflows the row it scrolls, and freezes the moment you select something
counts
total / up / down summarises the pool at a glance
auto
the toggle leading that row: on rides the fastest live server and pins whichever it is using at the left; off keeps that one

What you can do here

  • ← → select a chip — or click one
  • u switches the active outbound to it, immediately — and turns auto off
  • a turns auto selection on or off, from any pane — or click it
  • r re-probes the whole pool now

The same thing as rowt ping, rowt use <tag> and rowt use auto, without leaving the screen.

rowt15 / 25
The monitor · navigating

The keys are global.

Filtering, searching and windowing apply to the whole screen — you never have to focus a pane first.

rowt monitor — demo fixture
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│   _ __ _____      __| |_   MONITOR                                                                            uptime  3h 15m │
│  | '__/ _ \ \ /\ / /| __|  ● LIVE  mode      host · en0     server  JP-Tokyo 42 ms                                           │
│  | | | (_) \ V  V / | |_           sys proxy on             router  running · 3%                                             │
│  |_|  \___/ \_/\_/   \__|          collector on             watch   on                                                       │
│                                                                                                                              │
├─┤ live connections · escape ├──────────────────────────────────────────────┬─┤ errors & blocked · escape ├───────────────────┤
│ all    ↑ 2.9 MB/s   ↓ 3.5 MB/s      27     426.4M      1.9G                │ aggregated over                 5m [10m] 1h 24h │
│ escape ↑ 2.7 MB/s   ↓ 3.5 MB/s      18     417.1M      1.3G                │ transient    12 · 1 dom                         │
│ corp   ↑ 144 KB/s   ↓ 44 KB/s        5       8.1M    414.6M                │ persistent   50 · 5 dom                         │
│ direct ↑ 5 KB/s     ↓ 2 KB/s         4       1.2M    176.9M                │ blocked      57 · 5 dom                         │
├────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────┤
│ LANE   HOST:PORT                     #         UP      DOWN  RULE          │ COUNT   TYPE        DOMAIN                      │
│ escape i.ytimg.com:443               5       8.0M    352.2M  domain_suffix │    15   timeout     vpn.corp.example.com        │
│ escape raw.githubusercontent.com:443 2       915K     96.8M  domain_suffix │    13   blocked     googlesyndication.com       │
│ escape fonts.gstatic.com:443         3      12.5M     43.1M  domain_suffix │    13   blocked     doubleclick.net             │
│ escape www.youtube.com:443           5      18.2M    427.7M  domain_suffix │    12   dns         gateway.icloud.com          │
│ escape api.anthropic.com:443         2     376.1M    414.4M  domain_suffix │    11   timeout     dl.google.com               │
│ escape en.wikipedia.org:443          1       1.4M      1.8M  domain_suffix │    11   blocked     criteo.com                  │
│ escape netflix.com                   0         0B        0B                │    10   blocked     adnxs.com                   │
│ escape mail.google.com               0         0B        0B                │    10   blocked     google-analytics.com        │
│                                                                            │    10   reset       x.com                       │
│                                                                            │     8   timeout     rr5.googlevideo.com         │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
├────────────────────────────────────────────────────────────────────────────┴─┤ server health ├───────────────────────────────┤
│ auto off   10 servers · 9 up · 1 down                                                                                        │
│ ▶ JP-Tokyo  42 ms │ JP-Osaka 175 ms   KR-Seoul  72 ms   DE-Frankfurt 195 ms   HK-1  82 ms   SG-1  81 ms   TW-Taipei 110 ms   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Lane filter set to escape: both panes scope to it at once. Press 0 to clear.

Narrow

f · 1 2 3 0cycle the lane filter, or jump to escape / corp / direct; 0 clears
/regex search over hosts, filtering both panes as you type
w · [ ]errors window: 5m → 10m → 1h → 24h → all

Move

↑↓ · j kmove the selection; the first press locks a row by domain
←→ · h lswitch pane, or pick a server chip
Tabcycle connections → errors → server strip

Other

ycopy the selected domain
ppause sampling
?the full key list, any time
rowt16 / 25
The monitor · history

Where did the bytes actually go?

rowt monitor — demo fixture
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│   _ __ _____      __| |_   MONITOR                                                                            uptime  3h 15m │
│  | '__/ _ \ \ /\ / /| __|  ● LIVE  mode      host · en0     server  JP-Tokyo 42 ms                                           │
│  | | | (_) \ V  V / | |_           sys proxy on             router  running · 3%                                             │
│  |_|  \___/ \_/\_/   \__|          collector on             watch   on                                                       │
│                                                                                                                              │
├─┤ connections · ▲ upload · recent ├────────────────────────────────────────┬─┤ errors & blocked ├────────────────────────────┤
│ all                                           8K/s    8K/s   29.7M  714.0M │ aggregated over                 5m [10m] 1h 24h │
│ escape                                        7K/s    7K/s   26.5M  636.0M │ transient    12 · 1 dom                         │
│ corp                                        656B/s  656B/s    2.4M   56.7M │ persistent   50 · 5 dom                         │
│ direct                                      247B/s  247B/s    889K   21.3M │ blocked      57 · 5 dom                         │
├────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────┤
│ LANE   HOST                                    ↑1m     ↑5m     ↑1h    ↑24h │ COUNT   TYPE        DOMAIN                      │
│ escape i.ytimg.com:443                        0B/s    0B/s      0B      0B │    15   timeout     vpn.corp.example.com        │
│ escape raw.githubusercontent.com:443          0B/s    0B/s      0B      0B │    13   blocked     googlesyndication.com       │
│ escape fonts.gstatic.com:443                  0B/s    0B/s      0B      0B │    13   blocked     doubleclick.net             │
│ escape www.youtube.com:443                    2K/s    2K/s    6.8M  163.3M │    12   dns         gateway.icloud.com          │
│ escape api.anthropic.com:443                  2K/s    2K/s    8.6M  206.7M │    11   timeout     dl.google.com               │
│ escape en.wikipedia.org:443                   0B/s    0B/s      0B      0B │    11   blocked     criteo.com                  │
│ corp   jira.corp.example.com:443              0B/s    0B/s      0B      0B │    10   blocked     adnxs.com                   │
│ direct mirrors.debian.org:443               247B/s  247B/s    889K   21.3M │    10   blocked     google-analytics.com        │
│ direct dl.google.com:443                      0B/s    0B/s      0B      0B │    10   reset       x.com                       │
│ direct gateway.icloud.com:443                 0B/s    0B/s      0B      0B │     8   timeout     rr5.googlevideo.com         │
│ escape netflix.com                            3K/s    3K/s   10.4M  250.0M │                                                 │
│ corp   backups.corp.example.com             656B/s  656B/s    2.4M   56.7M │                                                 │
│ escape mail.google.com                      185B/s  185B/s    667K   16.0M │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
├────────────────────────────────────────────────────────────────────────────┴─┤ server health ├───────────────────────────────┤
│ auto off   10 servers · 9 up · 1 down                                                                                        │
│ ▶ JP-Tokyo  42 ms │ JP-Osaka 175 ms   KR-Seoul  72 ms   DE-Frankfurt 195 ms   HK-1  82 ms   SG-1  81 ms   TW-Taipei 110 ms   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
▲ upload
Press v for ▲ upload, again for ▼ download. Errors and server health are untouched — only this pane flips.

A collector sidecar records bytes per domain and lane into a tiered SQLite store — 5-second buckets rolled up to a year.

v
flip the pane: live → ▲ upload → ▼ download
s
span: recent (1m/5m/1h/24h) → days → year

Selection is by domain, so it rides the flip — line a host up in the live view and read its whole history without losing it.

rowt metrics top 3600 # heaviest, last hour rowt metrics query "<SQL>" # read-only passthrough
rowt17 / 25
The monitor · acting

Confirmed, reversible edits.

rowt monitor — demo fixture
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│   _ __ _____      __| |_   MONITOR                                                                            uptime  3h 15m │
│  | '__/ _ \ \ /\ / /| __|  ● LIVE  mode      host · en0     server  JP-Tokyo 42 ms                                           │
│  | | | (_) \ V  V / | |_           sys proxy on             router  running · 3%                                             │
│  |_|  \___/ \_/\_/   \__|          collector on             watch   on                                                       │
│                                                                                                                              │
├─┤ live connections ├───────────────────────────────────────────────────────┬─┤ errors & blocked ├────────────────────────────┤
│ all    ↑ 2.9 MB/s   ↓ 3.5 MB/s      27     426.4M      1.9G                │ aggregated over                 5m [10m] 1h 24h │
│ escape ↑ 2.7 MB/s   ↓ 3.5 MB/s      18     417.1M      1.3G                │ transient    12 · 1 dom                         │
│ corp   ↑ 144 KB/s   ↓ 44 KB/s        5       8.1M    414.6M                │ persistent   50 · 5 dom                         │
│ direct ↑ 5 KB/s     ↓ 2 KB/s         4       1.2M    176.9M                │ blocked      57 · 5 dom                         │
├────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────┤
│ LANE   HOST:PORT                     #         UP      DOWN  RULE          │ COUNT   TYPE        DOMAIN                      │
│▎escape i.ytimg.com:443               5       8.0M    352.2M  domain_suffix │    15   timeout     vpn.corp.example.com        │
│ escape raw.githubusercontent.com:443 2       915K     96.8M  domain_suffix │    13   blocked     googlesyndication.com       │
│ escape fonts.gstatic.com:443         3      12.5M     43.1M  domain_suffix │    13   blocked     doubleclick.net             │
│ escape www.youtube.com:443           5      18.2M    427.7M  domain_suffix │    12   dns         gateway.icloud.com          │
│ escape api.anthropic.com:443         2     376.1M    414.4M  domain_suffix │    11   timeout     dl.google.com               │
│ escape en.wikipedia.org:443          1       1.4M      1.8M  domain_suffix │    11   blocked     criteo.com                  │
│ corp   jira.corp.example.com:443     5       8.1M    414.6M  domain_suffix │    10   blocked     adnxs.com                   │
│ direct mirrors.debian.org:443        1       509K    128.6M  final         │    10   blocked     google-analytics.com        │
│ direct dl.google.com:443             1       104K     47.8M  final         │    10   reset       x.com                       │
│ direct gateway.icloud.com:443        2       610K      519K  final         │     8   timeout     rr5.googlevideo.com         │
│ escape netflix.com                   0         0B        0B                │                                                 │
│ corp   backups.corp.example.com      0         0B        0B                │                                                 │
│ escape mail.google.com               0         0B        0B                │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
│                                                                            │                                                 │
├────────────────────────────────────────────────────────────────────────────┴─┤ server health ├───────────────────────────────┤
│ auto off   10 servers · 9 up · 1 down                                                                                        │
│ ▶ JP-Tokyo  42 ms │ JP-Osaka 175 ms   KR-Seoul  72 ms   DE-Frankfurt 195 ms   HK-1  82 ms   SG-1  81 ms   TW-Taipei 110 ms   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
                                                                        CONFIRM  i.ytimg.com   → press e again to apply         
Armed on i.ytimg.com. Nothing is written until you confirm — and Esc, or simply walking away, cancels it.
e c b d
route the locked domain → escape / corp / block / back to direct
E C B D
the same on the parent suffix — x.y.z.com → z.com, covering a whole service in one keystroke
↵ / key×2
apply · esc cancels · idle 10s cancels itself
u · a · o
switch server · auto selection on/off · toggle the system proxy — all immediate, no arming

Each is a front-end to the exact rowt command you could have typed. Edits are batched: one router reload fires ~7s after the last settles.

An over-broad entry turns red and is refused — com is not a host, it is every .com.

rowt18 / 25
The monitor · reference

Everything, on one key.

rowt monitor — demo fixture
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│   _ __ _____      __| |_   MONITOR                                                                            uptime  3h 15m │
│  | '__/ _ \ \ /\ / /| __|  ● LIVE  mode      host · en0     server  JP-Tokyo 42 ms                                           │
│  | | | (_) \ V  V / |╭───────────────────────────────────────────────────────────────────────────────╮                       │
│  |_|  \___/ \_/\_/   │  rowt monitor — keys                                                          │                       │
│                      │                                                                               │                       │
├─┤ live connections ├─│  ↑↓ / j k   move selection (locks the row)                                    │───────────────────────┤
│ all    ↑ 2.9 MB/s   ↓│  ←→ / h l   switch pane · select server chip                                  │       5m [10m] 1h 24h │
│ escape ↑ 2.7 MB/s   ↓│  Tab        cycle focus (conns/errors/health)                                 │                       │
│ corp   ↑ 144 KB/s   ↓│  v          flip pane · live / ↑ upload / ↓ download                          │                       │
│ direct ↑ 5 KB/s     ↓│  s          span — metrics band (recent/days/year); from Live, opens ↑ upload │                       │
├──────────────────────│  f 1 2 3 0  lane filter / jump / clear                                        │───────────────────────┤
│ LANE   HOST:PORT     │  /          search hosts (regex) · esc clears                                 │N                      │
│ escape i.ytimg.com:44│  w [ ]      errors window (rolling)                                           │orp.example.com        │
│ escape raw.githubuser│  y          copy the selected domain                                          │esyndication.com       │
│ escape fonts.gstatic.│  e c b d t  route selected → escape/corp/                                     │eclick.net             │
│ escape www.youtube.co│             block/direct/hotspot (key×2 = apply)                              │ay.icloud.com          │
│ escape api.anthropic.│  E C B D T  same, on the parent suffix                                        │ogle.com               │
│ escape en.wikipedia.o│             (x.y.z.com → z.com)                                               │o.com                  │
│ corp   jira.corp.exam│             after ½s the entry turns editable:                                │.com                   │
│ direct mirrors.debian│             type · ^w drop leading label · ↵ apply                            │e-analytics.com        │
│ direct dl.google.com:│  u          use the selected server                                           │                       │
│ direct gateway.icloud│  a          auto server selection on/off                                      │ooglevideo.com         │
│ escape netflix.com   │             (off pins the server in use)                                      │                       │
│ corp   backups.corp.e│  o          toggle the system proxy on/off                                    │                       │
│ escape mail.google.co│  r          re-probe servers now                                              │                       │
│                      │  p          pause sampling   · esc  cancel                                    │                       │
│                      │  ?          toggle this help · q  quit                                        │                       │
│                      │                                                                               │                       │
│                      │  observe + confirmed, reversible overrides.                                   │                       │
├──────────────────────╰───────────────────────────────────────────────────────────────────────────────╯───────────────────────┤
│ auto off   10 servers · 9 up · 1 down                                                                                        │
│ ▶ JP-Tokyo  42 ms │ JP-Osaka 175 ms   KR-Seoul  72 ms   DE-Frankfurt 195 ms   HK-1  82 ms   SG-1  81 ms   TW-Taipei 110 ms   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Press ? at any time; esc closes it.

Worth knowing

mousewheel scrolls the list under the pointer; click a row, a lane, a window tab, a server chip, the proxy cell, or the auto toggle
themesauto-detected from the terminal background; --theme light pins it
fallbackwith no config or no router it renders a demo fixture rather than an error screen
read-onlythe data path never mutates anything — only the confirmed control keys do
cheapIO and CPU scale with new data, not with log or pool size
rowt19 / 25
Runs itself

What it does without being asked.

Only watch needs a one-time install. The rest is on by default.

corp sync

Reads the routing table and mirrors your corp VPN's live CIDRs into the corp lane, so proxied traffic to those ranges rides the tunnel. Re-run on every watchdog tick — roughly every two minutes and on each network change — so it tracks a VPN that reconnects with different routes. Hand-added entries are never touched.

watch

A LaunchAgent that reloads on every network change, probes the tunnel on a timer and recovers a wedged or crashed router, and clears a stale system proxy at login so rowt's effect never outlives a reboot.

captive portals

Hotel and airport logins break when a proxy is on. rowt detects the portal, drops the proxy so the login page loads, and restores it once you are through.

geosite

Add a whole maintained service — rowt escape add geosite:google — instead of enumerating suffixes. A specific entry always beats it.

metrics

The collector records per-domain bytes into a tiered store, 5s buckets to a year, queryable from the CLI or read in the monitor's flip view.

audit

Every state-changing operation is journalled with who ran it — you or the watchdog — including commands that hang, since BEGIN is written before the work.

rowt20 / 25
Advanced

Three modes for three situations.

host

The common one

sing-box runs on the Mac and the escape socket is bound to the physical NIC. Works whenever the corp client lets a bound socket out.

vm

When binding is blocked

Some corp clients enforce with a packet filter, so binding is not enough. The tunnel moves into a bridged Lima VM with its own LAN address — the filter sees a different machine.

local

Already outside

No tunnel at all, for when you are on an uncensored network. The escape lane's rules retarget to direct rather than disappearing, so they keep their precedence over broader block entries. No server needed.

Choosing

rowt up # auto-detect rowt up vm # force a mode rowt probe # which one works here?

rowt up with no argument probes: it tests whether a bound socket reaches the internet with the corp VPN up, and picks accordingly. It also checks the GFW canaries over the physical NIC — if they answer, you are already outside, and it chooses local.

Detection is most accurate with the corp VPN connected, so re-run it once after switching networks.

rowt21 / 25
Advanced

Moving it, and handing it over.

Take your setup to another machine

config export bundles only the source of truth — the server pool, subscriptions and the lane rules. Add --no-servers to share just the rules, with no credentials. The rendered config, state and binaries are machine-specific and regenerate themselves.

rowt config list # what would go in rowt config export --no-servers # → .tgz, no server pool rowt config import setup.tgz # MERGE + re-render

Import merges into your lanes and keeps your server pool — conflicts are confirmed first; --replace overwrites instead. A full bundle holds credentials — move it encrypted.

Let an agent drive it

rowt ships an agent skill: link it and a coding agent can run the setup, diagnose a lane, or explain a routing decision using the same commands you would.

rowt skill install rowt skill status

When you need to ask a human

rowt report

Dependencies, configs, per-server reachability, DNS, through-proxy tests, log and audit tail — with secrets masked, written to a file you can hand over.

rowt22 / 25
Under the hood

Why you can trust it with your traffic.

rowt began as one large shell script. It is being ported to Rust incrementally, and the port is held to the original by a differential harness rather than by hope.

Every command runs in a sandbox that cannot touch the machine, through both implementations, and four artifacts are compared: stdout, exit status, the whole config tree, and the trace of every effectful command.

cli surface 292/292 identical lane edits 28/28 render matrix 23/23 canonical JSON classifier 10/10 lane AND reason

What that buys

  • a rewrite that cannot quietly change behaviour
  • bugs found in the original — the harness has caught real routing faults the shell had for months
  • a shadow mode that runs both and records any disagreement, on the live machine, before anything is cut over

The same discipline shows up in the product: a lane entry that would match a whole TLD is refused, an armed edit expires, and every mutation is reversible and logged.

rowt23 / 25
Under the hood

By the numbers.

43klines, all told
222commits since 3 Jul 2026
81tagged releases
366Rust unit + integration tests
353differential parity cases
14shipped binaries

Where the code lives

Rust · crates18,928
Rust · monitor8,871
Bash · bin/rowt5,027
Parity harness4,266
Docs · markdown3,480
Python · legacy2,529

Python is on its way out — since 3.3.7 bin/rowt runs the Rust helpers and python@3.12 is no longer a dependency on either architecture.

How it is built

languages
Bash, Rust, a little Python, and jq for the original render
runtime
sing-box · SQLite (bundled) · ratatui for the TUI
workspaces
two — the CLI/core crates, and the monitor
gates
292 CLI · 28 lane · 23 render · 10 classifier · 25 sandbox scenarios
packaging
Homebrew tap; Apple Silicon pours 5 prebuilt binaries, Intel builds from source
zero-config
no daemon runs as root, and nothing writes the routing table

The port, phase by phase

0 · harness2 · classify + lanes 4 · the whole CLI6 · importers 1 · render — shadow window3 · watchdog — tick cutover 5 · Linux + tun mode

A strangler: every phase ships on its own, behind its own gate, with the shell still the daily driver. ROWT_IMPL=rust already hands a whole invocation to the Rust CLI — off by default until the shadow windows close.

rowt24 / 25

Start here.

brew install tanghong123/tap/rowt rowt onboard

Everything else is discoverable from there — rowt help, rowt <command> --help, and the checklist that tells you what to run next.

Docs: README.md · DESIGN.md · rowt-monitor/DESIGN.md

rowt25 / 25
← → or space to move