โ ๏ธ WORK IN PROGRESS This project is still in early development. Features may change, break, or be completely removed.
Jackknife is a command-line utility that allows you to run various Python tool scripts, each within its own isolated virtual environment managed by uv
.
- Isolated Environments: Each tool runs in its own dedicated virtual environment
- Fast Setup: Uses
uv
for lightning-fast dependency installation - Modular Design: Add new tools without modifying the core code
- Easy Updates: Update tool dependencies without affecting other tools
- Zero Global Pollution: No global package installations required
- No-Boilerplate Tools: Create tools without writing repetitive argparse code
- Cascading Execution: Run multiple tools in sequence with a single command
- Environment Optimization: Reuse compatible environments when possible to save space
-
Python: Version 3.8 or higher
-
uv: The extremely fast Python package installer and resolver
# Linux/macOS curl -LsSf https://astral.sh/uv/install.sh | sh # Windows powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
Verify installation:
uv --version
-
Clone the repository:
git clone https://github.com/alansynn/jackknife.git cd jackknife
-
Install Jackknife:
# Regular installation pip install . # Development mode (for making changes) pip install -e . # Development mode with testing dependencies pip install -e ".[dev]"
Jackknife now uses subcommands to organize its functionality:
To run a single tool or a chain of tools, use the run
subcommand:
jackknife run <tool_name | tool_chain> [tool_arguments...]
<tool_name>
: The name of the tool script (without the.py
extension) in thetools/
directory.<tool_chain>
: A comma-separated list of tool names, optionally with arguments in brackets (see below).[tool_arguments...]
: Any arguments you want to pass directly to the tool script (only applies when running a single tool).
Using the included giftomp4
tool:
# Show help for the giftomp4 tool
jackknife run giftomp4 --help
# Convert a GIF to MP4
jackknife run giftomp4 my_animation.gif -o my_video.mp4 --fps 24 --verbose
You can run multiple tools in sequence:
# Run multiple tools in sequence
jackknife run tool1,tool2,tool3
# Stop on first error (default behavior)
jackknife run tool1,tool2,tool3
# Continue even if a tool fails
jackknife run tool1,tool2,tool3 --continue-on-error
You can provide arguments for each tool in a chain using square brackets:
# Run tools with their own arguments
jackknife run "tool1[--option value],tool2[arg1 arg2],tool3[--flag]"
Note: When using tool-specific arguments in chains, you often need to quote the entire tool chain string to prevent the brackets from being interpreted by your shell.
Environment sharing options are part of the run
command:
# Run with environment sharing (default)
jackknife run mytool
# Run without environment sharing
jackknife run --no-share-environments mytool
You can also control this behavior globally with an environment variable:
# Disable environment sharing globally
export JACKKNIFE_SHARE_ENVIRONMENTS=false
jackknife run mytool
# Enable environment sharing globally
export JACKKNIFE_SHARE_ENVIRONMENTS=true
jackknife run mytool
Sometimes, you might want to manually work within a tool's isolated environment (e.g., to use its specific Python interpreter or installed packages directly). The activate
command helps with this:
jackknife activate <tool_name>
This command prints the necessary shell command to activate the tool's virtual environment. It does not activate the environment itself.
# Print the activation command for the 'cinit' tool's environment
jackknife activate cinit
# To actually activate it, use eval:
eval $(jackknife activate cinit)
# Now your shell is using the cinit environment
(cinit) $ python --version
(cinit) $ which python
# .../.jackknife_envs/cinit/bin/python
# Deactivate when done
(cinit) $ deactivate
$
:: Print the activation command path
jackknife activate cinit
:: You would typically run the printed .bat script directly
C:\Users\You\.jackknife_envs\cinit\Scripts\activate.bat
(cinit) C:\Your\Project> REM Now in the tool's environment
Note: The
activate
command only works if the tool has been run at least once withjackknife run <tool_name>
to create its environment.
Note: The first time you run a specific tool, Jackknife needs to create its isolated environment and install dependencies, which might take a few extra seconds. Subsequent runs will be much faster.
Jackknife comes with several useful tools:
giftomp4
: Converts animated GIFs to MP4 videos usingffmpeg
(requiresffmpeg
to be installed separately).jackknife run giftomp4 input.gif -o output.mp4 --fps 30
cinit
: Manages Cursor rules (link, add, edit) by interacting with~/.cursor/rules/
and the current directory's./.cursor/rules/
.# Interactively link rules from ~/.cursor/rules to ./.cursor/rules jackknife run cinit link # Add a new rule file to ~/.cursor/rules and optionally link it jackknife run cinit add path/to/my_rule.mdc # Select a rule from ~/.cursor/rules to open in your editor jackknife run cinit edit
mcpm
: Manages GitMCP server entries in~/.cursor/mcp.json
.jackknife run mcpm list # List configured servers jackknife run mcpm add github.com/owner/repo --name my-repo # Add a server jackknife run mcpm remove my-repo # Remove a server
piazzad
: Downloads resources from a Piazza course page (requires manual login via Selenium).# Example: jackknife run piazzad <piazza_resources_url> <network_id> -o <output_dir> jackknife run piazzad https://piazza.com/class/abc123xyz/resources abc123xyz -o ./course_downloads # Requires you to log in via the opened browser window.
- When you run
jackknife run giftomp4 ...
, the script findstools/giftomp4.py
. - It checks for a corresponding virtual environment in
~/.jackknife_envs/giftomp4
. - If needed (and not using a shared environment), it creates the environment and installs dependencies from
tools/giftomp4.requirements.txt
usinguv
. - It executes the tool script with your arguments using the isolated Python interpreter from the environment.
Adding new tools to Jackknife is straightforward. You can either write a standard Python script or use the provided helper decorators for easier argument parsing.
For detailed instructions and examples, please see the dedicated guide:
โก๏ธ docs/creating-tools.md
Here's a quick summary of the two approaches:
Leverage @tool
and @argument
from jackknife.tool_helpers
for automatic argument parsing. See tools/example_decorated.py
and the guide for details.
Write a standard script using argparse
, typer
, or similar. Ensure it has an if __name__ == "__main__":
block and uses sys.exit()
. See tools/example_traditional.py
and the guide for details.
Key Steps:
- Place your Python script (e.g.,
mytool.py
) inside thetools/
directory. - If your tool has dependencies, list them in
mytool.requirements.txt
in the same directory. - Run it:
jackknife run mytool [arguments...]
By default, environments are stored in ~/.jackknife_envs/
. You can change this location:
export JACKKNIFE_ENVS_DIR=/path/to/your/envs
jackknife run giftomp4 input.gif
Jackknife will create separate environments for each tool, or reuse compatible environments if sharing is enabled. Use jackknife activate <tool_name>
to get the command for entering a specific tool's environment manually.
Jackknife uses several tools to maintain high code quality:
Ruff is an extremely fast Python linter and formatter written in Rust. It replaces many traditional Python tools (Flake8, Black, isort, etc.) with a single, much faster alternative.
To run Ruff linting:
ruff check .
To format the code with Ruff:
ruff format .
We use pre-commit to manage our pre-commit hooks. After cloning the repository, install the hooks with:
pip install pre-commit
pre-commit install
This will automatically check the code quality before each commit.
Jackknife includes a comprehensive test suite using pytest and coverage reporting.
# Install development dependencies first
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with verbose output
pytest -v
# Run a specific test
pytest tests/test_cli.py::TestMain::test_successful_tool_execution
The test suite includes coverage reporting to ensure code quality:
# Run tests with coverage (automatically includes --cov options)
pytest
# Generate HTML coverage report only
pytest --cov-report=html --cov-report=term-missing
# View coverage report
open htmlcov/index.html
Current test coverage: 91%
- Unit Tests: Test individual functions in isolation
- Integration Tests: Test how components work together
- Functional Tests: End-to-end tests using real subprocess calls
- Add boilerplate-free tool development with decorators (
@tool
,@argument
) - Add Ruff for linting and formatting
- Add pre-commit hooks
- Add cascading tool execution (
run tool1,tool2,...
) - Add environment sharing for compatible tools (
--no-share-environments
) - Add
activate
command to get venv source string - Add
cinit
tool for Cursor rule management - Add
mcpm
tool for MCP server management - Add
piazzad
tool for Piazza resource downloading - Add tool discovery plugins (e.g., load tools from other installed packages)
- Add caching for environment checks/dependency resolution to speed up startup
- Implement tool update command (e.g.,
jackknife update mytool
to reinstall dependencies) - Add tool versioning and dependency locking (e.g., using
uv lock
) - Improve error handling and reporting for tool execution failures
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Make sure to run tests and pre-commit hooks before submitting your PR.
MIT License - See LICENSE file for details