diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e2cc73e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Monlet contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 1a3366f..5bb4f24 100644 --- a/README.md +++ b/README.md @@ -1,62 +1,149 @@ +English | [Русский](README.ru.md) + # Monlet -Monlet is a lightweight event and check monitoring system. +Monlet 0.1.0 is a small self-hosted monitoring system for local checks, host +heartbeats, incidents, and notification delivery state. -It is split into three independent applications: +![Monlet agents dashboard](docs/assets/readme/agents.png) -- `agent/` - a small Go binary installed on monitored hosts. -- `server/` - a Python/FastAPI backend that owns inventory, state, incidents, and notifications. -- `web/` - a Next.js dashboard with agent admission controls. +Monlet is built for the gap between ad-hoc shell checks and a full observability +platform. Agents run checks on the hosts where the facts live, push only +structured observations to the server, and leave incident and notification +lifecycle decisions to one central backend. -All three applications are implemented and run together via Docker Compose. The current release covers agent ingestion with operator admission, server-owned incident lifecycle and notifier outbox, a Next.js dashboard, and partitioned event retention. +## Why Monlet? -## Scope +Simple infrastructure often starts with cron jobs, shell probes, and a chat +webhook. That works until you need to answer basic operational questions: -Monlet v1 focuses on local checks, central state, and simple visibility: +- Which hosts are alive, stale, or dead? +- Which local checks are currently degraded? +- Did this failure open an incident, resolve one, or get deduplicated? +- Were notifications sent, retried, or failed? +- Can agents survive a server outage without creating duplicate events? -- agents run local checks from TOML config; -- agents expose Prometheus metrics and/or push facts to the server; -- server ingests heartbeats and check events idempotently; -- server owns current state, incident lifecycle, and notifier retries; -- web UI reads server APIs and does not mutate state. +Monlet keeps that model explicit without adding remote command execution, +remote config push, or a heavyweight incident-management platform. -## Non-goals for v1 +## What It Does -- remote command execution; -- remote config push; -- full RBAC; -- multi-tenant enterprise model; -- complex silences or inhibition engine; -- Grafana replacement; -- long-term log storage; -- full incident management platform; -- Kubernetes operator; -- plugin marketplace; -- distributed server cluster. +- A Go agent runs configured local commands from TOML. +- Agents send heartbeats and check events to the server over the `/api/v1` API. +- The FastAPI server owns inventory, current check state, incidents, retention, + and notifier outbox retries. +- The Next.js UI shows agents, checks, incidents, events, and notification + delivery state. +- Operator admission is required before a new agent key can affect monitoring + state. +- Server and agents expose Prometheus metrics for the monitoring system itself. -## Repository Map +## Screenshots -- `docs/` - architecture, ADRs, development, and operations docs. -- `plan/` - stage workflow and exit checkpoints. -- `api/` - versioned OpenAPI contract. -- `agent/` - Go agent: scheduler, runner, spool, metrics. -- `server/` - Python/FastAPI backend: ingestion, detector, notifier outbox. -- `web/` - Next.js dashboard and agent admission UI. -- `deploy/` - local and observability deployment examples. -- `examples/` - example checks and configs. +Agents and admission state: -## Start Here +![Monlet agents page](docs/assets/readme/agents.png) -Read in this order: +Current check states: -1. `docs/README.md` -2. `docs/architecture/overview.md` -3. `ROADMAP.md` -4. `TODO.md` -5. `plan/README.md` -6. `AGENTS.md` -7. `CLAUDE.md` +![Monlet checks page](docs/assets/readme/checks.png) -## Current Status +Open and resolved incidents: -Active development. Stages 0–6 are implemented. Run the stack via `docker compose up --build` from `deploy/`. See `docs/operations/deployment.md` and `docs/ops/` runbooks. +![Monlet incidents page](docs/assets/readme/incidents.png) + +Notifier outbox state: + +![Monlet outbox page](docs/assets/readme/outbox.png) + +## Features in 0.1.0 + +- Local command checks with `ok`, `warning`, `critical`, and `unknown` states. +- Heartbeat-based agent liveness with alive, stale, and dead status. +- Durable on-disk agent spool for server outages. +- Idempotent event ingestion and duplicate-safe replay. +- Server-owned incident open/resolve lifecycle. +- Notification outbox with retry and failure state. +- Debug, webhook, Telegram, and Alertmanager notifier implementations. +- Agent admission and blacklist controls. +- Partitioned PostgreSQL event storage and bounded retention. +- Docker Compose local stack and showcase stand. +- Prometheus metrics for server and agent runtime behavior. + +## Quick Start + +Run the local stack: + +```sh +cd deploy +MONLET_AUTH_TOKEN=$(openssl rand -hex 16) docker compose up --build +``` + +Services: + +- Web UI: +- Server API: +- Readiness: +- Metrics: + +Run the full demo stand: + +```sh +SHOWCASE_KEEP=1 bash deploy/e2e-showcase.sh +``` + +The showcase starts PostgreSQL, the server, the web UI, a mock webhook, and +several demo agents. It drives mixed check states, liveness transitions, +resolved incidents, notifier retries/failures, and spool replay. + +## Architecture + +Monlet is a monorepo with three independent applications: + +- `agent/` - Go binary installed on monitored hosts. +- `server/` - Python/FastAPI backend with PostgreSQL storage. +- `web/` - Next.js operator dashboard. + +The server owns incident and notification lifecycle. The agent sends facts only. +The web UI is read-only for monitoring state; agent admission and blacklist +controls are the v1 mutation surface. + +Public API contracts live in `api/openapi.yaml`. Design and operations docs live +under `docs/`. + +## Non-Goals + +Monlet 0.1.0 is intentionally not: + +- a remote command runner; +- a remote config-push system; +- a Grafana replacement; +- a full incident-management platform; +- a multi-tenant RBAC product; +- a Kubernetes operator; +- a distributed server cluster. + +## Development + +Start with: + +1. `deploy/README.md` +2. `agent/README.md` +3. `server/README.md` +4. `web/README.md` +5. `api/README.md` + +Dependency caches and virtual environments are kept inside the repository. See +the component READMEs for current local development commands. + +## Status + +Monlet is active early-stage software. The 0.1.0 release is usable for local +development, demos, and controlled internal deployments. Internal contracts may +still change while the public API remains versioned under `/api/v1`. + +`0.1.0` is the product release version. `/api/v1` is the API namespace. + +## License + +MIT. diff --git a/README.ru.md b/README.ru.md new file mode 100644 index 0000000..99d0334 --- /dev/null +++ b/README.ru.md @@ -0,0 +1,150 @@ +[English](README.md) | Русский + +# Monlet + +Monlet 0.1.0 - небольшой self-hosted мониторинг для локальных проверок, +heartbeat-состояния хостов, инцидентов и доставки уведомлений. + +![Панель агентов Monlet](docs/assets/readme/agents.png) + +Monlet закрывает промежуток между набором shell-проверок и полноценной +observability-платформой. Агенты запускают проверки там, где живут факты, +отправляют на сервер только структурированные наблюдения, а жизненный цикл +инцидентов и уведомлений остаётся в одном центральном backend. + +## Зачем Monlet? + +Простая инфраструктура часто начинается с cron-задач, shell-проб и webhook в +чат. Это работает, пока не нужно быстро ответить на базовые операционные +вопросы: + +- какие хосты alive, stale или dead; +- какие локальные проверки сейчас degraded; +- открылся ли инцидент, закрылся ли он или событие было deduplicated; +- ушло ли уведомление, попало ли в retry или failed; +- переживут ли агенты outage сервера без дублей событий. + +Monlet делает эту модель явной, но не добавляет remote command execution, +remote config push или тяжёлую incident-management платформу. + +## Что он делает + +- Go agent запускает локальные команды из TOML-конфига. +- Агенты отправляют heartbeats и check events на сервер через `/api/v1`. +- FastAPI server владеет inventory, текущим состоянием checks, incidents, + retention и retry для notifier outbox. +- Next.js UI показывает agents, checks, incidents, events и delivery state + уведомлений. +- Новый agent key должен пройти operator admission, прежде чем сможет влиять на + monitoring state. +- Server и agents экспортируют Prometheus metrics для самого Monlet. + +## Скриншоты + +Agents и admission state: + +![Страница агентов Monlet](docs/assets/readme/agents.png) + +Текущие check states: + +![Страница проверок Monlet](docs/assets/readme/checks.png) + +Open и resolved incidents: + +![Страница инцидентов Monlet](docs/assets/readme/incidents.png) + +Состояние notifier outbox: + +![Страница outbox Monlet](docs/assets/readme/outbox.png) + +## Возможности в 0.1.0 + +- Локальные command checks со статусами `ok`, `warning`, `critical` и `unknown`. +- Agent liveness по heartbeat: alive, stale и dead. +- Durable on-disk spool в агенте на случай outage сервера. +- Idempotent event ingestion и replay без дублей. +- Server-owned lifecycle для открытия и закрытия incidents. +- Notification outbox со статусами retry и failure. +- Debug, webhook, Telegram и Alertmanager notifier implementations. +- Agent admission и blacklist controls. +- Partitioned PostgreSQL event storage и bounded retention. +- Docker Compose local stack и showcase stand. +- Prometheus metrics для server и agent runtime behavior. + +## Быстрый старт + +Запустить локальный stack: + +```sh +cd deploy +MONLET_AUTH_TOKEN=$(openssl rand -hex 16) docker compose up --build +``` + +Сервисы: + +- Web UI: +- Server API: +- Readiness: +- Metrics: + +Запустить полный demo stand: + +```sh +SHOWCASE_KEEP=1 bash deploy/e2e-showcase.sh +``` + +Showcase поднимает PostgreSQL, server, web UI, mock webhook и несколько demo +agents. Он прогоняет mixed check states, liveness transitions, resolved +incidents, notifier retries/failures и spool replay. + +## Архитектура + +Monlet - monorepo с тремя независимыми приложениями: + +- `agent/` - Go binary для monitored hosts. +- `server/` - Python/FastAPI backend с PostgreSQL storage. +- `web/` - Next.js operator dashboard. + +Server владеет lifecycle инцидентов и уведомлений. Agent отправляет только +факты. Web UI read-only для monitoring state; agent admission и blacklist +controls - mutation surface для v1. + +Публичный API contract лежит в `api/openapi.yaml`. Design и operations docs +лежат в `docs/`. + +## Не цели + +Monlet 0.1.0 намеренно не является: + +- remote command runner; +- системой remote config push; +- заменой Grafana; +- полноценной incident-management платформой; +- multi-tenant RBAC продуктом; +- Kubernetes operator; +- distributed server cluster. + +## Разработка + +Начинать отсюда: + +1. `deploy/README.md` +2. `agent/README.md` +3. `server/README.md` +4. `web/README.md` +5. `api/README.md` + +Dependency caches и virtual environments хранятся внутри репозитория. Актуальные +команды local development описаны в component README. + +## Статус + +Monlet - активный early-stage проект. Release 0.1.0 пригоден для local +development, demos и controlled internal deployments. Internal contracts ещё +могут меняться, при этом public API остаётся versioned under `/api/v1`. + +`0.1.0` - версия product release. `/api/v1` - namespace API. + +## Лицензия + +MIT. diff --git a/agent/README.md b/agent/README.md index 4230f12..796af9b 100644 --- a/agent/README.md +++ b/agent/README.md @@ -54,10 +54,10 @@ resource_limits = { cpu_time = "5s", memory = "256MiB", open_files = 128 } executes it as `/bin/sh -c ` on the host where the agent runs. - Local-config only. Commands are loaded from the agent's TOML file on disk. - The server does not push config and does not execute remote commands; see - `docs/architecture/security.md#no-remote-execution`. Anyone able to edit the - agent config or replace the agent binary already has local root-equivalent - power, so shell execution adds no new attack surface beyond that file. + The server does not push config and does not execute remote commands. Anyone + able to edit the agent config or replace the agent binary already has local + root-equivalent power, so shell execution adds no new attack surface beyond + that file. - Argv arrays (`command = ["..."]`) are intentionally rejected by config validation. Use a shell string for both short and long commands. - Quoting and escaping are the operator's responsibility. Triple-quoted diff --git a/api/openapi.yaml b/api/openapi.yaml index 8b67665..5b88019 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -1,9 +1,9 @@ openapi: 3.1.0 info: title: Monlet API - version: 1.0.0 + version: 0.1.0 description: | - Monlet v1 API contract. Stage 1 frozen. + Monlet 0.1.0 API contract. The API namespace is `/api/v1`. All endpoints under `/api/v1`. Authentication is split (ADR-0007): diff --git a/deploy/README.md b/deploy/README.md index 5efc062..ec8bcfd 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -72,6 +72,6 @@ for demo/e2e only — production deploys the Go binary under systemd. - `docker-compose.showcase.yml` — override that adds demo agents + mock webhook. - `docker/agent.Dockerfile` — demo/e2e agent image (not for production). - `showcase/` — demo agent configs, check scripts, and mock webhook. -- `e2e-showcase.sh` — full showcase runner (Stage 6.1). +- `e2e-showcase.sh` — full showcase runner. -Docker images install Python/Node project dependencies inside the image; host venvs are never mounted (see `AGENTS.md`). +Docker images install Python/Node project dependencies inside the image; host venvs are never mounted. diff --git a/docs/assets/readme/agents.png b/docs/assets/readme/agents.png new file mode 100644 index 0000000..b5ea39b Binary files /dev/null and b/docs/assets/readme/agents.png differ diff --git a/docs/assets/readme/checks.png b/docs/assets/readme/checks.png new file mode 100644 index 0000000..95fe1ef Binary files /dev/null and b/docs/assets/readme/checks.png differ diff --git a/docs/assets/readme/incidents.png b/docs/assets/readme/incidents.png new file mode 100644 index 0000000..eb7d85d Binary files /dev/null and b/docs/assets/readme/incidents.png differ diff --git a/docs/assets/readme/outbox.png b/docs/assets/readme/outbox.png new file mode 100644 index 0000000..396cad1 Binary files /dev/null and b/docs/assets/readme/outbox.png differ diff --git a/examples/README.md b/examples/README.md index af2a020..bc3723a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,5 +1,3 @@ # Examples Examples for checks, configs, and local demos. - -Stage 0 includes only placeholders.