Contributing to the Documentation¶
Architecture¶
Mnemosyne assembles documentation from all three repos into a single MkDocs Material site.
┌────────────────────────┐ ┌──────────────────────────┐
│ aletheia/repo/docs/ │ │ │
│ aletheia/repo/ │───▶│ │
│ guidelines/ │ │ build.sh (assembler) │
├────────────────────────┤ │ │
│ helios/repo/docs/ │───▶│ + extract_infra.py │
│ helios/repo/content/ │ │ (config → snippets) │
├────────────────────────┤ │ │
│ aether/repo/docs/ │───▶│ + mkdocs build │
│ aether/repo/*.md │ │ │
└────────────────────────┘ └────────────┬─────────────┘
│
▼
/opt/docker/mnemosyne/site/
→ https://docs.groupe-suffren.com
- Config source (tracked in git):
aether/repo/mnemosyne/ - Runtime output (not tracked):
/opt/docker/mnemosyne/ - Served by nginx at
docs.groupe-suffren.com
Build and Preview¶
cd /opt/docker/aether/repo
make docs-build # assemble + build static site
make docs-serve # assemble + dev server on http://localhost:8888 (live reload)
make docs-deploy # build + deploy nginx config for the site
make docs-check # validate alert→runbook coverage
make docs-serve is the fastest inner loop — edit a markdown file, save, reload the browser.
Where to Put a New Page¶
| Topic | Source location | Appears in nav under |
|---|---|---|
| Developer / infra ops | aether/repo/docs/maintenance/ |
Developer Guide → Maintenance |
| Monitoring | aether/repo/docs/monitoring/ |
Developer Guide → Aether → Monitoring |
| Aether dev conventions | aether/repo/docs/development/ |
(add to mkdocs.yml nav) |
| Aletheia dev / guidelines | aletheia/repo/docs/ or aletheia/repo/guidelines/ |
Developer Guide → Aletheia |
| Helios dev / content | helios/repo/docs/ or helios/repo/content/ |
Developer Guide → Helios |
| French user guide | aletheia/repo/docs/guide-utilisateur/ |
Guide Utilisateur |
| French admin guide | aletheia/repo/docs/guide-admin/ |
Guide Administrateur |
After adding a markdown file, also add it to the nav: block in aether/repo/mnemosyne/mkdocs.yml
so it shows up in the navigation.
Convention: Code Comments Hold the "Why"¶
The authoritative source for why a config value exists is a comment in the config file, not the documentation. This keeps rationale co-located with the setting it explains.
Good:
# 1-hour ban is long enough to deter bots but short enough that a
# self-ban doesn't require on-call intervention (just wait it out).
bantime = 1h
Bad (rationale only in docs):
When editing a config file, enrich the comments if you change a value or notice missing rationale. Future readers — including Claude — use those comments to judge whether a change is safe.
Convention: Docs Include, Don't Duplicate¶
Factual data (container names, versions, memory limits, ports, retention values, alert names, thresholds) must never be hardcoded in docs. Use auto-generated snippets instead.
Good:
## Monitoring Stack
<!-- Auto-generated from monitoring/docker-compose.yml -->
<!-- Auto-generated by extract_infra.py — do not edit -->
| Container | Image | Memory Limit |
|---|---|---|
| `monitoring_prometheus` | `prom/prometheus:v3.10.0` | 1024m |
| `monitoring_alertmanager` | `prom/alertmanager:v0.28.1` | 128m |
| `monitoring_grafana` | `grafana/grafana:12.4` | 384m |
| `monitoring_node_exporter` | `prom/node-exporter:v1.10.2` | 64m |
| `monitoring_cadvisor` | `gcr.io/cadvisor/cadvisor:v0.55.1` | 256m |
| `monitoring_postgres_exporter` | `prometheuscommunity/postgres-exporter:v0.19.1` | 48m |
| `monitoring_redis_exporter` | `oliver006/redis_exporter:v1.82.0` | 48m |
| `monitoring_blackbox_exporter` | `prom/blackbox-exporter:v0.26.0` | 64m |
| `monitoring_loki` | `grafana/loki:3.6` | 384m |
| `monitoring_alloy` | `grafana/alloy:v1.14.1` | 384m |
| `monitoring_nginx_exporter` | `nginx/nginx-prometheus-exporter:1.4` | 32m |
| `monitoring_celery_exporter` | `danihodovic/celery-exporter:0.10.10` | 128m |
Bad:
## Monitoring Stack
| Container | Image | Memory |
|---|---|---|
| prometheus | prom/prometheus:v3.10.0 | 384m |
...
The first pattern auto-updates when configs change. The second drifts silently.
Available snippets¶
Generated into _generated/ on every make docs-build. Include with --8<-- "_generated/<name>.md".
| Snippet | Source |
|---|---|
monitoring-stack.md |
monitoring/docker-compose.yml |
shared-services.md |
shared/docker-compose.yml |
alert-catalog.md |
monitoring/prometheus/alerts/*.rules.yml |
backup-scope.md |
backups/scripts/backup.sh |
makefile-targets.md |
Makefile help text |
retention-periods.md |
multiple (docker-compose, loki, backup) |
monitored-domains.md |
monitoring/prometheus/prometheus.yml |
ssh-config.md |
security/sshd-00-hardening.conf |
fail2ban-jails.md |
security/fail2ban-aletheia.conf |
kernel-hardening.md |
security/sysctl-hardening.conf |
firewall-rules.md |
security/iptables-setup-docker.sh |
Adding a new extractor¶
If you need a snippet for data that's not yet covered:
- Add a function to
mnemosyne/scripts/extract_infra.pyfollowing the existing pattern - Register it in the
EXTRACTORSdict at the bottom of the file - Run
python3 mnemosyne/scripts/extract_infra.py <repo> /tmp/checkto verify output - Include the new snippet in the relevant doc via
--8<--
Convention: Alert Rules Need Runbooks¶
Every alert defined in monitoring/prometheus/alerts/*.rules.yml must have a matching entry in
docs/monitoring/runbooks.md. The make docs-check target validates this, and the pre-commit
hook runs it automatically when alert rule files are staged.
When adding a new alert rule:
- Define the rule in the appropriate
*.rules.ymlfile - Add a runbook section to
docs/monitoring/runbooks.md— at minimum, what the alert means and the first thing to check - Commit together. If you forget step 2, the pre-commit hook will warn.
Convention: Alert Rules Reference Real Metrics¶
make docs-check also diffs every metric name an alert expr: references against
the metric names live Prometheus actually has (/api/v1/label/__name__/values).
This catches the class make test-alerts structurally cannot: a rule built on a
metric nothing emits — a wrong exporter name, or a metric that needs a feature
flag no one turned on — passes every promtool test (the test author invents the
series from the same wrong assumption) while being dead in production. Three
rules have been found dead exactly this way.
The check (mnemosyne/scripts/check_metric_existence.py) needs a running
monitoring_prometheus, so it runs for real on the host / in the pre-commit path
and skips loudly — never silent-passes — when Prometheus is unreachable
(a laptop, offline CI). A metric that is legitimately absent in the steady state
(only appears after an event or feature flag) goes in the script's ALLOWLIST
with a reason; treat that as a tracked deferral to remove once the metric exists,
not a resolution.
Markdown Conventions¶
- Heading hierarchy: top-level
#matches the page title once. Use##for sections. - Admonitions: use
!!! warning,!!! danger,!!! note,!!! tip,!!! info. Reservedangerfor data-loss or security risks. - Code blocks: always specify the language (
```bash,```yaml,```markdown) for syntax highlighting. - Commands: show the full command with the directory context if it matters.
Prefer
cd /opt/docker/aether/repo && make fooovermake foo. - File paths: use backticks for inline paths (
`docs/maintenance/backups.md`). - Links: use relative markdown links within the same section (
[backups](backups.md)); absolute paths only for external references.
Testing Locally¶
Always preview changes before committing:
The dev server re-assembles on every file change, so edits show up immediately.
Build Warnings¶
make docs-build emits warnings for broken links, missing nav entries, and bad references.
Some are pre-existing (cross-repo archive links) but don't add new ones. Fix new warnings
before committing.
Enforcement Summary¶
| Rule | Enforced by |
|---|---|
| Every alert has a runbook | make docs-check + pre-commit hook |
| Every alert references a metric that exists | make docs-check metric-existence check (needs live Prometheus) |
| Factual data comes from configs, not hardcoded | Code review + docs_check.sh drift detection |
| Config rationale lives in comments | Code review |
| New page appears in nav | make docs-build warnings |
| Links resolve | make docs-build warnings |