Initializing Angreal Projects
Set up angreal task automation in a new or existing project.
What is an Angreal Project?
An angreal project is any directory containing a .angreal/ subdirectory with task files. Angreal provides development task automation - think of it as your project's make or npm run.
Quick Setup
Option A: Scaffold from an official template (recommended)
For a fresh project or to add angreal to a directory you've already created, use one of the official templates:
# Fresh project (creates a new subdirectory)
angreal init python
# Add angreal into an existing project root (no extra subdir)
cd my-existing-project
angreal init python --in-place
--in-place / -i strips the template's top-level templated directory and renders directly into the current working directory — this is the canonical path for "add angreal to my existing repo." Add --force if existing files would be overwritten, --defaults to skip prompts, or --values <file> to supply variables non-interactively. See the angreal-templates skill for the full template catalog (python, python-gh, python-gl, rust, data-science, airflow, …).
Option B: Hand-roll the .angreal directory
If no template matches or you want full control:
mkdir .angreal
2. Create Your First Task File
# .angreal/task_dev.py
import angreal
@angreal.command(name="hello", about="Test angreal setup")
def hello():
print("Angreal is working!")
return 0
3. Verify Setup
angreal tree # Should show: hello - Test angreal setup
angreal hello # Should print: Angreal is working!
Recommended Project Structure
Minimal Setup
my-project/
├── .angreal/
│ └── task_dev.py # Start with one task file
├── src/
└── ...
Standard Setup
my-project/
├── .angreal/
│ ├── task_dev.py # Development utilities
│ ├── task_test.py # Testing commands
│ ├── task_build.py # Build commands
│ └── task_docs.py # Documentation commands
├── src/
└── ...
With Shared Utilities
my-project/
├── .angreal/
│ ├── utils.py # Shared helper functions
│ ├── task_dev.py
│ ├── task_test.py
│ └── task_build.py
├── src/
└── ...
Starter Templates
Development Utilities
# .angreal/task_dev.py
import angreal
import subprocess
import os
@angreal.command(name="check-deps", about="Verify development tools")
def check_deps():
"""Check that required tools are installed."""
tools = ["python", "git"]
missing = []
for tool in tools:
result = subprocess.run(
["which", tool],
capture_output=True
)
if result.returncode != 0:
missing.append(tool)
if missing:
print(f"Missing tools: {', '.join(missing)}")
return 1
print("All tools available!")
return 0
@angreal.command(name="setup", about="Set up development environment")
def setup():
"""Initialize development environment."""
project_root = angreal.get_root().parent
# Example: Create virtual environment
venv_path = project_root / ".venv"
if not venv_path.exists():
print("Creating virtual environment...")
subprocess.run(["python", "-m", "venv", str(venv_path)])
print("Development environment ready!")
return 0
Testing Commands
# .angreal/task_test.py
import angreal
import subprocess
test = angreal.command_group(name="test", about="Testing commands")
@test()
@angreal.command(name="all", about="Run all tests")
def test_all():
project_root = angreal.get_root().parent
result = subprocess.run(
["pytest", "-v"],
cwd=project_root
)
return result.returncode
@test()
@angreal.command(name="unit", about="Run unit tests only")
def test_unit():
project_root = angreal.get_root().parent
result = subprocess.run(
["pytest", "tests/unit", "-v"],
cwd=project_root
)
return result.returncode
Build Commands
# .angreal/task_build.py
import angreal
import subprocess
@angreal.command(
name="build",
about="Build the project",
tool=angreal.ToolDescription("""
Build project artifacts.
## When to use
- Before releasing
- Testing production builds
## Examples
```
angreal build
angreal build --release
```
""", risk_level="safe")
)
@angreal.argument(
name="release",
long="release",
is_flag=True,
takes_value=False,
help="Build in release mode"
)
def build(release=False):
project_root = angreal.get_root().parent
cmd = ["python", "-m", "build"]
print(f"Building {'release' if release else 'debug'}...")
result = subprocess.run(cmd, cwd=project_root)
return result.returncode
Shared Utilities Module
# .angreal/utils.py
import angreal
import subprocess
from pathlib import Path
def get_project_root() -> Path:
"""Return the project root directory."""
return angreal.get_root().parent
def run_command(cmd, check=True, capture=False):
"""Run a command in the project root."""
result = subprocess.run(
cmd,
cwd=get_project_root(),
capture_output=capture,
text=True
)
if check and result.returncode != 0:
raise subprocess.CalledProcessError(
result.returncode, cmd
)
return result
def file_exists(relative_path: str) -> bool:
"""Check if a file exists relative to project root."""
return (get_project_root() / relative_path).exists()
Adding Angreal to Existing Projects
- Create
.angreal/ directory at project root
- Add task files for existing workflows
- Migrate shell scripts or Makefile targets to angreal tasks
- Add
.angreal/ to version control
Migrating from Makefile
Before (Makefile):
test:
pytest tests/
build:
python -m build
After (.angreal/task_build.py):
import angreal
import subprocess
@angreal.command(name="test", about="Run tests")
def test():
return subprocess.run(["pytest", "tests/"]).returncode
@angreal.command(name="build", about="Build package")
def build():
return subprocess.run(["python", "-m", "build"]).returncode
Best Practices
File Naming
- Use
task_<domain>.py pattern
- One domain per file:
tasktest.py, taskbuild.py
- Shared code in
utils.py or helpers.py
Initial Tasks to Create
- check-deps - Verify development tools are installed
- setup - Initialize development environment
- test - Run the test suite
- build - Build artifacts
Version Control
Add to .gitignore:
# Don't ignore .angreal/ - it should be versioned
# But ignore any generated files within it
.angreal/__pycache__/
.angreal/*.pyc
Verification Checklist
After setup, verify: