Skip to main content

Project Templating

Pace can automatically generate project-specific configuration files tailored to your technology stack. The pace init command detects your project type and creates an optimized config.pace file with tasks, hooks, and sensible defaults.

Quick Start

Navigate to your project directory and run:

pace init

Pace will:

  1. Detect your project type (Go, Node.js, Python, Rust)
  2. Analyze your project structure and configuration files
  3. Generate a config.pace file with appropriate tasks
  4. Update .gitignore to exclude .pace-cache/

Manual Project Type Selection

If auto-detection doesn't work or you want to specify the project type manually:

pace init --type go
pace init --type node
pace init --type python
pace init --type rust

Supported Project Types

Node.js/TypeScript Projects

Auto-detects:

  • Package manager (npm, pnpm, yarn, bun) from lock files
  • All scripts in package.json
  • TypeScript configuration

Generated tasks include:

  • install - Install dependencies using detected package manager
  • All scripts from package.json mapped as tasks
  • Common scripts (build, dev, test, lint, format) with smart defaults
  • Type-check task for TypeScript projects

Example output:

default build

task install [i] {
command "pnpm install"
description "Install dependencies"
inputs ["package.json", "pnpm-lock.yaml"]
outputs ["node_modules"]
cache true
}

task build [b] {
command "pnpm run build"
description "Build the project"
requires ["install"]
inputs ["src/**/*", "package.json"]
outputs ["dist", "build"]
cache true
}

task dev [d] {
command "pnpm run dev"
description "Start development server"
requires ["install"]
inputs ["src/**/*"]
watch true
}

task test [t] {
command "pnpm run test"
description "Run tests"
requires ["install"]
inputs ["src/**/*", "test/**/*", "**/*.test.*", "**/*.spec.*"]
cache true
}

Python Projects

Auto-detects:

  • Dependency manager (pip, poetry, pdm, pipenv)
  • Test framework (pytest, unittest)
  • Linter (ruff, flake8, pylint)
  • Formatter (ruff, black)
  • Entry point (main.py, app.py, etc.)

Generated tasks include:

  • install - Install dependencies using detected tool
  • run - Run application (if entry point detected)
  • test - Run tests with detected framework
  • lint - Lint code with detected linter
  • format - Format code with detected formatter
  • type-check - Type checking with mypy (if pyproject.toml exists)

Example output:

default run

task install [i] {
command "poetry install"
description "Install dependencies"
inputs ["pyproject.toml", "poetry.lock"]
cache true
}

task run [r] {
command "python main.py"
description "Run the application"
requires ["install"]
inputs ["**/*.py"]
}

task test [t] {
command "pytest"
description "Run tests"
requires ["install"]
inputs ["src/**/*.py", "tests/**/*.py", "test/**/*.py"]
cache true
}

task lint [l] {
command "ruff check ."
description "Lint code"
requires ["install"]
inputs ["**/*.py", "ruff.toml", ".ruff.toml"]
cache true
}

task format [f] {
command "ruff format ."
description "Format code"
inputs ["**/*.py", "ruff.toml", ".ruff.toml"]
}

task type-check {
command "mypy ."
description "Type check with mypy"
requires ["install"]
inputs ["**/*.py", "pyproject.toml"]
cache true
}

Rust Projects

Auto-detects:

  • Project type (binary, library, or both)
  • Package name from Cargo.toml
  • Workspace configuration and members
  • Benchmarks directory
  • Examples directory

Generated tasks include:

  • build - Build the project
  • release - Build release binary
  • test - Run tests
  • check - Fast syntax checking
  • lint - Clippy with strict warnings
  • format - Format code with rustfmt
  • format-check - Check formatting (for CI)
  • run - Run binary (only for binary projects)
  • bench - Run benchmarks (if benches/ exists)
  • examples - Build examples (if examples/ exists)

Example output:

default build

task build [b] {
command "cargo build"
description "Build the project"
inputs ["src/**/*.rs", "Cargo.toml", "Cargo.lock"]
outputs ["target/debug"]
cache true
}

task release [r] {
command "cargo build --release"
description "Build release binary"
requires ["test"]
inputs ["src/**/*.rs", "Cargo.toml", "Cargo.lock"]
outputs ["target/release"]
cache true
}

task test [t] {
command "cargo test"
description "Run tests"
inputs ["src/**/*.rs", "tests/**/*.rs"]
cache true
}

task lint [l] {
command "cargo clippy -- -D warnings"
description "Lint code with clippy"
inputs ["src/**/*.rs"]
cache true
}

task run {
command "cargo run"
description "Run the application"
depends-on ["build"]
inputs ["src/**/*.rs"]
watch true
}

Go Projects

Auto-detects:

  • Module name from go.mod
  • Project structure (standard, cmd-based, simple, library)
  • Main package location (handles cmd/* patterns)
  • golangci-lint configuration
  • tools.go pattern for dev tools
  • go:generate directives

Generated tasks include:

  • build - Build the application with correct output path
  • test - Run tests
  • lint - Run golangci-lint (if config exists)
  • run - Run the application
  • tools - Install dev tools (if tools/tools.go exists)
  • generate - Run go generate (if directives found)
  • tidy - Tidy go.mod and go.sum
  • vet - Run go vet

Example output:

default build

task build [b] {
command "go build -o bin/myapp ./cmd/server"
description "Build the application"
requires ["test"]
inputs ["**/*.go", "go.mod", "go.sum"]
outputs ["bin/myapp"]
cache true
}

task test [t] {
command "go test ./..."
description "Run tests"
inputs ["**/*.go"]
cache true
}

task lint [l] {
command "golangci-lint run"
description "Lint code"
inputs ["**/*.go", ".golangci.yml", ".golangci.yaml"]
cache true
}

task run [r] {
command "go run ./cmd/server"
description "Run the application"
inputs ["**/*.go"]
watch true
}

task generate {
command "go generate ./..."
description "Run go generate"
inputs ["**/*.go"]
}

task tidy {
command "go mod tidy"
description "Tidy go.mod and go.sum"
inputs ["go.mod"]
}

task vet {
command "go vet ./..."
description "Run go vet"
inputs ["**/*.go"]
cache true
}

Detection Logic

Node.js/TypeScript

Detected by presence of:

  • package.json
  • node_modules/ directory

Package manager detected from:

  • pnpm-lock.yaml → pnpm
  • yarn.lock → yarn
  • bun.lockb → bun
  • package-lock.json → npm (default)

Python

Detected by presence of:

  • *.py files
  • main.py
  • src/ or tests/ directories

Dependency manager detected from:

  • pyproject.toml with [tool.poetry] → poetry
  • pyproject.toml with [tool.pdm] → pdm
  • Pipfile → pipenv
  • requirements.txt → pip (default)

Rust

Detected by presence of:

  • Cargo.toml
  • src/ directory

Project type detected from:

  • src/main.rs or [[bin]] → binary
  • src/lib.rs or [lib] → library

Go

Detected by presence of:

  • go.mod or go.sum
  • main.go
  • cmd/ or pkg/ directories

Project structure detected from:

  • cmd/ + (pkg/ or internal/) → standard layout
  • cmd/ only → cmd-based layout
  • main.go at root → simple layout
  • No main package → library

Customizing Generated Configuration

The generated config.pace file is a starting point. You can:

  1. Add custom tasks - Extend with project-specific workflows
  2. Modify commands - Adjust to your project's needs
  3. Update file patterns - Refine inputs/outputs for better caching
  4. Add environment variables - Configure task execution context
  5. Set up hooks - Add pre/post execution logic

Example customization:

# Generated config
task build [b] {
command "go build -o bin/app ./..."
cache true
}

# Customized with version info
var version = "1.0.0"

task build [b] {
command "go build -ldflags '-X main.Version=${version}' -o bin/app ./..."
inputs ["**/*.go", "go.mod"]
outputs ["bin/app"]
cache true
env {
CGO_ENABLED = 0
GOOS = linux
}
}

Platform-Specific Commands

Generated clean hooks automatically adapt to your platform:

Unix/Linux/macOS:

hook clean {
command "rm -rf bin dist node_modules"
}

Windows:

hook clean {
command "if exist bin rmdir /s /q bin"
}

Best Practices

  1. Review generated config - Always check the generated file before committing
  2. Adjust file patterns - Refine inputs/outputs based on your project structure
  3. Add descriptions - Document custom tasks you add
  4. Version control - Commit config.pace to your repository
  5. Update regularly - Re-run pace init when your project structure changes significantly

Troubleshooting

Q: Pace doesn't detect my project type

  • Ensure required files are present (package.json, Cargo.toml, go.mod, etc.)
  • Use --type flag to specify manually
  • Check that you're in the project root directory

Q: Wrong package manager detected

  • Ensure lock file for your preferred manager exists
  • Node.js detection priority: pnpm → yarn → bun → npm

Q: Generated tasks don't match my workflow

  • Edit config.pace to customize tasks
  • Tasks are templates - modify to fit your needs
  • Consider contributing improvements to detection logic

Q: Some tasks are missing

  • Pace only generates tasks for detected features
  • Add custom tasks manually as needed
  • Some advanced features require manual configuration

Examples

See the Examples page for complete project configurations and common patterns.