sol 79d5e82803 feat: RHS panel initial fetch, floating widget, session cleanup (#5)
Phase 1: Fix RHS panel to fetch existing sessions on mount
- Add initial API fetch in useAllStatusUpdates() hook
- Allow GET /sessions endpoint without shared secret auth
- RHS panel now shows sessions after page refresh

Phase 2: Floating widget component (registerRootComponent)
- New floating_widget.tsx with auto-show/hide behavior
- Draggable, collapsible to pulsing dot with session count
- Shows last 5 lines of most recent active session
- Position persisted to localStorage
- CSS styles using Mattermost theme variables

Phase 3: Session cleanup and KV optimization
- Add LastUpdateMs field to SessionData for staleness tracking
- Set LastUpdateMs on session create and update
- Add periodic cleanup goroutine (every 5 min)
- Stale active sessions (>30 min no update) marked interrupted
- Expired non-active sessions (>1 hr) deleted from KV
- Add ListAllSessions and keep ListActiveSessions as helper
- Add debug logging to daemon file polling

Closes #5
2026-03-09 14:15:04 +00:00
2026-03-07 17:45:22 +00:00
2026-03-07 17:45:22 +00:00
2026-03-07 17:45:22 +00:00

Live Status v4

Real-time Mattermost progress updates for OpenClaw agent sessions.

Version 4 replaces the manual v1 live-status CLI with a transparent infrastructure daemon. Agents no longer need to call live-status. The watcher auto-updates Mattermost as they work.

Architecture

Two rendering modes (auto-detected):

Plugin Mode (preferred)

When the Mattermost plugin is installed, updates stream via WebSocket:

  • Custom post type custom_livestatus with terminal-style React rendering
  • Zero Mattermost post API calls during streaming (no "(edited)" label)
  • Auto-scroll, collapsible sub-agents, theme-compatible

REST API Fallback

When the plugin is unavailable, updates use the Mattermost REST API:

  • Blockquote-formatted posts updated via PUT
  • Shows "(edited)" label (Mattermost API limitation)
OpenClaw Gateway
  Agent Sessions
    -> writes {uuid}.jsonl as they run

  status-watcher daemon (SINGLE PROCESS)
    -> fs.watch + polling fallback on transcript directory
    -> Multiplexes all active sessions
    -> Auto-detects plugin (GET /health every 60s)
    -> Plugin mode: POST/PUT/DELETE to plugin REST endpoint
      -> Plugin broadcasts via WebSocket to React component
    -> REST fallback: PUT to Mattermost post API
    -> Shared HTTP connection pool (keep-alive, maxSockets=4)
    -> Throttled updates (leading edge + trailing flush, 500ms)
    -> Circuit breaker for API failure resilience
    -> Graceful shutdown (SIGTERM -> mark all boxes "interrupted")
    -> Sub-agent nesting (child sessions under parent status box)

  Mattermost Plugin (com.openclaw.livestatus)
    -> Go server: REST API + KV store + WebSocket broadcast
    -> React webapp: custom post type renderer
    -> Terminal-style UI with auto-scroll

  gateway:startup hook
    -> hooks/status-watcher-hook/handler.js
    -> Checks PID file; spawns daemon if not running

  Mattermost API (fallback)
    -> PUT /api/v4/posts/{id} (in-place edits, unlimited)
    -> Shared http.Agent (keepAlive, maxSockets=4)
    -> Circuit breaker: open after 5 failures, 30s cooldown

Install

Prerequisites

  • Node.js 22.x
  • OpenClaw gateway running
  • Mattermost bot token

One-command install

cd /path/to/MATTERMOST_OPENCLAW_LIVESTATUS
bash install.sh

This installs npm dependencies and deploys the gateway:startup hook. The daemon starts automatically on the next gateway restart.

Manual start (without gateway restart)

Set required env vars, then:

node src/watcher-manager.js start

Configuration

All config via environment variables. No hardcoded values.

Required

Variable Description
MM_TOKEN Mattermost bot token
MM_URL Mattermost base URL (e.g. https://slack.solio.tech)
TRANSCRIPT_DIR Path to agent sessions directory
SESSIONS_JSON Path to sessions.json

Optional

Variable Default Description
THROTTLE_MS 500 Min interval between Mattermost updates
IDLE_TIMEOUT_S 60 Inactivity before marking session complete
MAX_SESSION_DURATION_S 1800 Hard timeout per session (30 min)
MAX_STATUS_LINES 15 Max lines in status box (oldest dropped)
MAX_ACTIVE_SESSIONS 20 Concurrent status box limit
MAX_MESSAGE_CHARS 15000 Mattermost post truncation limit
HEALTH_PORT 9090 Health endpoint port (0 = disabled)
LOG_LEVEL info Logging level (pino)
PID_FILE /tmp/status-watcher.pid PID file location
CIRCUIT_BREAKER_THRESHOLD 5 Failures before circuit opens
CIRCUIT_BREAKER_COOLDOWN_S 30 Cooldown before half-open probe
TOOL_LABELS_FILE (built-in) External tool labels JSON override
DEFAULT_CHANNEL none Fallback channel for non-MM sessions
PLUGIN_URL none Plugin endpoint URL (enables plugin mode)
PLUGIN_SECRET none Shared secret for plugin authentication
PLUGIN_ENABLED true Enable/disable plugin auto-detection

Status Box Format

[ACTIVE] main | 38s
Reading live-status source code...
  exec: ls /agents/sessions [OK]
Analyzing agent configurations...
  exec: grep -r live-status [OK]
Writing new implementation...
  Sub-agent: proj035-planner
    Reading protocol...
    Analyzing JSONL format...
    [DONE] 28s
Plan ready. Awaiting approval.
[DONE] 53s | 12.4k tokens

Daemon Management

# Start
node src/watcher-manager.js start

# Stop (graceful shutdown)
node src/watcher-manager.js stop

# Status
node src/watcher-manager.js status

# Pass-through via legacy CLI
live-status start-watcher
live-status stop-watcher

# Health check
curl http://localhost:9090/health

Deployment Options

Hook (default)

The gateway:startup hook in hooks/status-watcher-hook/ auto-starts the daemon. No configuration needed beyond deploying the hook.

systemd

# Copy service file
cp deploy/status-watcher.service /etc/systemd/system/

# Create env file
cat > /etc/status-watcher.env <<EOF
MM_TOKEN=your_token
MM_URL=https://slack.solio.tech
TRANSCRIPT_DIR=/home/node/.openclaw/agents/main/sessions
SESSIONS_JSON=/home/node/.openclaw/agents/main/sessions/sessions.json
EOF

systemctl enable --now status-watcher

Docker

docker build -f deploy/Dockerfile -t status-watcher .
docker run -d \
  -e MM_TOKEN=your_token \
  -e MM_URL=https://slack.solio.tech \
  -e TRANSCRIPT_DIR=/sessions \
  -e SESSIONS_JSON=/sessions/sessions.json \
  -v /home/node/.openclaw/agents:/sessions:ro \
  -p 9090:9090 \
  status-watcher

Upgrade from v1

v1 required agents to call live-status create/update/complete manually. AGENTS.md contained a large "Live Status Protocol (MANDATORY)" section.

What changes

  1. The daemon handles all updates — no manual calls needed.
  2. AGENTS.md protocol section can be removed (see docs/v1-removal-checklist.md).
  3. skill/SKILL.md is now 9 lines: "status is automatic".
  4. live-status CLI still works for manual use but prints a deprecation notice.

Migration steps

  1. Run bash install.sh to deploy v4.
  2. Restart the gateway (hook activates).
  3. Verify the daemon is running: curl localhost:9090/health
  4. After 1+ hours of verified operation, remove the v1 AGENTS.md sections (see docs/v1-removal-checklist.md for exact sections to remove).

Troubleshooting

Daemon not starting:

  • Check PID file: cat /tmp/status-watcher.pid
  • Check env vars: MM_TOKEN, MM_URL, TRANSCRIPT_DIR, SESSIONS_JSON must all be set
  • Start manually and check logs: node src/watcher-manager.js start

No status updates appearing:

  • Check health endpoint: curl localhost:9090/health
  • Check circuit breaker state (shown in health response)
  • Verify MM_TOKEN has permission to post in the target channel

Duplicate status boxes:

  • Multiple daemon instances — check PID file, kill extras
  • node src/watcher-manager.js status shows if it's running

Session compaction:

  • When JSONL is truncated, the watcher detects it (stat.size < lastOffset)
  • Offset resets, status box shows [session compacted - continuing]
  • No crash, no data loss

Development

# Run all tests
npm test

# Run unit tests only
npm run test-unit

# Run integration tests only
npm run test-integration

# Lint + format + test
make check

Project Structure

src/
  watcher-manager.js    Entrypoint; PID file; graceful shutdown
  status-watcher.js     JSONL file watcher (inotify)
  session-monitor.js    sessions.json poller (2s interval)
  status-box.js         Mattermost post manager (throttle, circuit breaker)
  status-formatter.js   Status box text renderer
  circuit-breaker.js    Circuit breaker state machine
  config.js             Env var config with validation
  logger.js             pino wrapper
  health.js             HTTP health endpoint
  tool-labels.js        Tool name -> label resolver
  tool-labels.json      Built-in tool label defaults
  live-status.js        Legacy CLI (deprecated; backward compat)

hooks/
  status-watcher-hook/  gateway:startup hook (auto-start daemon)

deploy/
  status-watcher.service  systemd unit file
  Dockerfile              Container deployment

test/
  unit/                 Unit tests (59 tests)
  integration/          Integration tests (36 tests)
Description
No description provided
Readme 12 MiB
2026-03-15 11:20:52 +01:00
Languages
JavaScript 71%
TypeScript 10.7%
Go 9.4%
Shell 3.5%
CSS 3.5%
Other 1.9%