{"id":31650445,"url":"https://github.com/jinglemansweep/promenade","last_synced_at":"2026-05-15T08:42:24.181Z","repository":{"id":318378661,"uuid":"1070359270","full_name":"jinglemansweep/promenade","owner":"jinglemansweep","description":"Prometheus Terminal Dashboard","archived":false,"fork":false,"pushed_at":"2025-10-06T21:01:21.000Z","size":124,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-06T21:28:21.228Z","etag":null,"topics":["claude-code","command-line","dashboard","prometheus","textual"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jinglemansweep.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-05T19:08:37.000Z","updated_at":"2025-10-06T21:01:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"37ff3bcf-6aa4-4d62-8184-e49312e89454","html_url":"https://github.com/jinglemansweep/promenade","commit_stats":null,"previous_names":["jinglemansweep/promenade"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/jinglemansweep/promenade","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jinglemansweep%2Fpromenade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jinglemansweep%2Fpromenade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jinglemansweep%2Fpromenade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jinglemansweep%2Fpromenade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jinglemansweep","download_url":"https://codeload.github.com/jinglemansweep/promenade/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jinglemansweep%2Fpromenade/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278742889,"owners_count":26037915,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-07T02:00:06.786Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["claude-code","command-line","dashboard","prometheus","textual"],"created_at":"2025-10-07T08:29:38.161Z","updated_at":"2025-10-07T08:29:40.766Z","avatar_url":"https://github.com/jinglemansweep.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Promenade\n\nA powerful, customizable CLI dashboard for Prometheus metrics built with Python and Textual.\n\n![Promenade Dashboard](screenshot.svg)\n\n## Features\n\n- 📊 **Grid-based Layout**: Flexible grid system for organizing widgets\n- 🎨 **Conditional Formatting**: Dynamic styling based on metric values\n- 🔄 **Auto-refresh**: Configurable refresh intervals per dashboard\n- 🎯 **Custom Queries**: Full PromQL support\n- 🎠 **Multi-Dashboard Carousel**: Navigate between multiple dashboards with keyboard shortcuts\n- 🌈 **Theme Support**: Respects Textual themes\n- ⚡ **Fast \u0026 Lightweight**: Built on Textual framework\n- 📝 **YAML Configuration**: Simple, declarative dashboard definitions\n- 🏷️ **Widget Titles \u0026 Subtitles**: Customizable border titles and subtitles\n\n## Requirements\n\n- Python 3.12+\n- Prometheus server\n\n## Installation\n\n### Using UV (Recommended)\n\n```bash\n# Install dependencies\nuv sync\n\n# Activate virtual environment (if needed)\nsource .venv/bin/activate  # On Linux/macOS\n# or\n.venv\\Scripts\\activate  # On Windows\n```\n\n### Development Installation\n\nFor development work:\n\n```bash\n# Install dependencies including dev tools\nuv sync\n\n# Install pre-commit hooks\nuv run pre-commit install\n```\n\n### Alternative: Using pip\n\n```bash\n# Create virtual environment\npython -m venv .venv\nsource .venv/bin/activate\n\n# Install the package\npip install -e \".[dev]\"\n\n# Set up pre-commit hooks\npre-commit install\n```\n\n## Quick Start\n\n1. **Start your Prometheus server** (if not already running)\n\n2. **Create a dashboard configuration** (see `examples/example.yaml`)\n\n3. **Run the dashboard**:\n\n```bash\n# Using environment variable\nexport PROMETHEUS_URL=http://localhost:9090\npromenade examples/example.yaml\n\n# Or using command-line argument\npromenade examples/example.yaml --prometheus-url http://localhost:9090\n\n# Multiple dashboards (carousel mode)\npromenade dashboard1.yaml dashboard2.yaml dashboard3.yaml\n```\n\n## Configuration\n\n### Dashboard YAML Format\n\n```yaml\ntitle: \"My Dashboard\"\nrefresh_interval: 30  # Refresh all widgets every 30 seconds\ngrid_rows: 3          # Number of rows in the grid\ngrid_columns: 3       # Number of columns in the grid\n\nwidgets:\n  - title: \"CPU Usage\"                    # Optional widget title (top border)\n    subtitle: \"System\"                    # Optional subtitle (bottom-right border)\n    query: \"100 - (avg(rate(...)) * 100)\" # PromQL query\n    format_string: \"{value:.1f}%\"         # Python format string\n    row: 0                                 # Grid position (0-indexed)\n    column: 0\n    row_span: 1                            # Span multiple rows/columns\n    column_span: 1\n    border_style: \"rounded\"                # Border style\n    conditional_formats:                   # Conditional formatting rules\n      - condition: \"value \u003e 80\"\n        border_color: \"red\"\n        text_color: \"red\"\n```\n\n### Widget Configuration\n\n| Field | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `type` | string | No | `text` | Widget type: `text`, `digits`, `sparkline`, `progress` |\n| `title` | string | No | - | Widget title displayed in top border |\n| `subtitle` | string | No | - | Subtitle displayed in bottom-right border |\n| `query` | string | Yes | - | PromQL query to execute |\n| `format_string` | string | No | `{value}` | Python format string for display |\n| `row` | integer | Yes | - | Row position (0-indexed) |\n| `column` | integer | Yes | - | Column position (0-indexed) |\n| `row_span` | integer | No | 1 | Number of rows to span |\n| `column_span` | integer | No | 1 | Number of columns to span |\n| `border_style` | string | No | `solid` | Border style: `none`, `solid`, `dashed`, `double`, `heavy`, `rounded` |\n| `conditional_formats` | array | No | [] | List of conditional formatting rules |\n\n#### Widget Types\n\n**`text`** (default) - Simple text display\n- Standard metric display with formatted text\n- Supports all conditional formatting options\n\n**`digits`** - Large numeric display\n- Shows metrics in large, prominent multi-line characters\n- Ideal for important metrics you want to stand out\n- Best for numeric values\n\n**`sparkline`** - Time series trend visualization\n- Displays historical metric values as a compact bar chart\n- Automatically updates with new data points\n- Additional options:\n  - `sparkline_summary`: Summary function (`max`, `min`, `mean`) - default: `max`\n  - `sparkline_data_points`: Number of historical points to keep - default: `20`\n\n**`progress`** - Progress bar display\n- Shows metrics as a progress bar with optional percentage\n- Additional options:\n  - `progress_total`: Total value for progress bar (if `None`, treats value as 0-100%) - default: `100`\n  - `show_percentage`: Display percentage - default: `true`\n  - `show_eta`: Display ETA (always `false` for static metrics) - default: `false`\n\n### Conditional Formatting\n\nConditional formats are evaluated in order and applied when their condition is met:\n\n```yaml\nconditional_formats:\n  - condition: \"value \u003e 80\"           # Python expression with 'value' variable\n    border_color: \"$error\"             # Theme color (recommended) or CSS color\n    text_color: \"$error\"               # Also accepts: \"red\", \"#ff0000\", etc.\n    background_color: \"$surface\"\n    visible: true                      # Control widget visibility\n```\n\n**Available condition expressions:**\n- Numeric comparisons: `value \u003e 80`, `value \u003c= 50`\n- Complex logic: `value \u003e 50 and value \u003c 80`\n- Any valid Python expression with `value` variable\n\n**Color options:**\n\n**Recommended: Use Textual theme colors** (automatically adapt to any theme):\n- `$success` - Success/positive states (green in dark, dark green in light)\n- `$error` - Error/negative states (red in dark, dark red in light)\n- `$warning` - Warning states (yellow/orange)\n- `$primary` - Primary theme color\n- `$secondary` - Secondary theme color\n- `$accent` - Accent color for highlights\n\n**Alternative: Standard colors** (automatically adjusted for theme):\n- CSS color names: `red`, `lime`, `blue`, `yellow`, etc.\n- Hex codes: `#ff0000`, `#00ff00`, `#ffaa00`\n- ANSI colors: `ansi_red`, `ansi_green`, `ansi_yellow`, `ansi_blue`\n- Rich color library: Over 140 named colors available (see [Textual color documentation](https://textual.textualize.io/api/color/))\n\n**Automatic Theme Adjustment:**\n- **Theme colors** (`$success`, `$error`, etc.): Automatically perfect for any theme - **Recommended!**\n- **Standard colors**: Automatically adjusted for visibility:\n  - Dark themes: Brightened by 30%\n  - Light themes: Darkened by 30-70% based on color brightness\n  - Ensures visibility across all themes\n\n## Environment Variables\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `PROMETHEUS_URL` | Prometheus server URL | - |\n| `PROMETHEUS_TIMEOUT` | Request timeout in seconds | 10 |\n\n## CLI Usage\n\n```bash\npromenade [OPTIONS] CONFIG_FILES...\n\nArguments:\n  CONFIG_FILES  Path(s) to YAML dashboard configuration file(s)\n                Multiple files create a carousel of dashboards\n\nOptions:\n  -u, --prometheus-url TEXT  Prometheus server URL\n  -t, --theme TEXT          Textual theme (default: textual-dark)\n  -h, --help                Show help message\n```\n\n### Keyboard Shortcuts\n\n- `q` - Quit the application\n- `r` - Refresh all metrics on current dashboard immediately\n- `←` or `n` - Previous dashboard (in carousel mode)\n- `→` or `m` - Next dashboard (in carousel mode)\n\n## Examples\n\nSee the `examples/` directory for sample configurations:\n\n- `example.yaml` - Full-featured home lab monitoring dashboard\n- `widget_types.yaml` - Demonstrates all widget types (text, digits, sparkline, progress)\n\n### Example: System Monitoring Dashboard\n\n```yaml\ntitle: \"System Monitor\"\nrefresh_interval: 5\ngrid_rows: 2\ngrid_columns: 2\n\nwidgets:\n  - title: \"CPU Usage\"\n    subtitle: \"System\"\n    query: \"100 - (avg(rate(node_cpu_seconds_total{mode='idle'}[5m])) * 100)\"\n    format_string: \"{value:.1f}%\"\n    row: 0\n    column: 0\n    conditional_formats:\n      - condition: \"value \u003e 80\"\n        border_color: \"$error\"\n        text_color: \"$error\"\n\n  - title: \"Memory Usage\"\n    subtitle: \"System\"\n    query: \"(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100\"\n    format_string: \"{value:.1f}%\"\n    row: 0\n    column: 1\n    conditional_formats:\n      - condition: \"value \u003e 90\"\n        border_color: \"$error\"\n\n  - title: \"Active Connections\"\n    subtitle: \"Nginx\"\n    query: \"sum(nginx_connections_active)\"\n    format_string: \"{value:.0f}\"\n    row: 1\n    column: 0\n    row_span: 1\n    column_span: 2\n```\n\n## Development\n\n### Project Structure\n\n```\npromenade/\n├── src/promenade/\n│   ├── __init__.py\n│   ├── cli.py           # CLI entrypoint\n│   ├── app.py           # Main Textual application\n│   ├── config.py        # Configuration loader\n│   ├── schema.py        # Pydantic models\n│   ├── prometheus.py    # Prometheus client\n│   └── widgets.py       # Custom Textual widgets\n├── examples/            # Example dashboards\n├── pyproject.toml       # Project configuration\n└── README.md\n```\n\n### Running Tests\n\n```bash\n# Install test dependencies\nuv pip install -e \".[dev]\"\n\n# Run tests\npytest\n```\n\n### Code Quality\n\n```bash\n# Run linter\nruff check .\n\n# Run formatter\nruff format .\n\n# Run type checker\nmypy src/\n```\n\n## Troubleshooting\n\n### Connection Issues\n\nIf you see connection errors:\n1. Verify Prometheus is running: `curl http://localhost:9090/api/v1/query?query=up`\n2. Check the Prometheus URL is correct\n3. Ensure there are no firewall restrictions\n\n### Query Errors\n\nIf widgets show \"No data\":\n1. Test your query in Prometheus UI\n2. Verify metric names exist\n3. Check query syntax in PromQL\n\n### Display Issues\n\nIf widgets overlap or don't fit:\n1. Check `grid_rows` and `grid_columns` match your layout\n2. Verify `row + row_span \u003c= grid_rows`\n3. Verify `column + column_span \u003c= grid_columns`\n\n## Contributing\n\nContributions are welcome! Please:\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Run tests and linters\n5. Submit a pull request\n\n## License\n\nMIT License - see LICENSE file for details\n\n## Acknowledgments\n\n- Built with [Textual](https://textual.textualize.io/)\n- Inspired by Prometheus monitoring needs\n- Thanks to the Python community\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjinglemansweep%2Fpromenade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjinglemansweep%2Fpromenade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjinglemansweep%2Fpromenade/lists"}