{"id":46182069,"url":"https://github.com/composepack/composepack","last_synced_at":"2026-03-02T20:35:34.278Z","repository":{"id":324692380,"uuid":"1097933021","full_name":"composepack/composepack","owner":"composepack","description":"Dynamic templating and packaging for Docker Compose. Manage complex configurations with values.yaml defaults and overrides.","archived":false,"fork":false,"pushed_at":"2025-12-01T10:10:05.000Z","size":4656,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-03T19:52:08.222Z","etag":null,"topics":["config-management","configuration","devops","docker","docker-compose","infrastructure","packaging","templating"],"latest_commit_sha":null,"homepage":"","language":"Go","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/composepack.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-11-17T03:25:57.000Z","updated_at":"2025-12-01T08:34:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/composepack/composepack","commit_stats":null,"previous_names":["garearc/composepack","composepack/composepack"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/composepack/composepack","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/composepack%2Fcomposepack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/composepack%2Fcomposepack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/composepack%2Fcomposepack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/composepack%2Fcomposepack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/composepack","download_url":"https://codeload.github.com/composepack/composepack/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/composepack%2Fcomposepack/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30018583,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T17:00:27.440Z","status":"ssl_error","status_checked_at":"2026-03-02T17:00:03.402Z","response_time":60,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["config-management","configuration","devops","docker","docker-compose","infrastructure","packaging","templating"],"created_at":"2026-03-02T20:35:33.745Z","updated_at":"2026-03-02T20:35:34.269Z","avatar_url":"https://github.com/composepack.png","language":"Go","readme":"# **ComposePack**\n\n**English** | [简体中文](README.zh.md)\n\n\u003e 🧩 **Pack your Compose, ship it anywhere.**  \n\u003e The power of Helm-style configuration for Docker Compose.\n\n\u003cp align=\"center\"\u003e\n  \u003c!-- TODO: Replace with a real banner --\u003e\n  \u003cimg src=\"docs/images/banner.svg\" width=\"1000\" alt=\"ComposePack banner\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003c!-- Badges --\u003e\n  \u003ca href=\"https://github.com/composepack/composepack/actions/workflows/ci.yml\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/composepack/composepack/ci.yml?label=CI\" alt=\"CI Status\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/composepack/composepack/releases\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/v/release/composepack/composepack?display_name=tag\u0026sort=semver\" alt=\"Latest Release\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/composepack/composepack/blob/main/LICENSE\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/license/composepack/composepack\" alt=\"License\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/composepack/composepack/stargazers\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/stars/composepack/composepack?style=social\" alt=\"GitHub stars\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nDocker Compose is the standard for running multi-container applications, but it lacks **templating, dynamic configuration, and clean packaging.** Teams often struggle with giant YAML files, manual copy-pasting across environments, and complex `.env` file management.\n\n**ComposePack fixes this.**\n\nIt brings a **modern templating engine**, **overridable config system**, and a **packaging workflow** to Docker Compose—while remaining 100% compatible with the standard Docker CLI.\n\n### Why ComposePack?\n\n* 📝 **Go-Style Templates:** Write dynamic Compose files with logic (`if`, `range`, etc.).\n* ⚙️ **Structured Config:** Ship clean `values.yaml` defaults and allow user overrides.\n* 📦 **Real Packaging:** Distribute your app as a versioned, installable `.cpack` chart.\n* 🔐 **Reproducible Releases:** Render isolated, self-contained release directories.\n* 🚀 **Native Runtime:** Under the hood, it's just `docker compose`.\n\n## ⚖️ ComposePack vs. Docker Compose\n\n| Feature                   |   Docker Compose   |   **ComposePack**    |\n| :------------------------ | :----------------: | :------------------: |\n| **Templating**            | ❌ (Variables only) |  **✅ (Full logic)**  |\n| **Config Model**          |   ❌ (Flat .env)    | **✅ (Values.yaml)**  |\n| **Packaging**             |         ❌          |    **✅ (Charts)**    |\n| **Environment Isolation** |         ❌          | **✅ (Release Dirs)** |\n| **Drift Detection**       |         ❌          | **✅ (Diff command)** |\n| **Runtime Engine**        |         ✅          |        **✅**         |\n\n---\n\n## 📚 Table of Contents\n\n* [⚡ Quick 60-Second Demo](#-quick-60-second-demo)\n* [📦 Installation](#-installation)\n* [🧠 How It Works (High-Level)](#-how-it-works-high-level)\n* [🚀 How to Use](#-how-to-use)\n  * [🛠️ For Chart Creators (Shippers)](#️-for-chart-creators-shippers)\n  * [🧑‍💻 For Chart Users (Consumers)](#-for-chart-users-consumers)\n* [🧩 Template Basics](#-template-basics)\n* [📂 Chart Layout \u0026 File Types](#-chart-layout--file-types)\n* [🏗️ Runtime Layout](#️-runtime-layout)\n* [📏 Runtime Rules \u0026 Gotchas](#-runtime-rules--gotchas)\n* [📝 FAQ](#-faq)\n* [🤝 Contributing](#-contributing)\n\n---\n\n## ⚡ Quick 60-Second Demo\n\n```bash\n# 1. Scaffold a chart\ncomposepack init charts/demo --name demo --version 0.1.0\n\n# 2. Install it into a release with your own values\ncomposepack install charts/demo --name myapp -f values-prod.yaml --auto-start\n\n# 3. Watch logs\ncomposepack logs myapp --follow\n```\n\nThat’s it: templated config + reproducible runtime on top of plain Docker Compose.\n\n---\n\n## 📦 Installation\n\n\u003e ComposePack is a single binary with no external dependencies other than Docker \u0026 Docker Compose.\n\n### Homebrew (macOS/Linux)\n\n* If you’ve tapped `composepack/tap` already:\n\n```bash\nbrew install composepack\n```\n\n* First time using the tap:\n\n```bash\nbrew tap composepack/tap\nbrew install composepack\n```\n\nNote: once accepted to homebrew-core, `brew install composepack` will work without a tap on macOS and Linux.\n\n### Docker Image (CI/CD)\n\nFor use in GitHub Actions, GitLab CI, or other containerized environments:\n\n```bash\n# Use the official image\ndocker run --rm garearc/composepack:latest --version\n\n# Or pin to a specific version\ndocker run --rm garearc/composepack:v1.0.0 --version\n```\n\n**Example GitHub Actions workflow:**\n\n```yaml\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Install and run composepack\n        run: |\n          docker run --rm \\\n            -v ${{ github.workspace }}:/workspace \\\n            -w /workspace \\\n            garearc/composepack:latest \\\n            install charts/myapp --name prod\n```\n\nThe image is multi-arch (supports `linux/amd64` and `linux/arm64`) and is automatically published to Docker Hub on every release.\n\n### macOS / Linux (curl)\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/composepack/composepack/main/scripts/install.sh | bash\n```\n\n* Installs to `/usr/local/bin/composepack` or falls back to `~/.local/bin/composepack`\n* Override install directory with `COMPOSEPACK_INSTALL_DIR`\n\nUninstall:\n\n```bash\n./scripts/uninstall.sh\n```\n\n### Windows (PowerShell)\n\n```powershell\n./scripts/install.ps1 -Version v1.0.0 -InstallDir \"$env:ProgramFiles\\ComposePack\"\n```\n\nUninstall:\n\n```powershell\n./scripts/uninstall.ps1\n```\n\n### Build from source\n\n```bash\ngit clone https://github.com/composepack/composepack.git\ncd composepack\nmake build\n```\n\n`make generate` runs `go generate ./...` for Wire and other providers.\n\n---\n\n## 🧠 How It Works (High-Level)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/images/flow.svg\" width=\"1000\" alt=\"ComposePack flow\" /\u003e\n\u003c/p\u003e\n\n* You define a **chart** (templated Compose + assets).\n* Users pass values (`values.yaml`, `--set`, env vars).\n* ComposePack renders everything into a **self-contained release directory**.\n* Docker Compose runs exclusively from that directory.\n\n---\n\n## 🚀 How to Use\n\nComposePack has two kinds of users:\n\n* **Chart Creators (Shippers)** → build and package charts\n* **Chart Users (Consumers)** → install and run charts\n\nBelow is the workflow for each.\n\n---\n\n### 🛠️ For Chart Creators (Shippers)\n\n*(for teams packaging their applications)*\n\n#### 1️⃣ Create a new chart (scaffolding)\n\n```bash\ncomposepack init charts/example --name example --version 0.1.0\n```\n\nThis generates something like:\n\n```text\ncharts/example/\n  Chart.yaml\n  values.yaml\n  templates/\n    compose/00-app.tpl.yaml\n    files/config/message.txt.tpl\n    helpers/_helpers.tpl\n  files/\n    config/\n```\n\n#### 2️⃣ Template / render your chart locally\n\n```bash\ncomposepack template dev --chart charts/example\n```\n\nThis renders templates but does **not** create or modify a release.\n\n#### 3️⃣ Install your chart to test it\n\n```bash\ncomposepack install charts/example --name dev --auto-start\n```\n\nThis builds `.cpack-releases/dev/` and runs `docker compose up` inside it.\n\n#### 4️⃣ Package your chart for distribution\n\n```bash\ncomposepack package charts/example --destination dist/\n```\n\nCreates:\n\n```text\ndist/example-0.1.0.cpack.tgz\n```\n\nYou can also customize the output name:\n\n```bash\ncomposepack package charts/example --output dist/example.cpack.tgz\n```\n\nYou can host that `.cpack.tgz` on HTTP(S), ship it as an artifact, or check it into your internal distribution system.\n\n---\n\n### 🧑‍💻 For Chart Users (Consumers)\n\n*(for customers or internal developers consuming charts)*\n\n#### 1️⃣ Install from a packaged chart (or local dir)\n\n```bash\ncomposepack install example.cpack.tgz --name myapp -f custom-values.yaml --auto-start\n```\n\n`install` accepts:\n\n* A local `.cpack.tgz` archive\n* A local chart directory\n* An HTTP/HTTPS URL pointing to a packaged chart\n\n#### 2️⃣ Manage your deployment\n\n```bash\ncomposepack up myapp\ncomposepack down myapp --volumes\ncomposepack logs myapp --follow\ncomposepack ps myapp\ncomposepack template myapp\ncomposepack diff myapp --chart \u003cchart-source\u003e\n```\n\nAll runtime files for this release live in:\n\n```text\n.cpack-releases/myapp/\n  docker-compose.yaml\n  files/\n  release.json\n```\n\nIf needed, you can `cd` into this folder and run `docker compose` manually.\n\nWant to run these commands from somewhere else? Pass `--runtime-dir` to point directly at the release folder:\n\n```bash\ncomposepack up myapp --runtime-dir /opt/releases/myapp\ncomposepack logs myapp --runtime-dir /opt/releases/myapp --follow\n```\n\n#### 3️⃣ Preview changes before deploying (Drift Detection)\n\nBefore running `install` or `up`, you can see what would change:\n\n```bash\n# If release exists, chart source is auto-resolved\ncomposepack diff myapp\n\n# Or compare against a different chart\ncomposepack diff myapp --chart charts/myapp-v2\n```\n\nThis shows:\n\n* What services would be added, removed, or modified\n* Changes to the docker-compose.yaml configuration\n* File differences (with `--show-files`)\n\nExample output:\n\n```\n📝 Docker Compose Changes:\n\n-     image: myapp:v1.0\n+     image: myapp:v2.0\n\n⚠️  Affected Services:\n  • myapp-api (modified)\n```\n\n**Note:** In the examples above, `myapp` is the **release name** (the name you gave to your deployment). The chart source is auto-resolved from the release metadata, so you typically don't need to specify `--chart` unless comparing against a different chart.\n\nThis helps you answer: **\"Will running install now restart my database?\"**\n\n---\n\n## 🧩 Template Basics\n\nComposePack uses **Go templates** — the same templating style many Helm users already know.\n\nExample:\n\n```yaml\n# templates/compose/00-app.tpl.yaml\nservices:\n  app:\n    image: \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\"\n    environment:\n      DB_HOST: \"{{ .Values.db.host }}\"\n      DB_PASSWORD: \"{{ env \"DB_PASSWORD\" }}\"\n```\n\nYou have access to:\n\n* `.Values` — merged system + user values\n* `.Env` — environment variables\n* `.Release` — name, version, metadata\n* Standard Go template functions (`default`, `include`, `quote`, `toJson`, etc.)\n\nIf your team already uses Helm templates, the learning curve is almost zero.\n\n---\n\n## 📂 Chart Layout \u0026 File Types\n\nThis section explains **what lives where** inside a chart and how ComposePack treats those files.\n\n### High-level layout\n\nA typical chart looks like this:\n\n```text\nmyapp/\n  Chart.yaml\n  values.yaml\n  templates/\n    compose/\n      00-app.tpl.yaml\n      10-worker.tpl.yaml\n    files/\n      config/app.env.tpl\n    helpers/\n      _helpers.tpl\n  files/\n    config/\n    scripts/\n```\n\n### Key files \u0026 directories\n\n#### `Chart.yaml`\n\n* **Required**\n* Metadata about the chart:\n\n  * `name`: string (required)\n  * `version`: string (required)\n  * `description`: string\n  * `maintainers`: []string\n* Used by ComposePack to identify the chart and write `release.json`.\n\n#### `values.yaml`\n\n* **Required**\n* Default **system-level configuration** for the chart.\n* Users can layer their own `values-*.yaml` or `--set` overrides on top.\n* Think of this as “what the product ships with” vs “what users customize.”\n\n---\n\n#### `templates/compose/*.tpl.yaml`\n\n* **Required folder**\n* Each file is a **templated Docker Compose fragment**.\n* **Must end with `.tpl.yaml`.**\n* ComposePack:\n\n  1. Renders these templates using `.Values` and `.Env`.\n  2. Merges all rendered fragments into a **single `docker-compose.yaml`** per release.\n\nExample:\n\n```text\ntemplates/compose/\n  00-core.tpl.yaml\n  10-db.tpl.yaml\n  20-api.tpl.yaml\n```\n\n---\n\n#### `templates/files/*.tpl`\n\n* Optional.\n* Templated **runtime assets**:\n\n  * config files\n  * shell scripts\n  * anything written to disk for containers to mount.\n* **Must end with `.tpl`.**\n* ComposePack:\n\n  * Renders them\n  * Drops the `.tpl` suffix\n  * Writes them into the release’s `files/` directory.\n\nExample:\n\n```text\ntemplates/files/\n  config/app.env.tpl       -\u003e files/config/app.env\n  scripts/init.sh.tpl      -\u003e files/scripts/init.sh\n```\n\n---\n\n#### `templates/helpers/*.tpl`\n\n* Optional.\n* Reusable template snippets and helper functions.\n* Included via `{{ include \"helper.name\" . }}` from other templates.\n\nExample:\n\n```text\ntemplates/helpers/_helpers.tpl\n```\n\n```yaml\n{{- define \"myapp.fullname\" -}}\n{{ printf \"%s-%s\" .Release.Name .Chart.Name | trunc 63 | trimSuffix \"-\" }}\n{{- end -}}\n```\n\n---\n\n#### `files/`\n\n* Optional.\n* **Static assets** that do not need templating.\n* Everything under `files/` is copied as-is into the release’s `files/` directory.\n* Good for:\n\n  * static config\n  * certificates\n  * seed data\n  * scripts that never change\n\nExample:\n\n```text\nfiles/\n  config/defaults.json\n  scripts/migrate.sh\n```\n\nIn the release:\n\n```text\n.cpack-releases/\u003cname\u003e/\n  files/config/defaults.json\n  files/scripts/migrate.sh\n```\n\n---\n\n## 🏗️ Runtime Layout\n\nFor each release, ComposePack maintains a self-contained directory:\n\n```text\n.cpack-releases/\u003crelease\u003e/\n  docker-compose.yaml   # merged compose file (all fragments combined)\n  files/                # rendered \u0026 static assets referenced in templates\n    config/...\n    scripts/...\n  release.json          # metadata: chart, version, values, environment, etc.\n```\n\nThis is the **only** place Docker Compose runs from for that release.\n\n---\n\n## 📏 Runtime Rules \u0026 Gotchas\n\nThese are important design rules to keep your charts predictable and easy to debug.\n\n### 1️⃣ All mountable assets live under `./files/` at runtime\n\nIn the release directory, all non-compose assets live under `files/`.\nThat means **all local volume paths in your Compose templates must be under `./files/...`**.\n\nExample:\n\n```yaml\n# inside templates/compose/*.tpl.yaml\nservices:\n  app:\n    volumes:\n      - ./files/config/app.env:/app/app.env:ro\n      - ./files/scripts/init.sh:/docker-entrypoint.d/init.sh:ro\n```\n\nIf you reference paths outside `./files/`, your containers may fail to start because those files won’t exist in the runtime directory.\n\n---\n\n### 2️⃣ Suffix rules for templates\n\nComposePack relies on file suffixes to decide how to treat files:\n\n* Compose templates **must end with** `.tpl.yaml`\n\n  * Example: `10-api.tpl.yaml`\n* Other templated files **must end with** `.tpl`\n\n  * Example: `app.env.tpl`, `init.sh.tpl`\n* Static assets that need no templating → put them under `files/` **without** `.tpl`.\n\nIf the suffixes are wrong, files may be copied without rendering or ignored as compose fragments.\n\n---\n\n### 3️⃣ Runtime commands are bound to the release directory\n\nComposePack always runs Docker Compose from the release’s directory:\n\n```text\n.cpack-releases/\u003crelease\u003e/\n  docker-compose.yaml\n  files/\n```\n\nWhen you run:\n\n```bash\ncomposepack up myapp\n```\n\nit is equivalent to:\n\n```bash\ncd .cpack-releases/myapp\ndocker compose -f docker-compose.yaml up\n```\n\nYou must `cd` into the correct directory that contains `.cpack-releases` or specify the right `--runtime-dir`, otherwise, ComposePack won’t see the right file and volumes.\n\n---\n\n## 📝 FAQ\n\n### Does ComposePack replace **Docker** Compose?\n\nNo. ComposePack **wraps** Docker Compose, it doesn’t replace it.\n\n* ComposePack handles: templating, values, chart packaging, release directories  \n* Docker Compose handles: actually running the containers\n\nYou can always `cd` into `.cpack-releases/\u003cname\u003e/` and run `docker compose` manually if you prefer.\n\n### What's the difference between chart name, release name, and chart source?\n\nComposePack uses three different types of names:\n\n* **Chart Name** - The name of the chart package (from `Chart.yaml`). Example: `example`\n* **Release Name** - The name you give to a deployment instance (via `--name` flag). Example: `myapp`, `prod`, `staging`\n* **Chart Source** - The path/URL where the chart is located. Example: `charts/example`, `app.cpack.tgz`\n\n**In practice:**\n* When you run `composepack install charts/example --name myapp`:\n  * `charts/example` = chart source (where the chart is)\n  * `example` = chart name (from Chart.yaml)\n  * `myapp` = release name (what you call this deployment)\n* After installation, you use the **release name** in commands:\n  * `composepack up myapp` (not `composepack up example`)\n  * `composepack diff myapp` (chart source is auto-resolved)\n\nYou can deploy the same chart multiple times with different release names (e.g., `prod`, `staging`, `dev`).\n\nSee [docs/naming.md](docs/naming.md) for detailed explanation.\n\n### Why not just use raw docker-compose and .env files?\n\n`.env` is fine for small projects, but it has limits:\n\n* It’s **flat** (no nested structure)\n* It doesn’t distinguish **system defaults** from **user overrides** (chaining multiple `.env` files is super confusing and error-prone)\n* It’s hard to maintain across **upgrades**\n* You can’t easily ship a “product config” separate from customer config\n\nComposePack gives you:\n\n* default `values.yaml` for **system defaults**\n* user can specify their own `values-*.yaml` and `--set` overrides on top\n* a clear separation between **what you ship** and **what users customize**\n* a reproducible **release directory** for each environment\n\n### Why not use Helm?\n\nHelm is great — but it’s **designed for Kubernetes**, not Docker Compose.\n\nUse Helm when:\n\n* You’re deploying to a Kubernetes cluster\n* You’re already invested in K8s tooling and workflows\n\nUse **ComposePack** when:\n\n* You want Helm-style templating and chart packaging\n* You want to stay on **plain Docker Compose**\n* You don’t want the operational overhead of running Kubernetes\n\nThink of ComposePack as bringing the **Helm experience** to the Compose world.\n\n### Can I still run docker compose directly?\n\nYes. ComposePack writes everything into:\n\n```text\n.cpack-releases/\u003crelease\u003e/\n  docker-compose.yaml\n  files/\n  release.json\n````\n\nIf you prefer, you can:\n\n```bash\ncd .cpack-releases/\u003crelease\u003e\ndocker compose up\ndocker compose ps\ndocker compose logs\n```\n\nComposePack just standardizes how that directory is built.\n\n### Is ComposePack production ready?\n\nRight now the project is **early-stage** and evolving.\n\nIt’s suitable for:\n\n* Experimentation\n* Internal tools\n* Early adopters who are comfortable reading Go code and contributing\n\nIf you rely on it in production, please:\n\n* Open issues for any problems\n* Share feedback on missing features\n* Consider contributing bugfixes or docs improvements 🙏\n\n---\n\n## 🤝 Contributing\n\nWe welcome issues and PRs!\n\n### Development workflow\n\n```bash\nmake fmt\nmake test\nmake build\nmake generate\n```\n\n* CI (`.github/workflows/ci.yml`) runs formatting, vetting, and tests on PRs and pushes to `main`.\n* Tag releases with:\n\n```bash\ngit tag vX.Y.Z\ngit push --tags\n```\n\nThis triggers cross-compiled binaries to be uploaded to GitHub Releases.\n\n---\n\n\u003e If you find ComposePack useful, consider ⭐ starring the repo — it helps others discover it!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcomposepack%2Fcomposepack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcomposepack%2Fcomposepack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcomposepack%2Fcomposepack/lists"}