Sindri
A project-configurable command palette for common dev workflows. Sindri provides an interactive TUI (Text User Interface) and CLI for managing project-specific commands, making it easy to run setup, build, test, and deployment tasks.
Features
- 🎯 Interactive TUI: Beautiful terminal interface with search, filtering, and command details
- 📝 Project-Specific Config: Each repository defines its own commands via
sindri.toml - 🚀 Async Execution: Run commands asynchronously with live output streaming
- 🔄 Parallel Execution: Run multiple commands concurrently
- 📊 Multi-Stream Logs: View logs from multiple commands in split panes
- ⚙️ Rich Configuration: Support for dependencies, timeouts, retries, watch mode, and more
- 🐳 Docker Support: Built-in support for Docker and Docker Compose workflows
- 📦 Easy Installation: Install via
pip install sindri-dev, use in any project
Quickstart
Installation
pip install sindri-dev
Or install with optional extras:
pip install sindri-dev[docker,compose,git,version,pypi]
Or install from source:
git clone https://github.com/yourusername/sindri.git
cd sindri
pip install -e .
Initialize a Project
Navigate to your project directory and run:
sindri init
This creates a sindri.toml file with example commands. Edit it to match your project's needs.
Use Sindri
Open the interactive menu:
sindri
Or run commands directly:
sindri run setup
sindri run start --parallel
Configuration
Sindri uses TOML configuration files. The config file is discovered by searching upwards from the current working directory for sindri.toml or .sindri.toml.
Basic Configuration
version = "1.0"
project_name = "my-project"
[[commands]]
id = "setup"
title = "Setup Project"
description = "Install dependencies"
shell = "pip install -r requirements.txt"
tags = ["setup", "install"]
[[commands]]
id = "start"
title = "Start Service"
description = "Start the application"
shell = "python -m myproject.main"
tags = ["run", "start"]
Advanced Features
Command Dependencies
[[commands]]
id = "restart"
title = "Restart Service"
shell = "pkill -f app && sleep 1 && python -m app"
dependencies = { before = ["stop"] }
Watch Mode
[[commands]]
id = "tail-logs"
title = "Tail Logs"
shell = "tail -f logs/app.log"
watch = true
Environment Variables
[[commands]]
id = "run-dev"
title = "Run in Development Mode"
shell = "python -m app"
env = { DEBUG = "1", ENV = "development" }
Timeouts and Retries
[[commands]]
id = "long-task"
title = "Long Running Task"
shell = "python long_task.py"
timeout = 300 # 5 minutes
retries = 3
Command Groups
[[groups]]
id = "setup"
title = "Setup"
description = "Setup commands"
order = 1
commands = ["setup", "install"]
Docker Compose Profiles
[[compose_profiles]]
id = "dev"
title = "Development Profile"
profiles = ["dev"]
command = "up"
flags = ["-d"]
See examples/example-project/sindri.toml for a complete example.
CLI Commands
sindri init
Initialize a new Sindri configuration file in the current directory.
sindri init
sindri init --config custom.toml
sindri run <command-id>
Run one or more commands non-interactively.
sindri run setup
sindri run start web api --parallel
sindri run test --timeout 60 --retries 2
Options:
--config, -c: Path to config file--dry-run: Show what would be executed without running--verbose, -v: Enable verbose logging--json-logs: Output logs in JSON format--timeout, -t: Timeout in seconds--retries, -r: Number of retries on failure--parallel, -p: Run multiple commands in parallel
sindri list
List all available commands.
sindri list
sindri (default)
Open the interactive TUI menu.
sindri
sindri --config custom.toml
Options:
--config, -c: Path to config file--verbose, -v: Enable verbose logging--json-logs: Output logs in JSON format
TUI Navigation
The interactive TUI provides the following keybindings:
Ctrl+For/: Focus search inputEnter: Run selected command↑/↓: Navigate command listTab: Switch between panelsCtrl+CorQ: Quit
Recipes
Docker Workflow
[[commands]]
id = "docker-build"
title = "Build Docker Image"
shell = "docker build -t myapp:latest ."
tags = ["docker", "build"]
[[commands]]
id = "docker-run"
title = "Run Docker Container"
shell = "docker run -p 8000:8000 myapp:latest"
tags = ["docker", "run"]
Docker Compose Workflow
[[commands]]
id = "compose-up"
title = "Start Services"
shell = "docker compose up -d"
tags = ["docker", "compose"]
[[commands]]
id = "compose-logs"
title = "View Logs"
shell = "docker compose logs -f"
tags = ["docker", "compose", "logs"]
watch = true
Python Virtual Environment
[[commands]]
id = "setup"
title = "Setup Virtual Environment"
shell = "python -m venv venv && source venv/bin/activate && pip install -r requirements.txt"
tags = ["setup"]
[[commands]]
id = "activate"
title = "Activate Virtual Environment"
shell = "source venv/bin/activate"
tags = ["setup"]
Node.js Project
[[commands]]
id = "install"
title = "Install Dependencies"
shell = "npm install"
tags = ["setup", "install"]
[[commands]]
id = "dev"
title = "Start Dev Server"
shell = "npm run dev"
tags = ["run", "dev"]
[[commands]]
id = "build"
title = "Build for Production"
shell = "npm run build"
tags = ["build"]
Build Executable (PyInstaller)
[[commands]]
id = "build-exe"
title = "Build Executable"
shell = "pyinstaller --onefile --name myapp src/main.py"
tags = ["build", "executable"]
Test Suite with Coverage
[[commands]]
id = "test"
title = "Run Tests"
shell = "pytest tests/"
tags = ["test"]
[[commands]]
id = "test-cov"
title = "Run Tests with Coverage"
shell = "pytest --cov=myproject --cov-report=html tests/"
tags = ["test", "coverage"]
Screenshots
Note: Screenshots will be added here once the TUI is finalized.
Main Screen
Command Execution
Multi-Stream Logs
Architecture
Sindri is built with:
- Typer: CLI framework
- Textual: TUI framework
- Pydantic: Configuration validation
- asyncio: Async command execution
- structlog: Structured logging
Project Structure
sindri/
├── sindri/
│ ├── cli.py # CLI interface
│ ├── config.py # Config discovery and schema
│ ├── runner.py # Async execution engine
│ ├── logging.py # Structured logging
│ ├── utils.py # Utility functions
│ └── tui/ # TUI components
│ ├── app.py # Main TUI app
│ ├── screens.py # TUI screens
│ └── widgets.py # TUI widgets
├── tests/ # Test suite
├── examples/ # Example configurations
└── pyproject.toml # Project configuration
Development
Setup
git clone https://github.com/yourusername/sindri.git
cd sindri
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -e ".[dev]"
Running Tests
pytest
pytest --cov=sindri
Building
python -m build
Platform Support
- ✅ Linux: Full support
- ✅ macOS: Full support
- ⚠️ Windows: Supported with some limitations:
- Shell command syntax may differ (use
cmd.exesyntax or PowerShell) - Some Unix commands may not be available
- Path separators are handled automatically
- Shell command syntax may differ (use
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE file for details.
Acknowledgments
Metadata
Release files for sindri-dev 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sindri_dev-0.1.2.tar.gz | 67.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sindri_dev-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 142.2 kB
Release files / sindri_dev-0.1.2.tar.gz
| Download URL | sindri_dev-0.1.2.tar.gz |
|---|---|
| Size | 67.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d0e81a4da21c520cd38fbdb84d2580bdfe678997c2f481851d81d5d479ad951a
|
|
BLAKE2b-256 checksum How to use checksums |
f5905ab388d04cda46156b036d9f9d07568341907967656201274d2a45910687
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|
Release files / sindri_dev-0.1.2-py3-none-any.whl
| Download URL | sindri_dev-0.1.2-py3-none-any.whl |
|---|---|
| Size | 75.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b2b2b7d1c9a4c334588d5eae06b1f31597fa7a7ea9236e0112a2cc93abb78c69
|
|
BLAKE2b-256 checksum How to use checksums |
2de8adadcf40eb8a7388be5360bcae4e7f30f2d834215866596efd922ef5e6f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|