Rapidctl is a Python framework for creating custom CLI tools that execute commands inside containerized environments using Podman. It allows you to package and distribute CLI utilities where all dependencies and runtime environments are containerized, ensuring consistency across different systems.
Rapidctl solves the problem of distributing CLI tools with complex dependencies. Instead of requiring users to install specific versions of languages, libraries, or system packages, you package everything in a container and provide a lightweight Python wrapper that handles container orchestration transparently.
Rapidctl consists of three main layers:
βββββββββββββββββββββββββββββββββββββββ
β Your Custom CLI (e.g. examplectl) β β User-facing entry point
βββββββββββββββββββββββββββββββββββββββ€
β Bootstrap Layer (CtlClient) β β Configuration & validation
βββββββββββββββββββββββββββββββββββββββ€
β CLI Layer (PodmanCLI) β β Container orchestration
βββββββββββββββββββββββββββββββββββββββ€
β Podman API β β Container runtime
βββββββββββββββββββββββββββββββββββββββ
-
Bootstrap Layer (
rapidctl.bootstrap.client)CtlClient: Defines container configuration and validates container image names- Prevents command injection through input sanitization
-
Connectors (
rapidctl.bootstrap.connectors)- Connectors are used to connect to the container runtime
- Connectors are platform specific
- Connectors are used by the CLI Layer to interact with the container runtime
- Connectors are plugins for different ecosystems (Window, OSX, Linux, etc)
-
CLI Layer (
rapidctl.cli)PodmanCLI: Interfaces with Podman API for container operations- Handles image pulling, container management, and command execution
-
Actions (
rapidctl.cli.actions)- Actions are an operation to achieve an outcome
- Actions orchestrate and use one or more tasks to achieve their outcome
-
Tasks (
rapidctl.cli.tasks)- Tasks perform a single operation
- Tasks are the building blocks of actions
- Python 3.10+
- Podman installed and running (on macOS, you will be automatically prompted to start the machine if it is stopped)
podmanPython package
# Clone the repository
git clone https://github.com/yourusername/rapidctl.git
cd rapidctl
# Install dependencies
pip install podman
# Optional: Set the Podman socket path manually (auto-detected by default)
# export PODMAN_SOCKET="unix:///run/user/$(id -u)/podman/podman.sock"- Create your CLI wrapper (e.g.,
myctl):
#!/usr/bin/env python
import re
import sys
from rapidctl.cli.main import main
from rapidctl.bootstrap import client
# Create and configure the client
client = client.CtlClient()
client.container_repo = "docker.io/myorg/mytool-container"
client.baseline_version = "1.0.0"
client.client_version = "0.0.1"
# Run the CLI
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main(client))- Make it executable:
chmod +x myctl- Use your CLI:
./myctl <command> <args>The tool will automatically:
- Check if the container image exists locally
- Pull the image if needed
- Execute your command inside the container
A complete reference implementation and template for building your own CLI tool can be found in the rapidctl-examplectl repository.
It includes:
- A working CLI wrapper
- A
Dockerfilefor the container environment - Example command orchestration scripts
- Version management demonstrations
| Property | Type | Default | Description |
|---|---|---|---|
container_repo |
str |
None |
Container registry path (e.g., docker.io/user/image) |
baseline_version |
str |
"1.0.0" |
Container image tag/version |
client_version |
str |
"0.0.1" |
Your CLI tool version |
image_id |
str |
None |
Specific image ID (optional) |
command_path |
str |
"/opt/rapidctl/cmd/" |
Path inside container where commands are located |
PODMAN_SOCKET: Path to Podman socket (optional)- If not set, rapidctl will auto-detect the socket location using platform-specific connectors
- On macOS, auto-detection checks:
~/.local/share/containers/podman/machine/podman.sock/var/run/docker.sock- Machine-specific socket locations
- Override auto-detection by setting this variable:
export PODMAN_SOCKET="unix:///path/to/your/podman.sock"
- Useful for custom Podman installations or when running multiple Podman instances
Rapidctl includes container image name validation to prevent command injection attacks:
- Sanitizes registry URLs and image names
- Validates domain names and repository paths
- Removes dangerous characters (
;,|,&, etc.) - Supports standard Docker/Podman image formats
Example validated formats:
ubuntu:20.04docker.io/library/ubuntu:latestregistry.example.com/myproject/myimage:v1.2.3localhost:5000/my-image
Run the test suite:
# Run all tests
pytest tests/
# Run specific test
pytest tests/test_client.py
pytest tests/test_container_validator.pyrapidctl/
βββ rapidctl/
β βββ __init__.py
β βββ bootstrap/
β β βββ __init__.py
β β βββ client.py # CtlClient configuration
β β βββ state.py # State and cache management
β β βββ connectors/
β β βββ __init__.py
β β βββ base.py # BaseConnector interface
β β βββ linux.py
β β βββ osx.py
β βββ cli/
β β βββ __init__.py # PodmanCLI class
β β βββ main.py # Main entry point
β β βββ actions.py # High-level actions
β β βββ mcp.py # MCP server integration
β β βββ tasks.py # Low-level tasks
β βββ utils/
β β βββ version.py # Version utilities
β βββ errors/
β βββ __init__.py # Custom exceptions
βββ tests/
β βββ test_client.py
β βββ test_container_validator.py
β βββ ... (comprehensive test suite)
βββ examples/
β βββ example_connector_usage.py
βββ pyproject.toml # Packaging configuration
βββ README.md
Current Status: Alpha / In Development
- Limited error handling and recovery
- Complete command execution implementation
- Add comprehensive error handling
- Implement CLI argument parsing
- Implement MCP support
- Add logging framework
- Create packaging configuration (pyproject.toml)
- Expand test coverage
- Add CI/CD pipeline
- Platform-specific socket detection (macOS complete)
- Add Linux connector
- Add Windows connector
Contributions are welcome! Please feel free to submit issues or pull requests.
[Add your license here]
For questions or issues, please open an issue on GitHub.
Note: This project is under active development. APIs may change between versions.