mo
feat: enterprise capability expansion β app control, browser control, background execution
fce80d1 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:
- Execute β run local tools (files, shell, network, system info) on behalf of the cloud agent.
- 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
- Boot β
config.jsloads~/.mona-agent/credentials.jsonand resolves the cloud endpoint (MONA_CLOUDorhttps://agent.mona.expert). - Verify β the daemon authenticates with
POST /api/v1/agent/verify(Bearer token). The server returns the agent identity and capabilities. - Metrics β every 10 seconds the daemon POSTs a snapshot to
/api/v1/agent/stats: CPU %, load average, memory, disk, uptime, host and platform info. - Commands β on the Sngine control plane the device polls the cloud
task queue every 2 s (
GET /api/v1/agent/tasks, claim, then report viaPOST /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. - 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/statswith 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 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.