@flame0510/project-aether 1.6.2 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -2
  3. package/agent-templates/atlas/HEARTBEAT.md +1 -1
  4. package/app/agents/ImageDownloadBanner.tsx +171 -37
  5. package/app/api/agents/download-image/route.ts +29 -5
  6. package/app/api/agents/image-status/route.ts +17 -2
  7. package/app/api/assistant/route.ts +13 -4
  8. package/app/api/auth/login/route.ts +2 -2
  9. package/app/api/setup/agent-image/route.ts +6 -4
  10. package/app/api/system-health/route.ts +3 -3
  11. package/app/components/DashboardToolbar.tsx +2 -2
  12. package/app/components/LineageGraphPage.tsx +4 -4
  13. package/app/components/SessionDrawer.tsx +8 -8
  14. package/app/components/SystemCockpit.tsx +1 -1
  15. package/app/globals.css +1 -1
  16. package/app/setup/PageClient.tsx +1 -1
  17. package/bin/postinstall.js +5 -1
  18. package/daemon.js +13 -34
  19. package/docs/ARCHITECTURE.md +44 -26
  20. package/docs/CONTAINER-TERMINAL.md +17 -8
  21. package/docs/DESIGN-SYSTEM.md +21 -12
  22. package/docs/FRONTEND-ARCHITECTURE.md +2 -2
  23. package/docs/REV4A.md +35 -85
  24. package/docs/dev/API-REFERENCE.md +73 -19
  25. package/docs/dev/DATABASE.md +18 -7
  26. package/docs/dev/SESSION-MAINTENANCE-PLAN.md +6 -6
  27. package/docs/rag/DATA-FRESHNESS.md +20 -9
  28. package/docs/rag/GLOSSARY.md +2 -2
  29. package/docs/rag/REV4A-OVERVIEW.md +10 -6
  30. package/docs/rag/WHAT-I-CAN-ANSWER.md +3 -3
  31. package/lib/agent-images.ts +43 -14
  32. package/lib/buildAgentImage.ts +142 -6
  33. package/lib/patterns/sessionPresentation.ts +4 -2
  34. package/lib/rev4a-auth.d.ts +1 -0
  35. package/lib/rev4a-auth.js +18 -2
  36. package/next.config.mjs +9 -1
  37. package/package.json +2 -2
  38. package/scripts/backup.sh +48 -54
  39. package/scripts/check-language.mjs +21 -3
  40. package/scripts/restore.sh +77 -59
package/docs/REV4A.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Rev4a — VPS Dashboard
2
2
 
3
- > **Last updated:** 2026-09-15
3
+ > **Last updated:** 2026-09-26
4
4
 
5
5
  A Next.js 16 dashboard for monitoring and managing the OpenClaw ecosystem.
6
6
 
@@ -9,50 +9,34 @@ A Next.js 16 dashboard for monitoring and managing the OpenClaw ecosystem.
9
9
  **Process manager:** `rev4a serve` (single command). Production: systemd service (`rev4a.service`).
10
10
  **Repository:** `github.com/Flame0510/rev4a.git` (branch: `main`)
11
11
 
12
- ---
13
-
14
- ## Overview
15
-
16
- | Field | Value |
17
- |---|---|
18
- | VPS IP | `187.77.156.41` |
19
- | OS | Ubuntu 24.04.4 LTS |
20
- | Resources | 4 CPU, 15 GB RAM, 193 GB disk |
21
-
22
-
23
12
  ---
24
13
 
25
14
  ## Architecture
26
15
 
27
16
  ```
28
- Internet
17
+ Browser (directly, or through a reverse proxy of your choice)
29
18
  │
30
- ┌────┴────┐
31
- │ Traefik │ (Docker container, host network)
32
- │ :443 │
33
- └────┬────┘
19
+ ┌──────────┴──────────────────┐
20
+ │ rev4a serve │
21
+ │ (systemd: rev4a.service) │
22
+ │ Next.js 16 :3740 │
23
+ │ daemon.js │
24
+ │ terminal WS :3741 │
25
+ └──────────┬──────────────────┘
34
26
  │
35
- ┌──────────┴──────────┐
36
- │ rev4a │
37
- │ systemd (rev4a.service) │
38
- │ :3740 │
39
- │ Next.js 16 │
40
- └─────────────────────┘
27
+ docker exec / Docker API
41
28
  │
42
29
  ┌─────────────┴─────────────┐
43
- │ │
44
- docker exec / API docker exec / API
45
- │ │
46
- ┌──────┴──────┐ ┌────────┴────────┐
47
- │ openclaw-core│ │ openclaw-atlas │
48
- │ :3700-3708 │ │ :3731 → 3000 │
49
- │ AGENT_ID=core│ │ AGENT_ID=atlas │
50
- └──────────────┘ └─────────────────┘
30
+ ┌──────┴──────┐ ┌──────┴──────┐
31
+ │ agent │ … │ agent │
32
+ │ container │ │ container │
33
+ │ (OpenClaw) │ │ (OpenClaw) │
34
+ └─────────────┘ └─────────────┘
51
35
  ```
52
36
 
53
37
  ### Environment
54
38
 
55
- Rev4a reads the following environment variables. Set them in `/config` (UI) or directly in `.env`. See [.env.example](../.env.example) for the canonical, always-current list.
39
+ Rev4a reads the following environment variables. Set them in `/config` (UI) or directly in `.env`, except the three read before `.env` is loaded — `REV4A_DATA_DIR`, `REV4A_DOCKER_WAIT_SECONDS` (both from the process environment: a shell export or a systemd `Environment=` line) and `REV4A_SKIP_POSTINSTALL_BUILD` (read by `npm install`). See [.env.example](../.env.example) for the canonical, always-current list.
56
40
 
57
41
  | Variable | Required | Description |
58
42
  |---|---|---|
@@ -67,8 +51,11 @@ Rev4a reads the following environment variables. Set them in `/config` (UI) or d
67
51
  | `REV4A_WORKSPACE_ROOT` | No | Filesystem path for the local file explorer |
68
52
  | `REV4A_ROOT` | No | Installation root, used by `rev4a update` to detect a git checkout |
69
53
  | `REV4A_TIMEZONE` | No | IANA timezone used for scheduling and timestamps |
70
- | `REV4A_FORCE_INSECURE_COOKIE` | No | Allow a non-Secure session cookie — plain-HTTP deployments only |
54
+ | `REV4A_FORCE_INSECURE_COOKIE` | No | `1` allows a non-Secure session cookie — plain-HTTP deployments only (any other value, `true` included, does nothing) |
71
55
  | `REV4A_AGENT_IMAGE_REGISTRY` | No | Registry repository agent images are pulled from (default: `ghcr.io/flame0510/rev4a/openclaw-agent-base`); a `localhost` registry is reached over plain HTTP |
56
+ | `REV4A_DOCKER_WAIT_SECONDS` | No | How long `rev4a serve` waits for the Docker daemon at start-up (default `90`, capped at 600) |
57
+ | `REV4A_DEV_ORIGINS` | No | Extra comma-separated hostnames or IPs allowed to reach `next dev`; no effect on a production build |
58
+ | `REV4A_SKIP_POSTINSTALL_BUILD` | No | `1` in CI: `npm ci` then skips the post-install `next build` (the workflows build as a separate step). Any non-empty value skips it, `0` included — leave it unset to build |
72
59
 
73
60
  See [Alerts](#alerts-telegram) below for the Telegram alert variables.
74
61
 
@@ -91,10 +78,12 @@ to any specific reverse proxy.
91
78
 
92
79
  When environment variables are saved via the Config page (Save & Restart):
93
80
 
94
- 1. Values are written to `.env` in the project root
95
- 2. Secrets are loaded via `EnvironmentFile=` pointing to `.env` (chmod 600). Only non-secret vars (`NODE_ENV`, `PATH`, `REV4A_DB`) are in the unit file. Other vars (passwords, non-Rev4a keys) stay in `.env` for the application to read at runtime.
96
- 3. `systemctl daemon-reload` is run
97
- 4. The server restarts with the new environment
81
+ 1. Values are merged into the data directory's `.env` (`~/.config/rev4a/.env`; the
82
+ `.env` in the installation root is a link to it). An empty value removes the key.
83
+ 2. `sudo systemctl daemon-reload` is attempted; it is harmless where there is no systemd.
84
+ 3. **Save & Restart** runs `sudo systemctl restart rev4a.service`: the restart only works
85
+ when Rev4a runs as that systemd service. Started any other way, restart `rev4a serve`
86
+ yourself — `serve` reads `.env` at start-up, so nothing changes until then.
98
87
 
99
88
  ## Components
100
89
 
@@ -115,6 +104,7 @@ When environment variables are saved via the Config page (Save & Restart):
115
104
  | `/workspace` | File explorer with tree view + editor — VPS host or container workspaces |
116
105
  | `/lineage` | Agent lineage / orchestration tree |
117
106
  | `/memory` | Agent memory browser |
107
+ | `/gateway` (model rows) | Each model has a **Details** (`⋯`) action opening a modal with what is known about it: description, price and the provider it comes from, architecture and parameters (mixture of experts, layers, hidden size, attention heads, vision encoder, precision, weights on disk), reasoning modes, capabilities, benchmarks with their sources, licence and popularity. The facts come from the model's card on Hugging Face and — for the vendor's own size claim and benchmarks — from hand-curated entries that always cite a source and a date; nothing is estimated. |
118
108
  | `/crons` | Scheduled cron jobs — auto-discovered from the host gateway and every running agent container (Docker containers with `AGENT_ID` label), on/off toggle, run history per job |
119
109
  | `/credentials` | Third-party tool credentials (GitHub, Trello, Vercel, Supabase, Notion) — SQLite vault, synced into agent containers as CLI config or, for the REST-only providers, as a config file the agent reads |
120
110
  | `/setup` | First-run password setup — sets `REV4A_PASSWORD` and the JWT secret before the dashboard is reachable |
@@ -159,7 +149,7 @@ REV4A_TELEGRAM_BOT_TOKEN= # Telegram bot token
159
149
  REV4A_TELEGRAM_CHAT_ID= # Telegram chat to notify
160
150
  REV4A_ALERT_COOLDOWN_MS=600000 # Minimum time between repeat alerts for the same condition
161
151
  REV4A_ALERT_STALE_SECONDS=120 # How long without a DB write before the system is considered stale
162
- REV4A_ALERT_SMOKE=false # Set true to send a one-off test alert on startup
152
+ REV4A_ALERT_SMOKE=false # true enables GET /api/alerts/smoke (sends a test alert) in production
163
153
  ```
164
154
 
165
155
  **Behavior:**
@@ -220,14 +210,16 @@ echo 'vm.swappiness=10' > /etc/sysctl.d/99-rev4a-swap.conf
220
210
 
221
211
  ### Systemd environment override
222
212
 
223
- File: `/etc/systemd/system/rev4a-next.service` (EnvironmentFile)
213
+ File: `/etc/systemd/system/rev4a.service.d/override.conf` — a drop-in for the single
214
+ `rev4a.service` unit (`systemctl edit rev4a`). It is for the variables `.env` does not
215
+ carry: `rev4a serve` reads `~/.config/rev4a/.env` itself, and a key present there wins
216
+ over the same key set here — so secrets such as `REV4A_PASSWORD` or `REV4A_TOKEN`
217
+ belong in `.env` (or `/config`), not in the drop-in. It is also the only place for the
218
+ variables read before `.env` is loaded (`REV4A_DATA_DIR`, `REV4A_DOCKER_WAIT_SECONDS`).
224
219
 
225
220
  ```ini
226
221
  [Service]
227
- Environment=REV4A_PASSWORD=***
228
- Environment=REV4A_TOKEN=***
229
- Environment=REV4A_JWT_SECRET=***
230
- Environment=REV4A_DB=/path/to/rev4a/data/events.db
222
+ Environment=REV4A_DOCKER_WAIT_SECONDS=180
231
223
  Environment=NODE_ENV=production
232
224
  Environment=NEXT_TELEMETRY_DISABLED=1
233
225
  ```
@@ -484,48 +476,6 @@ Only models whose provider has a key in `data/provider-keys.json` are synced.
484
476
 
485
477
  ---
486
478
 
487
- ## Containers
488
-
489
- ### openclaw-atlas
490
-
491
- | Property | Value |
492
- |---|---|
493
- | Image | `openclaw-agent-base:<version>` (Node 24-bookworm-slim + OpenClaw) |
494
- | Port | `0.0.0.0:3731 → 3000` |
495
- | IP | `172.19.0.3` |
496
- | AGENT_ID | `atlas` |
497
- | Config mount | `/docker/atlas-data/openclaw-fixed.json → /root/.openclaw/openclaw.json` |
498
- | Auth mode | `token` |
499
-
500
- **Control UI:** `http://<vps-ip>:3731` — enter the gateway token to log in.
501
- Rev4a-generated direct links should use `#token=<gateway-token>` for automatic Control UI sign-in.
502
-
503
- ### openclaw-core
504
-
505
- | Property | Value |
506
- |---|---|
507
- | Image | `ghcr.io/hostinger/hvps-openclaw:latest` |
508
- | Ports | `:3711-3719` (mapped to container `:3700-3708`) |
509
- | AGENT_ID | `core` |
510
-
511
- ### openclaw-giacomo
512
-
513
- | Property | Value |
514
- |---|---|
515
- | Image | `ghcr.io/hostinger/hvps-openclaw:latest` |
516
- | Port | `:3730` |
517
- | AGENT_ID | `giacomo` |
518
-
519
- ### Other containers
520
-
521
- | Name | Image | Notes |
522
- |---|---|---|
523
- | `hermes` | `nousresearch/hermes-agent:latest` | Hermes agent |
524
- | `hermes-dashboard` | `nousresearch/hermes-agent:latest` | Hermes dashboard |
525
- | `traefik-traefik-1` | `traefik:latest` | Reverse proxy |
526
-
527
- ---
528
-
529
479
  ## Key Gotchas
530
480
 
531
481
  1. **`auth.mode: "none"` + `0.0.0.0:3000`** → OpenClaw refuses to bind. Must be `auth.mode: "token"`.
@@ -1,6 +1,6 @@
1
1
  # Rev4a API Reference
2
2
 
3
- > **Last updated:** 2026-09-15
3
+ > **Last updated:** 2026-09-26
4
4
 
5
5
  All routes are under `/api/`. Authentication is required on every endpoint
6
6
  unless otherwise noted.
@@ -249,7 +249,10 @@ Returns current provider configuration state.
249
249
  |---|---|
250
250
  | `summary=1` | Returns only `{ provider, label, configured }` per provider — no `models`, no `pricing`, no `apiKey`. The full response awaits live pricing from OpenRouter, a network round trip costing ~2.4s on a cold cache; callers that only need to know whether *any* provider is configured should use this. |
251
251
 
252
- **Response:**
252
+ **Response:** each provider carries its models, and a model carries `params` (the total
253
+ parameter count) when its Hugging Face card publishes one — the Gateway row shows it next
254
+ to the price, and a model without a card simply omits it.
255
+
253
256
  ```json
254
257
  {
255
258
  "providers": [
@@ -1576,7 +1579,7 @@ nothing opens until an operator approves it.
1576
1579
 
1577
1580
  **Response:**
1578
1581
  ```json
1579
- { "url": "http://212.0.113.7:3710/#token=…", "loopbackHost": false }
1582
+ { "url": "http://203.0.113.7:3710/#token=…", "loopbackHost": false }
1580
1583
  ```
1581
1584
 
1582
1585
  - `url` is the plain token link. The host is the one the request reached Rev4a on
@@ -1737,6 +1740,17 @@ in flight, so polling this endpoint does not re-query the registry every time.
1737
1740
  {
1738
1741
  "downloading": false,
1739
1742
  "downloadingVersion": null,
1743
+ "downloadPercent": null,
1744
+ "downloadMessage": null,
1745
+ "canceled": false,
1746
+ "lastResult": {
1747
+ "version": "2026.9.3",
1748
+ "result": "succeeded",
1749
+ "source": "registry",
1750
+ "message": "OpenClaw 2026.9.3 image downloaded",
1751
+ "at": 1758700000000
1752
+ },
1753
+ "serverTime": 1758700004000,
1740
1754
  "exists": true,
1741
1755
  "needsUpdate": false,
1742
1756
  "localVersions": ["2026.9.3"],
@@ -1754,6 +1768,11 @@ in flight, so polling this endpoint does not re-query the registry every time.
1754
1768
  | `newestLocal` | The version new agents are created on |
1755
1769
  | `available` | Newest supported version on the registry that is not downloaded and is newer than `newestLocal`, or null |
1756
1770
  | `downloading` / `downloadingVersion` | A download running, and its version |
1771
+ | `downloadPercent` | Fraction of layers finished, from `docker pull`'s own per-layer lines (`getDownloadProgress()`), 0-99. Null until it can be computed: while the version is resolved, while docker is still listing the layers, on a pull where every layer is already present, and on the local-build fallback |
1772
+ | `downloadMessage` | The latest line of docker's output, verbatim (the banner shows it under the percent) |
1773
+ | `canceled` | Whether the last finished download ended as cancelled — derived from `lastResult`, so a cancel that arrived after the image was already tagged does not make a successful download read as cancelled |
1774
+ | `serverTime` | The server's clock (epoch ms) when it answered; clients age `lastResult.at` with it instead of their own clock |
1775
+ | `lastResult` | The last download's outcome (`getLastDownloadResult()`, `lib/buildAgentImage.ts`), or null before any download has run this process. `result` is `succeeded` / `failed` / `canceled`; `source` (`present` / `registry` / `build`) only on success. Kept regardless of whether a download is running now, so a client that missed the live transition — a page reload, a return from another screen — still sees it via `at` (epoch ms); overwritten by the next download, never cleared on its own. Same idea as `finished` in `lib/cold-backup.ts` |
1757
1776
  | `registryReachable` | The tag list could be read |
1758
1777
 
1759
1778
  ### `POST /api/agents/download-image`
@@ -1770,19 +1789,42 @@ newest supported version the registry publishes.
1770
1789
  { "started": true, "version": "2026.9.3" }
1771
1790
  ```
1772
1791
 
1773
- **Errors:** `400` unsupported version; `409` a download is already in progress.
1792
+ **Errors:** `400` unsupported version; `409` a download is already in progress; `503`
1793
+ Docker is not available (refused here, before `202`, so the client gets the reason).
1774
1794
 
1775
1795
  The download is `lib/buildAgentImage.ts` → `downloadAgentImage({ version, onEvent, signal })`:
1776
1796
  - nothing to do when `openclaw-agent-base:<version>` is already here
1777
1797
  - `docker pull <registry>:<version>`, tag `openclaw-agent-base:<version>`, untag the
1778
- registry reference (`pullAgentImage()` in `lib/agent-images.ts`)
1798
+ registry reference — also when the tag step fails or is cancelled, so no
1799
+ `<registry>:<version>` reference is left behind (`pullAgentImage()` in `lib/agent-images.ts`)
1779
1800
  - when the pull fails and the repository Dockerfile's `ARG OPENCLAW_VERSION` is that
1780
1801
  version, `docker build --build-arg OPENCLAW_VERSION=<version>` instead; any other
1781
1802
  version fails
1782
1803
  - one download at a time (in-process lock, `getIsDownloading()` /
1783
- `getDownloadingVersion()`); output goes to `/tmp/rev4a-download-<timestamp>.log`
1804
+ `getDownloadingVersion()`); docker's output also goes to
1805
+ `/tmp/rev4a-download-<timestamp>.log` (mode 0600; logs older than 24 h are removed when a download ends) for diagnosis
1806
+ - progress: a layer counts as finished at `Pull complete` or `Already exists` (not at
1807
+ `Download complete`, which still has the extraction ahead); the percent is withheld
1808
+ until the first layer starts transferring — before that the layer list may be
1809
+ incomplete — never goes down, and stays below 100: completion is reported by
1810
+ `lastResult`, not by the percent
1811
+
1812
+ ### `DELETE /api/agents/download-image`
1813
+ Cancels the running download, if any (`cancelDownload()`): the `docker pull`/`docker build`
1814
+ process is killed, or never started when the cancel arrives before it (`runDocker` refuses
1815
+ an already-aborted signal, and the download checks after every wait). The rejected
1816
+ `downloadAgentImage()` promise carries a distinct `'canceled'` message, so the route's
1817
+ background `.catch` does not log it as a failure; `lastResult.result` becomes `canceled`.
1784
1818
 
1785
- ### `GET /api/agents-active`
1819
+ **Auth:** browser cookie or bearer token
1820
+
1821
+ **Response (202):**
1822
+ ```json
1823
+ { "canceling": true }
1824
+ ```
1825
+
1826
+ **Errors:** `404` nothing is running — the download has not started yet, or has
1827
+ already ended.
1786
1828
 
1787
1829
  ### `GET /api/agents-active`
1788
1830
  Configured agents (from `openclaw.json`) enriched with recent session activity
@@ -1864,42 +1906,54 @@ Register a parent→child relationship between sessions.
1864
1906
  ## Metrics
1865
1907
 
1866
1908
  ### `GET /api/metrics`
1867
- System metrics: latest snapshot + 24 h history + 24 h aggregates.
1909
+ System metrics from the daemon's `system_metrics` table: the latest sample, the most
1910
+ recent samples, and 24 h CPU aggregates.
1868
1911
 
1869
1912
  **Auth:** Bearer or browser cookie
1870
1913
 
1914
+ **Query:** `limit` — how many `history` rows (default 60, max 1000): the most recent ones, returned oldest first.
1915
+
1871
1916
  **Response:**
1872
1917
  ```json
1873
1918
  {
1874
- "latest": { "ts": 1749201000000, "cpu_percent": 12.5, "ram_used_mb": 1820, "ram_total_mb": 4096, "disk_used_gb": 38.2, "disk_total_gb": 100.0, "load_avg_1m": 0.42 },
1875
- "history": [ ...up to 288 rows (24h at 5min intervals)... ],
1876
- "stats_24h": { "avg_cpu": 14.2, "max_cpu": 68.0, "avg_ram_mb": 1750 }
1919
+ "latest": { "cpu": 12.5, "ram_used_mb": 1820, "ram_total_mb": 4096, "disk_used_gb": 38, "disk_total_gb": 100, "load_avg": 0.42, "ts": 1749201000 },
1920
+ "history": [ { "cpu": 12.5, "ram_used_mb": 1820, "ram_total_mb": 4096, "ts": 1749201000 } ],
1921
+ "stats_24h": { "cpu_avg": 14, "cpu_max": 68 }
1877
1922
  }
1878
1923
  ```
1879
1924
 
1925
+ `ts` is in **seconds**. The daemon records one sample per completed poll (every 30 s) and keeps
1926
+ 30 days. A host without the OpenClaw CLI records none: the daemon stays idle there,
1927
+ and `latest` is `null`.
1928
+
1880
1929
  ---
1881
1930
 
1882
1931
  ## System Health
1883
1932
 
1884
1933
  ### `GET /api/system-health`
1885
- Aggregated health checks with recommendations.
1934
+ Aggregated checks of the runtime, cron jobs and usage cost, with recommendations. It
1935
+ does not report CPU, RAM, disk or the Docker daemon (those are in `GET /api/metrics`).
1886
1936
 
1887
- **Auth:** browser cookie
1937
+ **Auth:** browser cookie or bearer token
1888
1938
 
1889
1939
  **Response:**
1890
1940
  ```json
1891
1941
  {
1892
1942
  "health": "ok",
1893
1943
  "checks": [
1894
- { "name": "daemon", "status": "ok", "detail": "last poll 18s ago" },
1895
- { "name": "disk", "status": "warn", "detail": "82% used" }
1944
+ { "id": "runtime.sessions", "label": "Runtime sessions", "health": "ok", "value": 1, "details": "last session activity 3m ago", "source": "runtime" }
1945
+ ],
1946
+ "recommendations": [
1947
+ { "id": "cost.review-usage-based", "severity": "warning", "source": "cost", "title": "High usage-based cost", "details": "…", "actionHref": "/gateway", "dismissible": true, "createdAt": "2026-09-26T10:00:00.000Z" }
1896
1948
  ],
1897
- "recommendations": [ "Consider archiving old sessions to reduce disk usage." ],
1898
- "generatedAt": 1749201500000
1949
+ "generatedAt": "2026-09-26T10:00:00.000Z"
1899
1950
  }
1900
1951
  ```
1901
1952
 
1902
- `health` values: `"ok"` / `"warn"` / `"error"`
1953
+ Checks: `runtime.sessions`, `runtime.ingestion`, `runtime.errors24h`,
1954
+ `cost.usageBasedToday`, `cron.jobs`. `health` (overall and per check) is `"ok"` /
1955
+ `"warning"` / `"error"`; a recommendation's `severity` is `"info"` / `"warning"` /
1956
+ `"critical"`. `generatedAt` and `createdAt` are ISO strings.
1903
1957
 
1904
1958
  ---
1905
1959
 
@@ -2619,7 +2673,7 @@ the process that spawned it, so that file is the only record of what happened.
2619
2673
 
2620
2674
  **Response:** `{ "success": true, "message": "...", "log": "update.log" }`
2621
2675
 
2622
- The banner records what it asked for, polls `/api/version` until the installed version
2676
+ The banner records what it asked for, polls `/api/update-check` until the installed version
2623
2677
  moves (or two minutes pass), reloads, and on the next mount either confirms
2624
2678
  "Updated to vX" or reports that the update did not complete and points at the log.
2625
2679
 
@@ -1,6 +1,6 @@
1
1
  # Rev4a — Database Reference
2
2
 
3
- > **Last updated:** 2026-08-28
3
+ > **Last updated:** 2026-09-26
4
4
 
5
5
  Rev4a uses a single SQLite file (`events.db`) in WAL mode.
6
6
 
@@ -105,7 +105,10 @@ CREATE TABLE system_metrics (
105
105
  CREATE INDEX idx_metrics_ts ON system_metrics(ts);
106
106
  ```
107
107
 
108
- Rows older than 24 h are pruned automatically by the daemon.
108
+ Rows older than 30 days are pruned automatically by the daemon (one row per completed 30 s poll;
109
+ none on a host without the OpenClaw CLI, where the daemon stays idle).
110
+ No feature consumes the `system_anomaly` events the daemon writes to `events` yet; they
111
+ only pass through the generic event feeds.
109
112
 
110
113
  ### `agent_upgrades` — agent updates and rollbacks
111
114
 
@@ -235,14 +238,22 @@ SELECT * FROM tree;
235
238
  ## Backup
236
239
 
237
240
  ```bash
238
- # Manual snapshot
239
- sqlite3 events.db ".backup events.db.bak-$(date +%s)"
241
+ # Everything Rev4a owns: the whole data directory (.env, data/, shared/)
242
+ bash scripts/backup.sh # -> ~/rev4a-backups/rev4a-backup-<UTC time>.tar.gz
243
+ bash scripts/restore.sh ~/rev4a-backups/rev4a-backup-<UTC time>.tar.gz
240
244
 
241
- # Automated (via backup.sh in repo root)
242
- bash /data/.openclaw/workspace-ops/rev4a-next-ts/backup.sh
245
+ # One database only, consistent while Rev4a runs (needs the sqlite3 CLI)
246
+ sqlite3 ~/.config/rev4a/data/events.db ".backup events-$(date +%s).db"
243
247
  ```
244
248
 
245
- Backups are stored in `backups/` inside the repo directory.
249
+ `backup.sh` archives the Rev4a data directory (`$REV4A_DATA_DIR`, default
250
+ `~/.config/rev4a`) whole, so a new file there is included without changing the script.
251
+ The archive (mode 0600, directory 0700) holds every secret in plain text; keep a copy
252
+ off the machine. `restore.sh` refuses an archive with links in it and a running
253
+ `rev4a serve`, archives the current state into `~/rev4a-backups` first, stops
254
+ `rev4a.service` when it runs, and replaces the data directory as a whole (a leftover
255
+ SQLite `-wal` cannot mix into the restored state), then resets the permissions. Agent volumes are not included —
256
+ the dashboard's cold backups cover them.
246
257
 
247
258
  ## Credentials Database (`credentials.db`)
248
259
 
@@ -597,11 +597,11 @@ POST /api/sessions/maintenance/cleanup
597
597
 
598
598
  ## 9. References
599
599
 
600
- - [Session maintenance](/concepts/session) — OpenClaw docs
601
- - [Session management deep dive](/reference/session-management-compaction) — store schema + maintenance rules
602
- - [Compaction](/concepts/compaction) — auto + manual compaction
603
- - [Session pruning](/concepts/session-pruning) — tool-result trimming
604
- - [Transcript hygiene](/reference/transcript-hygiene) — provider-specific fixups
605
- - [Cron jobs](/automation/cron-jobs) — cron.sessionRetention + run log config
600
+ - [Session maintenance](https://docs.openclaw.ai/concepts/session) — OpenClaw docs
601
+ - [Session management deep dive](https://docs.openclaw.ai/reference/session-management-compaction) — store schema + maintenance rules
602
+ - [Compaction](https://docs.openclaw.ai/concepts/compaction) — auto + manual compaction
603
+ - [Session pruning](https://docs.openclaw.ai/concepts/session-pruning) — tool-result trimming
604
+ - [Transcript hygiene](https://docs.openclaw.ai/reference/transcript-hygiene) — provider-specific fixups
605
+ - [Cron jobs](https://docs.openclaw.ai/automation/cron-jobs) — cron.sessionRetention + run log config
606
606
  - [Rev4a API Reference](API-REFERENCE.md)
607
607
  - [Rev4a Frontend Architecture](../FRONTEND-ARCHITECTURE.md)
@@ -1,6 +1,6 @@
1
1
  # Data Freshness in Rev4a
2
2
 
3
- > **Last updated:** 2026-09-15
3
+ > **Last updated:** 2026-09-26
4
4
 
5
5
  Understanding how current the data in Rev4a is — and what is truly real-time vs. periodically updated.
6
6
 
@@ -14,9 +14,8 @@ The daemon polls `openclaw sessions --json --all-agents` on a fixed 30-second
14
14
  timer. Session statuses, token counts, and costs are therefore up to 30 seconds
15
15
  behind reality.
16
16
 
17
- The code declares a shorter 15-second interval for when a session is `working`,
18
- but nothing uses it — the timer is always 30 seconds. Do not tell a user the
19
- dashboard speeds up during active work.
17
+ The interval is fixed: it does not speed up while a session is `working`. Do not tell
18
+ a user the dashboard refreshes faster during active work.
20
19
 
21
20
  **What this means for PULSE:** if you ask "is Argus working right now?", the
22
21
  answer reflects data that is up to 30 seconds old.
@@ -29,7 +28,7 @@ answer reflects data that is up to 30 seconds old.
29
28
 
30
29
  The `/api/stream` endpoint pushes updates to the dashboard every 5 seconds. It
31
30
  sends exactly three things:
32
- - New events (spawn, complete, error, tool_call)
31
+ - New events (spawn, complete, fail, spawn_timeout, system_anomaly)
33
32
  - The session list
34
33
  - Today's cost total
35
34
 
@@ -43,7 +42,8 @@ to 30 seconds to appear, plus up to 5 more to reach the browser.
43
42
 
44
43
  ## System metrics (CPU, RAM, disk)
45
44
 
46
- **Update frequency:** every daemon poll cycle (30 seconds)
45
+ **Update frequency:** every completed daemon poll cycle (30 seconds). A host without the
46
+ OpenClaw CLI records no metrics at all: the daemon stays idle there.
47
47
 
48
48
  **Retention:** 30 days (older rows are pruned automatically each cycle)
49
49
 
@@ -96,11 +96,22 @@ at most every 10 minutes, so a newly published version can take that long to app
96
96
  The banner polls the endpoint every 2 seconds for as long as the page is open, not only
97
97
  while something is running.
98
98
 
99
- The operation the banner triggers is a **`docker pull`**, not a build. While it
100
- runs the banner shows an indeterminate animated bar: there is no percentage, no
101
- byte count, and no log output in the UI. A log is written server-side to
99
+ The operation the banner triggers is a **`docker pull`**, not a build (unless the
100
+ pull fails and this repository's own Dockerfile builds that exact version, a
101
+ development fallback). While it runs the banner shows the percent of layers
102
+ finished and the latest line of docker's output; the bar is indeterminate until a
103
+ percent can be computed (while the version is resolved and the layers are listed,
104
+ and during the local-build fallback). The percent never goes down and stops at 99:
105
+ completion is announced by the outcome, not by 100%. A **Cancel** button, offered
106
+ once the download is running, stops it — the `docker pull`/`docker build` process is
107
+ killed, or never started if the cancel came first. A log is written server-side to
102
108
  `/tmp/rev4a-download-<timestamp>.log`, but nothing in the dashboard reads it.
103
109
 
110
+ The outcome comes from the server's own record of the last download: "ready" and
111
+ "canceled" show for 3 seconds, a failure stays until the next action. An outcome
112
+ that happened while the Agents page was closed or reloading is still reported if it
113
+ is less than 30 seconds old.
114
+
104
115
  ---
105
116
 
106
117
  ## Memory / context files
@@ -1,6 +1,6 @@
1
1
  # Rev4a Glossary
2
2
 
3
- > **Last updated:** 2026-09-15
3
+ > **Last updated:** 2026-09-26
4
4
 
5
5
  Terms you'll encounter while using the Rev4a dashboard.
6
6
 
@@ -46,7 +46,7 @@ A scheduled task that runs an agent automatically at a fixed time (e.g. every ni
46
46
  The main page of Rev4a (`/`). Shows live sessions, cost summary, health cards for Rev4a's runtime, cron and lineage, and a real-time event feed. It shows no CPU, RAM, disk or load average, and there is no setup banner: an incomplete wizard redirects to `/wizard`.
47
47
 
48
48
  ## Event
49
- A lifecycle occurrence for a session: spawned, completed, errored, or a tool call made. Events appear in the live feed on the Dashboard and are pushed via SSE every 5 seconds.
49
+ A lifecycle occurrence for a session: spawned, completed, failed, or missing too long (spawn timeout); the daemon also records system anomalies (high CPU or RAM) as events. Events appear in the live feed on the Dashboard and are pushed via SSE every 5 seconds.
50
50
 
51
51
  ## Gateway
52
52
  The routing layer that connects agents to AI providers. The Gateway page manages provider API keys and the model catalogue, and pushes that catalogue to every agent. Which model a given agent runs is set elsewhere, in the Model section of that agent's detail panel.
@@ -1,6 +1,6 @@
1
1
  # What is Rev4a?
2
2
 
3
- > **Last updated:** 2026-09-22
3
+ > **Last updated:** 2026-09-26
4
4
 
5
5
  Rev4a is the control panel for your AI agent infrastructure. It shows you everything your agents are doing, how much they cost, and whether the system is healthy — all in one dashboard.
6
6
 
@@ -58,10 +58,14 @@ went missing. Afterwards **Roll back to <version>** puts back the backup taken j
58
58
  the update, on the old version; anything the agent did after the update is lost. The agent
59
59
  must be running to start an update.
60
60
 
61
- That button runs a `docker pull` from the registry. It is a download, not a build.
62
- While it runs the banner shows an indeterminate animated bar with no percentage and
63
- no log output; there is no modal, no "View Progress", no "Run in Background", and
64
- no way to abort from the UI. Status is polled every 2 seconds.
61
+ The agent base image banner above (not this update — an agent's own **Update to
62
+ <version>** recreates it on an image already downloaded) is the one running the
63
+ `docker pull`. While it runs the banner shows the percent of layers finished and the
64
+ latest line of docker's output; a **Cancel** button, offered once the download is
65
+ running, stops it. There is no modal, no "View Progress", no "Run in Background". The
66
+ outcome ("ready" and "canceled" for 3 seconds, a failure until the next action) is
67
+ reported even when it happened while the Agents page was closed or reloading, if it is
68
+ less than 30 seconds old. Status is polled every 2 seconds.
65
69
 
66
70
  ### Create Agent (`/agents/create`)
67
71
  Wizard to spin up a new agent. Steps: choose a template (Prometheus, Argus, Atlas, etc.), name your agent, pick a model, set an optional port range (default: auto-assigned 10-port block, e.g. 3700-3709). The agent is created as a Docker container with a persistent volume — all config, workspace files, and credentials survive container restarts.
@@ -70,7 +74,7 @@ Wizard to spin up a new agent. Steps: choose a template (Prometheus, Argus, Atla
70
74
  Interactive graph showing session family trees — which agent spawned which child agent, across configurable time periods: 1d, 3d, 7d, 15d, 30d, and all. Click any node to inspect. Includes a live feed side panel.
71
75
 
72
76
  ### Gateway (`/gateway`)
73
- Connects agents to AI providers. Add and remove provider API keys, enable or disable individual models in the catalogue read from `models.config.json`, and push the resulting model list to every agent container. It does not assign models to agents: choosing which model an agent runs is done per agent, in the Model section of the agent's detail panel on the Agents page.
77
+ Connects agents to AI providers. Add and remove provider API keys, enable or disable individual models in the catalogue read from `models.config.json`, and push the resulting model list to every agent container. It does not assign models to agents: choosing which model an agent runs is done per agent, in the Model section of the agent's detail panel on the Agents page. Every model row has a **Details** button: the modal shows the model's description, price and provider, its architecture and parameter count when the weights are public, reasoning modes, capabilities, benchmarks with sources, licence and how much disk the weights take — the numbers come from the model card on Hugging Face and from curated entries that cite a source, never from estimates.
74
78
 
75
79
  ### Containers (`/containers`)
76
80
  Full list of all Docker containers on the server, including stopped ones. Each row shows name, status, image, IP, ports, and an agent pill where applicable. Click "Terminal" to open an interactive shell into that container.
@@ -1,6 +1,6 @@
1
1
  # What PULSE Can Answer
2
2
 
3
- > **Last updated:** 2026-09-22
3
+ > **Last updated:** 2026-09-26
4
4
 
5
5
  PULSE is the in-dashboard AI concierge for Rev4a. This document defines what she can and cannot answer.
6
6
 
@@ -95,13 +95,13 @@ PULSE is the in-dashboard AI concierge for Rev4a. This document defines what she
95
95
  - "Why are costs missing for some sessions?"
96
96
  - "Why can't I connect to the container terminal?"
97
97
  - "Why is the gateway sync not working?"
98
- - "Why am I seeing a setup banner?"
99
98
  - "How do I check if the daemon is running?"
100
99
  - "Why are credentials not showing in my agent?"
101
100
  - "What does the yellow diamond next to an agent mean?"
102
101
  - "Why is the agent base image banner showing?"
103
102
  - "How do I fix 'image is outdated'?"
104
- - "How do agent image updates work?" — The banner on the Agents page runs a `docker pull`. It is a download, not a build: there is no modal, no live log, and no way to abort from the UI.
103
+ - "How do agent image updates work?" — The banner on the Agents page runs a `docker pull` and shows the percent of layers finished and docker's latest output line, with a Cancel button once the download is running; there is no modal or live log. The outcome is reported even if it happened while you were away, as long as it is less than 30 seconds old.
104
+ - "How big is model X / how many parameters does it have?" — Open the **Details** modal from the model row on the Gateway page: parameter counts, architecture and benchmark numbers come from the model's card on Hugging Face, with the vendor's own claim where it makes one. Models whose weights are not published (OpenAI, Anthropic, Google, Qwen's Plus/Max line) show no parameter count: the size is not public and Rev4a does not estimate it.
105
105
  - "How do I update Rev4a itself?" — The "Update available" banner starts `rev4a update` in the background (the same command as from a shell). It installs the new version and Rev4a restarts itself, so the dashboard drops for a short while; the banner waits for the new version and then confirms it, or says the update did not complete. The update's output is written to `update.log` in the Rev4a data directory (`~/.config/rev4a/data/update.log`) — the only place that says why an update failed.
106
106
  - "Why is my Telegram bot not connecting?"
107
107
  - "Why can't I approve a pairing code?"