pulsos-cli 0.1.1

Cross-platform deployment monitoring CLI
pulsos-cli-0.1.1 is not a library.

PULSOS CLI

CI License: MIT

Cross-platform deployment monitoring CLI. Track deployments across GitHub Actions, Railway, and Vercel from a single terminal.

What is Pulsos

Pulsos is a terminal tool that gives you a unified view of deployments across GitHub Actions, Railway, and Vercel. It runs as a live TUI dashboard, as a persistent background daemon with a native system-tray icon, or as one-shot CLI output. The correlation engine matches deployment events across platforms by commit SHA and timestamp heuristics, so you can see how a single commit flows through your CI/CD pipeline.

Features

  • Live TUI with 5 tabs: Unified, Platform, Health, Settings, Logs
  • Cross-platform correlation — matches events by SHA and timestamp proximity
  • Health scoring per project (weighted: GitHub 40%, Railway 35%, Vercel 25%)
  • DORA metrics — Deployment Frequency, Lead Time, Change Failure Rate, Time to Restore
  • Real-time telemetry — Railway container metrics (CPU/RAM) and blackbox endpoint pings (TTFB/uptime)
  • Background daemonpulsos daemon start runs a persistent process with an Axum SSE server and native tray icon (macOS / Windows)
  • Auto-discovery of repos, projects, and services via repos sync
  • Saved views with filters for project, platform, branch, and status
  • ETag caching with rate-limit-aware adaptive polling
  • Credential storage — OS keyring with file fallback (~/.config/pulsos/credentials.toml)
  • Output formats — table, compact, JSON
  • Shell completions for bash, zsh, fish, powershell, elvish

Install

From crates.io

cargo install pulsos-cli

From source

git clone https://github.com/Vivallo04/pulsos-cli.git
cd pulsos-cli
cargo install --path crates/pulsos-cli

Homebrew (macOS / Linux)

brew install Vivallo04/tap/pulsos

Requirements

  • Rust 1.75+

Quick Start

# 1. Authenticate with your platforms
pulsos auth github
pulsos auth railway
pulsos auth vercel

# 2. Discover and track your repos/projects
pulsos repos sync

# 3. Launch the live TUI dashboard
pulsos status --watch

# Or get a one-shot table in your terminal
pulsos status --once

# Or run as a persistent background daemon
pulsos daemon start

What happens at each step:

  1. pulsos auth <platform> prompts for a token and stores it in your OS keyring (falls back to ~/.config/pulsos/credentials.toml).
  2. pulsos repos sync queries each authenticated platform, discovers available repos/projects/services, lets you pick which ones to track, and auto-generates correlations.
  3. pulsos status fetches recent deployments from all tracked resources, correlates them, and displays the result. With --watch it launches the live TUI; without flags it auto-detects (TUI if interactive terminal, one-shot otherwise).
  4. pulsos daemon start detaches the daemon to the background. The TUI automatically connects to the daemon's SSE stream when one is running, saving API quota.

Authentication

Token Resolution Order

Pulsos resolves tokens in this priority order:

  1. Environment variables — checked first
  2. OS keyring — via keyring crate (macOS Keychain, Windows Credential Manager, Linux Secret Service)
  3. CLI config detection — reads tokens from gh, railway, and vercel CLI config files

Environment Variables

Platform Variables
GitHub GH_TOKEN, GITHUB_TOKEN
Railway RAILWAY_TOKEN, RAILWAY_API_TOKEN
Vercel VERCEL_TOKEN

Interactive Setup

pulsos auth github              # Authenticate with GitHub
pulsos auth railway             # Authenticate with Railway
pulsos auth vercel              # Authenticate with Vercel

Each command prompts for a token, validates it against the platform API, and stores it.

Non-Interactive / CI

# Store tokens in one shot (CI mode)
pulsos auth --ci --github-token=ghp_xxx --railway-token=xxx --vercel-token=xxx

# Check which tokens are resolved
pulsos auth status

# Re-validate stored tokens; re-prompts if invalid
pulsos auth refresh

# Remove stored tokens
pulsos auth logout
pulsos auth logout --platform github

Token Detection Toggles

You can disable automatic detection of specific sources in config.toml:

[auth.token_detection]
detect_gh_cli = true
detect_railway_cli = true
detect_vercel_cli = true
detect_env_vars = true

Configuration

Config file location: ~/.config/pulsos/config.toml

Run pulsos config path to print the exact path, or pulsos config edit to open it in $EDITOR.

Full Example

[auth]
github_host = "github.mycompany.com"   # Default: "github.com"

[auth.token_detection]
detect_gh_cli = true
detect_railway_cli = false
detect_vercel_cli = true
detect_env_vars = true

[[github.organizations]]
name = "myorg"
include_patterns = ["api-*"]
exclude_patterns = ["*-legacy"]
auto_discover = true

[[railway.workspaces]]
name = "lambda-prod"
include_projects = ["my-saas-api"]
default_environment = "production"      # Default: "production"

[[vercel.teams]]
name = "lambda"
include_projects = ["my-saas-web"]
include_preview_deployments = true

[[correlations]]
name = "my-saas"
github_repo = "myorg/my-saas"
railway_project = "my-saas-api"
vercel_project = "my-saas-web"

[correlations.branch_mapping]
main = "production"
develop = "staging"

[[views]]
name = "production"
description = "Production systems"
projects = ["my-saas", "api-core"]
platforms = ["github", "railway", "vercel"]
branch_filter = "main"
status_filter = ["success", "failure"]
refresh_interval = 5

[[groups]]
name = "backend"
resources = ["api-core", "auth-service"]

[tui]
theme = "dark"                  # "dark" or "light"
fps = 10                        # Render frames per second
refresh_interval = 5            # Seconds between API polls
default_tab = "unified"         # "unified", "platform", "health", "settings", "logs"
show_sparklines = true
unicode = "auto"                # "auto", "always", "never"

[cache]
max_size_mb = 100

Config Sections

Section Purpose
[auth] GitHub Enterprise host, token detection toggles
[[github.organizations]] Org name, include/exclude repo patterns
[[railway.workspaces]] Workspace name, include/exclude projects, default environment
[[vercel.teams]] Team name, include projects, preview deployment toggle
[[correlations]] Link a GitHub repo, Railway project, and Vercel project under one name
[[views]] Named filter presets (projects, platforms, branch, status)
[[groups]] Named collections of resources for UI-level grouping
[tui] Theme, FPS, refresh interval, default tab, sparklines
[cache] Max cache size in MB

CLI Commands

Status

pulsos                              # Default: show deployment status
pulsos status                       # Same as above
pulsos status --watch               # Live TUI mode
pulsos status --once                # Force one-shot output
pulsos status --platform github     # Filter by platform
pulsos status --view production     # Use a saved view
pulsos status --branch main         # Filter by branch
pulsos status --format json         # JSON output
pulsos status --format compact      # Compact output

Auth

pulsos auth github                  # Authenticate with GitHub
pulsos auth railway                 # Authenticate with Railway
pulsos auth vercel                  # Authenticate with Vercel
pulsos auth github --token ghp_xxx  # Non-interactive with token
pulsos auth status                  # Check auth status across platforms
pulsos auth refresh                 # Re-validate tokens, re-prompt if invalid
pulsos auth refresh --platform github  # Refresh a specific platform
pulsos auth logout                  # Remove tokens (prompts for platform)
pulsos auth logout --platform github   # Remove a specific platform token
pulsos auth --ci --github-token=xxx    # CI mode: store tokens non-interactively
pulsos auth --from-env              # Only check env vars (skip keyring/interactive)

Repos

pulsos repos sync                   # Discover, select, and save (all platforms)
pulsos repos list                   # Show tracked repos/projects
pulsos repos add github:org/repo    # Add a resource
pulsos repos remove github:org/repo # Remove a resource
pulsos repos correlate my-saas      # Edit correlations for a project
pulsos repos groups list            # List resource groups
pulsos repos groups create mygroup -- github:org/repo railway:project
pulsos repos groups delete mygroup  # Delete a group
pulsos repos verify                 # Check access permissions for tracked resources

Views

pulsos views                        # List all views (default)
pulsos views list                   # List all views
pulsos views show production        # Display view details
pulsos views create                 # Create a view interactively
pulsos views edit production        # Edit a view interactively
pulsos views delete production      # Delete a view
pulsos views templates              # List built-in templates
pulsos views validate production    # Validate view projects against correlations
pulsos views export production -o view.json  # Export to JSON
pulsos views import view.json       # Import from JSON

Config

pulsos config                       # Print current config as TOML (default)
pulsos config show                  # Print current config as TOML
pulsos config path                  # Print config file path
pulsos config edit                  # Open config in $EDITOR
pulsos config wizard                # Run interactive platform setup wizard

Daemon

pulsos daemon run                   # Run the daemon in the foreground (owns main thread for tray icon)
pulsos daemon start                 # Start the daemon as a detached background process
pulsos daemon stop                  # Stop the running daemon (sends SIGTERM via PID file)
pulsos daemon status                # Print daemon running state and port

Daemon architecture:

  • daemon run starts an Axum SSE server on an ephemeral port, writes the port to ~/.config/pulsos/daemon.port, generates a random 64-char bearer token at ~/.config/pulsos/daemon.token (mode 0600 on Unix), and (on macOS/Windows) shows a native tray icon in the menu bar.
  • daemon start re-execs daemon run as a detached process (stdin/stdout/stderr closed).
  • daemon stop reads ~/.config/pulsos/daemon.pid and sends SIGTERM (Unix) or taskkill /F (Windows), then removes daemon.pid, daemon.port, and daemon.token.
  • daemon status checks the /health endpoint of the running daemon.
  • When a daemon is running, pulsos status --watch connects to its bearer-auth-protected SSE stream (/api/stream) instead of polling platform APIs directly, conserving rate-limit budget. The /health endpoint remains public (used by daemon status).
  • The tray icon shows three states: neutral (all OK), syncing (blue), alert (red — endpoint down or deployment failure on main/master).
  • Desktop notifications fire on endpoint state transitions (up→down, down→up) on macOS and Windows.

Other

pulsos doctor                       # Run diagnostics (system, auth, connectivity, cache)
pulsos completions bash             # Generate shell completions
pulsos completions zsh
pulsos completions fish
pulsos completions powershell
pulsos completions elvish

Global Flags

Flag Description
--format <table|compact|json> Output format (default: table)
--no-color Disable color output
--verbose Show debug information
--config <path> Custom config file path

TUI Keyboard Shortcuts

Key Action
15 Switch to tab (Unified, Platform, Health, Settings, Logs)
Tab / Shift+Tab Cycle tabs forward / backward
j / k or / Navigate rows
/ Enter search mode
Enter Apply search (in search mode)
Esc Exit search mode / cancel
r Force refresh
s Cycle sort order on Unified tab (by time / by platform)
q / Ctrl+C Quit

Platform Tab

Key Action
/ Switch provider subtab (GitHub / Railway / Vercel)
g Switch to GitHub subtab
w Switch to Railway subtab
v Switch to Vercel subtab
d Toggle GitHub job/step details panel (GitHub subtab only)

Platform Tab — Details Panel (GitHub)

Key Action
/ or j / k Navigate tree / scroll right panel
/ Enter Expand job or open right panel
Collapse job or focus left tree
PageDown / PageUp Scroll right panel by 20 lines
Ctrl+D / Ctrl+U Scroll right panel by 10 lines
Esc Close details panel

Logs Tab

Key Action
f Cycle log level filter (ALL → ERR → WARN → INFO → ALL)
c Copy selected log message to clipboard

Settings Tab

Key Action
t Enter token for selected platform
T Enter token (force override even with env token)
v Validate selected platform
x Remove stored token
o / Enter Start onboarding / discovery flow

Project Architecture

pulsos-cli/
├── crates/
│   ├── pulsos-core/          # Library crate
│   │   └── src/
│   │       ├── platform/     # GitHub, Railway, Vercel API clients + retry helper
│   │       ├── correlation/  # Event matching engine (SHA + timestamp heuristic)
│   │       ├── domain/       # DeploymentEvent, CorrelatedEvent, DoraMetrics,
│   │       │                 # ResourceMetrics, EndpointHealth, health scoring
│   │       ├── auth/         # Credential resolution, KeyringStore, FileCredentialStore, FallbackStore
│   │       ├── config/       # TOML config loading and saving
│   │       ├── cache/        # sled-based ETag cache
│   │       ├── health/       # Platform health checks (PlatformHealthReport) + PingEngine
│   │       ├── scheduler/    # Polling budget and adaptive scheduler
│   │       ├── analytics/    # DoraCalculator
│   │       └── sync/         # Auto-correlation builder (build_correlations, merge)
│   ├── pulsos-cli/           # Binary crate
│   │   ├── assets/           # Embedded tray icon PNGs (neutral, sync, alert — 16x16)
│   │   └── src/
│   │       ├── main.rs       # CLI entry point (clap); daemon run owns main thread for tray
│   │       ├── commands/     # Command handlers: status, auth, repos, views, config, doctor, daemon
│   │       │   ├── daemon.rs # pulsos daemon [run|start|stop|status]
│   │       │   ├── wizard.rs # First-run config wizard (auth + discovery + re-check)
│   │       │   └── ui/       # Full-screen interactive prompt layer (ScreenSession)
│   │       ├── daemon/       # Background daemon subsystem
│   │       │   ├── engine.rs # Wraps run_poller; broadcasts DataSnapshot via SSE channel
│   │       │   ├── server.rs # Axum SSE server (/api/stream, /health); writes daemon.port
│   │       │   ├── tray.rs   # Native tray icon (macOS/Windows only; tray-icon + tao + muda)
│   │       │   └── notify.rs # Desktop notifications on endpoint state transitions
│   │       ├── tui/          # ratatui live TUI (5 tabs: Unified, Platform, Health, Settings, Logs)
│   │       │   ├── poll.rs   # Background poller; connects to SSE if daemon is running
│   │       │   ├── actions.rs # ActionRequest/ActionResult async channel for settings
│   │       │   └── widgets/  # Per-tab rendering components + log_buffer, settings_flow
│   │       └── output/       # Table, compact, JSON formatters
│   └── pulsos-test/          # Test helpers and builders (EventBuilder, mock servers)
└── Cargo.toml                # Workspace root

Daemon File Locations

File Path Notes
Port file ~/.config/pulsos/daemon.port Written by SSE server on bind; mode 0600 on Unix
PID file ~/.config/pulsos/daemon.pid Written by daemon run on startup
Token file ~/.config/pulsos/daemon.token 64-char random hex bearer token; mode 0600 on Unix; removed on stop
Credentials ~/.config/pulsos/credentials.toml File-based fallback; mode 0600 on Unix
Config ~/.config/pulsos/config.toml Main TOML config

Polling Intervals (TUI / Poller)

Platform Interval Notes
GitHub 30s (adaptive) Backs off to 60s/120s as rate limit is consumed
Railway 15s
Vercel 15s
Health checks 30s Per-platform token + connectivity readiness
Container metrics 30s Railway CPU/RAM via GraphQL
Endpoint pings 8s Blackbox TTFB/uptime; does not consume platform quota

Development

Prerequisites

  • Rust 1.75+

Build

cargo build --workspace

Test

cargo test --workspace

Lint

cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings

Run Locally

cargo run --bin pulsos -- status
cargo run --bin pulsos -- status --watch
cargo run --bin pulsos -- doctor
cargo run --bin pulsos -- daemon run

License

MIT


Last Updated: 2026-02-23