File size: 6,937 Bytes
a9876bc fce80d1 a9876bc 181b8c1 a9876bc 181b8c1 fce80d1 181b8c1 a9876bc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | # mona-agent Architecture
How the open-source device daemon is built, and how it talks to the
mona.expert cloud.
## Overview
mona-agent is a **headless Node.js daemon** with two jobs:
1. **Execute** β run local tools (files, shell, network, system info) on
behalf of the cloud agent.
2. **Report** β stream device metrics and command results back to the cloud
in real time.
```
βββββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ
β Device (your machine) β β mona.expert cloud (SaaS) β
β β β β
β mona-agent β β Control plane API β
β ββββββββββββββββ ββββββββββββββ β β /api/v1/agent/verify β
β β ControlChannelββββΊβ tools/ β β β /api/v1/agent/stats β
β β (HTTPS + WS) β β files β β β /api/v1/agent/chat β¦ β
β β β β shell β β β β
β β metrics β β net β β β AI engine (the brain) β
β β commands β β sysinfo β β β Dashboard + device overview β
β ββββββββββββββββ ββββββββββββββ β β Key vault (AES-256) β
β β β β Audit log β
β βΌ β ββββββββββββββββββββββββββββββββ
β TUI (mona-agent gui) β
β headless daemon (mona-agent start) β
βββββββββββββββββββββββββββββββββββββββ
```
## Modules
| Module | Responsibility |
|---|---|
| `bin/mona-agent.js` | CLI entrypoint β `gui`, `start`, `login`, `connect`, `chat`, `exec` |
| `src/config.js` | Credentials, cloud endpoint resolution, platform detection |
| `src/cloud.js` | REST client for the control plane API (Bearer-auth) |
| `src/control.js` | Control channel: registration, command dispatch, metrics streaming |
| `src/api.js` | Local HTTP API + WebSocket (used by the local dashboard / desktop UI) |
| `src/tools/*` | The tool sandbox: `files`, `shell`, `net`, `sysinfo` |
| `src/tui.js` | Terminal dashboard β live log, scrollback, status bar |
| `src/log.js` | Structured logging (quiet in daemon mode) |
## Control channel lifecycle
1. **Boot** β `config.js` loads `~/.mona-agent/credentials.json` and
resolves the cloud endpoint (`MONA_CLOUD` or `https://agent.mona.expert`).
2. **Verify** β the daemon authenticates with `POST /api/v1/agent/verify`
(Bearer token). The server returns the agent identity and capabilities.
3. **Metrics** β every 10 seconds the daemon POSTs a snapshot to
`/api/v1/agent/stats`: CPU %, load average, memory, disk, uptime, host
and platform info.
4. **Commands** β on the Sngine control plane the device **polls the cloud
task queue** every 2 s (`GET /api/v1/agent/tasks`, claim, then report
via `POST /api/v1/agent/tasks/:id/result`). No inbound port, no
WebSocket upgrade required. On the Docker platform, commands arrive
over the WebSocket control channel instead.
5. **Resilience** β metrics streaming is independent of the WebSocket
channel. If the server cannot upgrade to WebSocket (e.g. shared hosting
behind LiteSpeed), the daemon transparently falls back to HTTPS polling
and keeps streaming β no reconnect storm.
## Agentic execution loop
Every task runs the same loop, wherever it came from (dashboard chat,
CLI, or the cloud queue):
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
β mona.expert brain β
β reason answer in text OR emit one tool call β
βββββββββββββββββ¬ββββββββββββββββββββββββ²βββββββββββ
task (HTTPS) β β tool result
βββββββββββββββββΌββββββββββββββββββββββββ΄βββββββββββ
β mona-agent β
β execute tool locally (sysinfo|shell|files|net) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
- Up to **8 tool steps per task** β the loop ends when the brain answers
in plain text.
- Tool protocol is provider-agnostic: the brain replies with a single
JSON object `{"tool":"<name>","args":{...}}` or plain text. No
provider-specific function-calling plumbing.
- Every step is reported to the cloud (`tool.call` / `tool.result`) and
appears live in the dashboard activity feed.
- The final answer is stored in the cloud conversation β history survives
restarts and is visible from every client.
## Metrics pipeline (HTTP-first)
The client was designed so that **metrics never depend on a WebSocket
upgrade**:
- Every 10 s: `POST /api/v1/agent/stats` with CPU, memory, disk, load,
uptime, hostname, platform, arch, version, IP.
- The cloud keeps the latest snapshot plus a rolling 180-point history per
device; the dashboard polls every 3 s β effectively live.
- A device is shown as **online** when its last snapshot is β€ 20 s old.
## Security model (client side)
- **No AI provider keys on the device.** Only a mona.expert device token is
stored (`~/.mona-agent/credentials.json`, mode 0600).
- **Guarded shell** β commands run through an allowlist; dangerous patterns
are blocked before execution.
- **Confined files tool** β reads/writes are limited to safe, allowed paths.
- **Egress-only** β the daemon opens outbound connections only; it listens
on localhost only (for the local dashboard).
See [SECURITY.md](../SECURITY.md) for the full model and disclosure policy.
## Why HTTPS polling instead of WebSockets?
The control plane runs on shared hosting (LiteSpeed), where WebSocket
proxying is not always available and long-running Node processes are not
possible. The client therefore uses:
- **WebSocket** when the server upgrades it (self-hosted / VPS setups),
- **HTTPS polling + streaming metrics** everywhere else.
One code path, two transports β the daemon decides at runtime.
|