From 8f47151a487fa640bd1883240bc2246d3c4fac1a Mon Sep 17 00:00:00 2001 From: Otto Date: Tue, 26 May 2026 23:47:07 +0200 Subject: [PATCH] docs(systemd): fix paths + add dashboard smoke + vendor units --- RUNBOOK.md | 12 +++++------ docs/RELEASE_CHECKLIST.md | 10 +++++----- scripts/smoke_dashboard.sh | 20 +++++++++++++++++++ systemd/openclaw-memory-archive.service | 9 +++++++++ systemd/openclaw-memory-archive.timer | 10 ++++++++++ systemd/openclaw-secondbrain-backup.service | 8 ++++++++ systemd/openclaw-secondbrain-backup.timer | 10 ++++++++++ .../openclaw-secondbrain-dashboard.service | 15 ++++++++++++++ ...enclaw-secondbrain-export-obsidian.service | 8 ++++++++ ...openclaw-secondbrain-export-obsidian.timer | 10 ++++++++++ .../openclaw-secondbrain-heartbeat.service | 8 ++++++++ systemd/openclaw-secondbrain-heartbeat.timer | 11 ++++++++++ ...openclaw-secondbrain-index-vectors.service | 10 ++++++++++ .../openclaw-secondbrain-index-vectors.timer | 10 ++++++++++ ...openclaw-secondbrain-ingest-memory.service | 8 ++++++++ .../openclaw-secondbrain-ingest-memory.timer | 10 ++++++++++ ...enclaw-secondbrain-ingest-obsidian.service | 8 ++++++++ ...openclaw-secondbrain-ingest-obsidian.timer | 10 ++++++++++ systemd/openclaw-secondbrain-notify@.service | 8 ++++++++ ...nclaw-secondbrain-proactive-search.service | 10 ++++++++++ ...penclaw-secondbrain-proactive-search.timer | 11 ++++++++++ systemd/openclaw-secondbrain-review.service | 8 ++++++++ systemd/openclaw-secondbrain-review.timer | 10 ++++++++++ systemd/openclaw-secondbrain-task@.service | 13 ++++++++++++ 24 files changed, 236 insertions(+), 11 deletions(-) create mode 100755 scripts/smoke_dashboard.sh create mode 100644 systemd/openclaw-memory-archive.service create mode 100644 systemd/openclaw-memory-archive.timer create mode 100644 systemd/openclaw-secondbrain-backup.service create mode 100644 systemd/openclaw-secondbrain-backup.timer create mode 100644 systemd/openclaw-secondbrain-dashboard.service create mode 100644 systemd/openclaw-secondbrain-export-obsidian.service create mode 100644 systemd/openclaw-secondbrain-export-obsidian.timer create mode 100644 systemd/openclaw-secondbrain-heartbeat.service create mode 100644 systemd/openclaw-secondbrain-heartbeat.timer create mode 100644 systemd/openclaw-secondbrain-index-vectors.service create mode 100644 systemd/openclaw-secondbrain-index-vectors.timer create mode 100644 systemd/openclaw-secondbrain-ingest-memory.service create mode 100644 systemd/openclaw-secondbrain-ingest-memory.timer create mode 100644 systemd/openclaw-secondbrain-ingest-obsidian.service create mode 100644 systemd/openclaw-secondbrain-ingest-obsidian.timer create mode 100644 systemd/openclaw-secondbrain-notify@.service create mode 100644 systemd/openclaw-secondbrain-proactive-search.service create mode 100644 systemd/openclaw-secondbrain-proactive-search.timer create mode 100644 systemd/openclaw-secondbrain-review.service create mode 100644 systemd/openclaw-secondbrain-review.timer create mode 100644 systemd/openclaw-secondbrain-task@.service diff --git a/RUNBOOK.md b/RUNBOOK.md index 3702bc7..33db4a4 100644 --- a/RUNBOOK.md +++ b/RUNBOOK.md @@ -2,16 +2,16 @@ This is the operational quick-reference for the shipped systemd timers/services and the optional FastAPI dashboard backend. -Repository root (on host): `/root/.openclaw/workspace` +Repository root (on host): `/root/.openclaw/workspace/second-brain` ## Systemd units (cron jobs) -Unit files are shipped in `systemd/` (repo root). Install them into `/etc/systemd/system/` (symlink or copy), then reload: +Unit files are shipped in `systemd/` (this repo). Install them into `/etc/systemd/system/` (symlink or copy), then reload: ```bash -sudo ln -sf /root/.openclaw/workspace/systemd/openclaw-secondbrain-*.service /etc/systemd/system/ -sudo ln -sf /root/.openclaw/workspace/systemd/openclaw-secondbrain-*.timer /etc/systemd/system/ -sudo ln -sf /root/.openclaw/workspace/systemd/openclaw-memory-archive.* /etc/systemd/system/ +sudo ln -sf /root/.openclaw/workspace/second-brain/systemd/openclaw-secondbrain-*.service /etc/systemd/system/ +sudo ln -sf /root/.openclaw/workspace/second-brain/systemd/openclaw-secondbrain-*.timer /etc/systemd/system/ +sudo ln -sf /root/.openclaw/workspace/second-brain/systemd/openclaw-memory-archive.* /etc/systemd/system/ sudo systemctl daemon-reload ``` @@ -61,7 +61,7 @@ python3 -m pip install -r second-brain/requirements-dashboard.txt SECOND_BRAIN_WORKSPACE="/root/.openclaw/workspace/second-brain" python3 second-brain/fastapi_app.py ``` -Default port is `8501` (same as Streamlit default). Do not run both on the same port. +Default port is `8501` (same as Streamlit default). You can override via `SECOND_BRAIN_PORT` (or `PORT`) when starting manually. Endpoint smoke tests: diff --git a/docs/RELEASE_CHECKLIST.md b/docs/RELEASE_CHECKLIST.md index 72013c8..8f0f765 100644 --- a/docs/RELEASE_CHECKLIST.md +++ b/docs/RELEASE_CHECKLIST.md @@ -1,6 +1,6 @@ # Second-Brain 2.0 — Release Checklist (Grundversion + FastAPI) -Scope: OpenClaw workspace at `/root/.openclaw/workspace` with `second-brain/` and the shipped `systemd/` unit files. +Scope: OpenClaw workspace at `/root/.openclaw/workspace` with `second-brain/` and the shipped `second-brain/systemd/` unit files. This checklist is copy/paste friendly. Run as a user with `sudo` (systemd commands need it). @@ -24,10 +24,10 @@ ls -la /etc/systemd/system/openclaw-memory-archive.* 2>/dev/null || true If missing, install them (symlink is fine; copy is fine too): ```bash -sudo ln -sf /root/.openclaw/workspace/systemd/openclaw-secondbrain-*.service /etc/systemd/system/ -sudo ln -sf /root/.openclaw/workspace/systemd/openclaw-secondbrain-*.timer /etc/systemd/system/ -sudo ln -sf /root/.openclaw/workspace/systemd/openclaw-memory-archive.* /etc/systemd/system/ -sudo ln -sf /root/.openclaw/workspace/systemd/openclaw-secondbrain-dashboard.service /etc/systemd/system/ +sudo ln -sf /root/.openclaw/workspace/second-brain/systemd/openclaw-secondbrain-*.service /etc/systemd/system/ +sudo ln -sf /root/.openclaw/workspace/second-brain/systemd/openclaw-secondbrain-*.timer /etc/systemd/system/ +sudo ln -sf /root/.openclaw/workspace/second-brain/systemd/openclaw-memory-archive.* /etc/systemd/system/ +sudo ln -sf /root/.openclaw/workspace/second-brain/systemd/openclaw-secondbrain-dashboard.service /etc/systemd/system/ sudo systemctl daemon-reload ``` diff --git a/scripts/smoke_dashboard.sh b/scripts/smoke_dashboard.sh new file mode 100755 index 0000000..235c277 --- /dev/null +++ b/scripts/smoke_dashboard.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +HOST="${SECOND_BRAIN_HOST:-127.0.0.1}" +PORT="${SECOND_BRAIN_PORT:-${PORT:-8501}}" +BASE_URL="http://${HOST}:${PORT}" + +if command -v systemctl >/dev/null 2>&1; then + if ! systemctl is-active --quiet openclaw-secondbrain-dashboard.service; then + echo "ERROR: openclaw-secondbrain-dashboard.service is not active" >&2 + exit 1 + fi +fi + +curl -fsS "${BASE_URL}/healthz" >/dev/null + +stats_json="$(curl -fsS "${BASE_URL}/api/stats")" +python3 -c 'import json,sys; json.load(sys.stdin)' <<<"$stats_json" + +echo "OK: dashboard smoke test passed (${BASE_URL})" diff --git a/systemd/openclaw-memory-archive.service b/systemd/openclaw-memory-archive.service new file mode 100644 index 0000000..a2f8c44 --- /dev/null +++ b/systemd/openclaw-memory-archive.service @@ -0,0 +1,9 @@ +[Unit] +Description=OpenClaw archive memory/*.md older than 7 days +OnFailure=openclaw-secondbrain-notify@%n.service + +[Service] +Type=oneshot +WorkingDirectory=/root/.openclaw/workspace +ExecStart=/bin/bash -lc 'flock -n /tmp/%n.lock /usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py archive_memory_md' + diff --git a/systemd/openclaw-memory-archive.timer b/systemd/openclaw-memory-archive.timer new file mode 100644 index 0000000..09e353c --- /dev/null +++ b/systemd/openclaw-memory-archive.timer @@ -0,0 +1,10 @@ +[Unit] +Description=OpenClaw archive memory/*.md daily + +[Timer] +OnCalendar=*-*-* 03:30:00 +Persistent=true + +[Install] +WantedBy=timers.target + diff --git a/systemd/openclaw-secondbrain-backup.service b/systemd/openclaw-secondbrain-backup.service new file mode 100644 index 0000000..54e23bd --- /dev/null +++ b/systemd/openclaw-secondbrain-backup.service @@ -0,0 +1,8 @@ +[Unit] +Description=OpenClaw Second-Brain backup_secondbrain +OnFailure=openclaw-secondbrain-notify@%n.service + +[Service] +Type=oneshot +WorkingDirectory=/root/.openclaw/workspace +ExecStart=/bin/bash -lc 'flock -n /tmp/%n.lock /usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py backup_secondbrain' diff --git a/systemd/openclaw-secondbrain-backup.timer b/systemd/openclaw-secondbrain-backup.timer new file mode 100644 index 0000000..359c3f3 --- /dev/null +++ b/systemd/openclaw-secondbrain-backup.timer @@ -0,0 +1,10 @@ +[Unit] +Description=OpenClaw Second-Brain backup_secondbrain (daily 02:00) + +[Timer] +OnCalendar=*-*-* 02:00:00 +Persistent=true + +[Install] +WantedBy=timers.target + diff --git a/systemd/openclaw-secondbrain-dashboard.service b/systemd/openclaw-secondbrain-dashboard.service new file mode 100644 index 0000000..6561ef6 --- /dev/null +++ b/systemd/openclaw-secondbrain-dashboard.service @@ -0,0 +1,15 @@ +[Unit] +Description=OpenClaw Second-Brain Dashboard (FastAPI) +After=network.target + +[Service] +Type=simple +WorkingDirectory=/root/.openclaw/workspace/second-brain +Environment=SECOND_BRAIN_WORKSPACE=/root/.openclaw/workspace/second-brain +Environment=SECOND_BRAIN_PORT=8501 +ExecStart=/root/.openclaw/workspace/second-brain/.venv/bin/uvicorn fastapi_app:app --host 0.0.0.0 --port 8501 +Restart=always +RestartSec=2 + +[Install] +WantedBy=multi-user.target diff --git a/systemd/openclaw-secondbrain-export-obsidian.service b/systemd/openclaw-secondbrain-export-obsidian.service new file mode 100644 index 0000000..c3a8964 --- /dev/null +++ b/systemd/openclaw-secondbrain-export-obsidian.service @@ -0,0 +1,8 @@ +[Unit] +Description=OpenClaw Second-Brain export_obsidian +OnFailure=openclaw-secondbrain-notify@%n.service + +[Service] +Type=oneshot +WorkingDirectory=/root/.openclaw/workspace +ExecStart=/bin/bash -lc 'flock -n /tmp/%n.lock /usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py export_obsidian' diff --git a/systemd/openclaw-secondbrain-export-obsidian.timer b/systemd/openclaw-secondbrain-export-obsidian.timer new file mode 100644 index 0000000..3c8f64b --- /dev/null +++ b/systemd/openclaw-secondbrain-export-obsidian.timer @@ -0,0 +1,10 @@ +[Unit] +Description=OpenClaw Second-Brain export_obsidian (hourly) + +[Timer] +OnCalendar=hourly +Persistent=true + +[Install] +WantedBy=timers.target + diff --git a/systemd/openclaw-secondbrain-heartbeat.service b/systemd/openclaw-secondbrain-heartbeat.service new file mode 100644 index 0000000..61b09ee --- /dev/null +++ b/systemd/openclaw-secondbrain-heartbeat.service @@ -0,0 +1,8 @@ +[Unit] +Description=OpenClaw Second-Brain heartbeat_secondbrain +OnFailure=openclaw-secondbrain-notify@%n.service + +[Service] +Type=oneshot +WorkingDirectory=/root/.openclaw/workspace +ExecStart=/bin/bash -lc 'flock -n /tmp/%n.lock /usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py heartbeat_secondbrain' diff --git a/systemd/openclaw-secondbrain-heartbeat.timer b/systemd/openclaw-secondbrain-heartbeat.timer new file mode 100644 index 0000000..0a42832 --- /dev/null +++ b/systemd/openclaw-secondbrain-heartbeat.timer @@ -0,0 +1,11 @@ +[Unit] +Description=OpenClaw Second-Brain heartbeat_secondbrain (every 6h) + +[Timer] +OnCalendar=*-*-* 00,06,12,18:00:00 +RandomizedDelaySec=300 +Persistent=true + +[Install] +WantedBy=timers.target + diff --git a/systemd/openclaw-secondbrain-index-vectors.service b/systemd/openclaw-secondbrain-index-vectors.service new file mode 100644 index 0000000..03b569f --- /dev/null +++ b/systemd/openclaw-secondbrain-index-vectors.service @@ -0,0 +1,10 @@ +[Unit] +Description=OpenClaw Second-Brain index_vectors +OnFailure=openclaw-secondbrain-notify@%n.service + +[Service] +Type=oneshot +WorkingDirectory=/root/.openclaw/workspace +Environment=HF_HOME=/root/.openclaw/workspace/second-brain/data/hf_cache +Environment=SENTENCE_TRANSFORMERS_HOME=/root/.openclaw/workspace/second-brain/data/st_cache +ExecStart=/bin/bash -lc 'flock -n /tmp/%n.lock /usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py index_vectors' diff --git a/systemd/openclaw-secondbrain-index-vectors.timer b/systemd/openclaw-secondbrain-index-vectors.timer new file mode 100644 index 0000000..035c8b0 --- /dev/null +++ b/systemd/openclaw-secondbrain-index-vectors.timer @@ -0,0 +1,10 @@ +[Unit] +Description=OpenClaw Second-Brain index_vectors (every 30 min) + +[Timer] +OnCalendar=*:0/30 +Persistent=true + +[Install] +WantedBy=timers.target + diff --git a/systemd/openclaw-secondbrain-ingest-memory.service b/systemd/openclaw-secondbrain-ingest-memory.service new file mode 100644 index 0000000..ef5480a --- /dev/null +++ b/systemd/openclaw-secondbrain-ingest-memory.service @@ -0,0 +1,8 @@ +[Unit] +Description=OpenClaw Second-Brain ingest_memory +OnFailure=openclaw-secondbrain-notify@%n.service + +[Service] +Type=oneshot +WorkingDirectory=/root/.openclaw/workspace +ExecStart=/bin/bash -lc 'flock -n /tmp/%n.lock /usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py ingest_memory' diff --git a/systemd/openclaw-secondbrain-ingest-memory.timer b/systemd/openclaw-secondbrain-ingest-memory.timer new file mode 100644 index 0000000..a2cd11e --- /dev/null +++ b/systemd/openclaw-secondbrain-ingest-memory.timer @@ -0,0 +1,10 @@ +[Unit] +Description=OpenClaw Second-Brain ingest_memory (every 10 min) + +[Timer] +OnCalendar=*:0/10 +Persistent=true + +[Install] +WantedBy=timers.target + diff --git a/systemd/openclaw-secondbrain-ingest-obsidian.service b/systemd/openclaw-secondbrain-ingest-obsidian.service new file mode 100644 index 0000000..643742b --- /dev/null +++ b/systemd/openclaw-secondbrain-ingest-obsidian.service @@ -0,0 +1,8 @@ +[Unit] +Description=OpenClaw Second-Brain ingest_obsidian +OnFailure=openclaw-secondbrain-notify@%n.service + +[Service] +Type=oneshot +WorkingDirectory=/root/.openclaw/workspace +ExecStart=/bin/bash -lc 'flock -n /tmp/%n.lock /usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py ingest_obsidian' diff --git a/systemd/openclaw-secondbrain-ingest-obsidian.timer b/systemd/openclaw-secondbrain-ingest-obsidian.timer new file mode 100644 index 0000000..f89864e --- /dev/null +++ b/systemd/openclaw-secondbrain-ingest-obsidian.timer @@ -0,0 +1,10 @@ +[Unit] +Description=OpenClaw Second-Brain ingest_obsidian (every 15 min) + +[Timer] +OnCalendar=*:0/15 +Persistent=true + +[Install] +WantedBy=timers.target + diff --git a/systemd/openclaw-secondbrain-notify@.service b/systemd/openclaw-secondbrain-notify@.service new file mode 100644 index 0000000..14f021d --- /dev/null +++ b/systemd/openclaw-secondbrain-notify@.service @@ -0,0 +1,8 @@ +[Unit] +Description=OpenClaw Second-Brain failure notify (%i) + +[Service] +Type=oneshot +WorkingDirectory=/root/.openclaw/workspace +ExecStart=/bin/bash -lc '/root/.openclaw/workspace/notify-telegram.sh "❌ Second-Brain job failed: %i. Check: journalctl -u %i -n 50 --no-pager"' + diff --git a/systemd/openclaw-secondbrain-proactive-search.service b/systemd/openclaw-secondbrain-proactive-search.service new file mode 100644 index 0000000..5886b0f --- /dev/null +++ b/systemd/openclaw-secondbrain-proactive-search.service @@ -0,0 +1,10 @@ +[Unit] +Description=OpenClaw Second-Brain proactive_search_wrapper +Wants=network-online.target +After=network-online.target +OnFailure=openclaw-secondbrain-notify@%n.service + +[Service] +Type=oneshot +WorkingDirectory=/root/.openclaw/workspace +ExecStart=/bin/bash -lc 'flock -n /tmp/%n.lock /usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py proactive_search_wrapper' diff --git a/systemd/openclaw-secondbrain-proactive-search.timer b/systemd/openclaw-secondbrain-proactive-search.timer new file mode 100644 index 0000000..9a8cad8 --- /dev/null +++ b/systemd/openclaw-secondbrain-proactive-search.timer @@ -0,0 +1,11 @@ +[Unit] +Description=OpenClaw Second-Brain proactive_search_wrapper (every 4h) + +[Timer] +OnCalendar=*-*-* 01,05,09,13,17,21:10:00 +RandomizedDelaySec=600 +Persistent=true + +[Install] +WantedBy=timers.target + diff --git a/systemd/openclaw-secondbrain-review.service b/systemd/openclaw-secondbrain-review.service new file mode 100644 index 0000000..2d161b0 --- /dev/null +++ b/systemd/openclaw-secondbrain-review.service @@ -0,0 +1,8 @@ +[Unit] +Description=OpenClaw Second-Brain review_brain +OnFailure=openclaw-secondbrain-notify@%n.service + +[Service] +Type=oneshot +WorkingDirectory=/root/.openclaw/workspace +ExecStart=/bin/bash -lc 'flock -n /tmp/%n.lock /usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py review_brain' diff --git a/systemd/openclaw-secondbrain-review.timer b/systemd/openclaw-secondbrain-review.timer new file mode 100644 index 0000000..f88cf84 --- /dev/null +++ b/systemd/openclaw-secondbrain-review.timer @@ -0,0 +1,10 @@ +[Unit] +Description=OpenClaw Second-Brain review_brain (every 30 min) + +[Timer] +OnCalendar=*:0/30 +Persistent=true + +[Install] +WantedBy=timers.target + diff --git a/systemd/openclaw-secondbrain-task@.service b/systemd/openclaw-secondbrain-task@.service new file mode 100644 index 0000000..37e99cd --- /dev/null +++ b/systemd/openclaw-secondbrain-task@.service @@ -0,0 +1,13 @@ +[Unit] +Description=OpenClaw Second-Brain task (%i) +Wants=network-online.target +After=network-online.target + +[Service] +Type=oneshot +WorkingDirectory=/root/.openclaw/workspace +ExecStart=/usr/bin/python3 /root/.openclaw/workspace/openclaw_cron_wrapper.py %i +Nice=10 +IOSchedulingClass=best-effort +IOSchedulingPriority=6 +