mona-agent / docs /ARCHITECTURE.md
mo
feat: enterprise capability expansion β€” app control, browser control, background execution
fce80d1
|
Raw
History Blame Contribute Delete
6.94 kB

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 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.