AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
翻譯準備中
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗The self-hosted AI network monitor. Your monitor says it's down. lanowl tells you why.
lanowl checks every device on your network once a minute and tells you once per incident, not once per blip. When something breaks, a local model, the owl, investigates with read-only tools and writes the cause into the alert you already have: the switch, the line, the update, the Wi-Fi. It changes nothing by itself: a fix is a proposal that runs only when you press a button.
Free and open source (AGPL-3.0). Self-hosted, no account, no telemetry. The model runs on your own Ollama; everything else works without it.
Documentation · Quick start · How alerts work · The security model
Set it up with your AI assistant. No YAML to learn: describe your network to Claude,
ChatGPT, Gemini or any other assistant, give it the example files, and it writes your
configuration. lanowl --check tells you both what to fix, and your passwords stay on your
machine. The prompt to copy.
Status: pre-alpha. lanowl comes out of a monitor that has run a real home network (MikroTik, OpenWrt, Linux servers, Shelly, cameras, a VPS hub, two remote sites) since August 2026, now turned into something anyone can install. Expect rough edges.
Besides telling you why, lanowl looks after the whole network from one install. What it does with a device besides watching it (updates, reboots, backups, security) is ticked device by device, and nothing that changes a device runs without your button.
ok, on backup or down. A failover to your backup line is not "no internet"./status, /security, /updates, /backups,
/reboot, /pause, /week.No file to copy or edit:
git clone https://github.com/alessandromatera/lanowl && cd lanowl
docker compose -f docker/compose.yaml up -d
docker exec lanowl lanowl --setup-code
At its first start lanowl writes its own config.yaml, inventory.yaml, secrets.yaml and
ssh key into the empty config/ folder. Then open http://<this host>:8088/ and the page sets
it up:
/start from your phone. Optional.The owl stays off until you tell lanowl where Ollama runs (Settings → The model): nothing
warns about a model you have not set up. Everything else in config.yaml, every login and
every token can be changed from the gear, too; a password or a token goes in and is never
shown again. On Linux, allow unprivileged ping first
(sysctl -w net.ipv4.ping_group_range="0 2147483647"), or every device reads DOWN.
Rather write the files yourself, or have an AI assistant write them from a description of your
network? Copy the examples into config/ instead: Quick start,
Set it up with an AI assistant.
What lanowl will do with each device, and why not:
docker compose -f docker/compose.yaml run --rm lanowl lanowl --check
A dry run, one sweep printed and nothing sent:
docker compose -f docker/compose.yaml run --rm lanowl python -m lanowl.main --once --no-llm --no-mqtt --no-telegram
Three files, all under config/, written by lanowl at its first start and changed from the
dashboard's gear (or by hand):
| file | what | shared? |
|---|---|---|
config.yaml | everything lanowl does, with every optional feature off | yes |
inventory.yaml | the devices: how each is watched, and what lanowl does with it | yes |
secrets.yaml | every secret: device logins, tokens, lanowl's ssh key; mode 600, write-only from the dashboard | never |
profiles/ | device kinds of your own (optional) | yes |
Two settings shape how the owl thinks:
network.description: a few sentences about your network, in your own words: the
links, the sites, what runs where, what you chose on purpose. Every prompt gets it.model.persona: owl (the default), or "" for plain prose. The owl speaks briefly,
opens its words on Telegram with its call, "Hoo.", and never changes a severity; its words
carry 🦉, what it checked by itself 🪶 and a fix it proposes 📜; the monitor's keep 🔴🟡🟢.A backup internet link is optional. Without wan.path.route_comment lanowl assumes one
line, and nothing speaks of failover. With it (a MikroTik dual-WAN), name your links
(wan.path.main / backup) and every message uses those names.
With a MikroTik as the main router, lanowl reads it: the DHCP leases (new devices, a device
DHCP moved), the routes (which internet link is in use), ARP and the ports' link state (for
gear that does not answer ping) and the log (the failover's own lines, logins). Everything
else works without it: leave mikrotik.dhcp_source empty.
On the router, a user that can read and nothing more, allowed only from lanowl's host
(here 192.168.88.5; older RouterOS calls a service's available-from address):
/user group add name=lanowl-ro policy=read,test,sniff,api,rest-api
/user add name=lanowl group=lanowl-ro address=192.168.88.5/32 password="a long one"
/ip service set www available-from=192.168.88.5/32
test and sniff let the model ping, traceroute and torch from the router when you ask it
to look into something; leave them out and it simply cannot. lanowl watches its own group:
a change to it that grants more than mikrotik.lanowl_policy is reported like any other
configuration change.
Then type its address (192.168.88.1; the setup fills in your gateway), the user and the
password in the first-run setup (or Settings → Add from the router's list), which also gives
the first two lines above with lanowl's address filled in. The third keeps WebFig over plain
HTTP from your own computer out too: yours to choose. By hand instead: in config.yaml, mikrotik.dhcp_source: "http://192.168.88.1" and mikrotik.credentials: router-read, and in secrets.yaml that
login: router-read: {user: lanowl, password: "a long one"}.
One kept connection instead of polling (recommended): the API over TLS. RouterOS will not self-sign a server certificate ("CA not found"), so a small local CA signs it:
/certificate add name=lanowl-ca common-name=lanowl-ca key-usage=key-cert-sign,crl-sign days-valid=3650
/certificate sign lanowl-ca
/certificate add name=lanowl-api common-name=192.168.88.1 subject-alt-name=IP:192.168.88.1 days-valid=3650
/certificate sign lanowl-api ca=lanowl-ca
/ip service set api-ssl certificate=lanowl-api available-from=192.168.88.5/32 disabled=no
and mikrotik.api.enabled: true. The certificate is self-signed, so lanowl trusts it by its
fingerprint: on the first connection the log says router API: pin this certificate: mikrotik.api.fingerprint: … — put that value in config.yaml. Until then the link is
encrypted but not authenticated.
If the router refuses the login, lanowl says so once — check the password and the user's
address= — and does not try again for 15 minutes, or until secrets.yaml changes: every
refused try is a login failure line in the router's log.
A failover script (dual WAN): put a comment on the main link's default route
(wan.path.route_comment), and give wan.watch.log_down_match / log_up_match the lines
your script logs when the main link goes down and up. A backup that switches its own uplink
on only when the router fails over to it (an LTE or radio link) is wan.path.backup_standby: true, and wan.standby reads it while the main link is down.
Each device is described once, in the inventory. Watching it needs only an address and its checks. What lanowl does with it besides is set on the device too:
- ip: 192.168.88.1
name: Router
kind: mikrotik # what it is
credentials: routers # its login, by name, in secrets.yaml
manage: [updates, upgrade, reboot, config, security, backup]
| feature | what lanowl does |
|---|---|
logs | reads its own log every hour; the owl tells what is not routine |
updates | checks its updates every morning |
upgrade | may propose installing them |
reboot | may propose a reboot |
restart | may propose restarting one of its listed services |
config | tells what changed in its configuration |
security | reviews what it exposes, every day |
backup | backs it up, monthly and before updates |
Built-in kinds and what each can do:
| kind | logs | updates | upgrade | reboot | restart | config | security | backup |
|---|---|---|---|---|---|---|---|---|
mikrotik | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
openwrt | ✓ | ✓ | ✓ | ✓ | ||||
linux | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
esxi | ✓ | ✓ | ✓ | ✓ | ||||
unifi | ✓ | ✓ | ✓ | |||||
homeassistant | ✓ | ✓ | ✓ | |||||
reolink | ✓ | |||||||
shelly | ✓ |
Any device can be rebooted through a Home Assistant button (a smart plug): give it a kind
(generic is enough), manage: [reboot] and reboot: {ha_button: button.nvr_plug_restart}.
A feature's options sit under its name: restart: {units: [mosquitto]},
backup: {paths: [etc, home]}, reboot: {risk: "...", hold_min: 10},
logs: {public: true, about: "..."}.
Logins (secrets.yaml) are a user with a password, lanowl's ssh key (key: true), or both
(the key logs in, the password is what sudo asks for). A user other than root needs sudo for
what reads or changes the system.
Every secret is in secrets.yaml, read again when it changes: the device logins, the
Telegram and Home Assistant tokens (tokens:), the logins lanowl reads the router and the
MQTT broker with (named by mikrotik.credentials and mqtt.credentials), and lanowl's ssh key
(ssh_key:). A deployment may give lanowl's own secrets in the environment instead
(LANOWL_TG_TOKEN, LANOWL_HA_TOKEN, LANOWL_MIKROTIK_USER/_PASS, LANOWL_MQTT_USER/_PASS,
LANOWL_SSH_KEY), or as Docker secrets through <name>_FILE. lanowl --check says where
each one comes from, never its value.
A kind of your own is a profile: config/profiles/<kind>.yaml, a command per operation
and a fixed parser for what it prints, never code. lanowl ships macos as one; copy it:
kind: macos
ops:
version: {cmd: "sw_vers -productName; sw_vers -productVersion", parse: lines}
updates: {cmd: "softwareupdate --list 2>&1", parse: {regex: '^\* Label: (?P<pkg>.+)$'}}
uptime: {cmd: "sysctl -n kern.boottime", parse: boottime}
reboot: {cmd: "shutdown -r now", sudo: true, back_s: 600}
config: {cmd: "scutil --get ComputerName; pmset -g custom"}
security: {cmd: "fdesetup status; csrutil status; spctl --status"}
Operations: version, updates, uptime, reboot, config, security, backup.
Parsers: text, lines, first_line, seconds, proc_uptime, boottime, {regex: ...}.
Any Ollama model with tool calling, set in config.yaml's model:
section (url, name). A larger model reasons better: a 27–35B model on a 32–64 GB machine
is comfortable. Without a model everything still works:
detection, alerts, digests, the dashboard. The switch on the dashboard (or /model off)
puts the owl to sleep.
SSH_ASKPASS, never argv.Host headers.AGPL-3.0. See LICENSE.
| ✓ |
generic |