Contributing to Meerkat
Thanks for helping Meerkat keep watch. Contributions of every size are welcome, from typo fixes to new monitors, notifiers and repair actions.
Where to start
- Issues labelled
good first issueare scoped to one evening. - Issues labelled
pluginare self-contained monitors, notifiers or actions (see docs/ROADMAP.md). - For anything larger, open a feature request first so the design can be agreed before you write code.
Project layout
| Path | What lives there |
|---|---|
app.py |
Entry point: loads config, starts background monitors, runs the check loop |
monitors/alerts.py |
AlertManager: dedupe, duration, cooldown, recovery messages |
monitors/<check>.py |
One file per periodic check (cpu, disk, sites, network, ...) |
monitors/docker.py, autofix.py, commands.py |
Background threads: Docker events, auto-heal, Telegram commands |
monitors/api.py |
Python REST API, Prometheus /metrics, fallback dashboard |
src/ |
Next.js dashboard: components/ui primitives, components/shell app frame, components/pages screens, lib data and copy |
website/ |
Public website, docs and live demo (deployed to GitHub Pages) |
e2e/ |
Playwright end-to-end and accessibility tests |
tests/ |
unittest suite with in-memory fakes for state, history and notifiers |
docs/ |
Architecture, roadmap and competitive analysis |
Development setup
python -m venv .venv && . .venv/bin/activate
pip install -r requirements-dev.txt
npm ci
Run the monitor API and the web app in two terminals:
MEERKAT_API_PORT=8711 python app.py
npm run dev # http://127.0.0.1:8710
Telegram is optional; without a token Meerkat logs the messages it would have sent.
Checks to run before opening a PR
ruff check .
mypy --ignore-missing-imports app.py monitors
python -m unittest discover -v tests
npm run build # only if you changed src/
CI runs the same commands plus a Docker image build.
Adding a new periodic check
A check is a function with the signature check_<name>(config, state, alerts) -> None:
- Read its settings from
config.get("<name>", {}). - Store the latest reading with
state.set("metrics.<name>...", value)so the API can show it. - Report the condition with
alerts.condition(alert_id=..., active=..., ...)for threshold alerts, oralerts.state_change(...)for "value changed" alerts. Never call the notifier directly;AlertManagerhandles dedupe, duration, cooldown and recovery. - Register it in the
checkslist inapp.pyand validate new config keys inmonitors/config.py. - Add tests using the
FakeState/FakeHistory/FakeNotifierpattern intests/test_alerts.py.
A formal plugin API (entry points with config schemas) is planned. See docs/ARCHITECTURE.md.
UI work
The dashboard has a written design contract: read DESIGN.md first. It explains who Meerkat is for, the principles, the invariants that must not change, the Savanna tokens and the components to reuse.
npm run dev:demo # dashboard with simulated data, no backend needed
npm run check:tokens # no color literals outside src/styles/tokens.css
npm run check:contrast # every token pair meets WCAG AA
npm run build:demo && npx playwright test # e2e + axe accessibility on desktop and mobile
Attach light, dark and mobile screenshots to UI pull requests. Changes to the design contract itself go through a design-rfc issue.
Style
- Python 3.12, type hints on public functions,
ruffclean. - Match the surrounding code: small modules, plain functions, result dicts
{"ok": bool, "message" | "error": str}for actions. - Anything that changes the host (restarts, interface bounces) must respect
actions.enabled,actions.blocked_containersand the action token.
Commit and PR conventions
- Use Conventional Commits (
feat:,fix:,docs:,test:,chore:) so release notes can be generated. - Keep one logical change per PR, and include a test for new behaviour.
- Fill in the PR template.
Licensing
Meerkat is licensed under Apache-2.0. By submitting a contribution you agree it is licensed under the same terms (Apache-2.0 section 5).
Code of conduct
This project follows the Contributor Covenant. Be kind.