sprout
A CLI tool to automate git worktree and Docker Compose development workflows.
Features
- 🌱 Create isolated development environments using git worktrees
- 🔧 Automatic
.envfile generation from templates - 🚢 Smart port allocation to avoid conflicts
- 📁 Centralized worktree management in
.sprout/directory - 🎨 Beautiful CLI interface with colors and tables
Installation
pip install sprout-cli
For development:
# Clone the repository
git clone https://github.com/AgenticSec/sprout.git
cd sprout
# Install in development mode
pip install -e ".[dev]"
Quick Start
Note: Sprout works in any git repository. .env.example files are optional - if you don't have them, sprout will simply create worktrees without .env generation.
- (Optional) Create a
.env.exampletemplate in your project root (and optionally in subdirectories) for automatic.envgeneration:
# API Configuration
API_KEY={{ API_KEY }}
API_PORT={{ auto_port() }}
# Database Configuration
DB_HOST=localhost
DB_PORT={{ auto_port() }}
# Branch-specific Configuration
SERVICE_NAME=myapp-{{ branch() }}
DEPLOYMENT_ENV={{ branch() }}
# Example: Docker Compose variables (preserved as-is)
# sprout will NOT process ${...} syntax - it's passed through unchanged
# DB_NAME=${DB_NAME}
For monorepo or multi-service projects, you can create .env.example files in subdirectories:
repo/
.env.example # Root configuration
service-a/
.env.example # Service A specific config
service-b/
.env.example # Service B specific config
- Create and navigate to a new development environment in one command:
cd $(sprout create feature-branch --path)
What happens when you run sprout create:
- If
.env.examplefiles exist: Sprout will generate corresponding.envfiles with populated variables and unique port assignments - If no
.env.examplefiles exist: Sprout will show a warning and create the worktree without.envgeneration
This single command:
- Creates a new git worktree for
feature-branch - Generates
.envfiles from your templates (if.env.examplefiles exist) - Outputs the path to the new environment
- Changes to that directory when wrapped in
cd $(...)
- Start your services:
docker compose up -d
Alternative: Two-Step Process
If you prefer to see the creation output first:
# Create the environment
sprout create feature-branch
# Then navigate to it
cd $(sprout path feature-branch)
Commands
sprout create <branch-name> [--path]
Create a new development environment with automated setup.
Options:
--path: Output only the worktree path (useful for shell command substitution)
Examples:
# Create and see progress messages
sprout create feature-xyz
# Create and navigate in one command
cd $(sprout create feature-xyz --path)
sprout ls
List all managed development environments with their status.
The output includes index numbers that can be used with other commands:
sprout ls
# Output:
# ┏━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓
# ┃ No. ┃ Branch ┃ Path ┃ Status ┃ Last Modified ┃
# ┡━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩
# │ 1 │ feature-auth │ .sprout/feat... │ │ 2025-06-27 14:30 │
# │ 2 │ bugfix-api │ .sprout/bugf... │ │ 2025-06-27 15:45 │
# └──────┴─────────────────┴─────────────────┴────────┴──────────────────┘
sprout rm <branch-name-or-index>
Remove a development environment (with confirmation prompts).
You can use either the branch name or the index number from sprout ls:
# Remove by branch name
sprout rm feature-auth
# Remove by index number
sprout rm 1
sprout path <branch-name-or-index>
Get the filesystem path of a development environment.
You can use either the branch name or the index number from sprout ls:
# Get path by branch name
sprout path feature-auth
# Output: /path/to/project/.sprout/feature-auth
# Get path by index number
sprout path 1
# Output: /path/to/project/.sprout/feature-auth
# Use with cd command
cd $(sprout path 2)
sprout --version
Show the version of sprout.
Template Syntax
sprout supports three types of placeholders in .env.example:
-
Variable Placeholders:
{{ VARIABLE_NAME }}- First: Checks if the variable exists in your environment (e.g.,
export API_KEY=xxx) - Then: If not found in environment, prompts for user input
- Example:
{{ API_KEY }}will use$API_KEYif set, otherwise asks you to enter it
- First: Checks if the variable exists in your environment (e.g.,
-
Auto Port Assignment:
{{ auto_port() }}- Automatically assigns available ports
- Avoids conflicts across ALL services in ALL sprout environments
- Checks system port availability
- Ensures global uniqueness even in monorepo setups
- Collects used ports from the
.envfiles of every worktree, skipping dependency and cache directories (node_modules,.venv,.git, ...)
-
Branch Name:
{{ branch() }}- Replaced with the current branch/subtree name
- Useful for branch-specific configurations
- Example:
SERVICE_NAME=myapp-{{ branch() }}becomesSERVICE_NAME=myapp-feature-auth
-
Docker Compose Syntax (Preserved):
${VARIABLE}- NOT processed by sprout - passed through as-is
- Useful for Docker Compose variable substitution
- Example:
${DB_NAME:-default}remains unchanged in generated.env
Environment Variable Resolution Example
# Set environment variable
export API_KEY="my-secret-key"
# Create sprout environment - API_KEY will be automatically used
sprout create feature-branch
# → API_KEY in .env will be set to "my-secret-key" without prompting
# For unset variables, sprout will prompt
sprout create another-branch
# → Enter a value for 'DATABASE_URL': [user input required]
Monorepo Tutorial
Try out the monorepo functionality with the included sample:
-
Navigate to the sample monorepo:
cd sample/monorepo
-
Set required environment variables:
export API_KEY="your-api-key" export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/myapp" export REACT_APP_API_KEY="your-frontend-api-key" export JWT_SECRET="your-jwt-secret" export SMTP_USER="your-smtp-username" export SMTP_PASS="your-smtp-password"
-
Create a development environment:
sprout create monorepo-feature
-
Navigate to the created environment:
cd .sprout/monorepo-feature
-
Verify all services have unique ports:
find . -name "*.env" -exec echo "=== {} ===" \; -exec cat {} \;
-
Start all services:
cd sample/monorepo docker-compose up -d
The sample includes:
- Root service: Database and Redis with shared configuration
- Frontend: React app with API integration
- Backend: REST API with authentication
- Shared: Utilities with message queue and monitoring
Each service gets unique, conflict-free ports automatically!
Documentation
- Architecture Overview - Design philosophy, architecture, and implementation details
- Detailed Usage Guide - Comprehensive usage examples and troubleshooting
Development
Setup
# Install development dependencies
make setup
Testing
# Run tests
make test
# Run tests with coverage
make test-cov
Code Quality
# Run linter
make lint
# Format code
make format
# Run type checking
make typecheck
Requirements
- Python 3.11+
- Git
- Docker Compose (optional, for Docker-based workflows)
License
See LICENSE file.
Metadata
Release files for sprout-cli 0.9.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sprout_cli-0.9.0.tar.gz | 24.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sprout_cli-0.9.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 41.2 kB
Release files / sprout_cli-0.9.0.tar.gz
| Download URL | sprout_cli-0.9.0.tar.gz |
|---|---|
| Size | 24.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b5e65da46e43c6c6bb1262217a6977ed09f1b06ca9c9576b7b61945056a205ed
|
|
BLAKE2b-256 checksum How to use checksums |
5919789e28db70dd65d98b44da3207c1ceb7ed486540da008a299403413aeab6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / sprout_cli-0.9.0-py3-none-any.whl
| Download URL | sprout_cli-0.9.0-py3-none-any.whl |
|---|---|
| Size | 17.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
456c9500f8a3b300363a4db76f54d2afbafee9d7fc100dcf6485e7f6a1c47421
|
|
BLAKE2b-256 checksum How to use checksums |
99b283b78e47c398c2f4f0c59c0d1b7f796419a5026cd69492bfb997ceec7f22
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|