{"id":50922427,"url":"https://github.com/stablekernel/cascade","last_synced_at":"2026-06-16T20:00:26.309Z","repository":{"id":363703431,"uuid":"1264518793","full_name":"stablekernel/cascade","owner":"stablekernel","description":"Declarative trunk-based CI/CD for GitHub Actions - generate your pipelines, environment cascade, and release lifecycle from a single manifest.","archived":false,"fork":false,"pushed_at":"2026-06-10T01:40:46.000Z","size":320,"stargazers_count":0,"open_issues_count":42,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T03:14:27.217Z","etag":null,"topics":["ci-cd","devops","github-actions","release-automation","trunk-based-development"],"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/stablekernel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-10T00:38:59.000Z","updated_at":"2026-06-10T01:41:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/stablekernel/cascade","commit_stats":null,"previous_names":["stablekernel/cascade"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/stablekernel/cascade","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fcascade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fcascade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fcascade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fcascade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stablekernel","download_url":"https://codeload.github.com/stablekernel/cascade/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fcascade/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34421326,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"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":["ci-cd","devops","github-actions","release-automation","trunk-based-development"],"created_at":"2026-06-16T20:00:15.450Z","updated_at":"2026-06-16T20:00:26.281Z","avatar_url":"https://github.com/stablekernel.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003ecascade\u003c/h1\u003e\n\n\u003c!-- Row 1: identity \u0026 quality --\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pkg.go.dev/github.com/stablekernel/cascade\"\u003e\u003cimg src=\"https://pkg.go.dev/badge/github.com/stablekernel/cascade.svg\" alt=\"Go Reference\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://goreportcard.com/report/github.com/stablekernel/cascade\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/stablekernel/cascade\" alt=\"Go Report Card\"\u003e\u003c/a\u003e\n  \u003ca href=\"./go.mod\"\u003e\u003cimg src=\"https://img.shields.io/github/go-mod/go-version/stablekernel/cascade\" alt=\"Go Version\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://stablekernel.github.io/cascade/\"\u003e\u003cimg src=\"https://img.shields.io/badge/docs-cascade-36D0C4\" alt=\"Docs\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003c!-- Row 2: project health \u0026 CI --\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/stablekernel/cascade/actions/workflows/validate.yaml\"\u003e\u003cimg src=\"https://github.com/stablekernel/cascade/actions/workflows/validate.yaml/badge.svg?branch=main\" alt=\"Validate\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/stablekernel/cascade/actions/workflows/e2e.yaml\"\u003e\u003cimg src=\"https://github.com/stablekernel/cascade/actions/workflows/e2e.yaml/badge.svg?branch=main\" alt=\"E2E\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/stablekernel/cascade/actions/workflows/codeql.yml\"\u003e\u003cimg src=\"https://github.com/stablekernel/cascade/actions/workflows/codeql.yml/badge.svg?branch=main\" alt=\"CodeQL\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://securityscorecards.dev/viewer/?uri=github.com/stablekernel/cascade\"\u003e\u003cimg src=\"https://api.securityscorecards.dev/projects/github.com/stablekernel/cascade/badge\" alt=\"OpenSSF Scorecard\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/stablekernel/cascade/releases/latest\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/stablekernel/cascade\" alt=\"Latest release\"\u003e\u003c/a\u003e\n  \u003ca href=\"./LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-Apache_2.0-blue.svg\" alt=\"License: Apache 2.0\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/src/assets/avatar.png\" alt=\"The cascade mascot\" width=\"220\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\u003cstrong\u003eDeclarative trunk-based CI/CD for GitHub Actions.\u003c/strong\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Define what to build and where to deploy in one manifest.\u003cbr\u003e\n  cascade generates the GitHub Actions wiring, tracks deployment state, manages releases,\u003cbr\u003e\n  and cascades promotions through your environments.\n\u003c/p\u003e\n\n---\n\n## How it works\n\nThe **manifest** (`.github/manifest.yaml`) is the single source of truth. It holds both the pipeline configuration and the live deployment state for every environment. You run `cascade generate-workflow` once; after that the generated workflows own their own execution.\n\n```mermaid\n%%{init: {'theme':'base','themeVariables':{'fontFamily':'ui-sans-serif, system-ui, sans-serif','primaryColor':'#0E8B82','primaryBorderColor':'#36D0C4','primaryTextColor':'#F4FBFA','lineColor':'#1F9B92','clusterBkg':'transparent','clusterBorder':'#36D0C4','tertiaryColor':'#B87333'}}}%%\nflowchart TD\n    M[\"\u003cb\u003e.github/manifest.yaml\u003c/b\u003e\u003cbr/\u003econfig + live state\"] --\u003e G[\"\u003cb\u003ecascade generate-workflow\u003c/b\u003e\"]\n    G --\u003e WF[\"Generated GitHub Actions\u003cbr/\u003eorchestrate.yaml + promote.yaml\"]\n\n    WF -- \"merge to trunk\" --\u003e O\n\n    subgraph O[\"Orchestrate (on merge)\"]\n        direction LR\n        O1[\"Setup\"] --\u003e O2[\"Validate\"] --\u003e O3[\"Build\"] --\u003e O4[\"Deploy first env\"] --\u003e O5[\"Finalize\"]\n    end\n\n    O -- \"workflow_dispatch · same artifacts, never rebuilt\" --\u003e P\n\n    subgraph P[\"Promote (cascade through environments)\"]\n        direction LR\n        dev[\"dev\"] --\u003e test[\"test\"] --\u003e staging[\"staging\"] --\u003e prod[\"prod\"]\n    end\n\n    P --\u003e R\n\n    subgraph R[\"Release lifecycle\"]\n        direction LR\n        draft[\"draft\"] --\u003e pre[\"prerelease\"] --\u003e pub[\"published\u003cbr/\u003eRC tags cleaned\"]\n    end\n\n    classDef accent fill:#B87333,stroke:#E8702A,color:#FFF7F0;\n    class M accent;\n```\n\n---\n\n## Cross-repo artifact tracking\n\nA primary repo can own the environment chain for artifacts that are built and versioned in other repos. Each external repo dispatches the primary's generated `external-update.yaml`, which writes `{sha, version}` into `state.\u003cenv\u003e.external.\u003cname\u003e` of the one shared manifest; concurrent updates serialize on that manifest, then the primary cascades every source through its own environments. A callback can also pull in an external repo's workflow synchronously via `uses:` during the primary's run.\n\n```mermaid\n%%{init: {'theme':'base','themeVariables':{'fontFamily':'ui-sans-serif, system-ui, sans-serif','primaryColor':'#0E8B82','primaryBorderColor':'#36D0C4','primaryTextColor':'#F4FBFA','lineColor':'#1F9B92','clusterBkg':'transparent','clusterBorder':'#36D0C4','tertiaryColor':'#B87333'}}}%%\nflowchart TD\n    subgraph EXT[\"External artifact repos\"]\n        direction LR\n        A[\"\u003cb\u003eartifact-a\u003c/b\u003e\u003cbr/\u003ebuilds its own artifact\"]\n        B[\"\u003cb\u003eartifact-b\u003c/b\u003e\u003cbr/\u003ebuilds its own artifact\"]\n    end\n\n    A -- \"workflow_dispatch\u003cbr/\u003esource_repo · deploy_name · environment\u003cbr/\u003esha · version · artifacts\" --\u003e EU\n    B -- \"workflow_dispatch\u003cbr/\u003esource_repo · deploy_name · environment\u003cbr/\u003esha · version · artifacts\" --\u003e EU\n\n    subgraph PRIMARY[\"Primary repo\"]\n        direction TB\n        EU[\"\u003cb\u003eexternal-update.yaml\u003c/b\u003e\u003cbr/\u003ecascade external update\"]\n        EU -- \"writes {sha, version}\" --\u003e ST[\"\u003cb\u003e.github/manifest.yaml\u003c/b\u003e\u003cbr/\u003estate.\u0026lt;env\u0026gt;.external.\u0026lt;name\u0026gt;\u003cbr/\u003econcurrent updates serialize\"]\n        ST --\u003e PR\n        subgraph PR[\"Promote (cascade through environments)\"]\n            direction LR\n            dev[\"dev\"] --\u003e test[\"test\"] --\u003e staging[\"staging\"] --\u003e prod[\"prod\"]\n        end\n    end\n\n    CB[\"Primary build / deploy callback\"] -. \"sync uses:\u003cbr/\u003eorg/artifact-repo/.github/workflows/\u0026lt;name\u0026gt;.yaml@ref\" .-\u003e SYNC[\"External workflow\u003cbr/\u003einvoked inline\"]\n\n    classDef accent fill:#B87333,stroke:#E8702A,color:#FFF7F0;\n    class ST accent;\n```\n\n---\n\n## Hotfix any environment\n\nMost pipelines can only hotfix the tip, which in practice means production. cascade hotfixes **any** environment: it stages the fix on a per-environment integration branch, deploys that one environment with a clean `-rc.N.hotfix.M` version, and rejoins trunk the next time a trunk SHA that already contains the fix is promoted. The example below lands a fix on **staging** while dev, test, and prod stay exactly where they are.\n\n```mermaid\n%%{init: {'theme':'base','themeVariables':{'fontFamily':'ui-sans-serif, system-ui, sans-serif','primaryColor':'#0E8B82','primaryBorderColor':'#36D0C4','primaryTextColor':'#F4FBFA','lineColor':'#1F9B92','clusterBkg':'transparent','clusterBorder':'#36D0C4','tertiaryColor':'#B87333'}}}%%\nflowchart TD\n    T[\"\u003cb\u003etrunk tip\u003c/b\u003e\u003cbr/\u003efix already merged (roll forward first)\"]\n\n    subgraph LADDER[\"Environments\"]\n        direction LR\n        dev[\"dev\"] --\u003e test[\"test\"] --\u003e staging[\"staging\"] --\u003e prod[\"prod\"]\n    end\n\n    T -- \"cherry-pick fix onto env/staging\u003cbr/\u003eat staging's recorded base_sha\" --\u003e CP[\"\u003cb\u003ehotfix/staging/\u0026lt;short-sha\u0026gt;\u003c/b\u003e\u003cbr/\u003ebase + fix, nothing else\"]\n    CP --\u003e RPR[\"\u003cb\u003eresolution PR\u003c/b\u003e (base env/staging)\u003cbr/\u003ecascade-hotfix · auto-merge on env checks\"]\n    RPR -- \"on merge: build -\u003e deploy staging only -\u003e finalize\" --\u003e DS\n\n    subgraph DS[\"staging diverged\"]\n        direction TB\n        SV[\"\u003cb\u003ev1.4.0-rc.2.hotfix.1\u003c/b\u003e\u003cbr/\u003eref: env/staging\u003cbr/\u003ebase_sha: trunk SHA · patches: [fix]\"]\n    end\n\n    DS -. \"targets staging\" .-\u003e staging\n\n    DS == \"later promotion of a trunk SHA containing the fix\u003cbr/\u003eclears divergence (patch-containment guard)\" ==\u003e staging\n\n    classDef accent fill:#B87333,stroke:#E8702A,color:#FFF7F0;\n    class SV accent;\n```\n\n---\n\n## Is cascade right for your repo?\n\ncascade earns its keep when you promote a built artifact through a chain of environments. It is a strong fit when most of these hold:\n\n- You deploy to **two or more environments** (say dev, test, prod) and want the *same* artifact promoted through them, never rebuilt per stage.\n- You are on **GitHub Actions** and would rather own your deploy logic in reusable workflows than run a separate CD platform.\n- You want **promotion gates, hotfix-to-any-environment, and rollback** without hand-wiring that state machine.\n- You can adopt **conventional commits** (cascade derives versions, changelogs, and the breaking-change gate from them).\n\nIt is likely overkill for a single environment with a plain build-and-release on push, or a repo with no deployments at all, though the no-environment mode still gives you conventional-commit versioning and releases.\n\n**Not trunk-based yet?** cascade promotes *from trunk*: you merge to one trunk branch and cascade promotes that line through your environments. If you run release branches or a GitFlow model today, adopting cascade means moving promotion onto a trunk-based flow. That is a deliberate shift, but cascade is a practical vehicle for it: your existing build and deploy steps become reusable-workflow callbacks, and cascade takes over the promotion, state, and release wiring on top of them.\n\n### What adopting looks like\n\nKeep the build and deploy logic you already have, wrap each as a `workflow_call` reusable workflow, describe your environments and callbacks in the manifest, and let cascade generate the orchestration. Tooling you already rely on stays yours: point cascade's changelog or release step at your own workflow, or switch it off, while cascade owns the promotion cascade.\n\nSee the **[Adoption guide](https://stablekernel.github.io/cascade/adoption/)** for the full walkthrough on migrating an existing pipeline and wiring in tooling you already use. For reference: the [Getting Started guide](https://stablekernel.github.io/cascade/getting-started/), the [Callback Contract](https://stablekernel.github.io/cascade/callback-contract/) for the inputs cascade passes your workflows, and the [hardening guide](https://stablekernel.github.io/cascade/security/hardening/) for the GitHub setup (branch protection, environments, scoped tokens).\n\n---\n\n## Quick start\n\n### 1. Install the CLI\n\n```bash\ngo install github.com/stablekernel/cascade/cmd/cascade@latest\n# or pin a specific version:\ngo install github.com/stablekernel/cascade/cmd/cascade@v0.1.0\n```\n\n### 2. Create the manifest\n\n```yaml\n# .github/manifest.yaml\nci:\n  config:\n    trunk_branch: main\n    cli_version: v0.1.0\n\n    environments: [dev, test, uat, prod]\n\n    builds:\n      - name: app\n        workflow: .github/workflows/build-app.yaml\n        triggers: [src/**, go.mod]\n\n    deploys:\n      - name: infra\n        workflow: .github/workflows/deploy-infra.yaml\n        triggers: [cdk/**]\n      - name: app\n        workflow: .github/workflows/deploy-app.yaml\n        depends_on: [app]   # waits for build-app to succeed\n\n    changelog:\n      contributors: true\n```\n\n### 3. Generate the workflows\n\n```bash\ncascade generate-workflow --config .github/manifest.yaml\n# Creates: .github/workflows/orchestrate.yaml\n#          .github/workflows/promote.yaml\n```\n\nCommit the generated files. cascade re-generates them whenever you update the manifest; the `-f` flag overwrites in place.\n\n### 4. Write your callbacks\n\ncascade calls your workflows via `workflow_call` and passes standard inputs. You own the build and deploy logic.\n\n```yaml\n# .github/workflows/build-app.yaml\non:\n  workflow_call:\n    inputs:\n      environment:\n        type: string\n        required: true\n      sha:\n        type: string\n        required: true\n    outputs:\n      artifact_id:\n        description: 'Immutable artifact identifier (e.g., Docker image digest)'\n        value: ${{ jobs.build.outputs.artifact_id }}\n```\n\ncascade is a metadata courier. You construct the registry and deploy operations yourself.\n\n---\n\n## Capabilities\n\ncascade generates workflows that handle the orchestration layer. Your callback workflows handle the domain logic. The manifest gives you control over:\n\n- **Change detection**: builds and deploys run only when their declared `triggers` match changed paths.\n- **Dependency ordering**: `depends_on` chains builds and deploys in the right order.\n- **Matrix builds**: fan out a single build over a matrix of inputs.\n- **Per-job runner selection**: set `runs_on` at the config or per-build/deploy level.\n- **Concurrency control**: configurable group and cancel-in-progress on orchestrate, promote, release, and external-update workflows.\n- **Extra triggers**: attach `schedule`, `repository_dispatch`, `workflow_run`, and `merge_group` events to orchestration.\n- **Dispatch inputs**: expose operator-facing manual-run inputs on the generated `workflow_dispatch`.\n- **PR plan preview**: a comment on each PR shows which builds and deploys would run.\n- **Merge queue lane**: a dedicated gate job runs before merge to protect trunk.\n- **Action pinning**: `pin_mode: sha` emits pinned SHA references for all cascade-managed action calls. Override individual actions via `action_pins`.\n- **Breaking-change gate**: `feat!:` or `BREAKING CHANGE:` commits block the prerelease-to-release boundary unless you override them.\n- **Artifact passing**: the `artifact_id` output from build callbacks is stored in state and forwarded to deploys and the publish callback.\n- **Publish callback**: once a release is published, a separate workflow call lets you retag RC artifacts in your registry.\n- **Schema version enforcement**: every CLI invocation checks `schema_version` on the manifest and rejects incompatible manifests with a clear error.\n\nFor a no-environment project (library or CLI), omit `environments` entirely. Commits produce RC pre-releases; a `promote` dispatch publishes the final release.\n\n---\n\n## Promotion\n\n\u003c!-- Promote flow described textually; see docs/images/promote-flow.png for a visual --\u003e\n\nPromotions are triggered via `workflow_dispatch` on the generated `promote.yaml`.\n\n| Mode | Behavior |\n|---|---|\n| `default` | Advance the chain one logical step |\n| `dev-to-test` | Promote dev to test |\n| `dev-to-uat` | Cascade: dev → test → uat (all intermediates updated atomically) |\n| `dev-to-prod` | Full cascade through all environments |\n| `uat-to-prod` | Partial cascade from uat onward |\n\nThese modes are generated from your configured environment names (`dev`, `test`, `uat`, `prod` shown here as an example); roles are positional, with the last environment as the release stage.\n\nThe same artifacts built on the first merge are promoted through the chain; nothing is rebuilt.\n\n---\n\n## State\n\nThe manifest tracks deployment state automatically. The `state:` section is managed by cascade; do not edit it by hand.\n\n```yaml\nci:\n  state:\n    dev:\n      sha: abc123\n      version: v1.2.0-rc.3\n      committed_at: \"2025-01-15T10:30:00Z\"\n      committed_by: github-actions[bot]\n      builds:\n        app:\n          sha: abc123\n          artifact_id: sha256:def456\n          built_at: \"2025-01-15T10:30:00Z\"\n      deploys:\n        infra:\n          sha: abc123\n          deployed_at: \"2025-01-15T10:31:00Z\"\n    release:\n      sha: abc000\n      version: v1.1.0\n  latest_release:\n    version: v1.1.0\n    sha: abc000\n```\n\n---\n\n## CLI reference\n\n| Command | Description |\n|---|---|\n| `generate-workflow` | Generate `orchestrate.yaml` and `promote.yaml` |\n| `orchestrate setup` | Detect changes, compute version, plan execution |\n| `orchestrate finalize` | Update state, manage release, commit manifest |\n| `promote preflight` | Validate, compute promotions, check breaking changes |\n| `promote finalize` | Update state after promotion deploys complete |\n| `generate-changelog` | Create changelog from conventional commits |\n| `manage-release` | Create, update, or publish GitHub releases |\n| `next-version` | Calculate next semantic version |\n| `detect-changes` | Determine which builds/deploys a file change triggers |\n| `parse-config` | Validate and print the parsed manifest (with schema warnings) |\n| `reset` | Wipe releases and state (for testing or a fresh start) |\n\nFull flag reference: [CLI reference](https://stablekernel.github.io/cascade/cli-reference/).\n\n---\n\n## Documentation\n\n| Document | Description |\n|---|---|\n| [Getting Started](https://stablekernel.github.io/cascade/getting-started/) | Step-by-step setup guide |\n| [Configuration](https://stablekernel.github.io/cascade/configuration/) | Full manifest reference |\n| [Workflows](https://stablekernel.github.io/cascade/workflows/) | Orchestrate and Promote explained |\n| [CLI Reference](https://stablekernel.github.io/cascade/cli-reference/) | All commands and flags |\n| [Callback Contract](https://stablekernel.github.io/cascade/callback-contract/) | How to write build/deploy/publish workflows |\n| [Architecture](https://stablekernel.github.io/cascade/architecture/) | System design and internals |\n| [Schema Versioning](https://stablekernel.github.io/cascade/versioning/) | Compatibility policy and migration guide |\n\n---\n\n## Roadmap to stable\n\ncascade is functional and self-hosted. Its own releases page shows the full pipeline running end to end. The remaining work before the v1.0.0 schema freeze falls into two areas.\n\n**Schema coverage.** A few GitHub Actions capabilities are modeled in the manifest shape but not yet emitted by the generator: environment gates, OIDC token configuration, and per-environment runner overrides. These sit on the direct path to v1.0.0.\n\n**Hardening.** This covers schema version enforcement (shipped), compatibility docs ([schema versioning](https://stablekernel.github.io/cascade/versioning/)), and more e2e coverage. The added tests confirm that the generated workflows behave correctly under edge cases such as empty builds, cross-repo coordination, and rollback to N-1.\n\nThe manifest schema field shapes were frozen in v0.1.0 as the v1 contract baseline. Minor versions between now and v1.0.0 may add new optional fields; no existing fields will be removed or renamed before v1.0.0.\n\nOpen work is tracked in [GitHub Issues](https://github.com/stablekernel/cascade/issues).\n\n---\n\n## Conventions\n\ncascade follows these conventions in its own codebase and in the generated workflows it produces:\n\n- **Additive manifest changes**: new fields are always optional with sensible defaults, so existing manifest files keep working across minor version bumps.\n- **Conventional commits**: commit messages follow `type: subject` (for example `feat:`, `fix:`, `docs:`), and the changelog generator reads this format.\n- **Callback isolation**: generated workflows call your workflows via `workflow_call`, and cascade never reaches into your callback logic.\n- **Metadata courier**: cascade passes artifact identifiers and versions between stages. It never touches your container registry, package registry, or deployment target directly.\n\n---\n\n## Development\n\n```bash\n# Build\ngo build -o cascade ./cmd/cascade\n\n# Test (all packages)\ngo test ./...\n\n# E2E tests (requires Docker)\ncd e2e \u0026\u0026 go test -v -timeout 20m ./...\n\n# Lint\ngolangci-lint run ./...\n\n# Regenerate cascade's own workflows (uses itself)\ngo run ./cmd/cascade generate-workflow --config .github/manifest.yaml -f\n```\n\n---\n\n## Contributing\n\nContributions are welcome. Please read [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup and workflow details.\n\ncascade uses the [Developer Certificate of Origin](https://developercertificate.org/). Sign off each commit with `git commit -s`. By participating you agree to the [Code of Conduct](./CODE_OF_CONDUCT.md).\n\n---\n\n## License\n\nApache 2.0. See [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstablekernel%2Fcascade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstablekernel%2Fcascade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstablekernel%2Fcascade/lists"}