Skip to content

Applications — track apps + restart EAT

The Applications system does three things:

  1. Tracks what should be running on a host (per app: type, identifier, expected state)
  2. Compares the actual state from inventory every 60 s against the expected
  3. Gives you one button to sign a TOTP-gated restart EAT for a specific app

In the dashboard — registering an app

  1. Sidebar → Applications (under ACTION)
  2. Top-right + Track an app button
  3. Fill in:
    • Agent — which host should run this app
    • Typesystemd unit / docker container / docker compose service / raw process
    • Name — free label for lists (e.g. “MyApp web”)
    • Identifier — concrete identifier per type:
      • systemd: unit name (nginx.service)
      • docker: container name (mycontainer)
      • compose: <project>::<service> (flowd_dev::app)
      • process: absolute path to binary (/opt/myapp/start.sh)
  4. Documentation (optional but recommended for MSP handover):
    • Owner email — who to ping when the app breaks
    • Runbook URL — link to internal docs
    • Notes — free text (deploy pipeline, dependencies, slack channel)
  5. Under Discovered on host you see the live list of systemd units + docker containers the agent just reported. Click a row to auto-fill Type + Identifier + Name
  6. Click the black Track this app button at the bottom

From now on: liveness worker starts within 60 s, expected state = running (you can change this later on the app’s detail page).

What happens next (per app, every 60 s)

PhaseWhat
1. observeWorker reads current state from the LATEST inventory snapshot of the agent
2. compareexpected_state vs observed (running/stopped/unknown)
3. mismatchOn difference: emit app.state_mismatch signal + bump consecutive_mismatch counter
4. alertAfter 3 consecutive mismatches: alert with warning severity
5. dashboardApp row shows red pixel + last_state_change timestamp

unknown (worker finds no row for this identifier in the latest snapshot) does not count as a mismatch — agent may be briefly down or it’s a new deployment. Only counts after four consecutive unknowns.

Restart via EAT (Emergency Action Token)

Every app row has a Restart button. Click → TOTP prompt → hub signs a Level 2 Ed25519 EAT and pushes via WebSocket to the agent. Agent runs monsys-action restart-app <id> as dedicated user (no permanent root) and the wrapper picks:

  • systemd: systemctl restart <unit>
  • docker: docker restart <container>
  • compose: docker compose -p <project> restart <service>
  • process: the configured restart_command (absolute path required)

Result (exit_code + stdout/stderr) gets pushed back and lands in audit_log + transparency_log as evidence — the same flow as every other EAT action on the platform.

Tags + grouping

Apps inherit the tags of their agent. An app on a host with tag production-db shows up in every filter/SLA engine that filters on that tag. Want to group apps per environment? Tag the host (not the app).

Or via API (advanced — for automation)

Terminal window
# List all apps for a tenant
curl https://app.monsys.ai/api/v1/apps \
-H "Authorization: Bearer $TOKEN"
# Register an app
curl -X POST https://app.monsys.ai/api/v1/apps \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "<agent_uuid>",
"name": "MyApp web",
"app_type": "docker",
"identifier": "eurooffice",
"owner_email": "jeroen@gotrust.be",
"runbook_url": "https://wiki.example.com/runbooks/myapp",
"notes": "Deploys via GitOps · slack #platform · depends on redis-prod"
}'
# Change expected_state
curl -X PATCH https://app.monsys.ai/api/v1/apps/<id> \
-H "Authorization: Bearer $TOKEN" \
-d '{"expected_state": "stopped"}'
# Restart (requires TOTP header)
curl -X POST https://app.monsys.ai/api/v1/apps/<id>/restart \
-H "Authorization: Bearer $TOKEN" \
-H "X-TOTP-Code: 123456" \
-d '{"reason": "Memory leak per ticket TKT-9001"}'
# Stop tracking
curl -X DELETE https://app.monsys.ai/api/v1/apps/<id> \
-H "Authorization: Bearer $TOKEN"

Discovered list is empty — what now

  • Agent hasn’t shipped extended inventory yet: new agents push it every 6 h (default inventory_interval_secs). Wait or trigger manually with monsys-agent --once on the host
  • Agent is offline: check /agents/<id>last_seen_at. Stale agents don’t report
  • Agent is on a binary older than v0.1.0+20260519: extended inventory has shipped since then. Trigger auto-update or upgrade manually
  • Bug fixed on 2026-05-20: discovery query was missing latest-snapshot scope AND tenant guard. Both now in the hub. Hard-refresh your browser after this fix

What does NOT belong on this page

  • Inventory itself (all services + packages + ports) → see Inventory tab on the agent detail page
  • Application CVE scanning (npm/pip/composer/go deps) → see Application CVEs
  • App-level alerts (cpu/mem/restart-count) → see Alert builder