render-dashboard/
├── README.md # Comprehensive documentation
├── QUICKSTART.md # 5-minute getting started guide
├── TESTING.md # Test scenarios and verification
├── PROJECT_STRUCTURE.md # This file
├── requirements.txt # Python dependencies
├── setup.py # Package configuration
├── .gitignore # Git ignore rules
│
├── config.yaml.example # Example configuration file
│
├── render-dashboard.plugin.zsh # ZSH completion plugin
├── install-zsh-plugin.sh # Automated plugin installer
│
└── render_dashboard/ # Main package
├── __init__.py # Package initialization
├── __main__.py # Entry point (CLI/TUI router)
├── models.py # Data models (Service, Deploy, etc.)
├── config.py # Configuration loading & validation
├── cli.py # CLI command mode handler
│
├── api/ # API client layer
│ ├── __init__.py
│ └── render.py # Async Render API client
│
└── ui/ # TUI layer
├── __init__.py
├── app.py # Main Textual application
└── widgets.py # Custom widgets (ServiceCard, StatusBar)
-
__main__.py: Entry point that routes to CLI or TUI based on arguments- No args → TUI dashboard
- With args → CLI command
-
models.py: Data classes for services and deploymentsService: Represents a Render service with statusDeploy: Represents a deployment with status and timingServiceStatus,DeployStatus: Enums for status values
-
config.py: Configuration management- Loads and validates
config.yaml - Supports environment variable substitution (
${RENDER_API_KEY}) - Service alias matching and resolution
- Loads and validates
Handles quick command-line access:
rd <service> <action>syntax- Service matching by alias (exact, partial, fuzzy)
- Browser URL generation and opening
- Status command (terminal output without browser)
Async HTTP client for Render API:
get_service(): Fetch service details and statusget_latest_deploy(): Fetch most recent deploymentget_service_with_deploy(): Combined fetch- Error handling for auth, rate limits, network issues
app.py: Main Textual application
- Service card container with scrolling
- Auto-refresh loop (configurable interval)
- Keyboard navigation and shortcuts
- Browser URL opening on actions
widgets.py: Custom UI components
ServiceCard: Display service with status, deploy info, actionsStatusBar: Shows last update time and controls- Focus handling for keyboard shortcuts
rd (no args)
↓
__main__.main()
↓
ui/app.run_dashboard()
↓
DashboardApp.on_mount()
↓
config.load_config() ← config.yaml
↓
api/render.py (fetch all services)
↓
ui/widgets.ServiceCard (display each)
↓
Auto-refresh loop (every 30s)
rd chat logs
↓
__main__.main() → ['chat', 'logs']
↓
cli.handle_cli_command()
↓
config.load_config()
↓
config.find_service_by_alias('chat')
↓
cli.get_service_url(service_id, 'logs')
↓
webbrowser.open(url)
RenderClient.get_service_with_deploy(service_id)
↓
httpx GET /v1/services/{serviceId}
↓
httpx GET /v1/services/{serviceId}/deploys?limit=1
↓
Parse response → Service + Deploy objects
↓
Return to caller (TUI or CLI)
- httpx for async HTTP (better than requests for concurrent calls)
- Textual natively supports async (perfect for auto-refresh)
- Multiple services fetched concurrently for fast TUI load
- Single
rdashcommand serves both modes - Argument detection in
__main__.pyroutes appropriately - Shared config and API client reduce code duplication
- Aliases from config enable short commands (
rd chat logs) - Partial matching for convenience (
rd ch logs) - Disambiguation for ambiguous matches
- All dashboard actions open Render URLs in browser
- Fallback to printing URL if browser fails
- Status command explicitly doesn't open browser
- Graceful degradation (service fetch errors don't crash TUI)
- Helpful error messages for config issues
- Validation on startup catches problems early
New CLI action:
- Add to
valid_actionsincli.py - Update
get_service_url()to generate URL - Document in README
New TUI widget:
- Create class in
ui/widgets.pyextending Textual widget - Add to
DashboardApp.compose()inui/app.py - Wire up interactions with messages/events
New API endpoint:
- Add method to
RenderClientinapi/render.py - Update
ServiceorDeploymodel if needed - Use in TUI or CLI as needed
New status indicator:
- Add to
ServiceStatusenum inmodels.py - Update
get_status_color()inServiceclass - Add CSS class in
widgets.pyif needed
- textual: TUI framework (reactive, async-native)
- httpx: Modern async HTTP client
- pyyaml: Config file parsing
- click: CLI argument parsing (if expanded)
- python-dateutil: Timestamp parsing
- pytest: Testing framework (future)
- black: Code formatting (future)
- mypy: Type checking (future)
1. Look for ./config.yaml
↓ (not found)
2. Look for ~/.config/render-dashboard/config.yaml
↓ (not found)
3. Show error: "No config.yaml found..."
Found config.yaml:
↓
Parse YAML
↓
Substitute ${RENDER_API_KEY} from environment
↓
Validate structure (required fields)
↓
Return AppConfig object
config.py: Config parsing, env var substitution, alias matchingapi/render.py: API client with mocked httpx responsesmodels.py: Data model validation
- CLI commands with test config
- TUI launch and navigation
- Browser URL generation
- See
TESTING.mdfor comprehensive checklist
- Concurrent API calls: All services fetched in parallel
- Cached completions: ZSH plugin caches service list
- Minimal re-renders: Textual only updates changed widgets
- Efficient polling: Only refresh when TUI is active
- API key in env var: Not stored in code or committed
- Config in gitignore: Prevents accidental commit
- HTTPS only: All API calls over TLS
- No sensitive logging: API key never logged
Questions? Check README.md for usage or TESTING.md for verification steps.