Autonomous, ultra-lightweight browser smoke-testing daemon & CLI toolset in Rust.
Continuously monitors web apps, validates DOM assertions, captures failure screenshots, and consumes <30 MB RAM.
Install and run SiteWarden on any Linux server with a single command:
curl -fsSL https://raw.githubusercontent.com/Shantodotdev/sitewarden/master/install.sh | bashThe script sets up /opt/sitewarden, initializes your config.yaml, sets permissions, pulls the official container image, and starts the background daemon.
- 🏎️ Hybrid Execution Engine:
- Pure-Rust Static Mode (
reqwest+scraper): Non-interactive tests run purely in-memory (~2 MB RAM, ~5ms latency, 0 browser processes). - On-Demand Headless Browser: Interactive tests (
click,type_text,wait_for_selector) launch headless Chromium on-demand and immediately release all memory upon completion.
- Pure-Rust Static Mode (
- 🌱 Low VPS Resource Footprint: Idles at ~25–30 MB RSS, designed specifically for budget $5/mo (512MB RAM) cloud VPS nodes.
- 📊 Interactive CLI Suite: Rich subcommands (
status,history,check,test,update,prune,doctor) for fast observability without sifting through logs. - 🔄 Zero-Downtime Hot-Reloading: Uses inotify filesystem watchers to detect changes to
config.yamland re-schedules cron cycles live in memory. - 📸 Failure Screenshots: Automatically captures full-page high-resolution screenshots on test failures and saves them to the host directory.
- 🎨 Vibrant Terminal Tree Reporting: Laser-aligned Unicode columns, ANSI color-coded actions, and clean ASCII summary scorecards.
2026-09-01T06:04:18Z INFO 🚀 Starting Smoke Test Cycle • 2026-09-01 06:04:18 UTC [2 Suites • 2 Tests (8 Steps) • Concurrency: 2]
2026-09-01T06:04:19Z INFO ▶ Executing Suite: Example Domain Health Check (https://example.com) [Engine: Browser • 1 Tests • 4 Steps]
▶ Test: Verify Homepage Heading and Body
├── [1/4] 🌐 navigate → / [OK • 38ms]
├── [2/4] ⏳ wait_for_selector → h1 [OK • 11ms]
├── [3/4] 🔍 assert_text → 'h1' contains 'Example Domain' [OK • 2ms]
├── [4/4] 👁️ assert_visible → p [OK • 7ms]
└── ✅ Test Passed (61ms)
┌──────────────────────────────────────────────────────────────────────────────────────────┐
│ SiteWarden Test Cycle Report │
├──────────────────────────────────────┬──────────┬────────────┬──────────┬────────────────┤
│ Suite Name │ Engine │ Result │ Tests │ Duration │
├──────────────────────────────────────┼──────────┼────────────┼──────────┼────────────────┤
│ Example Domain Health Check │ Browser │ ✅ PASS │ 1/1 (4) │ 211ms │
│ Wikipedia Navigation Test │ Browser │ ✅ PASS │ 1/1 (4) │ 962ms │
├──────────────────────────────────────┴──────────┴────────────┴──────────┴────────────────┤
│ ✅ All 2 Suites Passed (100%) • Total Cycle Time: 1.37s │
└──────────────────────────────────────────────────────────────────────────────────────────┘
When installed via install.sh, SiteWarden provides a global host CLI tool:
sitewarden [COMMAND] [OPTIONS]
Displays the overall daemon health, uptime, total runs, success rate, and screenshot disk usage:
sitewarden status┌───────────────────────── SiteWarden Service Status ──────────────────────────┐
│ Execution Mode: 🟢 Active Daemon (PID: 1482) │
│ Uptime & Cron: Up 4d 12h (Cron: '0 0 6 * * *') │
│ Version: v0.1.0 (Latest) │
├──────────────────────────────────────────────────────────────────────────────┤
│ Total Cycles: 148 runs (146 Passed, 2 Failed • 98.6% Success Rate) │
│ Last Run: 2026-09-01 06:04:18 UTC (✅ Passed, 1366ms) │
├──────────────────────────────────────────────────────────────────────────────┤
│ Monitored Suites: 2 configured (2 tests, 8 steps) │
│ Screenshots: 2 artifacts (1.42 MB) in /opt/sitewarden/screenshots │
└──────────────────────────────────────────────────────────────────────────────┘
Executes a specific test suite or all test suites immediately on demand:
# Run a specific suite
sitewarden test "Example Domain Health Check"
# Run all configured suites
sitewarden testStreams real-time structured logs from the background daemon:
sitewarden logsDisplays a timeline of recent test cycles:
sitewarden history --limit 5┌──────────────────────┬────────────────────────┬────────────┬──────────────┬────────────┐
│ Timestamp (UTC) │ Suites (Pass/Fail) │ Result │ Duration │ Trigger │
├──────────────────────┼────────────────────────┼────────────┼──────────────┼────────────┤
│ 2026-09-01 06:04:18 │ 2/2 (8 steps) │ ✅ PASS │ 1.37s │ Cycle │
│ 2026-09-01 00:00:00 │ 2/2 (8 steps) │ ✅ PASS │ 1.12s │ Cycle │
│ 2026-08-31 18:00:00 │ 1/2 (7 steps) │ ❌ FAIL │ 2.45s │ Cycle │
└──────────────────────┴────────────────────────┴────────────┴──────────────┴────────────┘
Pre-flight verification for config.yaml syntax, cron expressions, CSS selectors, and target endpoint reachability:
sitewarden check🔍 Validating configuration at: "config.yaml"
✅ YAML syntax and schema valid
✅ Schedule expression valid (Cron: '0 0 6 * * *')
✅ 2 Suites loaded (8 Total Steps)
🌐 Testing endpoint connectivity...
✅ Reachable: https://example.com (HTTP 200 OK) → [Headless Browser]
✅ Reachable: https://en.wikipedia.org (HTTP 200 OK) → [Headless Browser]
🎉 Configuration is 100% valid and production-ready!
Convenient daemon lifecycle controls:
sitewarden restart
sitewarden stop
sitewarden startCleans up old failure screenshot artifacts from disk to prevent VPS storage leaks:
# Simulate pruning screenshots older than 7 days
sitewarden prune --days 7 --dry-run
# Delete screenshots older than 14 days
sitewarden prune --days 14Runs environment and diagnostic health checks (Chromium binary detection, screenshot directory permissions, network DNS):
sitewarden doctorSiteWarden is configured declaratively using YAML:
# Cron schedule expression (sec min hour day month weekday)
schedule: "0 0 6 * * *"
# Resource limits & concurrency
browser_concurrency: 2
timeout_seconds: 30
screenshot_dir: "/app/screenshots"
# Declarative Test Suites
suites:
- name: "Marketing Site Health Check"
base_url: "https://example.com"
tests:
- name: "Verify Homepage Heading"
steps:
- action: navigate
path: "/"
- action: assert_text
selector: "h1"
contains: "Example Domain"
- action: assert_visible
selector: "p"
- name: "User Portal Flow"
base_url: "https://app.example.com"
tests:
- name: "Verify Login Interaction"
steps:
- action: navigate
path: "/login"
- action: wait_for_selector
selector: "input#email"
timeout_ms: 5000
- action: type_text
selector: "input#email"
text: "smoke-test@example.com"
- action: click
selector: "button#submit"| Action | Parameters | Description |
|---|---|---|
navigate |
path: "/route" |
Navigates to a relative path or absolute URL |
assert_text |
selector: "h1", contains: "Text" |
Asserts DOM element contains text substring |
assert_visible |
selector: ".btn" |
Asserts DOM element exists and is visible |
wait_for_selector |
selector: "#modal", timeout_ms: 5000 |
Polls DOM until element appears |
click |
selector: "button#submit" |
Scrolls to element and triggers click event |
type_text |
selector: "input#name", text: "val" |
Focuses input and types characters |
If you prefer deploying manually with Docker Compose:
mkdir -p /opt/sitewarden/screenshots && cd /opt/sitewarden
sudo chown -R 1000:1000 screenshots
curl -fsSL https://raw.githubusercontent.com/Shantodotdev/sitewarden/master/docker-compose.yml -o docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/Shantodotdev/sitewarden/master/config.example.yaml -o config.yaml
docker compose up -dTo compile and run SiteWarden natively:
# Clone repository
git clone https://github.com/Shantodotdev/sitewarden.git && cd sitewarden
# Run automated tests (29 unit & integration tests)
cargo test
# Run configuration pre-flight check
cargo run -- --config config.example.yaml check
# Run on-demand test cycle
cargo run -- --config config.example.yaml test
# Start background daemon
cargo run -- --config config.example.yaml daemonDual-licensed under either:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.