{"id":34736214,"url":"https://github.com/wislertt/bakefile","last_synced_at":"2026-04-15T04:00:58.933Z","repository":{"id":329701966,"uuid":"1120404613","full_name":"wislertt/bakefile","owner":"wislertt","description":"An OOP task runner in Python. Like a Makefile, but with tasks as Python class methods—so you can inherit, compose, and reuse them across projects.","archived":false,"fork":false,"pushed_at":"2026-04-10T01:41:25.000Z","size":1763,"stargazers_count":5,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-10T02:38:08.858Z","etag":null,"topics":["build-tool","cli","command-line","devops","justfile","makefile","pydantic","python","task-runner","typer"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wislertt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-21T06:18:34.000Z","updated_at":"2026-04-10T01:37:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"a9d07be1-f28d-42bf-b15f-80f4ac6ea1fb","html_url":"https://github.com/wislertt/bakefile","commit_stats":null,"previous_names":["wislertt/bakefile"],"tags_count":60,"template":false,"template_full_name":null,"purl":"pkg:github/wislertt/bakefile","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wislertt%2Fbakefile","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wislertt%2Fbakefile/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wislertt%2Fbakefile/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wislertt%2Fbakefile/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wislertt","download_url":"https://codeload.github.com/wislertt/bakefile/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wislertt%2Fbakefile/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31825515,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T18:05:02.291Z","status":"online","status_checked_at":"2026-04-15T02:00:06.175Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["build-tool","cli","command-line","devops","justfile","makefile","pydantic","python","task-runner","typer"],"created_at":"2025-12-25T03:40:21.482Z","updated_at":"2026-04-15T04:00:58.910Z","avatar_url":"https://github.com/wislertt.png","language":"Python","readme":"[![tests](https://img.shields.io/github/actions/workflow/status/wislertt/bakefile/cd.yml?branch=main\u0026label=tests\u0026logo=github)](https://github.com/wislertt/bakefile/actions/workflows/cd.yml)\n[![release](https://img.shields.io/github/actions/workflow/status/wislertt/bakefile/cd.yml?branch=main\u0026label=release\u0026logo=github)](https://github.com/wislertt/bakefile/actions/workflows/cd.yml)\n[![quality-gate-status](https://sonarcloud.io/api/project_badges/measure?project=wislertt_bakefile\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=wislertt_bakefile)\n[![security-rating](https://sonarcloud.io/api/project_badges/measure?project=wislertt_bakefile\u0026metric=security_rating)](https://sonarcloud.io/summary/new_code?id=wislertt_bakefile)\n[![vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=wislertt_bakefile\u0026metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=wislertt_bakefile)\n[![codecov](https://codecov.io/gh/wislertt/bakefile/graph/badge.svg?token=G0ZRDBGAJB)](https://codecov.io/gh/wislertt/bakefile)\n[![pypi](https://img.shields.io/pypi/v/bakefile.svg?color=blue)](https://pypi.python.org/pypi/bakefile)\n[![downloads](https://static.pepy.tech/personalized-badge/bakefile?period=total\u0026units=international_system\u0026left_color=grey\u0026right_color=blue\u0026left_text=pypi%20downloads)](https://pepy.tech/projects/bakefile)\n[![python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue?logo=python)](https://github.com/wislertt/bakefile/)\n\n# bakefile\n\nAn OOP task runner in Python. Like a Makefile, but with tasks as Python class methods—so you can inherit, compose, and reuse them across projects.\n\n## Why bakefile?\n\n- **Reusable** - Makefile/Justfile work well, but reusing tasks across projects is hard. bakefile uses OOP class methods—inherit, compose, and share them\n- **Python** - Use Python instead of DSL syntax. Access the full ecosystem with Python's language features, tooling, and type safety (ruff/ty)—with subprocess support for normal CLI commands\n- **Language-agnostic** - Write tasks in Python, run commands for any language (Go, Rust, JS, etc.)\n\n## Installation\n\nInstall via pip:\n\n```bash\npip install bakefile\n```\n\nOr via uv:\n\n```bash\nuv add bakefile          # as a project dependency\nuv tool install bakefile # as a global tool\n```\n\n## Quick Start\n\nCreate a file named `bakefile.py`:\n\n```python\nfrom bake import Bakebook, command, console\n\nclass MyBakebook(Bakebook):\n    @command()\n    def build(self) -\u003e None:\n        console.echo(\"Building...\")\n        # Use self.ctx to run commands\n        self.ctx.run(\"cargo build\")\n\nbakebook = MyBakebook()\n\n@bakebook.command()\ndef hello(name: str = \"world\"):\n    console.echo(f\"Hello {name}!\")\n```\n\n**Tip:** Or generate a bakefile automatically:\n\n```bash\nbakefile init           # Basic bakefile\nbakefile init --inline  # With PEP 723 standalone dependencies\n```\n\nRun your tasks:\n\n```bash\nbake hello              # Hello world!\nbake hello --name Alice # Hello Alice!\nbake build              # Building...\n```\n\n## Core Concepts\n\n### Two CLIs\n\nbakefile provides two command-line tools:\n\n- **`bake`** - Runs tasks from your `bakefile.py`\n- **`bakefile`** - Manages your `bakefile.py` (init, add-inline, lint, find-python, export, sync, lock, add, pip)\n\nDetailed CLI documentation in [Usage](#usage).\n\n### Bakebook\n\nA class in `bakefile.py` that holds your tasks:\n\n- **Inherit and reuse** - Create base classes with common tasks, extend them across projects\n- **Extends Pydantic's `BaseSettings`** - Define configuration as class attributes\n- **Uses `@command()` decorator** - Same syntax as Typer for defining CLI commands\n- **Provides `ctx.run()`** - Execute CLI commands (built on Python's subprocess) from your tasks\n\n```python\nfrom bake import Bakebook, command, Context, console\nfrom pydantic import Field\nfrom typing import Annotated\nimport typer\n\nclass MyBakebook(Bakebook):\n    # Pydantic configuration\n    api_url: str = Field(default=\"https://api.example.com\", env=\"API_URL\")\n\n    @command()\n    def fetch(self) -\u003e None:\n        # Run CLI commands via self.ctx\n        self.ctx.run(f\"curl {self.api_url}\")\n\nbakebook = MyBakebook()\n\n# Standalone functions also work\n@bakebook.command()\ndef test(\n    verbose: Annotated[bool, typer.Option(False, \"--verbose\", \"-v\")] = False,\n):\n    if verbose:\n        console.echo(\"Running tests...\")\n    bakebook.ctx.run(\"pytest\")\n```\n\n### PEP 723 Support\n\nbakefile supports [PEP 723](https://peps.python.org/pep-0723/) inline script metadata—your `bakefile.py` can declare its own dependencies. Add PEP 723 metadata to an existing bakefile with `bakefile add-inline`:\n\n```python\n# /// script\n# requires-python = \"\u003e=3.14\"\n# dependencies = [\n#     \"bakefile\u003e=0.0.0\",\n# ]\n# ///\n\nfrom bake import Bakebook, command, console\n\nbakebook = Bakebook()\n\n@bakebook.command()\ndef hello():\n    console.echo(\"Hello from standalone bakefile!\")\n```\n\n**Use case:** Ideal for non-Python projects without `pyproject.toml`. For Python projects, add bakefile to your project's dependencies instead.\n\n## Usage\n\n### Bakebook API\n\n#### Creating a Bakebook\n\n**Tip:** Generate a bakefile automatically with `bakefile init` or `bakefile add-inline`.\n\nCreate a bakebook by inheriting from `Bakebook` or instantiating it:\n\n```python\nfrom bake import Bakebook\n\nbakebook = Bakebook()\n```\n\n#### @command Decorator\n\n- **Pattern 1: Before instantiating** - Use `@command()` on class methods\n- **Pattern 2: After instantiating** - Use `@bakebook.command()` on standalone functions\n- **Accepts all Typer options** - `name`, `help`, `deprecated`, etc.\n\n```python\nfrom bake import Bakebook, command, console\nfrom typing import Annotated\nimport typer\n\n# Pattern 1: On class (use self.ctx for context access)\nclass MyBakebook(Bakebook):\n    @command()\n    def task1(self) -\u003e None:\n        console.echo(\"Task 1\")\n        self.ctx.run(\"echo 'Task 1 complete'\")\n\nbakebook = MyBakebook()\n\n# Pattern 2: On instance (use bakebook.ctx for context access)\n@bakebook.command(name=\"deploy\", help=\"Deploy application\")\ndef deploy(\n    env: Annotated[str, typer.Option(\"dev\", help=\"Environment to deploy\")],\n):\n    console.echo(f\"Deploying to {env}...\")\n    bakebook.ctx.run(f\"kubectl apply -f {env}.yaml\")\n```\n\n#### Context API\n\nThe `Bakebook` class provides a `.ctx` property for accessing CLI context:\n\n```python\nclass MyBakebook(Bakebook):\n    @command()\n    def my_command(self) -\u003e None:\n        # Run a command\n        self.ctx.run(\"echo hello\")\n\n        # Run with options\n        self.ctx.run(\n            \"pytest\",\n            capture_output=False,  # Stream to terminal\n            check=True,            # Raise on error\n            cwd=\"/tmp\",           # Working directory\n            env={\"KEY\": \"value\"}, # Environment variables\n        )\n\n        # Run a multi-line script\n        self.ctx.run_script(\n            title=\"Setup\",\n            script=\"\"\"\n                echo \"Step 1\"\n                echo \"Step 2\"\n            \"\"\",\n        )\n```\n\n#### Pydantic Settings\n\nBakebooks extend Pydantic's `BaseSettings` for configuration:\n\n```python\nfrom bake import Bakebook\nfrom pydantic import Field\n\nclass MyBakebook(Bakebook):\n    # Defaults\n    database_url: str = \"sqlite:///db.sqlite3\"\n\n    # With environment variable mapping\n    api_key: str = Field(default=\"default-key\", env=\"API_KEY\")\n\n    # With validation\n    port: int = Field(default=8000, ge=1, le=65535)\n```\n\nSettings are loaded from environment variables, `.env` files, or defaults.\n\n### `bake` CLI - Running Tasks\n\nThe `bake` command runs tasks from your `bakefile.py`. Run `bake --help` to see all available commands and options.\n\n#### Basic Execution\n\n```bash\nbake \u003ccommand\u003e [args]\n```\n\n```bash\nbake hello\nbake build\nbake test --verbose\n```\n\n#### Dry-Run Mode\n\nPreview what would happen without executing:\n\n```bash\nbake -n build\nbake --dry-run deploy\n```\n\n#### Verbosity Levels\n\nControl output verbosity:\n\n```bash\nbake build              # Silent (errors only)\nbake -v build           # Info level\nbake -vv build          # Debug level\n```\n\n#### Chaining Commands\n\nRun multiple commands sequentially:\n\n```bash\nbake -c lint test build\n```\n\nIf any command fails, the chain stops.\n\n#### Options\n\nOverride defaults when running bake:\n\n```bash\nbake -f tasks.py build                   # Custom filename\nbake -b my_bakebook build                # Custom bakebook object name\nbake -C /path/to/project build           # Run from different directory\n```\n\n### `bakefile` CLI - Managing bakefile.py\n\nThe `bakefile` command (short: `bf`) manages your `bakefile.py`.\n\n#### init\n\nCreate a new `bakefile.py`:\n\n```bash\nbakefile init           # Basic bakefile\nbakefile init --inline  # With PEP 723 inline metadata\nbakefile init --force   # Force overwrite existing bakefile\n```\n\n#### add-inline\n\nAdd PEP 723 inline metadata to an existing bakefile:\n\n```bash\nbakefile add-inline\n```\n\n#### lint\n\nLint `bakefile.py` (or entire project) with ruff and ty:\n\n```bash\nbakefile lint                   # Lint bakefile.py and all Python files\nbakefile lint --only-bakefile   # Lint only bakefile.py\nbakefile lint --no-ty           # Skip type checking\n```\n\n#### uv-based commands (PEP 723 bakefile.py only)\n\nConvenience wrappers around `uv` commands with `--script bakefile.py` added. For PEP 723 bakefile.py files only. For normal Python projects, use your preferred dependency manager (pip, poetry, uv, etc.).\n\n```bash\nbakefile sync                   # = uv sync --script bakefile.py\nbakefile lock                   # = uv lock --script bakefile.py\nbakefile add requests           # = uv add --script bakefile.py requests\nbakefile pip install            # = uv pip install --python \u003cbakefile-python-path\u003e\n```\n\n#### find-python\n\nFind the Python interpreter path for the bakefile:\n\n```bash\nbakefile find-python\n```\n\n#### export\n\nExport bakebook variables to external formats:\n\n```bash\nbakefile export                     # Shell format (default)\nbakefile export -f sh               # Shell format\nbakefile export -f dotenv           # .env format\nbakefile export -f json             # JSON format\nbakefile export -f yaml             # YAML format\nbakefile export -o config.sh        # Write to file\n\n# Examples:\nbakefile export -f dotenv -o .env       # .env file\nbakefile export -f json -o config.json  # JSON file\n```\n\n### `bakelib` - Optional Helpers\n\n**bakelib** is an optional collection of opinionated helpers built on top of Bakebook. Includes Spaces (pre-configured tasks) and Environ (multi-environment support).\n\nInstall with:\n\n```bash\npip install bakefile[lib]\n```\n\n**Note:** bakelib is optional—you can use bakefile without it. Create your own Bakebook classes if you prefer different conventions.\n\n#### PythonSpace\n\nPythonSpace provides common tasks for Python projects:\n\n```python\nfrom bakelib import PythonSpace\n\nbakebook = PythonSpace()\n```\n\nAvailable commands:\n\n- `bake lint` - Run prettier, toml-sort, ruff format, ruff check, ty, deptry\n- `bake test` - Run pytest with coverage on `tests/unit/`\n- `bake test-integration` - Run integration tests from `tests/integration/`\n- `bake test-all` - Run all tests\n- `bake clean` - Clean gitignored files (with exclusions)\n- `bake clean-all` - Clean all gitignored files\n- `bake setup-dev` - Setup Python development environment\n- `bake tools` - List development tools\n- `bake update` - Upgrade dependencies (includes uv lock --upgrade)\n\n#### Creating Custom Spaces\n\nCreate custom spaces by inheriting from BaseSpace:\n\n```python\nfrom bakelib import BaseSpace\n\nclass MySpace(BaseSpace):\n    def test(self) -\u003e None:\n        self.ctx.run(\"npm test\")\n\nbakebook = MySpace()\n```\n\nBaseSpace provides these tasks (override as needed):\n\n- `lint()` - Run prettier\n- `clean()` / `clean_all()` - Clean gitignored files\n- `setup_dev()` - Setup development environment\n- `tools()` - List development tools\n- `update()` - Upgrade dependencies\n\n#### Multi-Environment Bakebooks\n\nFor projects with multiple environments (dev, staging, prod), use environment bakebooks:\n\n```python\nfrom bakelib.environ import (\n    DevEnvBakebook,\n    StagingEnvBakebook,\n    ProdEnvBakebook,\n    get_bakebook,\n)\n\nbakebook_dev = DevEnvBakebook()\nbakebook_staging = StagingEnvBakebook()\nbakebook_prod = ProdEnvBakebook()\n\n# Select bakebook based on ENV environment variable\nbakebook = get_bakebook([bakebook_dev, bakebook_staging, bakebook_prod])\n```\n\n```bash\nENV=prod bake deploy    # Uses prod bakebook\nENV=dev bake deploy     # Uses dev bakebook\nbake deploy             # Defaults to dev (lowest priority)\n```\n\nCreate custom environments by inheriting from `BaseEnv`:\n\n```python\nfrom bakelib.environ import BaseEnv, EnvBakebook\n\nclass MyEnv(BaseEnv):\n    ENV_ORDER = [\"dev\", \"sit\", \"qa\", \"uat\", \"prod\"]\n\nclass MyEnvBakebook(EnvBakebook):\n    env_: MyEnv = MyEnv(\"local\")\n```\n\nFor more details, see the [bakelib source](https://github.com/wislertt/bakefile/tree/main/src/bakelib).\n\n## Development\n\n### Environment Setup\n\nClone and install the project:\n\n```bash\ngit clone https://github.com/wislertt/bakefile.git\ncd bakefile\n\n# Install bakefile as a global tool\nuv tool install bakefile\n\n# Setup development environment (macOS only)\n# Installs brew, bun, uv, and pre-commit hooks\nbake setup-dev\n\n# Verify development environment is setup correctly\n# Checks tool locations and runs lint + test\nbake assert-setup-dev\n```\n\n**Note:** `bake setup-dev` only supports macOS. For other platforms, run `bake --dry-run setup-dev` to see the commands and follow platform-specific alternatives.\n\nThe project uses [uv](https://github.com/astral-sh/uv) for dependency management.\n\n### Testing\n\nRun tests using the bake commands:\n\n```bash\nbake test              # Unit tests (fast)\nbake test-integration  # Integration tests (slow, real subprocess)\nbake test-all          # All tests with coverage\n```\n\n### Code Quality\n\nRun linters and formatters before committing:\n\n```bash\nbake lint              # Run prettier, toml-sort, ruff format, ruff check, ty, deptry\n```\n\n**Verification workflow:**\n\n1. Make changes\n2. Run `bake lint` to check code quality\n3. Run `bake test` to verify unit tests pass\n4. Commit when both pass\n\n## Contributing\n\nContributions are welcome! Please see [CLAUDE.md](/.claude/CLAUDE.md) for development guidelines, including:\n\n- Project structure and testing conventions\n- Code quality standards\n- Development workflow\n\n## License\n\nLicensed under the Apache License 2.0. See [LICENSE](/LICENSE) for the full text.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwislertt%2Fbakefile","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwislertt%2Fbakefile","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwislertt%2Fbakefile/lists"}