Scripts Reference
Overview
The scripts/ directory contains operational scripts for the dashboard: health monitoring, server lifecycle, data normalization, testing, project synchronization, and system improvement scanning.
Script Index
| Script | Language | Purpose |
|---|---|---|
restart-task-server.sh |
Bash | Stop and restart the dashboard and filesystem API servers |
dashboard-health.sh |
Bash | Health monitor with auto-restart |
smoke-test-dashboard.sh |
Bash | End-to-end API smoke test |
dashboard-validation.js |
Node.js | Deep validation of database integrity and API correctness |
normalize-task-dependency-statuses.js |
Node.js | Fix tasks stuck in in_progress with incomplete dependencies |
aggregate-department-metrics.js |
Node.js | Persist daily department KPI snapshots |
sync-openclaw-projects.mjs |
Node.js (ESM) | Seed and synchronize OpenClaw project hierarchy and tasks |
test-incremental-sync.js |
Node.js | Test updated_since pagination on task API |
apply-workflow-migration.sh |
Bash | Apply the workflow runs migration (001) |
backfill-run-costs.js |
Node.js | Backfill workflow_runs token/cost columns from OpenClaw session JSONL transcripts (dry run by default) |
dag-telemetry-counter.js |
Node.js | DAG GO/NO-GO telemetry counter: workflow-graph audit events → decision inputs + branch verdict |
mcp-adoption-counter.js |
Node.js | MCP tool-call adoption counter: mcp-tool-call audit rows → per-tool call counts, ok/error split, days-with-activity, never-called tools |
system-improvement-scan.sh |
Bash | Cron trigger for daily system improvement scan |
system-improvement-engine.py |
Python 3 | Analyze system state and create approval-gated improvement runs |
Detailed Reference
restart-task-server.sh
Stop any running dashboard server (and filesystem API), then start fresh using systemd-run when available (falls back to nohup).
Usage:
bash scripts/restart-task-server.sh
Behavior:
- Reads PID files (primary + legacy) and stops existing processes.
- Kills any orphan process on port
$PORTand$FILESYSTEM_API_PORT. - Starts
task-server.jsviasystemd-run --user(ornohup). - Starts
filesystem-api-server.mjsthe same way. - Verifies both servers pass their health checks.
- Writes PID files.
Environment Variables:
| Variable | Default | Description |
|---|---|---|
PORT |
3876 |
Dashboard server port |
HOST |
127.0.0.1 |
Bind address |
OPENCLAW_WORKSPACE |
../../ (relative) |
Workspace root |
FILESYSTEM_API_PORT |
3880 |
Filesystem API port |
STORAGE_TYPE |
postgres |
Storage backend |
POSTGRES_* |
— | Database connection settings (forwarded to server) |
Dependencies: systemd-run (optional), curl, lsof/fuser/ss
dashboard-health.sh
Health monitor that checks if the dashboard and filesystem API are running and responding. Can auto-restart on failure.
Usage:
bash scripts/dashboard-health.sh check # Default: check health, restart if down
bash scripts/dashboard-health.sh start # Force restart
bash scripts/dashboard-health.sh stop # Stop both servers
bash scripts/dashboard-health.sh status # Report health status
Behavior (check mode):
- Checks if port 3876 is listening.
- Sends GET to
/api/healthwith a 5-second timeout. - Sends GET to filesystem API health endpoint.
- If any check fails, calls
restart-task-server.sh.
Environment Variables:
| Variable | Default | Description |
|---|---|---|
PORT |
3876 |
Dashboard port |
HOST |
127.0.0.1 |
Bind address |
DASHBOARD_LOG_DIR |
$OPENCLAW_WORKSPACE/logs |
Log directory |
DASHBOARD_HEALTH_LOG_FILE |
$OPENCLAW_WORKSPACE/logs/dashboard-health.log |
Health check log |
Dependencies: curl, ss, lsof/fuser
smoke-test-dashboard.sh
Minimal end-to-end test that exercises the core API lifecycle: health check, filesystem read, project CRUD.
Usage:
bash scripts/smoke-test-dashboard.sh
Test steps:
- GET
/api/health-status— verify status field exists. - GET
/api/fs/file?path=AGENTS.md— verify filesystem API returns a file. - POST
/api/projects— create a temporary project. - GET
/api/projects/:id— read it back. - GET
/api/projects— list all projects. - DELETE
/api/projects/:id— clean up.
Exit codes: 0 on pass, 1 on any failure.
Environment Variables:
| Variable | Default | Description |
|---|---|---|
HOST |
127.0.0.1 |
Dashboard host |
PORT |
3876 |
Dashboard port |
FS_CANARY_PATH |
AGENTS.md |
File used for filesystem API test |
Dependencies: curl, python3 (for JSON parsing)
dashboard-validation.js
Comprehensive validation suite that checks database schema, data integrity, and API endpoints.
Usage:
node scripts/dashboard-validation.js
Checks performed:
- PostgreSQL connection
- Schema: Verifies
projects,tasks,workflows,audit_logtables exist - Data integrity: Orphaned tasks, missing required fields, invalid dependency references, circular dependencies, blocked tasks with incomplete dependencies, parent-child validity, completion rule consistency
- API endpoints:
/api/health,/api/stats, agent views, filesystem API, project CRUD, pagination limits, project-scoped task/timeline endpoints - QMD integration: Verifies QMD data directory exists
Exit codes: 0 (pass), 0 with warnings, 1 (failure).
Environment Variables:
| Variable | Default | Description |
|---|---|---|
POSTGRES_HOST |
localhost |
Database host |
POSTGRES_PORT |
5432 |
Database port |
POSTGRES_DB |
openclaw_dashboard |
Database name |
POSTGRES_USER |
openclaw |
Database user |
POSTGRES_PASSWORD |
(required) | Database password |
PORT |
3876 |
Dashboard port (for API base URL) |
DASHBOARD_API_BASE |
http://localhost:$PORT |
Override API base URL |
Dependencies: pg (npm), Node.js built-in http
normalize-task-dependency-statuses.js
Finds tasks in in_progress status that have incomplete dependencies and moves them to blocked.
Usage:
node scripts/normalize-task-dependency-statuses.js --dry-run
node scripts/normalize-task-dependency-statuses.js
node scripts/normalize-task-dependency-statuses.js --limit 25
Arguments:
| Argument | Description |
|---|---|
--dry-run |
List tasks that would be normalized without writing changes |
--limit N |
Only inspect the first N matching tasks (1–1000) |
-h, --help |
Show help |
Output: For each affected task, prints the task ID, title, and either the blocking dependencies (dry-run) or the new status.
Dependencies: storage/asana (project-local AsanaStorage module)
aggregate-department-metrics.js
Computes and persists daily department KPI snapshots into the department_daily_metrics table.
Usage:
node scripts/aggregate-department-metrics.js
node scripts/aggregate-department-metrics.js --yesterday
node scripts/aggregate-department-metrics.js --date 2026-03-12
node scripts/aggregate-department-metrics.js --date 2026-03-12 --backfill-days 7
Arguments:
| Argument | Description |
|---|---|
--date YYYY-MM-DD |
Target snapshot date (default: today UTC) |
--yesterday |
Shorthand for yesterday’s date |
--backfill-days N |
Persist N consecutive days ending at --date (1–366) |
-h, --help |
Show help |
Dependencies: storage/asana, metrics-api.js, fs (reads openclaw.json)
sync-openclaw-projects.mjs
Seeds and synchronizes the OpenClaw project hierarchy and tasks from a hardcoded definition. Designed for idempotent re-runs.
Usage:
node scripts/sync-openclaw-projects.mjs
Behavior:
- Archives stale projects matching legacy name patterns.
- Creates or updates the project tree (OpenClaw System → Dashboard & Task System, Memory & Recall, etc.).
- Creates or updates seed tasks within each project with status, priority, owner, labels, and preferred model metadata.
- Skips updates when existing data already matches.
Arguments: None.
Environment Variables:
| Variable | Default | Description |
|---|---|---|
DASHBOARD_API_BASE |
http://localhost:3876 |
Dashboard API base URL |
Dependencies: ESM fetch (Node.js built-in), no external packages.
test-incremental-sync.js
Tests the updated_since query parameter on /api/tasks/all for incremental sync support.
Usage:
node scripts/test-incremental-sync.js
Test steps:
- Fetches all projects, picks the first.
- Fetches all tasks for the project.
- Identifies the most recently updated task.
- Queries with
updated_sinceset to 10 minutes before that update. - Verifies the returned set matches a manual timestamp filter.
- Queries with a future timestamp and verifies zero results.
Exit codes: 0 on pass, 1 on failure.
Dependencies: node-fetch
apply-workflow-migration.sh
Applies the 001_add_workflow_runs.sql migration to the database with safety checks.
Usage:
bash scripts/apply-workflow-migration.sh
Behavior:
- Validates
psqlis available. - Tests database connectivity.
- Checks if
workflow_runstable already exists (prompts before overwriting). - Applies the migration SQL file.
- Reports created tables, views, and seeded templates.
Environment Variables: Standard POSTGRES_* variables.
Dependencies: psql
backfill-run-costs.js
One-shot backfill of the migration-022 token/cost columns (input_tokens, output_tokens, cached_tokens, model_id, cost_estimate, currency, reported_at) on workflow_runs from historical OpenClaw gateway session data.
Usage:
node scripts/backfill-run-costs.js # dry run (default)
node scripts/backfill-run-costs.js --apply # write to PostgreSQL
node scripts/backfill-run-costs.js --limit 5 --verbose
node scripts/backfill-run-costs.js --run-id <uuid>
Data source: session JSONL transcripts under <OPENCLAW_HOME|HOME>/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl — every assistant message line carries an exact per-message usage object (input, output, cacheRead, cacheWrite, and a gateway-reported cost). Chosen over the openclaw status CLI (context-size snapshot only, no input/output split), the state SQLite DB (no token tables), and sessions.json (single context snapshot) because it is the only source with exact cumulative token numbers.
Join key: workflow_runs.gateway_session_id (= claim_session_id when set) holds an OpenClaw session key (agent:<agentId>:<channel>:<id>), resolved through that agent’s sessions.json to the current sessionId plus its usageFamilySessionIds (rotated transcripts). Values written by other components — spawned-<runId8>-pid<n> from workflow-run-monitor.js, test fixtures — are reported as unmatched.
Windowing: a session key can outlive many runs (shared sessions like agent:main:main), so usage is summed only from assistant messages timestamped inside the run window [started_at, finished_at] (inclusive; open upper bound when finished_at is NULL). Runs without started_at are skipped rather than attributed a whole shared session.
Cost policy: cost_estimate is written only from positive gateway-reported per-message cost totals. When no price source exists (the case on this deployment: all recorded costs are 0 and no model catalog carries pricing), cost_estimate stays NULL — prices are never invented. currency is stamped USD; model_id gets the dominant provider/model among in-window usage messages.
Idempotency: only runs whose token/cost columns are ALL NULL are selected, writes go through the slice-1 storage/asana.js helper (updateWorkflowRunUsage, sets reported_at = NOW()), and each row is re-checked before update — re-runs never overwrite non-NULL values.
Behavior:
- Loads unreported runs with a gateway session binding (PostgreSQL via the shared storage pool).
- Resolves each session key to transcript files and aggregates in-window usage.
- Dry run prints what would be written;
--applyperforms batched sequential updates. - Prints a summary: considered / matched / unmatched-by-reason / skipped counts.
Graceful degradation: exits 0 with an honest summary when PostgreSQL is unreachable, migration 022 has not been applied, or no gateway transcripts survive (transcript retention means sessions older than ~July 2026 may be pruned).
Environment Variables: standard POSTGRES_* variables; OPENCLAW_HOME (default $HOME) for the gateway data root.
Dependencies: pg (via storage/asana.js)
dag-telemetry-counter.js
Operational counter for the workflow visual editor Stage 1 earn-use rule (docs/briefs/workflow-visual-editor-stage1.md §6): reads the workflow-graph-open / workflow-graph-feedback audit_log rows written by POST /api/workflow-graph/events since the staging deploy date 2026-08-25 and prints the decision inputs plus the current GO/NO-GO branch for the roadmap review landing ~2026-09-14.
Usage:
node scripts/dag-telemetry-counter.js
npm run dag:telemetry
Decision window: 2026-08-25 → 2026-09-14 inclusive (21 days, UTC calendar days).
Branch rule (mechanical, per brief §6):
| Branch | Condition |
|---|---|
go |
≥8 distinct render-days AND ≥3 explicit edit asks (👍 feedback rows) |
no_go |
<4 distinct render-days AND zero asks |
middle |
everything else → review with numbers |
Output: distinct render-days, total opens, 👍/👎 counts, distinct templates touched, days remaining in the window, a GO pace check, and the branch verdict. Render-days count only workflow-graph-open rows (per the brief’s metric definition); templates are collected from both event types. An early-window empty result numerically lands no_go — the report always prints days remaining so an in-flight window is never mistaken for a final verdict.
Graceful degradation: any database-layer failure (unreachable PostgreSQL, missing database, missing audit_log table, auth failure) prints an honest unavailable message and exits 0 — the script must work in CI-less, DB-less contexts without failing. Unavailable is never reported as zero.
Environment Variables: standard POSTGRES_* variables (same as dashboard-validation.js; connection timeout 5 s so DB-less contexts fail fast).
Dependencies: pg (already required by the dashboard; no new dependencies). Pure evaluation lives in evaluateDagTelemetry(rows, nowMs) — covered DB-free by tests/test-dag-telemetry.js.
mcp-adoption-counter.js
Operational counter for MCP tool-call adoption (improvement-loop queue: answers “did anything actually call our tools?” with data): reads the mcp-tool-call audit_log rows written by POST /api/mcp/telemetry (routes/mcp-telemetry-routes.js, fed by fire-and-forget emission in lib/mcp-server.js) since the MCP slice-1 ship date 2026-08-25 and prints total calls, the ok/error split, days-with-activity, first/last call timestamps, a per-tool breakdown, and which registered tools have NEVER been called this window.
Usage:
node scripts/mcp-adoption-counter.js
npm run mcp:telemetry
Output: totals + ok/error split (unattributed-outcome rows reported separately), tools-used vs registered count, distinct UTC days with activity, first/last call ISO timestamps, per-tool table sorted by call count, and the never-called list. Distinct client sessions are honestly reported as not derivable — the stdio transport carries no session identity. An empty window prints “adoption has not started” rather than an empty table.
Graceful degradation: identical contract to dag-telemetry-counter.js — any database-layer failure (unreachable PostgreSQL, missing database, missing audit_log table, auth failure) prints an honest unavailable message and exits 0. Unavailable is never reported as zero.
Environment Variables: standard POSTGRES_* variables (same as dashboard-validation.js; connection timeout 5 s so DB-less contexts fail fast).
Dependencies: pg (already required by the dashboard; no new dependencies). Pure aggregation lives in evaluateMcpAdoption(rows) — covered DB-free by tests/test-mcp-telemetry.js.
system-improvement-scan.sh
Cron-triggered wrapper that creates a workflow run for the system improvement scan.
Usage:
bash scripts/system-improvement-scan.sh
Behavior:
- Checks if a scan is already active (skips if so).
- Checks if a scan completed in the last 20 hours (skips if so).
- Creates a
system-improvement-scanworkflow run via POST/api/workflow-runs. - Logs result to
$LOG_DIR/system-improvement-scan.log.
Suggested cron: 0 8 * * * (daily at 08:00).
Dependencies: curl, python3
system-improvement-engine.py
Analyzes the current system state (templates, runs, approvals, cron health) and creates approval-gated workflow runs for improvement suggestions.
Usage:
python3 scripts/system-improvement-engine.py
Analysis areas:
- Artifact contracts — templates missing output definitions
- Workflow health — failed or stuck runs
- Cron health — stale or missing cron job logs
- Workflow output — low artifact capture rate on completed runs
- Approval gaps — publishing/site-change runs bypassing approval gates
Behavior:
- Gathers system state from dashboard API endpoints and log file timestamps.
- Analyzes opportunities based on thresholds.
- Deduplicates against existing pending approvals.
- Creates approval-gated workflow runs for each actionable suggestion.
- Prints a JSON summary to stdout.
Suggested cron: Triggered by system-improvement-scan.sh via workflow run.
Dependencies: Python 3.10+ (stdlib only — urllib, json, subprocess)