diff --git a/docs/docs/10-overview.md b/docs/docs/10-overview.md
index 8b3469f63..cf5054407 100644
--- a/docs/docs/10-overview.md
+++ b/docs/docs/10-overview.md
@@ -13,7 +13,7 @@ technologies, like [Argo CD](https://argoproj.github.io/cd/), to streamline and
automate the progressive rollout of changes across the many stages of an
application's lifecycle.
-![Screenshot](../static/img/screenshot.png)
+![Screenshot](./assets/screenshot.png)
Kargo's goal is to provide an intuitive and flexible layer "above" existing GitOps tooling, wherein you can describe the relationships between various application instances deployed to different environments as well as procedures for progressing changes from one application instance's source of truth to the next.
diff --git a/docs/docs/20-quickstart.md b/docs/docs/20-quickstart.md
index b14740eb0..f37187b65 100644
--- a/docs/docs/20-quickstart.md
+++ b/docs/docs/20-quickstart.md
@@ -227,7 +227,7 @@ all three Argo CD `Application`s have not yet synced because they're not
configured to do so automatically, and in fact, the branches referenced by their
`targetRevision` fields do not even exist yet.
-![Argo-dashboard-screenshot](../static/img/argo-dashboard.png)
+![Argo-dashboard-screenshot](./assets/argo-dashboard.png)
## Your First Kargo Project
@@ -787,7 +787,7 @@ the previous section.
This will take you to a list of `Project`s. It currently includes only
the one created in the previous step.
- ![Kargo-dashboard](../static/img/kargo-projects.png)
+ ![Kargo-dashboard](./assets/kargo-projects.png)
1. Select kargo-demo:
@@ -801,13 +801,13 @@ the previous section.
* Three `Stage`s representing distinct instances of our demo
application.
- ![Kargo-dashboard-screenshot](../static/img/kargo-dashboard-projects.png)
+ ![Kargo-dashboard-screenshot](./assets/kargo-dashboard-projects.png)
* An interactive Freight Timeline with `Freight` ordered
chronologically, with newer `Freight` to the left and older `Freight` to
the right.
- ![Kargo-Freight-Timeline](../static/img/kargo-frieght-timeline.png)
+ ![Kargo-Freight-Timeline](./assets/kargo-frieght-timeline.png)
1. After a few seconds, a piece of `Freight` should appear in the Freight
Timeline, if it isn't there already.
@@ -838,17 +838,17 @@ the previous section.
1. To promote `Freight` to the `test` `Stage`, select the target icon on the
left border of test:
- ![Kargo-Promote](../static/img/kargo-promote-option.png)
+ ![Kargo-Promote](./assets/kargo-promote-option.png)
Next, select the `Freight` from the Freight Timeline and confirm
the promotion by selecting Yes:
- ![Kargo-Promote](../static/img/kargo-promote-option-2.png)
+ ![Kargo-Promote](./assets/kargo-promote-option-2.png)
When promotion process is complete, you'll see a check mark next to
test, indicating that the promotion was successful.
- ![Kargo-dashboard-screenshot](../static/img/kargo-dashboard-promotion.png)
+ ![Kargo-dashboard-screenshot](./assets/kargo-dashboard-promotion.png)
Following the promotion, health checks will run periodically. When a `Stage`
is in a healthy state, this will be reflected with a heart icon. You can
@@ -868,7 +868,7 @@ the previous section.
`test`, which designates it as eligible for promotion to the next `Stage` --
in our case, `uat`.
- ![Kargo-Freight-Verified](../static/img/kargo-freight-verified.png)
+ ![Kargo-Freight-Verified](./assets/kargo-freight-verified.png)
:::note
Although this example does not demonstrate it, it is also possible to verify
diff --git a/docs/static/img/architecture.png b/docs/docs/assets/architecture.png
similarity index 100%
rename from docs/static/img/architecture.png
rename to docs/docs/assets/architecture.png
diff --git a/docs/static/img/argo-dashboard.png b/docs/docs/assets/argo-dashboard.png
similarity index 100%
rename from docs/static/img/argo-dashboard.png
rename to docs/docs/assets/argo-dashboard.png
diff --git a/docs/static/img/kargo-dashboard-projects.png b/docs/docs/assets/kargo-dashboard-projects.png
similarity index 100%
rename from docs/static/img/kargo-dashboard-projects.png
rename to docs/docs/assets/kargo-dashboard-projects.png
diff --git a/docs/static/img/kargo-dashboard-promotion.png b/docs/docs/assets/kargo-dashboard-promotion.png
similarity index 100%
rename from docs/static/img/kargo-dashboard-promotion.png
rename to docs/docs/assets/kargo-dashboard-promotion.png
diff --git a/docs/static/img/kargo-freight-verified.png b/docs/docs/assets/kargo-freight-verified.png
similarity index 100%
rename from docs/static/img/kargo-freight-verified.png
rename to docs/docs/assets/kargo-freight-verified.png
diff --git a/docs/static/img/kargo-frieght-timeline.png b/docs/docs/assets/kargo-frieght-timeline.png
similarity index 100%
rename from docs/static/img/kargo-frieght-timeline.png
rename to docs/docs/assets/kargo-frieght-timeline.png
diff --git a/docs/static/img/kargo-projects.png b/docs/docs/assets/kargo-projects.png
similarity index 100%
rename from docs/static/img/kargo-projects.png
rename to docs/docs/assets/kargo-projects.png
diff --git a/docs/static/img/kargo-promote-option-2.png b/docs/docs/assets/kargo-promote-option-2.png
similarity index 100%
rename from docs/static/img/kargo-promote-option-2.png
rename to docs/docs/assets/kargo-promote-option-2.png
diff --git a/docs/static/img/kargo-promote-option.png b/docs/docs/assets/kargo-promote-option.png
similarity index 100%
rename from docs/static/img/kargo-promote-option.png
rename to docs/docs/assets/kargo-promote-option.png
diff --git a/docs/docs/assets/kargo.png b/docs/docs/assets/kargo.png
new file mode 100644
index 000000000..67bd6ad0a
Binary files /dev/null and b/docs/docs/assets/kargo.png differ
diff --git a/docs/static/img/logo.svg b/docs/docs/assets/logo.svg
similarity index 100%
rename from docs/static/img/logo.svg
rename to docs/docs/assets/logo.svg
diff --git a/docs/static/img/screenshot.png b/docs/docs/assets/screenshot.png
similarity index 100%
rename from docs/static/img/screenshot.png
rename to docs/docs/assets/screenshot.png
diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js
index 58f8aec4f..28f574f15 100644
--- a/docs/docusaurus.config.js
+++ b/docs/docusaurus.config.js
@@ -31,7 +31,7 @@ const config = {
docs: {
sidebarPath: require.resolve('./sidebars.js'),
sidebarCollapsible: false,
- routeBasePath: '/', // Serve the docs at the site's roo
+ routeBasePath: '/', // Serve the docs at the site's root
},
blog: false,
pages: false,
@@ -85,6 +85,11 @@ const config = {
label: 'Kargo.io',
position: 'left',
},
+ {
+ type: 'docsVersionDropdown',
+ position: 'right',
+ dropdownActiveClassDisabled: true,
+ },
{
href: 'https://github.com/akuity/kargo',
label: 'GitHub',
diff --git a/docs/versioned_docs/version-1.0/10-overview.md b/docs/versioned_docs/version-1.0/10-overview.md
new file mode 100644
index 000000000..cf5054407
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/10-overview.md
@@ -0,0 +1,38 @@
+---
+slug: /
+sidebar_label: Overview
+description: Find out more about Kargo - a next-generation continuous delivery and application lifecycle orchestration platform for Kubernetes
+---
+
+# What is Kargo?
+
+Kargo is a next-generation continuous delivery and application lifecycle
+orchestration platform for Kubernetes. It builds upon
+[GitOps](https://opengitops.dev/) principles and integrates with existing
+technologies, like [Argo CD](https://argoproj.github.io/cd/), to streamline and
+automate the progressive rollout of changes across the many stages of an
+application's lifecycle.
+
+![Screenshot](./assets/screenshot.png)
+
+Kargo's goal is to provide an intuitive and flexible layer "above" existing GitOps tooling, wherein you can describe the relationships between various application instances deployed to different environments as well as procedures for progressing changes from one application instance's source of truth to the next.
+
+:::info
+Watch the *Multi-Stage Deployment Pipelines the GitOps Way* talk by Jesse Suen & Kent Rancourt of Akuity at GitOpsCon EU 2024.
+
+
+
+
+
+
+:::
+
+:::info
+Join the Akuity Community [Discord server](https://discord.gg/dHJBZw6ewT)!
+:::
+
+## Next Steps
+
+To learn more about Kargo, consider checking out our
+[concepts doc](./concepts) or get hands-on right away with our
+[quickstart](./quickstart)!
diff --git a/docs/versioned_docs/version-1.0/15-concepts.md b/docs/versioned_docs/version-1.0/15-concepts.md
new file mode 100644
index 000000000..677fff62a
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/15-concepts.md
@@ -0,0 +1,788 @@
+---
+sidebar_label: Key Concepts
+description: Find out more about key Kargo concepts - stages, freight, warehouses, promotions, and more
+---
+# Key Kargo Concepts
+
+:::note
+We're currently reorganizing and updating the documentation.
+During this process, you may encounter sections that are incomplete,
+repetitive, or fragmented. Please bear with us as we work to make improvements.
+:::
+
+## The Basics
+
+### What is a Project
+
+A **project** is a collection of related Kargo resources that describe one or
+more delivery pipelines and is the basic unit of organization and tenancy in
+Kargo.
+
+RBAC rules are also defined at the project level and project administrators
+may use projects to define policies, such as whether a **stage** is eligible
+for automatic promotions of new **freight**.
+
+:::note
+For technical information on the corresponding `Project` resource
+type, refer to [Working with Projects](./30-how-to-guides/11-working-with-projects.md).
+:::
+
+### What is a Stage?
+
+When you hear the term “environment”, what you envision will depend
+significantly on your perspective. A developer, for example, may think of
+an "environment" as a specific _instance_ of an application they work on,
+while a DevOps engineer, may think of an "environment" as a particular segment
+of the infrastructure they maintain.
+
+To eliminate confusion, Kargo avoids the term "environment" altogether in favor of **stage**.
+The important feature of a stage is that its name ("test" or "prod," for instance)
+denotes an application instance's _purpose_ and not necessarily its _location_.
+[This blog post](https://akuity.io/blog/kargo-stage-not-environment/) discusses
+the rationale behind this choice.
+
+_Stages are Kargo's most important concept._ They can be linked together in a
+directed acyclic graph to describe a delivery pipeline. Typically, such a
+pipeline may feature a "test" or "dev" stage as its starting point, with one or
+more "prod" stages at the end.
+
+### What is Freight?
+
+**Freight** is Kargo's second most important concept. A single "piece of
+freight" is a set of references to one or more versioned artifacts, which may
+include one or more:
+
+* Container images (from image repositories)
+
+* Kubernetes manifests (from Git repositories)
+
+* Helm charts (from chart repositories)
+
+Freight can therefore be thought of as a sort of meta-artifact. Freight is what
+Kargo seeks to progress from one stage to another.
+For detailed guidance on working with Freight, refer to
+[this guide](./30-how-to-guides/15-working-with-freight.md).
+
+### What is a Warehouse?
+
+A **warehouse** is a _source_ of freight. A warehouse subscribes to one or more:
+
+* Container image repositories
+
+* Git repositories
+
+* Helm charts repositories
+
+Anytime something new is discovered in any repository to which a warehouse
+subscribes, the warehouse produces a new piece of freight.
+
+### What is a Promotion?
+
+A **promotion** is a request to move a piece of freight into a specified stage.
+
+## Corresponding Resource Types
+
+Each of Kargo's fundamental concepts maps directly onto a custom Kubernetes
+resource type.
+
+### `Stage` Resources
+
+Each Kargo stage is represented by a Kubernetes resource of type `Stage`.
+
+A `Stage` resource's `spec` field decomposes into three main areas of concern:
+
+* Requested freight
+
+* Promotion template
+
+* Verification
+
+The following sections will explore each of these in greater detail.
+
+#### Requested Freight
+
+The `spec.requestedFreight` field is used to describe one or more "types" of
+`Freight`, as specified by an `origin`, that the `Stage`'s promotion process, as
+specified by `spec.promotionTemplate`, will operate on, and the acceptable
+sources from which to obtain that `Freight`. Those sources may include the
+origin itself (e.g. a `Warehouse`) and/or any number of "upstream" `Stage`
+resources.
+
+:::info
+`Warehouse`s are the only type of origin at present, but it is anticipated that
+future versions of Kargo will introduce additional origin types. This is why
+"types" of `Freight` are described by an `origin` field having `kind` and `name`
+subfields instead of being described only by the name of a `Warehouse`.
+:::
+
+For each `Stage`, the Kargo controller will periodically check for `Freight`
+resources that are newly available for promotion to that `Stage`.
+
+When a `Stage` accepts `Freight` directly from its origin, _all_ new `Freight`
+created by that origin (e.g. a `Warehouse` ) are immediately available for
+promotion to that `Stage`.
+
+When a `Stage` accepts `Freight` from one or more "upstream" `Stage` resources,
+`Freight` is considered available for promotion to that `Stage` only after being
+_verified_ in at least one of the upstream `Stage`s. Alternatively, users with
+adequate permissions may manually _approve_ `Freight` for promotion to any given
+`Stage` without requiring upstream verification.
+
+:::tip
+Explicit approvals are a useful method for applying the occasional "hotfix"
+without waiting for a `Freight` resource to traverse the entirety of a pipeline.
+:::
+
+In the following example, the `test` `Stage` requests `Freight` that has
+originated from the `my-warehouse` `Warehouse` and indicates that it will accept
+new `Freight` _directly_ from that origin:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Stage
+metadata:
+ name: test
+ namespace: kargo-demo
+spec:
+ requestedFreight:
+ - origin:
+ kind: Warehouse
+ name: my-warehouse
+ sources:
+ direct: true
+ # ...
+```
+
+In this example, the `uat` `Stage` requests `Freight` that has originated from
+the `my-warehouse` `Warehouse`, but indicates that it will accept such `Freight`
+only after it has been _verified_ in the `test` `Stage`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Stage
+metadata:
+ name: uat
+ namespace: kargo-demo
+spec:
+ requestedFreight:
+ - origin:
+ kind: Warehouse
+ name: my-warehouse
+ sources:
+ stages:
+ - test
+ # ...
+```
+
+Stages may also request `Freight` from multiple sources. The following example
+illustrates a `Stage` that requests `Freight` from both a `microservice-a` and
+`microservice-b` `Warehouse`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Stage
+metadata:
+ name: test
+ namespace: kargo-demo
+spec:
+ requestedFreight:
+ - origin:
+ kind: Warehouse
+ name: microservice-a
+ sources:
+ direct: true
+ - origin:
+ kind: Warehouse
+ name: microservice-b
+ sources:
+ direct: true
+ # ...
+```
+
+:::tip
+By requesting `Freight` from multiple sources, a `Stage` can effectively
+participate in _multiple pipelines_ that may each deliver different collections
+of artifacts independently of the others. At present, this is most useful for
+the delivery of microservices that are developed and deployed in parallel,
+although other uses of this feature are anticipated in the future.
+:::
+
+#### Promotion Templates
+
+The `spec.promotionTemplate` field is used to describe _how_ to transition
+`Freight` into the `Stage`. The `spec.promotionTemplate.steps` field describes
+the discrete steps of a promotion process in detail.
+
+In the following, very common example, the `promotionTemplate` describes steps
+to:
+
+1. Clone a Git repository containing Kubernetes manifests and Kustomize
+ configuration, checking out two different branches to two different
+ directories.
+
+1. Clears the contents of one working tree, with intentions to fully replace its
+ contents.
+
+1. Runs the equivalent of `kustomize edit set image` to update a
+ `kustomization.yaml` file with a reference to an updated
+ `public.ecr.aws/nginx/nginx` container image.
+
+1. Renders the updated manifests using the equivalent of `kustomize build`.
+
+1. Commits the updated manifests and pushes them to the `stage/test` of the
+ remote repository.
+
+1. Forces Argo CD to sync the `kargo-demo-test` application to the latest commit
+ of the `stage/test` branch.
+
+```yaml
+promotionTemplate:
+ spec:
+ steps:
+ - uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+ - uses: git-clear
+ config:
+ path: ./out
+ - uses: kustomize-set-image
+ as: update-image
+ config:
+ path: ./src/base
+ images:
+ - image: public.ecr.aws/nginx/nginx
+ - uses: kustomize-build
+ config:
+ path: ./src/stages/test
+ outPath: ./out
+ - uses: git-commit
+ as: commit
+ config:
+ path: ./out
+ messageFromSteps:
+ - update-image
+ - uses: git-push
+ config:
+ path: ./out
+ targetBranch: stage/test
+ - uses: argocd-update
+ config:
+ apps:
+ - name: kargo-demo-test
+ sources:
+ - repoURL: https://github.com/example/repo.git
+ desiredCommitFromStep: commit
+```
+
+__For complete documentation of all of Kargo's built-in promotion steps, refer
+to the [Promotion Steps Reference](./35-references/10-promotion-steps.md).__
+
+#### Verifications
+
+The `spec.verification` field is used to describe optional verification
+processes that should be executed after a `Promotion` has successfully deployed
+`Freight` to a `Stage`, and if applicable, after the `Stage` has reached a
+healthy state.
+
+Verification processes are defined through _references_ to one or more
+[Argo Rollouts `AnalysisTemplate` resources](https://argoproj.github.io/argo-rollouts/features/analysis/)
+that reside in the same `Project`/`Namespace` as the `Stage` resource.
+
+:::info
+Argo Rollouts `AnalysisTemplate` resources (and the `AnalysisRun` resources that
+are spawned from them) were intentionally built to be re-usable in contexts
+other than Argo Rollouts. Re-using this resource type to define verification
+processes means those processes benefit from this rich and battle-tested feature
+of Argo Rollouts.
+:::
+
+The following example depicts a `Stage` resource that references an
+`AnalysisTemplate` named `kargo-demo` to validate the `test` `Stage` after any
+successful `Promotion`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Stage
+metadata:
+ name: test
+ namespace: kargo-demo
+spec:
+ # ...
+ verification:
+ analysisTemplates:
+ - name: kargo-demo
+```
+
+It is also possible to specify additional labels, annotations, and arguments
+that should be applied to `AnalysisRun` resources spawned from the referenced
+`AnalysisTemplate`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Stage
+metadata:
+ name: test
+ namespace: kargo-demo
+spec:
+ # ...
+ verification:
+ analysisTemplates:
+ - name: kargo-demo
+ analysisRunMetadata:
+ labels:
+ foo: bar
+ annotations:
+ bat: baz
+ args:
+ - name: foo
+ value: bar
+```
+
+An `AnalysisTemplate` could be as simple as the following, which merely executes
+a Kubernetes `Job` that is defined inline:
+
+```yaml
+apiVersion: argoproj.io/v1alpha1
+kind: AnalysisTemplate
+metadata:
+ name: kargo-demo
+ namespace: kargo-demo
+spec:
+ metrics:
+ - name: test
+ provider:
+ job:
+ metadata:
+ spec:
+ backoffLimit: 1
+ template:
+ spec:
+ containers:
+ - name: test
+ image: alpine:latest
+ command:
+ - sleep
+ - "10"
+ restartPolicy: Never
+```
+
+:::note
+Please consult the
+[relevant sections](https://argoproj.github.io/argo-rollouts/features/analysis/)
+of the Argo Rollouts documentation for comprehensive coverage of the full range
+of `AnalysisTemplate` capabilities.
+:::
+
+#### Status
+
+A `Stage` resource's `status` field records:
+
+* The current phase of the `Stage` resource's lifecycle.
+
+* Information about the last `Promotion` and any in-progress `Promotion`.
+
+* History of `Freight` that has been deployed to the `Stage` (from most to
+ least recent) along with the results of any associated verification processes.
+
+* The health status of any associated Argo CD `Application` resources.
+
+For example:
+
+```yaml
+status:
+ freightHistory:
+ - id: 101bca5b0e18ca7913978a1da956308d2544f741
+ items:
+ Warehouse/my-warehouse:
+ commits:
+ - healthCheckCommit: 111eaf55aa41f21bb9bb707ba1baa748b83ec51e
+ id: 961cfaedbc53aacdb65110028839a2c1c281290d
+ repoURL: https://github.com/example/kargo-demo.git
+ images:
+ - digest: sha256:b2487a28589657b318e0d63110056e11564e73b9fd3ec4c4afba5542f9d07d46
+ repoURL: public.ecr.aws/nginx/nginx
+ tag: 1.27.0
+ name: 666209fd9755a1e48bec6b27f5f447747410dd9e
+ origin:
+ kind: Warehouse
+ name: my-warehouse
+ verificationHistory:
+ - analysisRun:
+ name: test.01j2w7aknhf3j7jteyqs72hnbg.101bca5
+ namespace: kargo-demo-09
+ phase: Successful
+ finishTime: "2024-07-15T22:13:57Z"
+ id: 5535a484-bbd0-4f12-8cf4-be2c8e0041c9
+ phase: Successful
+ startTime: "2024-07-15T22:13:34Z"
+ health:
+ argoCDApps:
+ - healthStatus:
+ status: Healthy
+ name: kargo-demo-09-test
+ namespace: argocd
+ syncStatus:
+ revision: 111eaf55aa41f21bb9bb707ba1baa748b83ec51e
+ status: Synced
+ status: Healthy
+ lastPromotion:
+ finishedAt: "2024-07-15T22:13:25Z"
+ freight:
+ commits:
+ - healthCheckCommit: 111eaf55aa41f21bb9bb707ba1baa748b83ec51e
+ id: 961cfaedbc53aacdb65110028839a2c1c281290d
+ repoURL: https://github.com/example/kargo-demo.git
+ name: 666209fd9755a1e48bec6b27f5f447747410dd9e
+ origin:
+ kind: Warehouse
+ name: kargo-demo
+ name: test.01j2w7a15cxjjgejresfyw6ysp.666209f
+ status:
+ finishedAt: "2024-07-15T22:13:25Z"
+ freight:
+ commits:
+ - healthCheckCommit: 111eaf55aa41f21bb9bb707ba1baa748b83ec51e
+ id: 961cfaedbc53aacdb65110028839a2c1c281290d
+ repoURL: https://github.com/example/kargo-demo.git
+ name: 666209fd9755a1e48bec6b27f5f447747410dd9e
+ origin:
+ kind: Warehouse
+ name: kargo-demo
+ freightCollection:
+ id: 101bca5b0e18ca7913978a1da956308d2544f741
+ items:
+ Warehouse/kargo-demo:
+ commits:
+ - healthCheckCommit: 111eaf55aa41f21bb9bb707ba1baa748b83ec51e
+ id: 961cfaedbc53aacdb65110028839a2c1c281290d
+ repoURL: https://github.com/example/kargo-demo.git
+ name: 666209fd9755a1e48bec6b27f5f447747410dd9e
+ origin:
+ kind: Warehouse
+ name: kargo-demo
+ verificationHistory:
+ - analysisRun:
+ name: test.01j2w7aknhf3j7jteyqs72hnbg.101bca5
+ namespace: kargo-demo-09
+ phase: ""
+ id: 5535a484-bbd0-4f12-8cf4-be2c8e0041c9
+ phase: Pending
+ startTime: "2024-07-15T22:13:34Z"
+ phase: Succeeded
+ observedGeneration: 1
+ phase: Steady
+```
+
+### `Freight` Resources
+
+Each piece of Kargo freight is represented by a Kubernetes resource of type
+`Freight`. `Freight` resources are immutable except for their `alias` field
+and `status` subresource (mutable only by the Kargo controller).
+
+A single `Freight` resource references one or more versioned artifacts, such as:
+
+* Container images (from image repositories)
+
+* Kubernetes manifests (from Git repositories)
+
+* Helm charts (from chart repositories)
+
+A `Freight` resource's `metadata.name` field is a SHA1 hash of a canonical
+representation of the artifacts referenced by the `Freight` resource. (This is
+enforced by an admission webhook.) The `metadata.name` field is therefore a
+"fingerprint", deterministically derived from the `Freight`'s contents.
+
+To provide a human-readable identifier for a `Freight` resource, a `Freight`
+resource has an `alias` field. This alias is
+a human-readable string that is unique within the `Project` to which the
+`Freight` belongs. Kargo automatically generates unique aliases for all
+`Freight` resources, but users may update them to be more meaningful.
+
+:::tip
+Assigning meaningful and recognizable aliases to important pieces of `Freight`
+traversing your pipeline(s) can make it easier to track their progress from one
+`Stage` to another.
+:::
+
+:::note
+For more information on aliases, refer to the [aliases](./30-how-to-guides/15-working-with-freight.md#aliases)
+and [updating aliases](./30-how-to-guides/15-working-with-freight.md#updating-aliases)
+sections of the "Working with Freight" how-to guide.
+:::
+
+A `Freight` resource's `status` field records a list of `Stage` resources in
+which the `Freight` has been _verified_ and a separate list of `Stage` resources
+for which the `Freight` has been manually _approved_.
+
+`Freight` resources look similar to the following:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Freight
+metadata:
+ name: 47b33c0c92b54439e5eb7fb80ecc83f8626fe390
+ namespace: kargo-demo
+ labels:
+ kargo.akuity.io/alias: fruitful-ferret
+alias: fruitful-ferret
+images:
+- digest: sha256:b2487a28589657b318e0d63110056e11564e73b9fd3ec4c4afba5542f9d07d46
+ repoURL: public.ecr.aws/nginx/nginx
+ tag: 1.27.0
+commits:
+- repoURL: https://github.com/example/kargo-demo.git
+ id: 1234abc
+warehouse: my-warehouse
+status:
+ verifiedIn:
+ test: {}
+ approvedFor:
+ prod: {}
+```
+
+### `Warehouse` Resources
+
+Each Kargo warehouse is represented by a Kubernetes resource of type
+`Warehouse`.
+
+A `Warehouse` resource's most important field is its `spec.subscriptions` field,
+which is used to subscribe to one or more:
+
+* Container image repositories
+
+* Git repositories
+
+* Helm charts repositories
+
+The following example shows a `Warehouse` resource that subscribes to a
+container image repository and a Git repository:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Warehouse
+metadata:
+ name: my-warehouse
+ namespace: kargo-demo
+spec:
+ subscriptions:
+ - image:
+ repoURL: public.ecr.aws/nginx/nginx
+ semverConstraint: ^1.26.0
+ - git:
+ repoURL: https://github.com/example/kargo-demo.git
+```
+:::info
+Kargo uses [semver](https://github.com/masterminds/semver#checking-version-constraints) to handle semantic versioning constraints.
+:::
+
+#### Git Subscription Path Filtering
+
+In some cases, it may be necessary to constrain the paths within a Git
+repository that a `Warehouse` will consider as triggers for `Freight`
+production. This is especially useful for GitOps repositories that are
+"monorepos" containing configuration for multiple applications.
+
+The paths that may or must not trigger `Freight` production may be specified
+using a combination of the `includePaths` and `excludePaths` fields of a Git
+repository subscription.
+
+The following example demonstrates a `Warehouse` with a Git repository
+subscription that will only produce new `Freight` when the latest commit
+(selected by the applicable commit selection strategy) contains changes in the
+`apps/guestbook` directory since the last piece of `Freight` produced by the
+`Warehouse`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Warehouse
+metadata:
+ name: my-warehouse
+ namespace: kargo-demo
+spec:
+ subscriptions:
+ - git:
+ repoURL: https://github.com/example/kargo-demo.git
+ includePaths:
+ - apps/guestbook
+```
+
+The next example demonstrates the opposite: a `Warehouse` with a Git repository
+subscription that will only produce new `Freight` when the latest commit
+(selected by the applicable commit selection strategy) contains changes to paths
+_other than_ the repository's `docs/` directory:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Warehouse
+metadata:
+ name: my-warehouse
+ namespace: kargo-demo
+spec:
+ subscriptions:
+ - git:
+ repoURL: https://github.com/example/kargo-demo.git
+ excludePaths:
+ - docs
+```
+
+`includePaths` and `excludePaths` may be combined to include a broad set of
+paths and then exclude a subset of those. The following example demonstrates a
+`Warehouse` with a Git repository subscription that will only produce new
+`Freight` when the latest commit (selected by the applicable commit selection
+strategy) contains changes _within_ the `apps/guestbook` directory _other than_
+the `apps/guestbook/README.md`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Warehouse
+metadata:
+ name: my-warehouse
+ namespace: kargo-demo
+spec:
+ subscriptions:
+ - git:
+ repoURL: https://github.com/example/kargo-demo.git
+ includePaths:
+ - apps/guestbook
+ excludePaths:
+ - apps/guestbook/README.md
+```
+
+:::note
+It is important to understand that new `Freight` will be produced when the
+latest commit (selected by the applicable commit selection strategy) contains
+_even a single change_ that is:
+
+1. Implicitly included via undefined `includePaths`.
+
+ OR
+
+ Explicitly included via `includePaths`.
+
+ AND
+
+2. Not explicitly excluded via `excludePaths`.
+:::
+
+:::info
+By default, the strings in the `includePaths` and `excludePaths` fields are
+treated as exact paths to files or directories. (Selecting a directory will
+implicitly select all paths within that directory.)
+
+Paths may _also_ be specified using glob patterns (by prefixing the string with
+`glob:`) or regular expressions (by prefixing the string with `regex:` or
+`regexp:`).
+:::
+
+### `Promotion` Resources
+
+Each Kargo promotion is represented by a Kubernetes resource of type
+`Promotion`.
+
+A `Promotion` resource's two most important fields are its `spec.freight` and
+`spec.stage` fields, which respectively identify a piece of `Freight` and a
+target `Stage` to which that `Freight` should be promoted.
+
+`Promotions` are, in some cases, created automatically by Kargo. In other cases,
+they are created manually by users. In either case, a `Promotion` resource
+resembles the following:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Promotion
+metadata:
+ name: 47b33c0c92b54439e5eb7fb80ecc83f8626fe390-to-test
+ namespace: kargo-demo
+spec:
+ stage: test
+ freight: 47b33c0c92b54439e5eb7fb80ecc83f8626fe390
+```
+
+:::info
+The name in a `Promotion`'s `metadata.name` field is inconsequential. Only
+the `spec` matters.
+:::
+
+When a `Promotion` has concluded -- whether successfully or unsuccessfully --
+the `Promotion`'s `status` field is updated to reflect the outcome. For example:
+
+```yaml
+status:
+ phase: Succeeded
+```
+
+## Role-Based Access Control
+
+As with all resource types in Kubernetes, permissions to perform various actions
+on resources of different types are governed by
+[RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/).
+
+For all Kargo resource types, Kubernetes RBAC functions exactly as one would
+expect, with one notable exception.
+
+Often, it is necessary to grant a user permission to create `Promotion`
+resources that reference certain `Stage` resources, but not others. To address
+this, Kargo utilizes an admission control webhook that conducts access reviews
+to determine if a user creating a `Promotion` resource has the virtual `promote`
+verb for the `Stage` referenced by the `Promotion` resource.
+
+:::info
+[This blog post](https://blog.aquasec.com/kubernetes-verbs) is an excellent
+primer on virtual verbs in Kubernetes RBAC.
+:::
+
+The following `Role` resource describes permissions to create `Promotion`
+references that reference the `uat` `Stage` only:
+
+```yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: uat-promoter
+ namespace: kargo-demo
+rules:
+- apiGroups:
+ - kargo.akuity.io
+ resources:
+ - promotions
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+- apiGroups:
+ - kargo.akuity.io
+ resources:
+ - stages
+ resourceNames:
+ - uat
+ verbs:
+ - promote
+```
+
+To grant a fictional user `alice`, in the QA department, the ability to promote
+to `uat` only, create a corresponding `RoleBinding`:
+
+```yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: alice-uat-promoter
+ namespace: kargo-demo
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: uat-promoter
+subjects:
+- kind: User
+ name: alice
+```
diff --git a/docs/versioned_docs/version-1.0/20-quickstart.md b/docs/versioned_docs/version-1.0/20-quickstart.md
new file mode 100644
index 000000000..ef87a6b43
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/20-quickstart.md
@@ -0,0 +1,926 @@
+---
+description: Learn about Kargo by progressing a change through multiple stages in a local Kubernetes cluster
+sidebar_label: Quickstart
+---
+
+# Kargo Quickstart
+
+This guide presents a basic introduction to Kargo. Together, we will:
+
+1. Install Kargo and its dependencies into an existing, local Kubernetes
+ cluster.
+
+ OR
+
+ Create a new local Kubernetes cluster with Kargo and its dependencies
+ already installed.
+
+1. Demonstrate how Kargo can progress changes through multiple stages by
+ interacting with your GitOps repository and Argo CD `Application` resources.
+
+1. Clean up.
+
+:::info
+If you're looking to contribute to Kargo, you may wish to consult the
+[contributor guide](./contributor-guide) instead.
+:::
+
+## Starting a Local Cluster
+
+Any of the following approaches require [Helm](https://helm.sh/docs/) v3.13.1 or
+greater to be installed.
+
+
+
+
+If you are a
+[Docker Desktop](https://www.docker.com/products/docker-desktop/)
+user, you can follow
+[these instructions](https://docs.docker.com/desktop/kubernetes/) to enable
+its built-in Kubernetes support.
+
+:::info
+Although this is one of the fastest paths to a local Kubernetes cluster, be
+aware that Docker Desktop supports only a _single_ Kubernetes cluster. If
+that cluster reaches a state you are dissatisfied with, resetting it will
+remove not just Kargo-related resources, but _all_ your workloads and data.
+:::
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/release-1.0/hack/quickstart/install.sh | sh
+```
+
+
+
+
+[OrbStack](https://orbstack.dev/) is a fast, lightweight, drop-in replacement
+for Docker Desktop for Mac OS only. You can follow
+[these instructions](https://docs.orbstack.dev/kubernetes/) to enable its
+built-in Kubernetes support.
+
+:::info
+Although this is one of the fastest paths to a local Kubernetes cluster, be
+aware that OrbStack supports only a _single_ Kubernetes cluster. If
+that cluster reaches a state you are dissatisfied with, resetting it will
+remove not just Kargo-related resources, but _all_ your workloads and data.
+:::
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/release-1.0/hack/quickstart/install.sh | sh
+```
+
+
+
+
+If you have any Docker-compatible container runtime installed (including native
+Docker, Docker Desktop, or OrbStack), you can easily launch a disposable cluster
+just for this quickstart using
+[kind](https://kind.sigs.k8s.io/#installation-and-usage).
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/release-1.0/hack/quickstart/kind.sh | sh
+```
+
+:::info
+While this option is a bit more complex than using Docker Desktop or OrbStack
+directly, it offers the advantage of being fully-disposable. If your cluster
+reaches a state you are dissatisfied with, you can simply destroy it and
+launch a new one.
+:::
+
+
+
+
+If you have any Docker-compatible container runtime installed (including native
+Docker, Docker Desktop, or OrbStack), you can easily launch a disposable cluster
+just for this quickstart using [k3d](https://k3d.io).
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/release-1.0/hack/quickstart/k3d.sh | sh
+```
+
+:::info
+While this option is a bit more complex than using Docker Desktop or OrbStack
+directly, it offers the advantage of being fully-disposable. If your cluster
+reaches a state you are dissatisfied with, you can simply destroy it and
+launch a new one.
+:::
+
+
+
+
+:::info
+If you are averse to piping a downloaded script directly into a shell, please
+feel free to download the applicable script and inspect its contents prior to
+execution.
+
+Any approach you select should only:
+
+1. Launch a new, local Kubernetes cluster, if applicable
+1. Install cert-manager
+1. Install Argo CD
+1. Install Argo Rollouts
+1. Install Kargo
+
+:::
+
+
+
+
+:::note
+If Kargo installation fails with a `401`, verify that you are using Helm v3.13.1
+or greater.
+
+If Kargo installation fails with a `403`, it is likely that Docker is configured
+to authenticate to `ghcr.io` with an expired token. The Kargo chart and images
+are accessible anonymously, so this issue can be resolved simply by logging out:
+
+```shell
+docker logout ghcr.io
+```
+
+:::
+
+At the end of this process:
+
+* The Argo CD dashboard will be accessible at [localhost:31443](https://localhost:31443).
+
+ The username and password are both `admin`.
+
+* The Kargo dashboard will be accessible at [localhost:31444](https://localhost:31444).
+
+ The admin password is `admin`.
+
+* You can safely ignore all cert errors for both of the above.
+
+## Create a GitOps Repository
+
+Let's begin by creating a repository on GitHub to house variations of our
+application manifests for three different stages of a sample application: test,
+UAT, and production.
+
+1. Visit https://github.com/akuity/kargo-demo and fork the repository into your
+ own GitHub account.
+
+1. You can explore the repository and see that the `main` branch contains common
+ configuration in a `base/` directory as well as stage-specific overlays in
+ paths of the form `stages//`.
+
+ :::note
+ This layout is typical of a GitOps repository using
+ [Kustomize](https://kustomize.io/) for configuration management and is not
+ at all Kargo-specific.
+
+ Kargo also works just as well with [Helm](https://helm.sh).
+ :::
+
+1. We'll be using it later, so save the location of your GitOps repository in an
+ environment variable:
+
+ ```shell
+ export GITOPS_REPO_URL=
+ ```
+
+## Create Argo CD Application Resources
+
+In this step, we will use an Argo CD `ApplicationSet` resource to create and
+manage three Argo CD `Application` resources that deploy the sample application
+at three different stages of its lifecycle, with three slightly different
+configurations, to three different namespaces in our local cluster:
+
+```shell
+cat <
+ export GITHUB_PAT=
+ ```
+
+1. Next, we'll create several Kargo resources:
+
+ * A `Project`, which, when reconciled, will effect all boilerplate project
+ initialization, including the creation of a specially-labeled `Namespace`
+ with the same name as the `Project`
+
+ * A `Secret` containing credentials for our GitOps repository
+
+ * A `Warehouse` that subscribes to a container image repository
+
+ * Three `Stage` resources -- `test`, `uat`, and `prod`
+
+ Although we will use Kargo's UI throughout most of this quickstart, with the
+ amount of configuration we're about to create, it is easiest to do it
+ declaratively using either `kubectl` or the `kargo` CLI.
+
+ :::info
+ For demo purposes, using `kubectl` is the quickest way to declaratively
+ define your first `Project`. The `kargo` CLI, however, does offer
+ Kargo-specific functionality, and for Kargo users who lack direct access to
+ the underlying cluster, it also offers authentication via OpenID Connect.
+ You might consider choosing this option below if you wish to become more
+ familiar with it.
+ :::
+
+
+
+
+ To create Kargo resources, use the following command:
+
+ ```shell
+ cat <
+
+
+
+ Install the Kargo CLI:
+
+
+
+
+ ```shell
+ arch=$(uname -m)
+ [ "$arch" = "x86_64" ] && arch=amd64
+ curl -L -o kargo https://github.com/akuity/kargo/releases/v1.0.4/download/kargo-"$(uname -s | tr '[:upper:]' '[:lower:]')-${arch}"
+ chmod +x kargo
+ ```
+
+ Then move `kargo` to a location in your file system that is included in the
+ value of your `PATH` environment variable.
+
+
+
+
+ ```shell
+ Invoke-WebRequest -URI https://github.com/akuity/kargo/releases/v1.0.4/download/kargo-windows-amd64.exe -OutFile kargo.exe
+ ```
+
+ Then move `kargo.exe` to a location in your file system that is included in the value
+ of your `PATH` environment variable.
+
+
+
+
+ Log in:
+
+ ```shell
+ kargo login https://localhost:31444 \
+ --admin \
+ --password admin \
+ --insecure-skip-tls-verify
+ ```
+
+ To create Kargo resources, use the following command:
+
+ ```shell
+ cat <
+
+
+1. Navigate to the [Kargo Dashboard](https://localhost:31444/):
+
+ 1. Log in using the password `admin`.
+
+ This will take you to a list of `Project`s. It currently includes only
+ the one created in the previous step.
+
+ ![Kargo-dashboard](./assets/kargo-projects.png)
+
+ 1. Select kargo-demo:
+
+ Here you can see a detailed overview of the `Project` we previously
+ created. It includes:
+
+ * An interactive, visual representation of your pipeline, composed of:
+ * A container image repository.
+ * A `Warehouse` that discovers new images as they are pushed to the
+ repository.
+ * Three `Stage`s representing distinct instances of our demo
+ application.
+
+ ![Kargo-dashboard-screenshot](./assets/kargo-dashboard-projects.png)
+
+ * An interactive Freight Timeline with `Freight` ordered
+ chronologically, with newer `Freight` to the left and older `Freight` to
+ the right.
+
+ ![Kargo-Freight-Timeline](./assets/kargo-frieght-timeline.png)
+
+1. After a few seconds, a piece of `Freight` should appear in the Freight
+ Timeline, if it isn't there already.
+
+ :::note
+ Note that the timeline _may_ not refresh automatically and you may need to
+ refresh the page to see new `Freight`.
+
+ This inconvenience will be addressed in a forthcoming update.
+ :::
+
+ :::info
+ `Freight` is a set of references to one or more versioned artifacts, which
+ may include:
+
+ * Container images (from image repositories)
+
+ * Kubernetes manifests (from Git repositories)
+
+ * Helm charts (from chart repositories)
+
+ This introductory example has `Freight` that references only a specific
+ version of the `public.ecr.aws/nginx/nginx` container image.
+ :::
+
+## Your First Promotion
+
+1. To promote `Freight` to the `test` `Stage`, select the target icon on the
+ left border of test:
+
+ ![Kargo-Promote](./assets/kargo-promote-option.png)
+
+ Next, select the `Freight` from the Freight Timeline and confirm
+ the promotion by selecting Yes:
+
+ ![Kargo-Promote](./assets/kargo-promote-option-2.png)
+
+ When promotion process is complete, you'll see a check mark next to
+ test, indicating that the promotion was successful.
+
+ ![Kargo-dashboard-screenshot](./assets/kargo-dashboard-promotion.png)
+
+ Following the promotion, health checks will run periodically. When a `Stage`
+ is in a healthy state, this will be reflected with a heart icon. You can
+ also verify the status by visiting the test instance of the demo application
+ at [localhost:30081](http://localhost:30081).
+
+ The Freight Timeline will also automatically update following the
+ promotion. It is color-coded to indicate which `Stage`s are actively using
+ each piece of `Freight`.
+
+1. Select the test to reveal additional details about the `Stage`
+ including its status, current `Freight`, and history.
+
+1. Select the `Freight` from the Freight Timeline to reveal
+ additional details. Importantly, you can see that (by virtue of the `test`
+ `Stage` having achieved a healthy state) the `Freight` is now _verified_ in
+ `test`, which designates it as eligible for promotion to the next `Stage` --
+ in our case, `uat`.
+
+ ![Kargo-Freight-Verified](./assets/kargo-freight-verified.png)
+
+ :::note
+ Although this example does not demonstrate it, it is also possible to verify
+ the `Freight` in a `Stage` using user-defined processes. See the
+ [relevant section](./15-concepts.md#verifications) of the concepts page to
+ learn more.
+ :::
+
+## Behind the Scenes
+
+So what has Kargo done behind the scenes?
+
+Visiting our fork of https://github.com/akuity/kargo-demo, we will see that
+Kargo has recently created a `stage/test` branch for us. It has taken the latest
+manifests from the `main` branch as a starting point, run `kustomize edit set
+image` and `kustomize build` within the `stages/test/` directory, and written
+the resulting manifests to a stage-specific branch -- the same branch referenced
+by the `test` Argo CD `Application`'s `targetRevision` field.
+
+:::info
+Although not required for all uses cases, using stage-specific branches is a
+practice highly recommended by the Kargo team.
+:::
+
+## Promote to UAT and then Production
+
+Unlike our `test` `Stage`, which subscribes directly to an image repository,
+our `uat` and `prod` `Stage`s both subscribe to other, _upstream_ `Stage`s,
+thereby forming a _pipeline_:
+
+1. `uat` subscribes to `test`
+1. `prod` subscribes to `uat`.
+
+We leave it as an exercise to the reader to use the dashboard to progress the
+`Freight` from `test` to `uat` and again from `uat` to `prod`.
+
+:::info
+The `uat` and `prod` instances of our site should be accessible at:
+
+* `uat`: [localhost:30082](http://localhost:30082)
+* `prod`: [localhost:30083](http://localhost:30083)
+:::
+
+:::info
+It is possible to automate promotion of new, qualified `Freight` for designated
+`Stage`s and also possible to used RBAC to limit who can trigger manual
+promotions for each `Stage`, however, both these topics are beyond the scope of
+this introduction.
+:::
+
+## Cleaning up
+
+Congratulations! You've just gotten hands on with Kargo for the first time!
+
+Now let's clean up!
+
+
+
+
+Docker Desktop supports only a _single_ Kubernetes cluster. If you are
+comfortable deleting not just just Kargo-related resources, but _all_ your
+workloads and data, the cluster can be reset from the Docker Desktop
+Dashboard.
+
+If, instead, you wish to preserve non-Kargo-related workloads and data, you
+will need to manually uninstall Kargo and its prerequisites:
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/release-1.0/hack/quickstart/uninstall.sh | sh
+```
+
+
+
+
+OrbStack supports only a _single_ Kubernetes cluster. If you are
+comfortable deleting not just just Kargo-related resources, but _all_ your
+workloads and data, you can destroy the cluster with:
+
+```shell
+orb delete k8s
+```
+
+If, instead, you wish to preserve non-Kargo-related workloads and data, you
+will need to manually uninstall Kargo and its prerequisites:
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/release-1.0/hack/quickstart/uninstall.sh | sh
+```
+
+
+
+
+Simply destroy the cluster:
+
+```shell
+kind delete cluster --name kargo-quickstart
+```
+
+
+
+
+Simply destroy the cluster:
+
+```shell
+k3d cluster delete kargo-quickstart
+```
+
+
+
diff --git a/docs/versioned_docs/version-1.0/30-how-to-guides/10-installing-kargo.md b/docs/versioned_docs/version-1.0/30-how-to-guides/10-installing-kargo.md
new file mode 100644
index 000000000..1e104c588
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/30-how-to-guides/10-installing-kargo.md
@@ -0,0 +1,92 @@
+---
+description: Learn how to install Kargo using this step-by-step guide
+sidebar_label: Installing Kargo
+---
+
+# Installing Kargo
+
+## Basic Installation
+
+Installing Kargo with default configuration is quick and easy.
+
+You will need:
+
+* [Helm](https://helm.sh/docs/): These instructions were tested with v3.13.1.
+* A Kubernetes cluster with [cert-manager](https://cert-manager.io/),
+ [Argo CD](https://argo-cd.readthedocs.io), and
+ [Argo Rollouts](https://argoproj.github.io/argo-rollouts/)
+ pre-installed. These instructions were tested with:
+ * Kubernetes: v1.27.4
+ * cert-manager: v1.11.5
+ * Argo CD: v2.9.3
+ * Argo Rollouts: v1.6.4
+
+:::info
+`cert-manager` is used for self-signing a certificate used to identify Kargo's
+webhook server to the Kubernetes API server. If you do not wish to use
+`cert-manager` for this purpose, you may provision your own certificate through
+other means. Refer to the advanced installation section for more information.
+:::
+
+:::info
+We are working toward transitioning Argo CD and Argo Rollouts from required
+dependencies to _suggested_ dependencies.
+:::
+
+:::note
+If your Argo CD control plane manages multiple Kubernetes clusters, be advised
+that Kargo is intended to be installed into the same cluster as the Argo CD
+control plane and _not_ into the individual clusters that Argo CD is managing.
+:::
+
+The following command will install Kargo with default configuration and a
+user-specified admin password:
+
+```shell
+helm install kargo \
+ oci://ghcr.io/akuity/kargo-charts/kargo \
+ --version 1.0.4 \
+ --namespace kargo \
+ --create-namespace \
+ --set api.adminAccount.passwordHash='$2a$10$Zrhhie4vLz5ygtVSaif6o.qN36jgs6vjtMBdM6yrU1FOeiAAMMxOm' \
+ --set api.adminAccount.tokenSigningKey=iwishtowashmyirishwristwatch \
+ --wait
+```
+
+:::caution
+If deploying to an internet-facing cluster, be certain to do one of the
+following:
+
+* Disable the admin account with `--set api.adminAccount.enabled=false`
+
+* Choose your own strong password and signing key.
+:::
+
+## Advanced Installation
+
+1. Extract the default values from the Helm chart and save it to a convenient
+ location. In the example below, we save it to `~/kargo-values.yaml`
+
+ ```shell
+ helm inspect values \
+ oci://ghcr.io/akuity/kargo-charts/kargo > ~/kargo-values.yaml
+ ```
+
+1. Edit and save the values.
+
+ :::info
+ You will find this configuration file contains helpful comments for every
+ option, so specific options are not covered in detail here.
+ :::
+
+1. Proceed with installation, using your modified values:
+
+ ```shell
+ helm install kargo \
+ oci://ghcr.io/akuity/kargo-charts/kargo \
+ --version 1.0.4 \
+ --namespace kargo \
+ --create-namespace \
+ --values ~/kargo-values.yaml \
+ --wait
+ ```
diff --git a/docs/versioned_docs/version-1.0/30-how-to-guides/11-working-with-projects.md b/docs/versioned_docs/version-1.0/30-how-to-guides/11-working-with-projects.md
new file mode 100644
index 000000000..7e3ca6e46
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/30-how-to-guides/11-working-with-projects.md
@@ -0,0 +1,110 @@
+---
+description: Learn how to work effectively with Projects
+sidebar_label: Working with Projects
+---
+
+# Working with Projects
+
+Each Kargo project is represented by a cluster-scoped Kubernetes resource of
+type `Project`. Reconciliation of such a resource effects all boilerplate
+project initialization, including the creation of a specially-labeled
+`Namespace` with the same name as the `Project`. All resources belonging to a
+given `Project` should be grouped together in that `Namespace`.
+
+A minimal `Project` resource looks like the following:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Project
+metadata:
+ name: example
+```
+
+:::note
+Deletion of a `Project` resource results in the deletion of the corresponding
+`Namespace`. For convenience, the inverse is also true -- deletion of a
+project's `Namespace` results in the deletion of the corresponding `Project`
+resource.
+:::
+
+:::info
+There are compelling advantages to using `Project` resources instead of
+permitting users to create `Namespace` resources directly:
+
+* The required label indicating a `Namespace` is a Kargo project cannot be
+forgotten or misapplied.
+
+* Users can be granted permission to indirectly create `Namespace` resources for
+Kargo projects _only_ without being granted more general permissions to create
+_any_ new `Namespace` directly.
+
+* Boilerplate configuration is automatically created at the time of `Project`
+creation. This includes things such as project-level RBAC resources and
+`ServiceAccount` resources.
+:::
+
+## Promotion Policies
+
+A `Project` resource can additionally define project-level configuration. At
+present, this only includes **promotion policies** that describe which `Stage`s
+are eligible for automatic promotion of newly available `Freight`.
+
+:::note
+Promotion policies are defined at the project-level because users with
+permission to update `Stage` resources in a given project `Namespace` may _not_
+have permission to create `Promotion` resources. Defining promotion policies at
+the project-level therefore restricts such users from enabling automatic
+promotions for a `Stage` to which they may lack permission to promote to
+manually. It leaves decisions about eligibility for auto-promotion squarely in
+the hands of someone like a "project admin."
+:::
+
+In the example below, the `test` and `uat` `Stage`s are eligible for automatic
+promotion of newly available `Freight`, but any other `Stage`s in the `Project`
+are not:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Project
+metadata:
+ name: example
+spec:
+ promotionPolicies:
+ - stage: test
+ autoPromotionEnabled: true
+ - stage: uat
+ autoPromotionEnabled: true
+```
+
+## Namespace Adoption
+
+At times, `Namespace`s may require specific configuration to
+comply with regulatory or organizational requirements. To
+account for this, Kargo supports the adoption of pre-existing
+`Namespace`s that are labeled with `kargo.akuity.io/project: "true"`.
+This enables pre-configuring such `Namespace`s according to your
+own requirements.
+
+:::info
+Requiring a `Namespace` to have the `kargo.akuity.io/project: "true"` label to be eligible for adoption by a new `Project` is intended to prevent accidental or willful hijacking of an existing `Namespace`.
+:::
+
+The following example demonstrates adoption of a `Namespace` that's been
+pre-configured with with a label unrelated to Kargo:
+
+```yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: example
+labels:
+ kargo.akuity.io/project: "true"
+ example.com/org: platform-eng
+---
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Project
+metadata:
+ name: example
+spec:
+ # ...
+```
diff --git a/docs/versioned_docs/version-1.0/30-how-to-guides/15-working-with-freight.md b/docs/versioned_docs/version-1.0/30-how-to-guides/15-working-with-freight.md
new file mode 100644
index 000000000..ac0c86a36
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/30-how-to-guides/15-working-with-freight.md
@@ -0,0 +1,209 @@
+---
+description: Learn how to work effectively with freight
+sidebar_label: Working with Freight
+---
+
+# Working With Freight
+
+**Freight** is an important Kargo concept. A single "piece of freight" is a set
+of references to one or more versioned artifacts, which may include one or more:
+
+* Container images (from image repositories)
+
+* Kubernetes manifests (from Git repositories)
+
+* Helm charts (from chart repositories)
+
+Freight can therefore be thought of as a sort of meta-artifact. Freight is what
+Kargo seeks to progress from one stage to another.
+
+:::info
+To learn the fundamentals of freight and the warehouses that produce freight,
+visit the [concepts doc](../concepts).
+:::
+
+The remainder of this page describes features of freight that will enable you
+to work more effectively.
+
+## Names
+
+Like all Kubernetes resources, Kargo `Freight` resources have a `metadata.name`
+field, which uniquely identifies each resource of that type within a given Kargo
+project (a specially labeled Kubernetes namespace). When a `Warehouse` produces
+a new `Freight` resource, it will compute a canonical representation of the
+artifacts referenced by that resource and use that, in turn, to compute a SHA-1
+hash. This becomes the value of the `metadata.name` field. The deterministic
+method of computing this value makes it a unique "fingerprint" of the
+collection of artifacts referenced by the `Freight` resource.
+
+## Aliases
+
+While the `metadata.name` field contains a predictably computed SHA-1 hash,
+such identifiers are, unarguably, not very user-friendly.
+To make `Freight` resources easier for human users to identify, `Warehouse`s
+automatically generate a human-friendly alias for every `Freight` resource they
+produce and apply it as the value of the `Freight` resource's
+`kargo.akuity.io/alias`
+[label](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/).
+
+:::info
+Generating aliases of the form `-` is a strategy borrowed
+from Docker, which generates similar names for containers not explicitly named
+by users.
+:::
+
+:::info
+Why a label?
+
+Kubernetes enforces the immutability of the `metadata.name` field for all
+resources.
+
+Kubernetes
+[labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/),
+by contrast, are both mutable and indexed, which makes them ideal for use as
+secondary identifiers.
+:::
+
+When using the Kargo CLI to query for `Freight` resources, the `alias` field is
+always displayed:
+
+```shell
+kargo get freight --project kargo-demo
+```
+
+Sample output:
+
+```shell
+NAME ALIAS AGE
+f5f87aa23c9e97f43eb83dd63768ee41f5ba3766 mortal-dragonfly 35s
+```
+
+It is also displayed when using `kubectl` to query for `Freight` resources:
+
+```shell
+kubectl get freight --namespace kargo-demo
+```
+
+Sample output:
+
+```shell
+NAME ALIAS AGE
+f5f87aa23c9e97f43eb83dd63768ee41f5ba3766 mortal-dragonfly 35s
+```
+
+:::info
+The Kargo UI, to make efficient use of screen real estate, displays aliases
+only, but a `Freight` resource's `name` can always be discovered by hovering
+over its alias.
+:::
+
+:::note
+Kargo CLI commands will accept `Freight` aliases as an alternative to a
+`Freight` name. Refer to the help text for the `kargo` command for more
+information.
+:::
+
+### Updating Aliases
+
+While every `Freight` resource is automatically assigned an alias, users may
+sometimes wish to override that alias with one of their own choosing. This can
+make it easier to identify a particularly important (or problematic) `Freight`
+resource as it progresses through the `Stage`s of a pipeline.
+
+This is conveniently accomplished via the Kargo CLI:
+
+```shell
+kargo update freight \
+ --project=kargo-demo \
+ --name=f5f87aa23c9e97f43eb83dd63768ee41f5ba3766 \
+ --new-alias=frozen-tauntaun
+```
+Alternatively, you can reference the `Freight` to which you want to assign a new alias using its existing alias:
+
+```shell
+kargo update freight \
+ --project=kargo-demo \
+ --old-alias=mortal-dragonfly \
+ --new-alias=frozen-tauntaun
+```
+
+This can also be accomplished via `kubectl` commands `apply`, `edit`, `patch`,
+etc. by updating the `alias` field of the `Freight` resource.
+
+:::info
+The `alias` field is a convenient way to update the `Freight` resource's
+`kargo.akuity.io/alias` label, which causes a webhook to sync the field value
+to the label value. The precedence rules for syncing between the field and
+label values are as follows:
+
+- If the field has a non-empty value, the label will assume the field's value.
+- If the field has an empty value, the field will assume the label's value.
+
+It's worth noting that removing an alias entirely requires clearing both the
+field and label values, but this is expected to be a rare occurrence.
+:::
+
+## Manual Approvals
+
+The [concepts doc](../concepts#verifications) describes the
+usual process by which `Freight` resources are _verified_ at each `Stage` in a
+pipeline before becoming available to the next `Stage` or `Stage`s. In brief, it
+typically requires the `Stage` to reach a healthy state _and_, if applicable,
+any user-defined verification processes to complete with favorable results.
+
+This is suitable for the average case wherein a new `Freight` resource is
+expected to traverse the entirety of a pipeline on its way to production,
+however, it is nearly inevitable that the occasional need for a "hotfix" will
+arise, in which case it may sometimes be desirable to bypass one or more
+`Stage`s in the pipeline.
+
+To enable this, Kargo provides the ability to manually approve a `Freight`
+resource for promotion to any given `Stage`. This is conveniently accomplished
+via the Kargo CLI:
+
+```shell
+kargo approve \
+ --freight f5f87aa23c9e97f43eb83dd63768ee41f5ba3766 \
+ --stage prod \
+ --project kargo-demo
+```
+
+:::note
+Manual approvals cannot be granted via `kubectl` due to technical factors
+preventing `kubectl` from updating `status` subresources of Kargo resources.
+:::
+
+:::note
+Manually granting approval for a `Freight` resource to be promoted to any given
+`Stage` requires the same level of permissions as would be required to carry out
+that promotion, although, granting manual approval does _not_ automatically
+create a corresponding `Promotion` resource.
+:::
+
+After successfully granting manual approval for a `Freight` resource to be
+promoted to a given `Stage`, the `Freight` resource's `status` field will
+reflect that approval.
+
+The following depicts a `Freight` resource that has been verified in a `test`
+`Stage` through the usual process, but has been manually approved for promotion
+to the `prod` `Stage`. i.e. Any `Stage`s between `test` and `prod` may be
+bypassed.
+
+```shell
+kargo get freight \
+ --project kargo-demo \
+ --output jsonpath-as-json={.status}
+```
+
+```shell
+[
+ {
+ "approvedFor": {
+ "prod": {}
+ },
+ "verifiedIn": {
+ "test": {}
+ }
+ }
+]
+```
diff --git a/docs/versioned_docs/version-1.0/30-how-to-guides/20-managing-credentials.md b/docs/versioned_docs/version-1.0/30-how-to-guides/20-managing-credentials.md
new file mode 100644
index 000000000..9af532276
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/30-how-to-guides/20-managing-credentials.md
@@ -0,0 +1,592 @@
+---
+description: Find out how to manage repository credentials for use by Kargo
+sidebar_label: Managing Credentials
+---
+
+# Managing Credentials
+
+To manage the progression of freight from stage to stage, Kargo will often
+require read/write permissions on private GitOps repositories and read-only
+permissions on private container image and/or Helm chart repositories.
+
+This section presents an overview of how these credentials can be managed.
+
+## Credentials as Kubernetes `Secret` Resources
+
+:::caution
+Kargo formerly borrowed its general credential-management approach from Argo CD,
+but has since diverged.
+:::
+
+Kargo expects any credentials it requires to have been stored as specially
+labeled Kubernetes `Secret` resources containing specially-formatted data. These
+`Secret`s take the following form:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name:
+ namespace:
+ labels:
+ kargo.akuity.io/cred-type: image
+stringData:
+ repoURL:
+ username:
+ password:
+```
+
+The `name` of such a `Secret` is inconsequential and may follow any convention
+preferred by the user.
+
+:::info
+Kargo uses Kubernetes `Namespace`s to mark project boundaries. `Secret`s
+representing credentials will typically exist in the same `Namespace` as the
+`Stage` resources that will require them. There are exceptions to this, which
+are covered in the next section.
+:::
+
+The label key `kargo.akuity.io/cred-type` and its value, one of `git`, `helm`,
+or `image`, is important, as it designates the `Secret` as representing
+credentials for a Git repository, a Helm chart repository, or a container image
+repository, respectively.
+
+The `Secret`'s `data` field (set above using plaintext in the `stringData`
+field), MUST contain the following keys:
+
+* `repoURL`: The full URL of the repository the credentials are for.
+
+* Either:
+
+ * `username`: The username to use when authenticating to the repository.
+
+ * `password`: A password or personal access token.
+
+ :::info
+ If the value of the `password` key is a personal access token, the value of
+ the `username` field may be inconsequential. You should consult your
+ repository's documentation for more information.
+ :::
+
+ OR:
+
+ * `sshPrivateKey`: A PEM-encoded SSH private key. Applicable to Git
+ repositories only.
+
+
+Optionally, the following keys may also be included:
+
+* `repoURLIsRegex`: Set this to `true` if the value of the `repoURL` key
+ is a regular expression. Any other value of this key or the absence of this
+ key is interpreted as `false`.
+
+:::note
+When Kargo searches for repository credentials in a project `Namespace`, it
+_first_ checks all appropriately labeled `Secret`s for a `repoURL` value
+matching the repository URL exactly. Only if no `Secret` is an exact match does
+it check all appropriately labeled `Secret`s for a `repoURL` value containing a
+regular expression matching the repository URL.
+
+When searching for an exact match, and again when searching for a pattern match,
+appropriately labeled `Secret`s are considered in lexical order by name.
+:::
+
+:::caution
+Only username/password (or personal access token) authentication is
+supported at this time. Others are likely to be added in the future.
+:::
+
+## Global Credentials
+
+In cases where one or more sets of credentials are needed widely across _all_
+Kargo projects, the administrator/operator installing Kargo may opt-in to
+designating one or more `Namespace`s as homes for "global" credentials using the
+`controller.globalCredentials.namespaces` setting in Kargo's Helm chart.
+Refer to
+[the advanced section of the installation guide](./10-installing-kargo.md#advanced-installation)
+for more details.
+
+:::note
+Any matching credentials (exact match _or_ pattern match) found in a project's
+own `Namespace` take precedence over those found in any global credentials
+`Namespace`.
+
+When Kargo searches for repository credentials in global credentials
+`Namespace`s, it _first_ checks all appropriately labeled `Secret`s for a
+`repoURL` value matching the repository URL exactly. Only if no `Secret` is an
+exact match does it check all appropriately labeled `Secret`s for a
+`repoURL` value containing a regular expression matching the repository URL.
+
+When searching for an exact match, and again when searching for a pattern match,
+appropriately labeled `Secret`s are considered in lexical order by name.
+
+When Kargo is configured with multiple global credentials `Namespace`s, they are
+searched in lexical order by name. Only after no exact match _and_ no pattern
+match is found in one global credentials `Namespace` does Kargo search the next.
+:::
+
+:::caution
+It is important to understand the security implications of this feature. Any
+credentials stored in a global credentials `Namespace` will be available to
+_all_ Kargo projects.
+:::
+
+## Managing Credentials with the CLI
+
+The Kargo CLI can be used to manage credentials in a project's `Namespace.`
+
+The following example creates credentials for a Git repository:
+
+```shell
+kargo create credentials --project kargo-demo my-credentials \
+ --git --repo-url https://github.com/example/kargo-demo.git \
+ --username my-username --password my-my-personal-access-token
+```
+
+```shell
+secret/my-credentials created
+```
+
+:::caution
+If you do not wish for your password or personal access token to be stored
+in your shell history, you may wish to omit the `--password` flag, in which
+case the CLI will prompt you to enter the password interactively.
+:::
+
+Credentials can be listed or viewed with `kargo get credentials`:
+
+```shell
+kargo get credentials --project kargo-demo my-credentials
+```
+
+```shell
+NAME TYPE REGEX REPO AGE
+my-credentials git false https://github.com/example/kargo-demo.git 8m25s
+```
+
+If requesting output as YAML or JSON, passwords and other potentially sensitive
+information will be redacted.
+
+```shell
+kargo get credentials --project kargo-demo my-credentials -o yaml
+```
+
+```shell
+apiVersion: v1
+kind: Secret
+metadata:
+ creationTimestamp: "2024-05-30T20:02:46Z"
+ labels:
+ kargo.akuity.io/cred-type: git
+ name: my-credentials
+ namespace: kargo-demo
+ resourceVersion: "17614"
+ uid: ca2660e4-867d-4709-b1a7-57fbb93fc6dc
+stringData:
+ password: '*** REDACTED ***'
+ repoURL: https://github.com/example/kargo-demo.git
+ username: my-username
+type: Opaque
+```
+
+Credentials can be updated using the `kargo update credentials` command and
+the flags corresponding to attributes of the credential that you wish to modify.
+Other attributes of the credentials will remain unchanged.
+
+The following example updates `my-credentials` with a regular expression for the
+repository URL:
+
+```shell
+kargo update credentials --project kargo-demo my-credentials \
+ --repo-url '^http://github.com/' --regex
+```
+
+```shell
+secret/my-credentials updated
+```
+
+And credentials can, of course, be deleted with `kargo delete credentials`:
+
+```shell
+kargo delete credentials --project kargo-demo my-credentials
+```
+
+```shell
+secret/my-credentials deleted
+```
+
+:::note
+While the CLI may be a fine way of managing project-level credentials whilst
+getting to know Kargo, it is unquestionably more secure to use other means to
+ensure the existence of these specially-formatted `Secret`s in the appropriate
+project `Namespace`s.
+:::
+
+## Git Provider-Specific Authentication Options
+
+This section provides Git provider-specific guidance on credential management.
+
+### GitHub
+
+#### Personal Access Token
+
+GitHub supports authentication using a
+[personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens),
+which can be used in place of a password. The corresponding username must be
+the GitHub handle of the user who created the token. These can be stored in
+the `username` and `password` fields of a `Secret` resource as described
+[in the first section](#credentials-as-kubernetes-secret-resources) of this
+document.
+
+:::info
+This method of authentication may be best when wishing to rigorously enforce
+the principle of least privilege, as personal access tokens can be scoped to
+specific permissions on specific repositories.
+
+A drawback to this method, however, is that the token is owned by a specific
+GitHub user, and if that user should lose their own access to the repositories
+in question, Kargo will also lose access.
+:::
+
+#### GitHub App Authentication
+
+[GitHub Apps](https://docs.github.com/en/apps) can be used
+[as an authentication method](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/about-authentication-with-a-github-app).
+
+1. [Create a GitHub App](https://github.com/settings/apps/new):
+
+ 1. In the GitHub App name field, specify a unique
+ name.
+ 1. Set the Homepage URL to any URL you like.
+ 1. Under Webhook, de-select
+ Active.
+ 1. Under Permissions → Repository
+ permissions → Contents, select whether
+ the App will require Read-only or Read
+ and write permissions. _The App will receive these
+ permissions on all repositories into which it is installed._
+ 1. Under Where can this GitHub App be installed?,
+ leave Only on this account selected.
+ 1. Click Create GitHub App.
+ 1. Take note of the App ID.
+ 1. Scroll to the bottom of the page and click Generate a private
+ key. The resulting key will be downloaded immediately. Store
+ it securely.
+ 1. On the left-hand side of the page, click Install
+ App.
+ 1. Choose an account to install the App into by clicking
+ Install.
+ 1. Select Only select repositories and choose the
+ repositories you wish to grant the App access to. Remember that the App
+ will receive the permissions you selected earlier on _all_ of these
+ repositories.
+ 1. Click Install.
+ 1. In your browser's address bar, take note of the numeric identifier at the
+ end of the current page's URL. This is the Installation
+ ID.
+
+2. Create a `Secret` resource with the following structure:
+
+ ```yaml
+ apiVersion: v1
+ kind: Secret
+ metadata:
+ name:
+ namespace:
+ labels:
+ kargo.akuity.io/cred-type: git
+ stringData:
+ githubAppID:
+ githubAppPrivateKey:
+ githubAppInstallationID:
+ repoURL:
+ repoURLIsRegex:
+ ```
+
+:::info
+Compared to personal access tokens, a benefit of authenticating with a GitHub
+App is that the App's permissions are not tied to a specific GitHub user.
+:::
+
+:::caution
+It is all too easy to violate the principle of least privilege when
+authenticating using this method.
+
+For convenience sake, it may be tempting to register a single GitHub App and
+select a broad set of repositories when installing that App into your
+organization. It may also be tempting to create a single set of
+[global credentials](#global-credentials) such that all Kargo projects can use
+them to access their repositories, _however_, this will have the undesirable
+effect of granting _all_ Kargo projects access to _all_ of the repositories
+selected when the App was installed.
+
+It is, instead, recommended to register a separate GitHub App for
+each Kargo project. When installing each App into your organization, only those
+repositories to which each Kargo project requires access should be selected.
+
+GitHub organizations are limited to registering 100 GitHub Apps, however, so
+this approach may not be feasible for organizations with many Kargo projects.
+:::
+
+:::caution
+A second way in which authentication using GitHub Apps may violate the principle
+of least privilege involves the fact that the same permissions are granted to
+the App on _all_ repositories that are selected when it is installed.
+
+If a Kargo project requires read-only access to one repository and read/write
+access to another, it is not possible to grant the App different permissions on
+the two. This may then lead to granting broader permissions than are strictly
+necessary.
+:::
+
+## Image Registry-Specific Authentication Options
+
+While many container image registries support authentication using long-lived
+credentials, such as a username and password (or personal access token), some
+either require or offer more secure options.
+
+This section provides registry-specific guidance on credential management and
+also covers options for gaining image repository access using workload identity
+on applicable platforms.
+
+### Amazon Elastic Container Registry (ECR)
+
+The authentication options described in this section are applicable only to
+container image repositories whose URLs indicate they are hosted in ECR.
+
+#### Long-Lived Credentials
+
+Elastic Container Registries do not _directly_ support long-lived credentials,
+however, an AWS access key ID and secret access key
+[can be used to obtain an authorization token](https://docs.aws.amazon.com/AmazonECR/latest/userguide/registry_auth.html#registry-auth-token)
+that is valid for 12 hours. Kargo can seamlessly obtain such a token and will
+cache it for a period of 10 hours.
+
+To use this option, your `Secret` should take the following form:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name:
+ namespace:
+ labels:
+ kargo.akuity.io/cred-type: image
+stringData:
+ awsAccessKeyID:
+ awsSecretAccessKey:
+ repoURL:
+```
+
+:::caution
+Following the principle of least privilege, the IAM user associated with the
+access key ID and secret access key should be limited only to read-only access
+to the required ECR repositories.
+:::
+
+:::caution
+This method of authentication is a "lowest common denominator" approach that
+will work regardless of where Kargo is deployed. i.e. if running Kargo outside EKS, this method will still work.
+
+If running Kargo within EKS, you may wish to either consider using EKS Pod Identity or IRSA
+instead.
+:::
+
+#### EKS Pod Identity or IAM Roles for Service Accounts (IRSA)
+
+If Kargo locates no `Secret` resources matching a repository URL and is deployed
+within an EKS cluster, it will attempt to use
+[EKS Pod Identity](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html)
+or
+[IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)
+to authenticate. Both of these rely upon some external setup. Leveraging either
+eliminates the need to store ECR credentials in a `Secret` resource.
+
+Follow
+[this overview](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html#pod-id-setup-overview)
+to set up EKS Pod Identity in your EKS cluster or
+[this one](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)
+to set up IRSA. For either, you will assign an IAM role to the
+`kargo-controller` `ServiceAccount` within the `Namespace` to which Kargo is (or
+will be) installed.
+
+:::note
+To use IRSA, you will additionally need to specify the
+[ARN](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html) of
+the controller's IAM role as the value of the
+`controller.serviceAccount.iamRole` setting in Kargo's Helm chart. Refer to
+[the advanced section of the installation guide](./10-installing-kargo.md#advanced-installation)
+for more details.
+:::
+
+
+At this point, an IAM role will be associated with the Kargo _controller_,
+however, that controller acts on behalf of multiple Kargo projects, each of
+which may require access to _different_ ECR repositories. To account for this,
+when Kargo attempts to access an ECR repository on behalf of a specific project,
+it will first attempt to
+[assume an IAM role](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html)
+specific to that project. The name of the role it attempts to assume will
+_always_ be of the form `kargo-project-`. It is this role that
+should be granted read-only access to applicable ECR repositories.
+
+:::info
+The name of the IAM role associated with each Kargo project is deliberately
+not configurable to prevent project admins from attempting to coerce Kargo into
+assuming arbitrary IAM roles.
+:::
+
+:::caution
+For optimal adherence to the principle of least permissions, the IAM role
+associated with the `kargo-controller` `ServiceAccount` should be limited only
+to the ability to assume project-specific IAM roles. Project-specific IAM roles
+should be limited only to read-only access to applicable ECR repositories.
+:::
+
+:::info
+If the Kargo controller is unable to assume a project-specific IAM role, it will
+fall back to using its own IAM role directly. For organizations without strict
+tenancy requirements, this can eliminate the need to manage a large number of
+project-specific IAM roles. While useful, this approach is not strictly
+recommended.
+:::
+
+Once Kargo is able to gain necessary permissions to access an ECR repository,
+it will follow a process similar to that described in the previous section to
+obtain a token that is valid for 12 hours and cached for 10.
+
+### Google Artifact Registry
+
+The authentication options described in this section are applicable only to
+container image repositories whose URLs indicate they are hosted in Google
+Artifact Registry.
+
+:::note
+Google Container Registry (GCR) has been deprecated in favor of Google Artifact
+Registry. For authentication to repositories with legacy GCR URLs, the same
+options outlined here may be applied.
+:::
+
+#### Long-Lived Credentials
+
+:::caution
+Google Artifact Registry does _directly_ support long-lived credentials
+[as described here](https://cloud.google.com/artifact-registry/docs/docker/authentication#json-key).
+The username `_json_key_base64` and the base64-encoded service account key
+may be stored in the `username` and `password` fields of a `Secret` resource as
+described [in the first section](#credentials-as-kubernetes-secret-resources) of
+this document. Kargo and Google both strongly discourage this method of
+authentication however.
+:::
+
+Google documentation recommends
+[using a service account key to obtain an access token](https://cloud.google.com/artifact-registry/docs/docker/authentication#token)
+that is valid for 60 minutes. Compared to the discouraged method of using the
+service account key to authenticate to the registry directly, this process does
+_not_ transmit the service account key over the wire. Kargo can seamlessly carry
+out this process and will cache the access token for a period of 40 minutes.
+
+To use this option, your `Secret` should take the following form:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name:
+ namespace:
+ labels:
+ kargo.akuity.io/cred-type: image
+stringData:
+ gcpServiceAccountKey:
+ repoURL:
+```
+
+:::note
+Service account keys contain structured data, so it is important that the
+key be base64-encoded.
+:::
+
+:::caution
+Following the principle of least privilege, the service account associated with
+the service account key should be limited only to read-only access to the
+required Google Artifact Registry repositories.
+:::
+
+:::caution
+This method of authentication is a "lowest common denominator" approach that
+will work regardless of where Kargo is deployed. i.e. If running Kargo outside
+of GKE, this method will still work.
+
+If running Kargo within GKE, you may wish to consider using Workload Identity
+Federation instead.
+:::
+
+#### Workload Identity Federation
+
+If Kargo locates no `Secret` resources matching a repository URL, and if Kargo
+is deployed within a GKE cluster, it will attempt to use
+[Workload Identity Federation](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
+to authenticate, but this relies upon some external setup. Leveraging this
+option eliminates the need to store credentials in a `Secret` resource.
+
+First, follow
+[these directions](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#enable_on_cluster)
+to provision a new GKE cluster with Workload Identity Federation enabled or
+[these directions](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#enable-existing-cluster)
+to enable Workload Identity Federation on an existing GKE cluster.
+
+At this point, the `kargo-controller` `ServiceAccount` within the `Namespace` to
+which Kargo is (or will be) installed will be associated with an _IAM principal
+identifier_, which takes the following form:
+
+```plaintext
+principal://iam.googleapis.com/projects//locations/global/workloadIdentityPools/.svc.id.goog/subject/ns//sa/kargo-controller
+```
+
+Although associated with this _one_ principal, the Kargo controller acts on
+behalf of multiple Kargo projects, each of which may require access to
+_different_ Google Artifact Registry repositories. To account for this, when
+Kargo attempts to access a Google Artifact Registry repository on behalf of a
+specific project, it will first attempt to
+[impersonate a Google service account](https://cloud.google.com/iam/docs/service-account-impersonation)
+specific to that project. The name of the service account it attempts to
+impersonate will _always_ be of the form
+`kargo-project-@.iam.gserviceaccount.com`.
+It is this service account that should be granted read-only access to applicable
+Google Artifact Registry repositories.
+
+:::info
+The name of the Google service account associated with each Kargo project is
+deliberately not configurable to prevent Kargo project admins from attempting to
+coerce Kargo into impersonating arbitrary Google service accounts.
+:::
+
+Once Kargo is able to impersonate the appropriate Google service account for a
+given project, it will follow a process similar to that described in the
+previous section to obtain a token that is valid for 60 minutes and cached for
+40.
+
+:::caution
+Following the principle of least privilege, the IAM principal associated with
+the `kargo-controller` `ServiceAccount` should be limited only to the ability to
+impersonate project-specific Google service accounts. Project-specific Google
+service accounts should be limited only to read-only access to the applicable
+Google Artifact Registry repositories.
+:::
+
+### Azure Container Registry (ACR)
+
+Azure Container Registry directly supports long-lived credentials.
+
+It is possible to
+[create tokens with repository-scoped permissions](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-repository-scoped-permissions),
+with or without an expiration date. These tokens can be stored in the
+`username` and `password` fields of a `Secret` resource as described
+[in the first section](#credentials-as-kubernetes-secret-resources) of this
+document.
+
+:::info
+Support for authentication to ACR repositories using workload identity, on par
+with Kargo's support for ECR and Google Artifact Registry, is likely to be
+included in a future release of Kargo.
+:::
diff --git a/docs/versioned_docs/version-1.0/30-how-to-guides/30-managing-user-permissions.md b/docs/versioned_docs/version-1.0/30-how-to-guides/30-managing-user-permissions.md
new file mode 100644
index 000000000..57aabce2a
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/30-how-to-guides/30-managing-user-permissions.md
@@ -0,0 +1,293 @@
+---
+description: Learn how to manage user permissions
+sidebar_label: Managing User Permissions
+---
+
+# Managing User Permissions
+
+Kargo is typically configured to support single-sign-on (SSO) using an external
+identity provider that implements the
+[OpenID Connect](https://openid.net/developers/how-connect-works/) (OIDC)
+ protocol.
+
+:::info
+Refer to
+[the advanced section of the installation guide](./10-installing-kargo.md#advanced-installation)
+for more details on how to configure Kargo to use an external identity provider.
+:::
+
+Kargo also implements authorization of all user actions using pure Kubernetes
+[RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/). i.e.
+Permission to perform various actions on various Kargo resources is therefore
+granted via `RoleBinding` resources that associate users or `ServiceAccount`
+resources with `Role` resources.
+
+Because Kargo users log into the Kargo CLI or UI via SSO, their identifies are
+not known to Kargo's underlying Kubernetes cluster. This represents an
+impediment to using Kubernetes RBAC to authorize the actions of such users.
+
+Kargo answers this challenge through a scheme that permits users to be mapped
+to zero or more Kubernetes `ServiceAccount` resources. The remainder of this
+page describes how to create those mappings.
+
+## User to `ServiceAccount` Mappings
+
+Whether logged into the Kargo CLI or UI, Kargo users are interacting with Kargo
+via the Kargo API server. The Kargo API server authenticates users via a bearer
+token issued by the external identity provider. On every request, the Kargo
+API server validates and decodes the token to obtain trusted information about
+the user which, importantly, includes _claims_ such as username, email address,
+and group membership. The exact claims available depend on the identity provider
+and the configuration of the Kargo API server. (Refer again to
+[the advanced section of the installation guide](./10-installing-kargo.md#advanced-installation).)
+
+Also at the time of authentication, the Kargo API server queries the Kubernetes
+API server to obtain a list of all `ServiceAccount` resources to which the user
+has been mapped. Kargo typically restricts this search to `ServiceAccount` resources
+in Kargo project namespaces only (i.e. only those labeled with
+`kargo.akuity.io/project: "true"`). Refer to the next section for exceptions to
+this rule.
+
+ServiceAccount resources may be mapped to users through the use of annotations
+whose key begins with `rbac.kargo.akuity.io/claim.`. The value of the annotation
+may be a single value, or a comma-delimited list of values.
+
+In the following example, the `ServiceAccount` resource is mapped to all of:
+
+* Users identified as `alice` or `bob`.
+* A user with the email address `carl@example.com`.
+* All users in _either_ the `devops` or `kargo-admin` group.
+
+```yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: admin
+ namespace: kargo-demo
+ annotations:
+ rbac.kargo.akuity.io/claim.sub: alice,bob
+ rbac.kargo.akuity.io/claim.email: carl@example.com
+ rbac.kargo.akuity.io/claim.groups: devops,kargo-admin
+```
+
+A user may be mapped to multiple `ServiceAccount` resources. A user's effective
+permissions are therefore the union of the permissions associated with all such
+`ServiceAccount` resources.
+
+## Managing Project-Level "Kargo Roles" with the CLI
+
+The Kargo CLI offers several conveniences for working with "Kargo Roles," which
+are simplified abstractions over Kubernetes `ServiceAccount`, `Role`, and
+`RoleBinding` resources.
+
+A Kargo Role combines the "who" of a `ServiceAccount` (with the mapping
+annotations described in the previous section) with the "what" of a `Role`
+resource's policy rules.
+
+Creating a Kargo Role, therefore, effects creation of an underlying
+`ServiceAccount`/`Role`/`RoleBinding` trio. Similarly, deleting a Kargo Role
+deletes those same underlying resources. Updating a Kargo Role via `grant` or
+`revoke` commands updates the underlying `ServiceAccount` or `RoleBinding`
+accordingly.
+
+:::info
+Before diving into the commands for Kargo Role management, please note the
+following details:
+
+* A Kargo Role _exists_ as long as an underlying `ServiceAccount` resource with
+ the same name exists in the Project namespace.
+* If any `RoleBinding` resources in the Project namespace reference the
+ `ServiceAccount` resource, then all of the `Role` resources referenced by
+ those `RoleBinding` resources are also considered part of the Kargo Role, as
+ are the `RoleBinding` resources themselves.
+* Kargo can only _manage_ Kargo Roles that are:
+ * Comprised of precisely one `RoleBinding` and `Role` resource.
+ * Explicitly annotated as _being_ Kargo-managed.
+* Kargo also normalizes the representation of policy rules in any `Role`
+ resource it manages, which is necessary to ensure that `grant` and `revoke`
+ operations can modify policy rules accurately, without unintended side
+ effects.
+
+In practice, if you GitOps your Project-level `ServiceAccount`, `Role`, and
+`RoleBinding` resources, those resources should _not_ be annotated as being
+Kargo-managed. This will prevent modification of those resources through
+imperative Kargo CLI commands like `grant` and `revoke`.
+:::
+
+All Kargo Roles associated with a Project are listed using the `kargo get roles`
+command:
+
+```shell
+kargo get roles --project kargo-demo
+```
+
+```shell
+NAME KARGO MANAGED AGE
+default false 20m
+```
+
+Here we see that Kargo counts a Kargo Role as existing due to the existence of
+the `default` `ServiceAccount` resource that Kubernetes automatically creates in
+any new namespace, including Kargo Project namespaces. Because the `default`
+`ServiceAccount` lacks the necessary annotations, Kargo does not consider it
+Kargo-managed.
+
+We can create a new Kargo-manged Kargo role with the `kargo create role`
+command:
+
+```shell
+kargo create role developer --project kargo-demo
+```
+
+```shell
+role.rbac.kargo.akuity.io/developer created
+```
+
+If we list the Kargo Roles again, we see the new `developer` Kargo Role, and
+that it is Kargo-managed:
+
+```shell
+kargo get roles --project kargo-demo
+```
+
+```shell
+NAME KARGO MANAGED AGE
+default false 24m
+developer true 64s
+```
+
+We can view a YAML representation of the `developer` Kargo Role and see that
+it's not very interesting yet:
+
+```shell
+kargo get role developer --project kargo-demo -o yaml
+```
+
+```shell
+apiVersion: rbac.kargo.akuity.io/v1alpha1
+kargoManaged: true
+kind: Role
+metadata:
+ creationTimestamp: "2024-05-01T13:27:20Z"
+ name: developer
+ namespace: kargo-demo
+```
+
+To make things more interesting, we can grant the `developer` Kargo Role to
+a users having the value `developer` in their `groups` claim:
+
+```shell
+kargo grant --role developer --claim groups=developer --project kargo-demo
+```
+
+```shell
+role.rbac.kargo.akuity.io/developer updated
+```
+
+And we can grant broad permissions on `Stage` resources to the `developer` Kargo
+Role:
+
+```shell
+kargo grant --role developer \
+ --verb '*' --resource-type stages \
+ --project kargo-demo
+```
+
+```shell
+role.rbac.kargo.akuity.io/developer updated
+```
+
+We can view the updated `developer` Kargo Role and see that it is now
+considerably more interesting:
+
+```shell
+kargo get role developer --project kargo-demo -o yaml
+```
+
+```yaml
+apiVersion: rbac.kargo.akuity.io/v1alpha1
+claims:
+ - name: groups
+ values:
+ - developer
+kargoManaged: true
+kind: Role
+metadata:
+ creationTimestamp: "2024-05-01T13:27:20Z"
+ name: developer
+ namespace: kargo-demo
+rules:
+- apiGroups:
+ - kargo.akuity.io
+ resources:
+ - stages
+ verbs:
+ - create
+ - delete
+ - deletecollection
+ - get
+ - list
+ - patch
+ - update
+ - watch
+```
+
+We can also revoke the `developer` Kargo Role from the `developer` group or
+revoke any permissions from the `developer` Kargo Role using the `kargo revoke`
+command, which supports all the same flags as the `kargo grant` command.
+
+Last, it may sometimes be useful to view a Kargo Role's underlying
+`ServiceAccount`, `Role`, and `RoleBinding` resources. This may be useful, for
+instance, to users who have managed Project-level permissions imperatively up to
+a point and now wish to make the transition to GitOps'ing those permissions.
+
+```shell
+kargo get role developer --as-kubernetes-resources --project kargo-demo
+```
+
+```yaml
+NAME K8S SERVICE ACCOUNT K8S ROLE BINDINGS K8S ROLES AGE
+developer developer developer developer 13m
+```
+
+It is also possible to request alternative representations of the underlying
+resources:
+
+```shell
+kargo get role developer \
+ --as-kubernetes-resources -o yaml \
+ --project kargo-demo
+```
+
+:::note
+Output of the above command is not shown here due to its length.
+:::
+
+Last, it is, of course, possible to delete a Kargo Role:
+
+```shell
+kargo delete role developer --project kargo-demo
+```
+
+```shell
+role.rbac.kargo.akuity.io/developer deleted
+```
+
+## Global Mappings
+
+In cases where certain, broad sets of permissions may be required by a large
+numbers of users, the administrator/operator installing Kargo may opt-in to
+designating one or more namespaces as homes for "global" `ServiceAccount`
+resources using the `api.oidc.globalServiceAccounts` setting in Kargo's Helm
+chart. Refer to
+[the advanced section of the installation guide](./10-installing-kargo.md#advanced-installation)
+for more details.
+
+Note that `ServiceAccount` resources in designated namespaces are not _truly_
+global because they are _still_ mapped to users according to the rules described
+in the previous section.
+
+Making use of this feature could be, for instance, a convenient method of
+granting read-only access to all Kargo resources in all projects to all users
+within an organization. Additional permissions may then be granted to users on a
+project-by-project basis.
diff --git a/docs/versioned_docs/version-1.0/30-how-to-guides/_category_.json b/docs/versioned_docs/version-1.0/30-how-to-guides/_category_.json
new file mode 100644
index 000000000..5011e45cd
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/30-how-to-guides/_category_.json
@@ -0,0 +1,4 @@
+{
+ "label": "How-to Guides",
+ "link": null
+}
diff --git a/docs/versioned_docs/version-1.0/35-references/10-promotion-steps.md b/docs/versioned_docs/version-1.0/35-references/10-promotion-steps.md
new file mode 100644
index 000000000..1f71129ea
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/35-references/10-promotion-steps.md
@@ -0,0 +1,1170 @@
+---
+sidebar_label: Promotion Steps Reference
+description: Learn about all of Kargo's built-in promotion steps
+---
+
+# Promotion Steps Reference
+
+This reference document describes the promotion steps that are built directly
+into Kargo. Steps are presented roughly in the order in which they might appear
+in a typical promotion process. Similarly, configuration options for each step
+are laid out in order of their applicability to typical use cases.
+
+## `git-clone`
+
+`git-clone` is often the first step in a promotion process. It creates a
+[bare clone](https://git-scm.com/docs/git-clone#Documentation/git-clone.txt-code--barecode)
+of a remote Git repository, then checks out one or more branches, tags, or
+commits to working trees at specified paths. Checking out different revisions to
+different paths is useful for the common scenarios of combining content from
+multiple sources or rendering Stage-specific manifests to a Stage-specific
+branch.
+
+:::note
+It is a noteworthy limitation of Git that one branch cannot be checked out in
+multiple working trees.
+:::
+
+### `git-clone` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `repoURL` | `string` | Y | The URL of a remote Git repository to clone. |
+| `insecureSkipTLSVerify` | `boolean` | N | Whether to bypass TLS certificate verification when cloning (and for all subsequent operations involving this clone). Setting this to `true` is highly discouraged in production. |
+| `checkout` | `[]object` | Y | The commits, branches, or tags to check out from the repository and the paths where they should be checked out. At least one must be specified. |
+| `checkout[].branch` | `string` | N | A branch to check out. Mutually exclusive with `tag` and `fromFreight=true`. If none of these is specified, the default branch will be checked out. |
+| `checkout[].create` | `boolean` | N | In the event `branch` does not already exist on the remote, whether a new, empty, orphaned branch should be created. Default is `false`, but should commonly be set to `true` for Stage-specific branches, which may not exist yet at the time of a Stage's first promotion. |
+| `checkout[].tag` | `string` | N | A tag to check out. Mutually exclusive with `branch` and `fromFreight=true`. If none of these is specified, the default branch will be checked out. |
+| `checkout[].fromFreight` | `boolean` | N | Whether a commit to check out should be obtained from the Freight being promoted. A value of `true` is mutually exclusive with `branch` and `tag`. If none of these is specified, the default branch will be checked out. Default is `false`, but is often set to `true`. |
+| `checkout[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). |
+| `checkout[].path` | `string` | Y | The path for a working tree that will be created from the checked out revision. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+
+### `git-clone` Examples
+
+
+
+
+
+The most common usage of this step is to check out a commit specified by the
+Freight being promoted as well as a Stage-specific branch. Subsequent steps are
+likely to perform actions that revise the contents of the Stage-specific branch
+using the commit from the Freight as input.
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+# Prepare the contents of ./out ...
+# Commit, push, etc...
+```
+
+
+
+
+
+For this more advanced example, consider a Stage that requests Freight from two
+Warehouses, where one provides Kustomize "base" configuration, while the other
+provides a Stage-specific Kustomize overlay. Rendering the manifests intended
+for such a Stage will require combining the base and overlay configurations
+with the help of a [`copy`](#copy) step. For this case, a `git-clone` step may be
+configured similarly to the following:
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ fromOrigin:
+ kind: Warehouse
+ name: base
+ path: ./src
+ - fromFreight: true
+ fromOrigin:
+ kind: Warehouse
+ name: test-overlay
+ path: ./overlay
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: copy
+ config:
+ inPath: ./overlay/stages/test/kustomization.yaml
+ outPath: ./src/stages/test/kustomization.yaml
+- uses: kustomize-build
+ config:
+ path: ./src/stages/test
+ outPath: ./out
+# Commit, push, etc...
+```
+
+
+
+
+
+## `git-clear`
+
+`git-clear` deletes the _the entire contents_ of a specified Git working tree
+(except for the `.git` file). It is equivalent to executing
+`git add . && git rm -rf --ignore-unmatch .`. This step is useful for the common
+scenario where the entire content of a Stage-specific branch is to be replaced
+with content from another branch or with content rendered using some
+configuration management tool.
+
+### `git-clear` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a Git working tree whose entire contents are to be deleted. |
+
+### `git-clear` Example
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+# Prepare the contents of ./out ...
+# Commit, push, etc...
+```
+
+## `copy`
+
+`copy` copies files or the contents of entire directories from one specified
+location to another.
+
+### `copy` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `inPath` | `string` | Y | Path to the file or directory to be copied. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `outPath` | `string` | Y | Path to the destination. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+
+### `copy` Example
+
+The most common (though still advanced) usage of this step is to combine content
+from two working trees to use as input to a subsequent step, such as one that
+renders Stage-specific manifests.
+
+Consider a Stage that requests Freight from two Warehouses, where one provides
+Kustomize "base" configuration, while the other provides a Stage-specific
+Kustomize overlay. Rendering the manifests intended for such a Stage will
+require combining the base and overlay configurations:
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ fromOrigin:
+ kind: Warehouse
+ name: base
+ path: ./src
+ - fromFreight: true
+ fromOrigin:
+ kind: Warehouse
+ name: test-overlay
+ path: ./overlay
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: copy
+ config:
+ inPath: ./overlay/stages/test/kustomization.yaml
+ outPath: ./src/stages/test/kustomization.yaml
+# Render manifests to ./out, commit, push, etc...
+```
+
+## `kustomize-set-image`
+
+`kustomize-set-image` updates the `kustomization.yaml` file in a specified
+directory to reflect a different revision of a container image. It is equivalent
+to executing `kustomize edit set image`. This step is commonly followed by a
+[`kustomize-build`](#kustomize-build) step.
+
+### `kustomize-set-image` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a directory containing a `kustomization.yaml` file. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `images` | `[]object` | Y | The details of changes to be applied to the `kustomization.yaml` file. At least one must be specified. |
+| `images[].image` | `string` | Y | Name/URL of the image being updated. The Freight being promoted presumably contains a reference to a revision of this image. |
+| `images[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). |
+| `images[].newName` | `string` | N | A substitution for the name/URL of the image being updated. This is useful when different Stages have access to different container image repositories (assuming those different repositories contain equivalent images that are tagged identically). This may be a frequent consideration for users of Amazon's Elastic Container Registry. |
+| `images[].useDigest` | `boolean` | N | Whether to update the `kustomization.yaml` file using the container image's digest instead of its tag. |
+
+### `kustomize-set-image` Examples
+
+
+
+
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ fromOrigin:
+ kind: Warehouse
+ name: base
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: kustomize-set-image
+ config:
+ path: ./src/base
+ images:
+ - image: my/image
+# Render manifests to ./out, commit, push, etc...
+```
+
+
+
+
+
+For this example, consider the promotion of Freight containing a reference to
+some revision of the container image
+`123456789012.dkr.ecr.us-east-1.amazonaws.com/my-image`. This image exists in the
+`us-east-1` region of Amazon's Elastic Container Registry. However, assuming the
+Stage targeted by the promotion is backed by environments in the `us-west-2`
+region, it will be necessary to make a substitution when updating the
+`kustomization.yaml` file. This can be accomplished like so:
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ fromOrigin:
+ kind: Warehouse
+ name: base
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: kustomize-set-image
+ config:
+ path: ./src/base
+ images:
+ - image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-image
+ newName: 123456789012.dkr.ecr.us-west-2.amazonaws.com/my-image
+# Render manifests to ./out, commit, push, etc...
+```
+
+
+
+
+
+### `kustomize-set-image` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `commitMessage` | `string` | A description of the change(s) applied by this step. Typically, a subsequent [`git-commit`](#git-commit) step will reference this output and aggregate this commit message fragment with other like it to build a comprehensive commit message that describes all changes. |
+
+## `kustomize-build`
+
+`kustomize-build` renders manifests from a specified directory containing a
+`kustomization.yaml` file to a specified file or to many files in a specified
+directory. This step is useful for the common scenario of rendering
+Stage-specific manifests to a Stage-specific branch. This step is commonly
+preceded by a [`git-clear`](#git-clear) step and followed by
+[`git-commit`](#git-commit) and [`git-push`](#git-push) steps.
+
+### `kustomize-build` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a directory containing a `kustomization.yaml` file. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `outPath` | `string` | Y | Path to the file or directory where rendered manifests are to be written. If the path ends with `.yaml` or `.yml` it is presumed to indicate a file and is otherwise presumed to indicate a directory. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `plugin.helm.apiVersions` | `[]string` | N | Optionally specifies a list of supported API versions to be used when rendering manifests using Kustomize's Helm chart plugin. This is useful for charts that may contain logic specific to different Kubernetes API versions. |
+| `plugin.helm.kubeVersion` | `string` | N | Optionally specifies a Kubernetes version to be assumed when rendering manifests using Kustomize's Helm chart plugin. This is useful for charts that may contain logic specific to different Kubernetes versions. |
+
+### `kustomize-build` Examples
+
+
+
+
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: kustomize-build
+ config:
+ path: ./src/stages/test
+ outPath: ./out/manifests.yaml
+# Commit, push, etc...
+```
+
+
+
+
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: kustomize-build
+ config:
+ path: ./src/stages/test
+ outPath: ./out
+# Commit, push, etc...
+```
+
+
+
+
+
+## `helm-update-image`
+
+`helm-update-image` updates the values of specified keys in a specified Helm
+values file (e.g. `values.yaml`) to reflect a new version of a container image.
+This step is useful for the common scenario of updating such a `values.yaml`
+file with new version information which is referenced by the Freight being
+promoted. This step is commonly followed by a [`helm-template`](#helm-template)
+step.
+
+### `helm-update-image` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to Helm values file (e.g. `values.yaml`). This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `images` | `[]object` | Y | The details of changes to be applied to the values file. At least one must be specified. |
+| `images[].image` | `string` | Y | Name/URL of the image being updated. The Freight being promoted presumably contains a reference to a revision of this image. |
+| `images[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins) |
+| `images[].key` | `string` | Y | The key to update within the values file. See Helm documentation on the [format and limitations](https://helm.sh/docs/intro/using_helm/#the-format-and-limitations-of---set) of the notation used in this field. |
+| `images[].value` | `string` | Y | Specifies how the value of `key` is to be updated. Possible values for this field are limited to:
`ImageAndTag`: Replaces the value of `key` with a string in form `:`
`Tag`: Replaces the value of `key` with the image's tag
`ImageAndDigest`: Replaces the value of `key` with a string in form `@`
`Digest`: Replaces the value of `key` with the image's digest
|
+
+### `helm-update-image` Example
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: helm-update-image
+ config:
+ path: ./src/charts/my-chart/values.yaml
+ images:
+ - image: my/image
+ key: image.tag
+ value: Tag
+# Render manifests to ./out, commit, push, etc...
+```
+
+### `helm-update-image` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `commitMessage` | `string` | A description of the change(s) applied by this step. Typically, a subsequent [`git-commit`](#git-commit) step will reference this output and aggregate this commit message fragment with other like it to build a comprehensive commit message that describes all changes. |
+
+## `helm-update-chart`
+
+`helm-update-chart` performs specified updates on the `dependencies` section of
+a specified Helm chart's `Chart.yaml` file. This step is useful for the common
+scenario of updating a chart's dependencies to reflect new versions of charts
+referenced by the Freight being promoted. This step is commonly followed by a
+[`helm-template`](#helm-template) step.
+
+### `helm-update-chart` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a Helm chart (i.e. to a directory containing a `Chart.yaml` file). This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `charts` | `[]string` | Y | The details of dependency (subschart) updates to be applied to the chart's `Chart.yaml` file. |
+| `charts[].repository` | `string` | Y | The URL of the Helm chart repository in the `dependencies` entry whose `version` field is to be updated. Must _exactly_ match the `repository` field of that entry. |
+| `charts[].name` | `string` | Y | The name of the chart in in the `dependencies` entry whose `version` field is to be updated. Must exactly match the `name` field of that entry. |
+| `charts[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins) |
+
+### `helm-update-chart` Examples
+
+
+
+
+
+Given a `Chart.yaml` file such as the following:
+
+```yaml
+apiVersion: v2
+name: example
+type: application
+version: 0.1.0
+appVersion: 0.1.0
+dependencies:
+- repository: https://example-chart-repo
+ name: some-chart
+ version: 1.2.3
+```
+
+The `dependencies` can be updated to reflect the version of `some-chart`
+referenced by the Freight being promoted like so:
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: helm-update-chart
+ config:
+ path: ./src/charts/my-chart
+ charts:
+ - repository: https://example-chart-repo
+ name: some-chart
+# Render manifests to ./out, commit, push, etc...
+```
+
+
+
+
+
+:::caution
+Classic (HTTP/HTTPS) Helm chart repositories can contain many differently named
+charts. A specific chart, therefore, can be identified by a repository URL and
+a chart name.
+
+OCI repositories, on the other hand, are organizational constructs within OCI
+_registries._ Each OCI repository is presumed to contain versions of only a
+single chart. As such, a specific chart can be identified by a repository URL
+alone.
+
+Kargo Warehouses understand this distinction well, so a subscription to an OCI
+chart repository will utilize its URL only, _without_ specifying a chart name.
+For example:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Warehouse
+metadata:
+ name: my-warehouse
+ namespace: kargo-demo
+spec:
+ subscriptions:
+ - chart:
+ repoURL: oci://example-chart-registry/some-chart
+ semverConstraint: ^1.0.0
+```
+
+Helm deals with this difference somewhat more awkwardly, however. When a Helm
+chart references a chart in an OCI repository, it must reference the _registry_
+by URL in the `repository` field and _still_ specify a chart name in the name
+field. For example:
+
+```yaml
+apiVersion: v2
+name: example
+type: application
+version: 0.1.0
+appVersion: 0.1.0
+dependencies:
+- repository: oci://example-chart-registry
+ name: some-chart
+ version: 1.2.3
+```
+
+__When using `helm-update-chart` to update the dependencies in a `Chart.yaml`
+file, you must play by Helm's rules and use the _registry_ URL in the
+`repository` field and the _repository_ name (chart name) in the `name` field.__
+:::
+
+:::info
+As a general rule, when configuring Kargo to update something, observe the
+conventions of the thing being updated, even if those conventions differ from
+Kargo's own. Kargo is aware of such differences and will adapt accordingly.
+:::
+
+Given a `Chart.yaml` file such as the following:
+
+```yaml
+apiVersion: v2
+name: example
+type: application
+version: 0.1.0
+appVersion: 0.1.0
+dependencies:
+- repository: oci://example-chart-registry
+ name: some-chart
+ version: 1.2.3
+```
+
+The `dependencies` can be updated to reflect the version of
+`oci://example-chart-registry/some-chart` referenced by the Freight being
+promoted like so:
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: helm-update-chart
+ config:
+ path: ./src/charts/my-chart
+ charts:
+ - repository: oci://example-chart-registry
+ name: some-chart
+# Render manifests to ./out, commit, push, etc...
+```
+
+
+
+
+
+### `helm-update-chart` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `commitMessage` | `string` | A description of the change(s) applied by this step. Typically, a subsequent [`git-commit`](#git-commit) step will reference this output and aggregate this commit message fragment with other like it to build a comprehensive commit message that describes all changes. |
+
+## `helm-template`
+
+`helm-template` renders a specified Helm chart to a specified directory or to
+many files in a specified directory. This step is useful for the common scenario
+of rendering Stage-specific manifests to a Stage-specific branch. This step is
+commonly preceded by a [`git-clear`](#git-clear) step and followed by
+[`git-commit`](#git-commit) and [`git-push`](#git-push) steps.
+
+### `helm-template` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a Helm chart (i.e. to a directory containing a `Chart.yaml` file). This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `outPath` | `string` | Y | Path to the file or directory where rendered manifests are to be written. If the path ends with `.yaml` or `.yml` it is presumed to indicate a file and is otherwise presumed to indicate a directory. |
+| `releaseName` | `string` | N | Optional release name to use when rendering the manifests. This is commonly omitted. |
+| `namespace` | `string` | N | Optional namespace to use when rendering the manifests. This is commonly omitted. GitOps agents such as Argo CD will generally ensure the installation of manifests into the namespace specified by their own configuration. |
+| `valuesFiles` | `[]string` | N | Helm values files (apart from the chart's default `values.yaml`) to be used when rendering the manifests. |
+| `includeCRDs` | `boolean` | N | Whether to include CRDs in the rendered manifests. This is `false` by default. |
+| `kubeVersion` | `string` | N | Optionally specifies a Kubernetes version to be assumed when rendering manifests. This is useful for charts that may contain logic specific to different Kubernetes versions. |
+| `apiVersions` | `[]string` | N | Allows a manual set of supported API versions to be specified. |
+
+### `helm-template` Examples
+
+
+
+
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: helm-template
+ config:
+ path: ./src/charts/my-chart
+ valuesFiles:
+ - ./src/charts/my-chart/test-values.yaml
+ outPath: ./out/manifests.yaml
+# Commit, push, etc...
+```
+
+
+
+
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: helm-template
+ config:
+ path: ./src/charts/my-chart
+ valuesFiles:
+ - ./src/charts/my-chart/test-values.yaml
+ outPath: ./out
+# Commit, push, etc...
+```
+
+
+
+
+
+## `git-commit`
+
+`git-commit` commits all changes in a working tree to its checked out branch.
+This step is often used after previous steps have put the working tree into the
+desired state and is commonly followed by a [`git-push`](#git-push) step.
+
+### `git-commit` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a Git working tree containing changes to be committed. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `message` | `string` | N | The commit message. Mutually exclusive with `messageFromSteps`. |
+| `messageFromSteps` | `[]string` | N | References the `commitMessage` output of previous steps. When one or more are specified, the commit message will be constructed by concatenating the messages from individual steps. Mutually exclusive with `message`. |
+| `author` | `[]object` | N | Optionally provider authorship information for the commit. |
+| `author.name` | `string` | N | The committer's name. |
+| `author.email` | `string` | N | The committer's email address. |
+
+### `git-commit` Example
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: kustomize-set-image
+ as: update-image
+ config:
+ images:
+ - image: my/image
+- uses: kustomize-build
+ config:
+ path: ./src/stages/test
+ outPath: ./out
+- uses: git-commit
+ config:
+ path: ./out
+ messageFromSteps:
+ - update-image
+# Push, etc...
+```
+
+### `git-commit` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `commit` | `string` | The ID (SHA) of the commit created by this step. If the step short-circuited and did not create a new commit because there were no differences from the current head of the branch, this value will be the ID of the existing commit at the head of the branch instead. Typically, a subsequent [`argocd-update`](#argocd-update) step will reference this output to learn the ID of the commit that an applicable Argo CD `ApplicationSource` should be observably synced to under healthy conditions. |
+
+## `git-push`
+
+`git-push` pushes the committed changes in a specified working tree to a
+specified branch in the remote repository. This step typically follows a `git-commit` step and is often followed by a `git-open-pr` step.
+
+### `git-push` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a Git working tree containing committed changes. |
+| `targetBranch` | `string` | N | The branch to push to in the remote repository. Mutually exclusive with `generateTargetBranch=true`. If neither of these is provided, the target branch will be the same as the branch currently checked out in the working tree. |
+| `generateTargetBranch` | `boolean` | N | Whether to push to a remote branch named like `kargo///promotion`. If such a branch does not already exist, it will be created. A value of 'true' is mutually exclusive with `targetBranch`. If neither of these is provided, the target branch will be the currently checked out branch. This option is useful when a subsequent promotion step will open a pull request against a Stage-specific branch. In such a case, the generated target branch pushed to by the `git-push` step can later be utilized as the source branch of the pull request. |
+
+### `git-push` Examples
+
+
+
+
+
+```yaml
+steps:
+# Clone, prepare the contents of ./out, etc...
+- uses: git-commit
+ config:
+ path: ./out
+ message: rendered updated manifests
+- uses: git-push
+ config:
+ path: ./out
+```
+
+
+
+
+
+```yaml
+steps:
+# Clone, prepare the contents of ./out, etc...
+- uses: git-commit
+ config:
+ path: ./out
+ message: rendered updated manifests
+- uses: git-push
+ as: push
+ config:
+ path: ./out
+ generateTargetBranch: true
+# Open a PR and wait for it to be merged or closed...
+```
+
+
+
+
+
+### `git-push` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `branch` | `string` | The name of the remote branch pushed to by this step. This is especially useful when the `generateTargetBranch=true` option has been used, in which case a subsequent [`git-open-pr`](#git-open-pr) will typically reference this output to learn what branch to use as the head branch of a new pull request. |
+| `commit` | `string` | The ID (SHA) of the commit pushed by this step. |
+
+## `git-open-pr`
+
+`git-open-pr` opens a pull request in a specified remote repository using
+specified source and target branches. This step is often used after a `git-push`
+and is commonly followed by a `git-wait-for-pr` step.
+
+At present, this feature only supports GitHub pull requests and GitLab merge
+requests.
+
+### `git-open-pr` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `repoURL` | `string` | Y | The URL of a remote Git repository. |
+| `provider` | `string` | N | The name of the Git provider to use. Currently only `github` and `gitlab` are supported. Kargo will try to infer the provider if it is not explicitly specified. |
+| `insecureSkipTLSVerify` | `boolean` | N | Indicates whether to bypass TLS certificate verification when interfacing with the Git provider. Setting this to `true` is highly discouraged in production. |
+| `sourceBranch` | `string` | N | Specifies the source branch for the pull request. Mutually exclusive with `sourceBranchFromStep`. |
+| `sourceBranchFromStep` | `string` | N | Indicates the source branch should be determined by the `branch` key in the output of a previous promotion step with the specified alias. Mutually exclusive with `sourceBranch`. |
+| `targetBranch` | `string` | N | The branch to which the changes should be merged. |
+| `createTargetBranch` | `boolean` | N | Indicates whether a new, empty orphaned branch should be created and pushed to the remote if the target branch does not already exist there. Default is `false`. |
+
+### `git-open-pr` Example
+
+```yaml
+steps:
+# Clone, prepare the contents of ./out, commit, etc...
+- uses: git-push
+ as: push
+ config:
+ path: ./out
+ generateTargetBranch: true
+- uses: git-open-pr
+ as: open-pr
+ config:
+ repoURL: https://github.com/example/repo.git
+ createTargetBranch: true
+ sourceBranchFromStep: push
+ targetBranch: stage/prod
+# Wait for the PR to be merged or closed...
+```
+
+### `git-open-pr` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `prNumber` | `number` | The numeric identifier of the pull request opened by this step. Typically, a subsequent [`git-wait-for-pr`](#git-wait-for-pr) step will reference this output to learn what pull request to monitor. |
+
+## `git-wait-for-pr`
+
+`git-wait-for-pr` waits for a specified open pull request to be merged or
+closed. This step commonly follows a `git-open-pr` step and is commonly followed
+by an `argocd-update` step.
+
+### `git-wait-for-pr` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `repoURL` | `string` | Y | The URL of a remote Git repository. |
+| `provider` | `string` | N | The name of the Git provider to use. Currently only `github` and `gitlab` are supported. Kargo will try to infer the provider if it is not explicitly specified. |
+| `insecureSkipTLSVerify` | `boolean` | N | Indicates whether to bypass TLS certificate verification when interfacing with the Git provider. Setting this to `true` is highly discouraged in production. |
+| `prNumber` | `string` | N | The number of the pull request to wait for. Mutually exclusive with `prNumberFromStep`. |
+| `prNumberFromStep` | `string` | N | References the `prNumber` output from a previous step. Mutually exclusive with `prNumber`. |
+
+### `git-wait-for-pr` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `commit` | `string` | The ID (SHA) of the new commit at the head of the target branch after merge. Typically, a subsequent [`argocd-update`](#argocd-update) step will reference this output to learn the ID of the commit that an applicable Argo CD `ApplicationSource` should be observably synced to under healthy conditions. |
+
+### `git-wait-for-pr` Example
+
+```yaml
+steps:
+# Clone, prepare the contents of ./out, commit, etc...
+- uses: git-push
+ as: push
+ config:
+ path: ./out
+ generateTargetBranch: true
+- uses: git-open-pr
+ as: open-pr
+ config:
+ repoURL: https://github.com/example/repo.git
+ createTargetBranch: true
+ sourceBranchFromStep: push
+ targetBranch: stage/prod
+- uses: git-wait-for-pr
+ as: wait-for-pr
+ config:
+ repoURL: https://github.com/example/repo.git
+ prNumberFromStep: open-pr
+```
+
+## `argocd-update`
+
+`argocd-update` updates one or more Argo CD `Application` resources in various
+ways. Among other scenarios, this step is useful for the common one of forcing
+an Argo CD `Application` to sync after previous steps have updated a remote
+branch referenced by the `Application`. This step is commonly the last step in a
+promotion process.
+
+:::note
+For an Argo CD `Application` resource to be managed by a Kargo `Stage`,
+the `Application` _must_ have an annotation of the following form:
+
+```yaml
+kargo.akuity.io/authorized-stage: ":"
+```
+
+Such an annotation offers proof that a user who is themselves authorized
+to update the `Application` in question has consented to a specific
+`Stage` updating the `Application` as well.
+
+The following example shows how to configure an Argo CD `Application`
+manifest to authorize the `test` `Stage` of the `kargo-demo` `Project`:
+
+```yaml
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: kargo-demo-test
+ namespace: argocd
+ annotations:
+ kargo.akuity.io/authorized-stage: kargo-demo:test
+spec:
+ # Application specifications go here
+```
+:::
+
+### `argocd-update` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `apps` | `[]object` | Y | Describes Argo CD `Application` resources to update and how to update them. At least one must be specified. |
+| `apps[].name` | `string` | Y | The name of the Argo CD `Application`. |
+| `apps[].namespace` | `string` | N | The namespace of the Argo CD `Application` resource to be updated. If left unspecified, the namespace will be the Kargo controller's configured default -- typically `argocd`. |
+| `apps[].sources` | `[]object` | N | Describes Argo CD `ApplicationSource`s to update and how to update them. |
+| `apps[].sources[].repoURL` | `string` | Y | The value of the target `ApplicationSource`'s own `repoURL` field. This must match exactly. |
+| `apps[].sources[].chart` | `string` | N | Applicable only when the target `ApplicationSource` references a Helm chart repository, the value of the target `ApplicationSource`'s own `chart` field. This must match exactly. |
+| `apps[].sources[].desiredCommitFromStep` | `string` | N | Applicable only when `repoURL` references a Git repository, this field references the `commit` output from a previous step and uses it as the desired revision for the source. If this is left undefined, the desired revision will be determined by Freight (if possible). Note that the source's `targetRevision` will not be updated to this commit unless `updateTargetRevision=true` is set. The utility of this field is to ensure that health checks on Argo CD `ApplicationSource`s can account for scenarios where the desired revision differs from what may be found in Freight, likely due to the use of rendered branches and/or PR-based promotion workflows. |
+| `apps[].sources[].updateTargetRevision` | `boolean` | Y | Indicates whether the target `ApplicationSource` should be updated such that its `targetRevision` field points at the most recently Git commit (if `repoURL` references a Git repository) or chart version (if `repoURL` references a chart repository). |
+| `apps[].sources[].kustomize` | `object` | N | Describes updates to an Argo CD `ApplicationSource`'s Kustomize-specific properties. |
+| `apps[].sources[].kustomize.images` | `[]object` | Y | Describes how to update an Argo CD `ApplicationSource`'s Kustomize-specific properties to reference specific versions of container images. |
+| `apps[].sources[].kustomize.images[].repoURL` | `string` | Y | URL of the image being updated. The Freight being promoted must contain a reference to a revision of this image. |
+| `apps[].sources[].kustomize.images[].newName` | `string` | N | A substitution for the name/URL of the image being updated. This is useful when different Stages have access to different container image repositories (assuming those different repositories contain equivalent images that are tagged identically). This may be a frequent consideration for users of Amazon's Elastic Container Registry. |
+| `apps[].sources[].kustomize.images[].useDigest` | `boolean` | N | Whether to use the container image's digest instead of its tag. |
+| `apps[].sources[].kustomize.images[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). If not specified, may inherit a value from `apps[].sources[].kustomize.fromOrigin`. |
+| `apps[].sources[].kustomize.fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). If not specified, may inherit a value from `apps[].sources[].fromOrigin`. |
+| `apps[].sources[].helm` | `object` | N | Describes updates to an Argo CD `ApplicationSource`'s Helm parameters. |
+| `apps[].sources[].helm.images` | `[]object` | Y | Describes how to update an Argo CD `ApplicationSource`'s Helm parameters to reference specific versions of container images. |
+| `apps[].sources[].helm.images[].repoURL` | `string` | Y | URL of the image being updated. The Freight being promoted must contain a reference to a revision of this image. |
+| `apps[].sources[].helm.images[].key` | `string` | Y | The key to update within the target `ApplicationSource`'s `helm.parameters` map. See Helm documentation on the [format and limitations](https://helm.sh/docs/intro/using_helm/#the-format-and-limitations-of---set) of the notation used in this field. |
+| `apps[].sources[].helm.images[].value` | `string` | Y | Specifies how the value of `key` is to be updated. Possible values for this field are limited to:
`ImageAndTag`: Replaces the value of `key` with a string in form `:`
`Tag`: Replaces the value of `key` with the image's tag
`ImageAndDigest`: Replaces the value of `key` with a string in form `@`
`Digest`: Replaces the value of `key` with the image's digest
|
+| `apps[].sources[].helm.images[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). If not specified, may inherit a value from `apps[].sources[].helm.fromOrigin` |
+| `apps[].sources[].helm.fromOrigin` | `object` | N | See [specifying origins].(#specifying-origins). If not specified, may inherit a value from `apps[].sources[]`. |
+| `apps[].sources[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). If not specified, may inherit a value from `apps[].fromOrigin`. |
+| `apps[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). If not specified, may inherit a value from `fromOrigin`. |
+| `fromOrigin` | `object` | N | See [specifying origins](#specifying-origins) |
+
+### `argocd-update` Examples
+
+
+
+
+
+```yaml
+steps:
+# Clone, render manifests, commit, push, etc...
+- uses: git-commit
+ as: commit
+ config:
+ path: ./out
+ messageFromSteps:
+ - update-image
+- uses: git-push
+ config:
+ path: ./out
+- uses: argocd-update
+ config:
+ apps:
+ - name: my-app
+ sources:
+ - repoURL: https://github.com/example/repo.git
+ desiredCommitFromStep: commit
+```
+
+
+
+
+
+:::caution
+Without making any modifications to a Git repository, this example simply
+updates a "live" Argo CD `Application` resource to point its `targetRevision`
+field at a specific version of a Helm chart, which Argo CD will pull directly
+from the the chart repository.
+
+While this can be a useful technique, it should be used with caution. This is
+not "real GitOps" since the state of the `Application` resource is not backed
+up in a Git repository. If the `Application` resource were deleted, there would
+be no remaining record of its desired state.
+:::
+
+```yaml
+steps:
+- uses: argocd-update
+ config:
+ apps:
+ - name: my-app
+ sources:
+ - repoURL: https://example-chart-repo
+ chart: my-chart
+ updateTargetRevision: true
+```
+
+
+
+
+
+:::caution
+Without making any modifications to a Git repository, this example simply
+updates Kustomize-specific properties of a "live" Argo CD `Application`
+resource.
+
+While this can be a useful technique, it should be used with caution. This is
+not "real GitOps" since the state of the `Application` resource is not backed up
+in a Git repository. If the `Application` resource were deleted, there would be
+no remaining record of its desired state.
+:::
+
+```yaml
+steps:
+- uses: argocd-update
+ config:
+ apps:
+ - name: my-app
+ sources:
+ - repoURL: https://github.com/example/repo.git
+ kustomize:
+ images:
+ - repoURL: my/image
+```
+
+
+
+
+
+:::caution
+Without making any modifications to a Git repository, this example simply
+updates Helm-specific properties of a "live" Argo CD `Application` resource.
+
+While this can be a useful technique, it should be used with caution. This is
+not "real GitOps" since the state of the `Application` resource is not backed
+up in a Git repository. If the `Application` resource were deleted, there would
+be no remaining record of its desired state.
+:::
+
+```yaml
+steps:
+- uses: argocd-update
+ config:
+ apps:
+ - name: my-app
+ sources:
+ - repoURL: https://github.com/example/repo.git
+ helm:
+ images:
+ - repoURL: my/image
+ key: image.tag
+ value: Tag
+```
+
+
+
+
+
+### `argocd-update` Health Checks
+
+The `argocd-update` step is unique among all other built-in promotion steps in
+that, on successful completion, it will register health checks to be performed
+upon the target Stage on an ongoing basis. This health check configuration is
+_opaque_ to the rest of Kargo and is understood only by health check
+functionality built into the step. This permits Kargo to factor the health and
+sync state of Argo CD `Application` resources into the overall health of a Stage
+without requiring Kargo to understand `Application` health directly.
+
+:::info
+Although the `argocd-update` step is the only promotion step to currently
+utilize this health check framework, we anticipate that future built-in and
+third-party promotion steps will take advantage of it as well.
+:::
+
+## Specifying Origins
+
+Many promotion steps, or parts of those steps, will (whether optionally or
+unconditionally) attempt to learn the desired revision(s) of some artifact(s) by
+consulting the revisions of those artifact(s) references by the Freight being
+promoted.
+
+By way of example, this `kustomize-set-image` step will consult the Freight
+being promoted to learn the desired revision of the `my/image` container image:
+
+```yaml
+- uses: kustomize-set-image
+ config:
+ path: ./src/base
+ images:
+ - image: my/image
+```
+
+In some _advanced_ uses cases, Stages may request Freight from multiple origins
+(Warehouses). In such scenarios, it is possible (although somewhat rare) that
+the multiple Freight being promoted may collectively reference multiple distinct
+revisions of the same artifact. In such as case, it can become ambiguous which
+revision of an artifact referenced by a promotion step should be used.
+
+To permit disambiguation in cases such as those described above, all promotion
+steps that have the potential to reference Freight from multiple origins support
+a `fromOrigin` option that can be used to clarify which piece of Freight's
+reference to the artifact should be used by identifying the origin (Warehouse)
+from which the Freight should have originated.
+
+The best way to illustrate this involves a complex example wherein a Stage
+requests Freight from two Warehouses. Both Warehouses subscribe to the same Git
+repository, with one watching for changes to a Kustomize "base" configuration
+and the other watching for changes to a Stage-specific Kustomize overlay.
+Rendering the manifests intended for such a Stage will require combining the
+base and overlay configurations with the help of a [`copy`](#copy) step. For
+this case, a `git-clone` step may be configured similarly to the following:
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ fromOrigin:
+ kind: Warehouse
+ name: base
+ path: ./src
+ - fromFreight: true
+ fromOrigin:
+ kind: Warehouse
+ name: test-overlay
+ path: ./overlay
+ - branch: stage/test
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: copy
+ config:
+ inPath: ./overlay/stages/test/kustomization.yaml
+ outPath: ./src/stages/test/kustomization.yaml
+- uses: kustomize-build
+ config:
+ path: ./src/stages/test
+ outPath: ./out
+# Commit, push, etc...
+```
+
+Note that when checking out specific revisions of the
+`https://github.com/example/repo.git` repository to different working trees, the
+`git-clone` step has twice utilized `fromOrigin` to clarify which of the Freight
+being promoted should be used to determine the revision to check out.
+
+:::info
+`fromOrigin` never needs to be specified in the majority of use cases wherein
+there is no inherent ambiguity. Kargo will automatically select the correct
+revision of an artifact when there is only one possibility. When Kargo detects
+that there may be multiple possibilities, it will fail and raise an error
+indicating that the user must disambiguate by specifying `fromOrigin` in
+applicable steps.
+:::
diff --git a/docs/versioned_docs/version-1.0/35-references/_category_.json b/docs/versioned_docs/version-1.0/35-references/_category_.json
new file mode 100644
index 000000000..bf7735e44
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/35-references/_category_.json
@@ -0,0 +1,4 @@
+{
+ "label": "Reference Docs",
+ "link": null
+}
diff --git a/docs/versioned_docs/version-1.0/40-contributor-guide/10-hacking-on-kargo.md b/docs/versioned_docs/version-1.0/40-contributor-guide/10-hacking-on-kargo.md
new file mode 100644
index 000000000..1b9e692af
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/40-contributor-guide/10-hacking-on-kargo.md
@@ -0,0 +1,455 @@
+---
+description: Learn how to set up a development environment to begin contributing to Kargo
+sidebar_label: Hacking on Kargo
+---
+
+# Hacking on Kargo
+
+Kargo is implemented in Go. For maximum productivity in your text editor or IDE,
+it is recommended that you have installed the latest stable releases of Go and
+applicable editor/IDE extensions, however, this is not strictly required to be
+successful.
+
+## Running Tests
+
+In order to minimize the setup required to apply small changes and to reduce the
+incidence of tests passing locally, but failing during the continuous
+integration process due to environmental differences, we've made it easy to
+execute tests within a container that is maximally similar to those used in CI.
+
+To take advantage of this, you only need `make` and
+[Docker](https://docs.docker.com/engine/install/) (or a Docker-compatible
+container-runtime).
+
+To run all unit tests:
+
+```shell
+make hack-test-unit
+```
+
+:::info
+If you wish to opt-out of executing the tests within a container (for
+performance reasons, perhaps), drop the `hack-` prefix from the target:
+
+```shell
+make test-unit
+```
+
+This will require Go to be installed locally.
+:::
+
+## Running Linters
+
+It is also possible to execute a variety of different linters that perform
+static code analysis, detect code hygiene issues, assert adherence to project
+standards, etc. As with unit tests, we've made it easy to execute linters within
+a container that is maximally similar to those used in CI.
+
+To lint Go code only:
+
+```shell
+make hack-lint-go
+```
+
+To lint generated protobuf definitions only:
+
+```shell
+make hack-lint-proto
+```
+
+To lint Helm charts only:
+
+```shell
+make hack-lint-charts
+```
+
+To run _all_ linters with one command:
+
+```shell
+make hack-lint
+```
+
+:::info
+If you wish to opt-out of executing any or all linters within a container (for
+performance reasons, perhaps), drop the `hack-` prefix from the desired target.
+
+This will require quite a variety of tools to be installed locally, so we do not
+recommend this if you can avoid it.
+:::
+
+## Executing Code Generation
+
+Anytime the contents of the `api/` directory have been modified, a code
+generation process must be manually executed. As with tests and linters, this
+process is easy to execute within a container, which eliminates the need to
+install various tools or specific versions thereof:
+
+```shell
+make hack-codegen
+```
+
+:::info
+If you wish to opt-out of executing code-generation within a container (for
+performance reasons, perhaps), drop the `hack-` prefix from the target:
+
+```shell
+make codegen
+```
+
+This will require quite a variety of tools to be installed locally, so we do not
+recommend this if you can avoid it.
+:::
+
+## Building the Image
+
+To build source into a Docker image that will be tagged as `kargo:dev`,
+execute the following:
+
+```shell
+make hack-build
+```
+
+:::info
+There is seldom a need to do this, as the next section will cover a better
+option for rapidly building and deploying Kargo from source.
+:::
+
+## Iterating Quickly
+
+This section focuses on the best approaches for gaining rapid feedback on
+changes you make to Kargo's code base.
+
+The fastest path to learning whether changes you have applied work as desired is
+to execute unit tests as described in previous sections. If the changes you are
+applying are complex, it can also be advantageous to exercise them, end-to-end,
+as a user would. Because Kargo is dependent on a Kubernetes cluster, this raises
+the question of how Kargo can not only be built from source, but also deployed
+to a live Kubernetes cluster efficiently enough to enable a tight feedback loop
+as you continue iterating on your changes.
+
+The remainder of this section covers the approaches we recommend for enabling
+this.
+
+:::info
+We may eventually provide convenient methods of running _some_ Kargo components
+as native processes.
+:::
+
+1. Launch or re-use an existing local Kubernetes cluster.
+
+ Any of the following options are viable:
+
+
+
+
+ If you are a
+ [Docker Desktop](https://www.docker.com/products/docker-desktop/)
+ user, you can follow
+ [these instructions](https://docs.docker.com/desktop/kubernetes/) to enable
+ its built-in Kubernetes support.
+
+ :::info
+ A specific benefit of this option is that nothing special is required in
+ terms of creating a local image registry connected to the cluster.
+ Additionally, this approach requires no specific port-forwarding rules to be
+ defined.
+ :::
+ :::info
+ Although this is one of the fastest paths to a local Kubernetes cluster, be
+ aware that Docker Desktop supports only a _single_ Kubernetes cluster. If
+ that cluster reaches a state you are dissatisfied with, resetting it will
+ remove not just Kargo-related resources, but _all_ your workloads and data.
+ :::
+
+ To install Kargo's prerequisites, you will need
+ [Helm](https://helm.sh/docs/intro/install/) installed first, and can then
+ execute a convenient `make` target:
+
+ ```shell
+ make hack-install-prereqs
+ ```
+
+
+
+
+ [OrbStack](https://orbstack.dev/) is a fast, lightweight, drop-in replacement
+ for Docker Desktop for Mac OS only. You can follow
+ [these instructions](https://docs.docker.com/desktop/kubernetes/) to enable
+ its built-in Kubernetes support.
+
+ :::info
+ A specific benefit of this option is that nothing special is required in
+ terms of creating a local image registry connected to the cluster.
+ Additionally, this approach requires no specific port-forwarding rules to be
+ defined.
+ :::
+ :::info
+ Although this is one of the fastest paths to a local Kubernetes cluster, be
+ aware that OrbStack supports only a _single_ Kubernetes cluster. If
+ that cluster reaches a state you are dissatisfied with, resetting it will
+ remove not just Kargo-related resources, but _all_ your workloads and data.
+ :::
+
+ To install Kargo's prerequisites, you will need
+ [Helm](https://helm.sh/docs/intro/install/) installed first, and can then
+ execute a convenient `make` target:
+
+ ```shell
+ make hack-install-prereqs
+ ```
+
+
+
+
+ If you have any Docker-compatible container runtime installed (including
+ native Docker, Docker Desktop, or OrbStack), you can easily launch a
+ disposable cluster to facilitate Kargo development using
+ [kind](https://kind.sigs.k8s.io/#installation-and-usage).
+
+ This option also requires
+ [ctlptl](https://github.com/tilt-dev/ctlptl#how-do-i-install-it) and
+ [Helm](https://helm.sh/docs/intro/install/) to be installed.
+
+ The following `make` target will launch a kind cluster with a local image
+ registry wired into it, various port-forwarding rules pre-configured, and
+ Kargo's prerequisites installed:
+
+ ```shell
+ make hack-kind-up
+ ```
+
+ :::info
+ While this option is a bit more complex than using Docker Desktop or OrbStack
+ directly, it offers the advantage of being fully-disposable. If your cluster
+ reaches a state you are dissatisfied with, you can simply destroy it and
+ launch a new one.
+ :::
+
+
+
+
+ If you have any Docker-compatible container runtime installed (including
+ native Docker, Docker Desktop, or OrbStack), you can easily launch a
+ disposable cluster to facilitate Kargo development using
+ [k3d](https://k3d.io).
+
+ This option also requires
+ [ctlptl](https://github.com/tilt-dev/ctlptl#how-do-i-install-it) and
+ [Helm](https://helm.sh/docs/intro/install/) to be installed.
+
+ The following `make` target will launch a kind cluster with a local image
+ registry wired into it, various port-forwarding rules pre-configured, and
+ Kargo's prerequisites installed:
+
+ ```shell
+ make hack-k3d-up
+ ```
+
+ :::info
+ While this option is a bit more complex than using Docker Desktop or OrbStack
+ directly, it offers the advantage of being fully-disposable. If your cluster
+ reaches a state you are dissatisfied with, you can simply destroy it and
+ launch a new one.
+ :::
+
+
+
+
+ Whichever approach you choose, your cluster will end up with recent, stable
+ versions of [cert-manager](https://cert-manager.io/) and
+ [Argo CD](https://argoproj.github.io/cd/) installed.
+
+ :::info
+ The Argo CD dashboard will be exposed at
+ [localhost:30080](https://localhost:30080).
+
+ The username and password are both `admin`.
+
+ You may safely ignore any certificate warnings.
+ :::
+
+1. Build and deploy Kargo from source:
+
+ [Tilt](https://docs.tilt.dev/#macoslinux) is a convenient tool that builds
+ container images from source and seamlessly deploys them to a local
+ Kubernetes cluster. More importantly, it enables developers to rapidly
+ rebuild and replace running components with the click of a button.
+
+ :::warning
+ If using OrbStack, be advised it is only compatible with Tilt as of Tilt
+ v0.33.6. Please use that version or greater.
+ :::
+
+ ```shell
+ tilt up
+ ```
+
+ Tilt will also launch a web-based UI running at
+ [http://localhost:10350](http://localhost:10350). Visit this in your web
+ browser to view the build and deployment status of each Kargo component as
+ well as the logs from each component.
+
+ :::info
+ Tilt is often configured to watch files and automatically rebuild and replace
+ running components when their source code is changed. This is deliberately
+ disabled for Kargo since the Docker image takes long enough to build that
+ it’s better to conserve system resources by only rebuilding when you choose.
+ The web UI makes it easy to identify components whose source has been
+ altered. They can be rebuilt and replaced with a single click.
+ :::
+
+1. If necessary, build the CLI from source:
+
+ ```shell
+ make hack-build-cli
+ ```
+
+ This will produce an executable at `bin/kargo--`.
+
+ You can log in using:
+
+ ```shell
+ bin/kargo-- login http://localhost:30081 \
+ --admin \
+ --password admin \
+ --insecure-skip-tls-verify
+ ```
+
+1. If necessary, access the Kargo UI at
+ [localhost:30082](http://localhost:30082).
+
+ The admin account password is `admin`.
+
+ You may safely ignore any certificate warnings.
+
+1. When you are done with Tilt, interrupt the running `tilt up` process with
+ `ctrl + c`. Components _will remain running in the cluster_, but Tilt will no
+ longer be in control. If Tilt is restarted later, it will retake control of
+ the already-running components.
+
+ If you wish to undeploy everything Tilt has deployed for you, use `tilt
+ down`.
+
+1. Clean up your local Kubernetes cluster.
+
+
+
+
+ Docker Desktop supports only a _single_ Kubernetes cluster. If you are
+ comfortable deleting not just just Kargo-related resources, but _all_ your
+ workloads and data, the cluster can be reset from the Docker Desktop
+ Dashboard.
+
+ If, instead, you wish to preserve non-Kargo-related workloads and data, you
+ will need to manually uninstall Kargo's prerequisites:
+
+ ```
+ make hack-uninstall-prereqs
+ ```
+
+
+
+
+ OrbStack supports only a _single_ Kubernetes cluster. If you are
+ comfortable deleting not just just Kargo-related resources, but _all_ your
+ workloads and data, you can destroy the cluster with:
+
+ ```shell
+ orb delete k8s
+ ```
+
+ If, instead, you wish to preserve non-Kargo-related workloads and data, you
+ will need to manually uninstall Kargo's prerequisites:
+
+ ```
+ make hack-uninstall-prereqs
+ ```
+
+
+
+
+ To destroy the cluster, use:
+
+ ```shell
+ make hack-kind-down
+ ```
+
+ :::info
+ This command deliberately leaves your local image registry running so that if
+ you resume work later, you are doing so with a local registry that’s already
+ primed with most layers of Kargo’s image.
+
+ If you wish to stop the registry, use:
+
+ ```shell
+ docker stop kargo-dev-registry
+ ```
+
+ To destroy it, use:
+
+ ```shell
+ docker rm -f kargo-dev-registry
+ ```
+ :::
+
+
+
+
+ To destroy the cluster, use:
+
+ ```shell
+ make hack-k3d-down
+ ```
+
+ :::info
+ This command deliberately leaves your local image registry running so that if
+ you resume work later, you are doing so with a local registry that’s already
+ primed with most layers of Kargo’s image.
+
+ If you wish to stop the registry, use:
+
+ ```shell
+ docker stop kargo-dev-registry
+ ```
+
+ To destroy it, use:
+
+ ```shell
+ docker rm -f kargo-dev-registry
+ ```
+ :::
+
+
+
+
+## Contributing to Documentation
+
+Contributors should ensure that their changes are accompanied by relevant documentation
+updates. This helps maintain the project's sustainability. Pull requests with
+corresponding documentation updates are more likely to be merged faster.
+
+To make this process smoother, you can refer to [Docusaurus](https://docusaurus.io/docs)
+for guidance on writing and maintaining docs effectively.
+
+### Previewing Doc Changes Locally
+
+After making your changes, preview the documentation locally to ensure everything renders
+correctly. You can either run it in a container or natively on your system.
+
+To build and serve the docs inside a container:
+
+```shell
+make hack-serve-docs
+```
+
+:::info
+If you wish to opt-out of executing code-generation within a container (for
+performance reasons, perhaps), drop the `hack-` prefix from the target to run the docs natively on your system:
+
+```shell
+make serve-docs
+```
+
+This will require quite a variety of tools to be installed locally, so we do not
+recommend this if you can avoid it.
+:::
diff --git a/docs/versioned_docs/version-1.0/40-contributor-guide/15-release-procedures.md b/docs/versioned_docs/version-1.0/40-contributor-guide/15-release-procedures.md
new file mode 100644
index 000000000..eab00608f
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/40-contributor-guide/15-release-procedures.md
@@ -0,0 +1,170 @@
+---
+description: Steps required by Kargo maintainers to orchestrate a minor or major release of Kargo.
+sidebar_label: Release Procedures
+---
+
+# Release Procedures
+
+This document outlines the few manual steps that Kargo maintainers must follow
+to orchestrate a minor or major release of Kargo.
+
+## Conventions
+
+Throughout this document, we will use:
+
+* `M` and `m` to denote the major and minor version numbers of the upcoming
+ release (i.e. the one being performed), respectively.
+
+* `M-1` and `m-1` to denote the _previous_ major and minor version numbers,
+ respectively.
+
+* `M+1` and `m+1` to denote the _next_ major and minor version numbers,
+ respectively.
+
+* `L` to denote the latest minor version of the `M-1` line.
+
+## Timeline
+
+The steps outlined below should be started on the Monday preceding the expected
+release date -- which is always a Friday.
+
+## Steps
+
+1. Open a PR [similar to this one](https://github.com/akuity/kargo/pull/1932)
+ to revise the roadmap.
+
+ * The roadmap should be updated to reflect that work for the `vM.m.0`
+ release is complete.
+ * Planned work that was not completed should be moved to a future release.
+ * The next release (`vM.m+1.0` or `vM+1.0.0`) should be updated to reflect
+ that work is in-progress, along with the expected release date.
+
+ :::note
+ "Edge" documentation at
+ [main.kargo.akuity.io](https://main.docs.kargo.io) is continuously
+ published from the `main` branch and production documentation at
+ [kargo.akuity.io](https://docs.kargo.io) is continuously published from
+ the previous release branch (`release-M.m-1` or `release-M-1.L`). There
+ are two consequences of this:
+
+ * The production documentation will _not_ immediately reflect changes made
+ to the `main` branch, nor will it reflect changes made to the release branch
+ for the upcoming release. (Which does not exist yet. See next step.)
+
+ * This step should ideally be performed _prior_ to the creation of the
+ release branch (see next step) in order to avoid the need for two separate
+ PRs to update both branches.
+ :::
+
+1. Create a release branch of the form `release-M.m`.
+
+ This can be done locally by a maintainer. Presuming `upstream` is a remote
+ pointing to the main Kargo repository:
+
+ ```shell
+ git checkout main
+ git pull upstream main
+ git checkout -b release-M.m
+ git push upstream release-M.m
+ ```
+
+ :::note
+ After the creation of this branch, anything merged to `main` is excluded
+ from the upcoming release unless explicitly cherry-picked into the
+ `release-M.m branch`. As such, this step should ideally be performed
+ _after_ the majority of work for the upcoming release is complete.
+
+ In some cases, this may be performed early to:
+
+ * Un-block work on the next release.
+ * Facilitate the creation of a release candidate for use by non-engineers
+ while work on the upcoming release continues.
+ :::
+
+1. Merge any release-specific upgrade logic into the `release-M.m` branch.
+
+ :::info
+ Pre-`v1.0.0`, we are making a best effort to automatically compensate for
+ breaking changes between minor releases for users upgrading _directly_ from
+ any release in the `v0.m-1` line. This means release-specific upgrade
+ logic does not need to be merged into `main`.
+ :::
+
+1. Open a PR [similar to this one](https://github.com/akuity/kargo/pull/1925)
+ against the previous release branch (`release-M.m-1` or `release-M-1.L`) to
+ lock production documentation (e.g. for download and installation procedures)
+ into permanently reflecting the latest stable release.
+
+ :::note
+ Production documentation is continuously published from the previous
+ release branch, so this step is necessary to ensure that the production
+ documentation is not inadvertently broken by any subsequent steps.
+
+ This step will also ensure that when the current production documentation
+ is archived, it will reflect the latest release to which that documentation
+ was applicable.
+ :::
+
+1. Cut `vM.m.0-rc.1` from the Kargo
+ [release page](https://github.com/akuity/kargo/releases/new).
+
+ * The release process itself is fully-automated.
+ * Be certain to reference the head of the `release-M.m` branch and _not_ `main`.
+ * Be sure to check the __"Set as a pre-release"__ box.
+ * Wait for the
+ [automated release process](https://github.com/akuity/kargo/actions/workflows/release.yaml)
+ to complete.
+
+1. Open a PR [like this one](https://github.com/akuity/kargo/pull/1926) against
+ `main` to make the edge documentation (e.g. for download and installation
+ procedures) reflect the recently built release candidate.
+
+ :::info
+ The edge documentation is continuously published from the `main` branch, so
+ this step makes it easy for non-engineers to test the release candidate by
+ adhering to instructions in the edge documentation, without any need to
+ compensate for the release candidate not being counted as "latest" on
+ account of being a pre-release.
+ :::
+
+1. Alert non-engineer stakeholders to the availability of the release candidate.
+
+1. Bug fixes and last minute features should be merged to `main` and backported
+ to the `release-M.m` (in bulk, when possible).
+
+1. Repeat steps 5-8 as necessary until the release candidate is deemed stable
+ by relevant stakeholders.
+
+1. Draft release notes for the upcoming release.
+
+ :::info
+ This can be done concurrently with the previous steps.
+
+ Some stakeholders may desire early access to these notes to inform blog
+ posts, marketing materials, etc.
+ :::
+
+1. Cut `vM.m.0` from the Kargo
+ [release page](https://github.com/akuity/kargo/releases/new).
+
+ * Be certain to reference the head of the `release-M.m` branch and _not_ `main`.
+ * Be certain to include the final draft of the release notes.
+ * Be sure to check the __"Set as the latest release"__ box.
+ * Wait for the
+ [automated release process](https://github.com/akuity/kargo/actions/workflows/release.yaml)
+ to complete.
+
+1. Mark the release branch (`release-M.m`) as the __"Production branch"__
+ [in Netlify](https://app.netlify.com/sites/docs-kargo-akuity-io/configuration/deploys#branches-and-deploy-contexts).
+
+ * Also add the previous release branch (`release-M.m-1` or
+ `release-M-1.L`) to __"Branch deploys"__.
+ * After changing the __"Production branch"__, it will be necessary to
+ [manually trigger a deployment](https://app.netlify.com/sites/docs-kargo-akuity-io/deploys)
+ of the production documentation.
+
+1. Open a PR to revert the changes from step 6.
+
+1. Inform relevant stakeholders that the release is complete.
+
+1. 🎉 Celebrate!
diff --git a/docs/versioned_docs/version-1.0/40-contributor-guide/20-signing-commits.md b/docs/versioned_docs/version-1.0/40-contributor-guide/20-signing-commits.md
new file mode 100644
index 000000000..d9f580933
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/40-contributor-guide/20-signing-commits.md
@@ -0,0 +1,73 @@
+---
+description: Find out how to sign commits when contributing to Kargo
+sidebar_label: Signing Commits
+---
+
+# Signing Commits
+
+All commits merged into Kargo's main branch MUST bear a DCO (Developer
+Certificate of Origin) sign-off. This is a line placed at the end of a commit
+message containing a contributor’s “signature.” In adding this, the contributor
+certifies that they have the right to contribute the material in question.
+
+Here are the steps to sign your work:
+
+1. Verify the contribution in your commit complies with the
+ [terms of the DCO](https://developercertificate.org/).
+
+1. Add a line like the following to your commit message:
+
+ ```
+ Signed-off-by: Joe Smith
+ ```
+
+ You MUST use your legal name -- handles or other pseudonyms are not
+ permitted.
+
+ While you could manually add DCO sign-off to every commit, there is an easier
+ way:
+
+ 1. Configure your git client appropriately. This is one-time setup.
+
+ ```shell
+ git config user.name
+ git config user.email
+ ```
+
+ If you work on multiple projects that require a DCO sign-off, you can
+ configure your git client to use these settings globally instead of only
+ for Kargo:
+
+ ```shell
+ git config --global user.name
+ git config --global user.email
+ ```
+
+ 1. Use the --signoff or -s (lowercase) flag when making each commit. For
+ example:
+
+ ```shell
+ git commit --message "" --signoff
+ ```
+
+ If you ever make a commit and forget to use the `--signoff` flag, you can
+ amend your commit with this information before pushing:
+
+ ```shell
+ git commit --amend --signoff
+ ```
+
+ 1. You can verify the above worked as expected using `git log`. Your latest
+ commit should look similar to this one:
+
+ ```shell
+ Author: Joe Smith
+ Date: Thu Feb 2 11:41:15 2018 -0800
+
+ Update README
+
+ Signed-off-by: Joe Smith
+ ```
+
+ Notice the `Author` and `Signed-off-by` lines match. If they do not, the
+ PR will be rejected by the automated DCO check.
diff --git a/docs/versioned_docs/version-1.0/40-contributor-guide/30-code-of-conduct.md b/docs/versioned_docs/version-1.0/40-contributor-guide/30-code-of-conduct.md
new file mode 100644
index 000000000..ac3901b34
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/40-contributor-guide/30-code-of-conduct.md
@@ -0,0 +1,137 @@
+---
+sidebar_label: Code of Conduct
+description: Contributor Code of Conduct for the open source Kargo project
+---
+
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual
+identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall
+ community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or advances of
+ any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email address,
+ without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+[kent@akuity.io](mailto:kent@akuity.io).
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series of
+actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
+ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within the
+community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
+[https://www.contributor-covenant.org/translations][translations].
+
+[homepage]: https://www.contributor-covenant.org
+[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
diff --git a/docs/versioned_docs/version-1.0/40-contributor-guide/5-debugging-kargo.md b/docs/versioned_docs/version-1.0/40-contributor-guide/5-debugging-kargo.md
new file mode 100644
index 000000000..f606be7fb
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/40-contributor-guide/5-debugging-kargo.md
@@ -0,0 +1,63 @@
+---
+description: Steps to help you debug Kargo when you run into issues.
+sidebar_label: Debugging Kargo
+---
+
+# Debugging Kargo
+
+From time to time, you may need to debug Kargo. This document outlines options
+to help you achieve a better understanding of what Kargo (internally) is doing,
+especially when you are running into issues which are not immediately obvious
+by just reading the code.
+
+As a Kargo user, you may not need to debug Kargo itself, but this document may
+serve you when a Kargo maintainer asks you to provide additional information
+about an issue you are facing.
+
+## Enabling pprof endpoints
+
+Kargo components can be configured to expose [`pprof` endpoints](https://golang.org/pkg/net/http/pprof/).
+These endpoints can be used to profile the components when they are running,
+and can be useful to understand what the components are doing and where they
+are spending time.
+
+To enable the `pprof` endpoint on a component, you can set the
+`PPROF_BIND_ADDRESS` environment variable to the address where the component
+should listen for `pprof` requests. For example, to enable the `pprof` endpoint
+on port `6060` of the controller, you can set the `PPROF_BIND_ADDRESS`
+environment variable to `:6060`.
+
+```yaml
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: kargo-controller
+spec:
+ # ...omitted for brevity
+ template:
+ spec:
+ containers:
+ - name: kargo-controller
+ env:
+ - name: PPROF_BIND_ADDRESS
+ value: ":6060"
+```
+
+After setting the `PPROF_BIND_ADDRESS` environment variable, the `pprof`
+endpoints will be available at `http://:6060/debug/pprof/`.
+
+### Collecting a profile
+
+To collect a profile, you can port-forward the `pprof` address to your local
+machine and collect the data from an endpoint of choice. For example, to
+collect a heap profile, you can run:
+
+```console
+$ kubectl port-forward -n deployment/ 6060
+$ curl -Sk -v http://localhost:6060/debug/pprof/heap > heap.out
+```
+
+This will collect a heap profile in the `heap.out` file, which you can then
+[analyze using `go`](https://go.dev/blog/pprof), or share with a Kargo
+maintainer.
diff --git a/docs/versioned_docs/version-1.0/40-contributor-guide/index.md b/docs/versioned_docs/version-1.0/40-contributor-guide/index.md
new file mode 100644
index 000000000..45d0c8252
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/40-contributor-guide/index.md
@@ -0,0 +1,16 @@
+---
+description: A comprehensive introduction for developers who are looking to get involved with contributing directly to the Kargo project
+sidebar_label: Contributor Guide
+---
+
+# Kargo Contributor Guide
+
+This contributor guide is intended as a comprehensive introduction for
+developers who are looking to get involved with contributing directly to the
+Kargo project.
+
+This guide is decomposed into the following, high-level topics:
+
+* [Hacking on Kargo](./10-hacking-on-kargo.md)
+* [Signing Commits](./20-signing-commits.md)
+* [Code of Conduct](./30-code-of-conduct.md)
diff --git a/docs/versioned_docs/version-1.0/50-roadmap.md b/docs/versioned_docs/version-1.0/50-roadmap.md
new file mode 100644
index 000000000..d6070f705
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/50-roadmap.md
@@ -0,0 +1,126 @@
+---
+sidebar_label: Roadmap
+Description: See what's on the roadmap of Kargo and find out more about the latest releases
+---
+
+# Kargo Roadmap
+
+Over a series of releases, Kargo's maintainers have settled into a cadence of a
+minor release roughly every five weeks, with two or three major features
+completed per release.
+
+:::caution
+This roadmap tracks only _major_ features and is subject to change at any time,
+for the most up-to-date information, please see the [GitHub
+Project](https://github.com/akuity/kargo/milestones)
+:::
+
+## In Progress
+
+### v1.1.0
+
+__Expected:__ 22 November 2024
+
+This release will focus on improving the flexibility of the promotion steps
+introduced in v0.9.0 through the addition of support for an expression language.
+
+This release also kicks off a three phase plan with the end goal of enabling
+custom/third-party promotion steps.
+
+## Upcoming
+
+### v1.2.0
+
+This release is to be the second phase of three advancing Kargo toward support
+for custom/third-party promotion steps, with a focus on ensuring a secure and
+isolated execution environment for those steps.
+
+### v1.3.0
+
+The third and final phase of the three advancing Kargo toward support for
+custom/third-party promotion steps will focus on:
+
+* Establishing a formal specification for developers wishing to implement their
+ own promotion steps.
+
+* Building the mechanisms whereby operators may install and users may leverage
+ versioned, custom/third-party promotion steps.
+
+### v1.4.0 and Beyond
+
+* Packaging common workflows as pre-defined, composite promotion steps.
+* TBD
+
+## Completed
+
+### v1.0.0
+
+v1.0.0 was our long-anticipated GA release containing only small features,
+bug fixes, stability improvements, and the final removal of the legacy
+promotion mechanisms that were deprecated in v0.9.0.
+
+### v0.9.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| [Promotion Steps](https://github.com/akuity/kargo/issues/2219) | strategic refactor | Transitioned from opinionated promotion mechanisms to an ordered lists of more finely-grained promotion directives steps reminiscent of GitHub Actions. These enable greater flexibility in addressing outlying use cases and have left us with a clear path forward for to eventually enable third-party integrations. |
+| Production Readiness | chore |
Prioritized stability of existing features.
Paid down technical debt.
**This does not mean v0.9.0 is production-ready. It means it is several steps closer to it.**
|
+
+### v0.8.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| Auth via [GitHub Apps](https://docs.github.com/en/apps) | feature | Support GitHub Apps as an authentication option for GitHub repositories. |
+| Multiple `Freight` per `Stage` | feature | Permit `Stage`s to host multiple pieces of `Freight` from different `Warehouse`s. Different artifacts, or sets of artifacts, can be promoted through parallel pipelines with different/independent cadence. |
+| Production Readiness | chore |
Prioritized stability of existing features.
Paid down technical debt.
**This does not mean v0.8.0 is production-ready. It means it is several steps closer to it.**
|
+
+### v0.7.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| Multiple `Warehouse`s | feature | Improved UI support for displaying Freight from multiple `Warehouse`s. |
+| Manual `Freight` Creation | feature | Added UI feature for manual `Freight` creation. |
+| ECR/GAR Support | feature | Added multiple options for authenticating to image repositories in ECR and Google Artifact Registry, including support for EKS Pod Identity and GKE Workload Identity Federation. |
+| [Patch Promotions](https://github.com/akuity/kargo/issues/1250) | poc | Support a generalized option to promote arbitrary configuration (e.g. strings, files, and directories) to other paths of a GitOps repository. |
+| Production Readiness | chore | Prioritized stability of existing features. **This does not mean v0.7.0 is production-ready. It means it is several steps closer to it.** |
+
+### v0.6.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| Project Management | feature | Added user / role / permission management capabilities to the CLI and UI. |
+| Events | feature | Kargo emits noteworthy events as Kubernetes events. Events are also viewable in the UI. |
+| Production Readiness | chore | Prioritized stability of existing features. **This does not mean v0.6.0 is production-ready. It means it is several steps closer to it.** |
+
+### v0.5.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `Warehouse` Rules/Filters | feature | Introduced optional path-based constraints on Git repository subscriptions. |
+| Credential Storage | refactor | Simplified and streamlined format and storage of repository credentials. |
+| Credential Management | feature | Added credential management capabilities to the CLI and UI. |
+| CLI Improvements | refactor | Overhauled the CLI to make the tree of sub-commands more intuitive, with improved consistency in usage and documentation from command to command. |
+| UI Improvements | feature | Achieved near-parity with CLI features. |
+
+### v0.4.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `Warehouse` Rules/Filters | feature | Introduced optional tag-based constraints on Git repository subscriptions. |
+| Project Management | feature |
Introduced `Project` CRD to simplify project initialization.
Removed `PromotionPolicy` CRD and folded its functionality directly into the `Project` CRD.
|
+
+### v0.3.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| GitHub PR-Based Promotion | feature | Pull request-based promotions are now supported on GitHub. |
+| Verifications | feature | `Stage` resources can now execute a user-defined verification process after a promotion. These can be defined using Argo Rollouts `AnalysisTemplate` resources, and executions take the form of `AnalysisRun` resources. |
+| Improved RBAC | feature | SSO user identities can now be mapped to Kubernetes `ServiceAccount` resources using annotations. |
+
+### v0.2.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `Freight` CRD | feature | Freight changed from being a property of a `Stage`, to being its own `Freight` CRD. |
+| `Warehouse` CRD | feature | `Freight` production was decoupled from a pipeline's first `Stage` and now comes from a `Warehouse`. |
+| Kargo Render | breaking change | The Bookkeeper project was rebranded as Kargo Render -- a Kargo sub-project for rendering manifests. |
diff --git a/docs/versioned_docs/version-1.0/assets/architecture.png b/docs/versioned_docs/version-1.0/assets/architecture.png
new file mode 100644
index 000000000..e4baba6d3
Binary files /dev/null and b/docs/versioned_docs/version-1.0/assets/architecture.png differ
diff --git a/docs/versioned_docs/version-1.0/assets/argo-dashboard.png b/docs/versioned_docs/version-1.0/assets/argo-dashboard.png
new file mode 100644
index 000000000..fcdee7a1f
Binary files /dev/null and b/docs/versioned_docs/version-1.0/assets/argo-dashboard.png differ
diff --git a/docs/versioned_docs/version-1.0/assets/kargo-dashboard-projects.png b/docs/versioned_docs/version-1.0/assets/kargo-dashboard-projects.png
new file mode 100644
index 000000000..3d6df83f7
Binary files /dev/null and b/docs/versioned_docs/version-1.0/assets/kargo-dashboard-projects.png differ
diff --git a/docs/versioned_docs/version-1.0/assets/kargo-dashboard-promotion.png b/docs/versioned_docs/version-1.0/assets/kargo-dashboard-promotion.png
new file mode 100644
index 000000000..4087592de
Binary files /dev/null and b/docs/versioned_docs/version-1.0/assets/kargo-dashboard-promotion.png differ
diff --git a/docs/versioned_docs/version-1.0/assets/kargo-freight-verified.png b/docs/versioned_docs/version-1.0/assets/kargo-freight-verified.png
new file mode 100644
index 000000000..d9e7f8d07
Binary files /dev/null and b/docs/versioned_docs/version-1.0/assets/kargo-freight-verified.png differ
diff --git a/docs/versioned_docs/version-1.0/assets/kargo-frieght-timeline.png b/docs/versioned_docs/version-1.0/assets/kargo-frieght-timeline.png
new file mode 100644
index 000000000..7ae78a0c5
Binary files /dev/null and b/docs/versioned_docs/version-1.0/assets/kargo-frieght-timeline.png differ
diff --git a/docs/versioned_docs/version-1.0/assets/kargo-projects.png b/docs/versioned_docs/version-1.0/assets/kargo-projects.png
new file mode 100644
index 000000000..6f4737479
Binary files /dev/null and b/docs/versioned_docs/version-1.0/assets/kargo-projects.png differ
diff --git a/docs/versioned_docs/version-1.0/assets/kargo-promote-option-2.png b/docs/versioned_docs/version-1.0/assets/kargo-promote-option-2.png
new file mode 100644
index 000000000..fe37f0d95
Binary files /dev/null and b/docs/versioned_docs/version-1.0/assets/kargo-promote-option-2.png differ
diff --git a/docs/versioned_docs/version-1.0/assets/kargo-promote-option.png b/docs/versioned_docs/version-1.0/assets/kargo-promote-option.png
new file mode 100644
index 000000000..1532d4136
Binary files /dev/null and b/docs/versioned_docs/version-1.0/assets/kargo-promote-option.png differ
diff --git a/docs/versioned_docs/version-1.0/assets/kargo.png b/docs/versioned_docs/version-1.0/assets/kargo.png
new file mode 100644
index 000000000..67bd6ad0a
Binary files /dev/null and b/docs/versioned_docs/version-1.0/assets/kargo.png differ
diff --git a/docs/versioned_docs/version-1.0/assets/logo.svg b/docs/versioned_docs/version-1.0/assets/logo.svg
new file mode 100644
index 000000000..9db6d0d06
--- /dev/null
+++ b/docs/versioned_docs/version-1.0/assets/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/versioned_docs/version-1.0/assets/screenshot.png b/docs/versioned_docs/version-1.0/assets/screenshot.png
new file mode 100644
index 000000000..d059fd67e
Binary files /dev/null and b/docs/versioned_docs/version-1.0/assets/screenshot.png differ
diff --git a/docs/versioned_docs/version-1.1/10-overview.md b/docs/versioned_docs/version-1.1/10-overview.md
new file mode 100644
index 000000000..cf5054407
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/10-overview.md
@@ -0,0 +1,38 @@
+---
+slug: /
+sidebar_label: Overview
+description: Find out more about Kargo - a next-generation continuous delivery and application lifecycle orchestration platform for Kubernetes
+---
+
+# What is Kargo?
+
+Kargo is a next-generation continuous delivery and application lifecycle
+orchestration platform for Kubernetes. It builds upon
+[GitOps](https://opengitops.dev/) principles and integrates with existing
+technologies, like [Argo CD](https://argoproj.github.io/cd/), to streamline and
+automate the progressive rollout of changes across the many stages of an
+application's lifecycle.
+
+![Screenshot](./assets/screenshot.png)
+
+Kargo's goal is to provide an intuitive and flexible layer "above" existing GitOps tooling, wherein you can describe the relationships between various application instances deployed to different environments as well as procedures for progressing changes from one application instance's source of truth to the next.
+
+:::info
+Watch the *Multi-Stage Deployment Pipelines the GitOps Way* talk by Jesse Suen & Kent Rancourt of Akuity at GitOpsCon EU 2024.
+
+
+
+
+
+
+:::
+
+:::info
+Join the Akuity Community [Discord server](https://discord.gg/dHJBZw6ewT)!
+:::
+
+## Next Steps
+
+To learn more about Kargo, consider checking out our
+[concepts doc](./concepts) or get hands-on right away with our
+[quickstart](./quickstart)!
diff --git a/docs/versioned_docs/version-1.1/15-concepts.md b/docs/versioned_docs/version-1.1/15-concepts.md
new file mode 100644
index 000000000..1348a7b81
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/15-concepts.md
@@ -0,0 +1,788 @@
+---
+sidebar_label: Key Concepts
+description: Find out more about key Kargo concepts - stages, freight, warehouses, promotions, and more
+---
+# Key Kargo Concepts
+
+:::note
+We're currently reorganizing and updating the documentation.
+During this process, you may encounter sections that are incomplete,
+repetitive, or fragmented. Please bear with us as we work to make improvements.
+:::
+
+## The Basics
+
+### What is a Project
+
+A **project** is a collection of related Kargo resources that describe one or
+more delivery pipelines and is the basic unit of organization and tenancy in
+Kargo.
+
+RBAC rules are also defined at the project level and project administrators
+may use projects to define policies, such as whether a **stage** is eligible
+for automatic promotions of new **freight**.
+
+:::note
+For technical information on the corresponding `Project` resource
+type, refer to [Working with Projects](./30-how-to-guides/11-working-with-projects.md).
+:::
+
+### What is a Stage?
+
+When you hear the term “environment”, what you envision will depend
+significantly on your perspective. A developer, for example, may think of
+an "environment" as a specific _instance_ of an application they work on,
+while a DevOps engineer, may think of an "environment" as a particular segment
+of the infrastructure they maintain.
+
+To eliminate confusion, Kargo avoids the term "environment" altogether in favor of **stage**.
+The important feature of a stage is that its name ("test" or "prod," for instance)
+denotes an application instance's _purpose_ and not necessarily its _location_.
+[This blog post](https://akuity.io/blog/kargo-stage-not-environment/) discusses
+the rationale behind this choice.
+
+_Stages are Kargo's most important concept._ They can be linked together in a
+directed acyclic graph to describe a delivery pipeline. Typically, such a
+pipeline may feature a "test" or "dev" stage as its starting point, with one or
+more "prod" stages at the end.
+
+### What is Freight?
+
+**Freight** is Kargo's second most important concept. A single "piece of
+freight" is a set of references to one or more versioned artifacts, which may
+include one or more:
+
+* Container images (from image repositories)
+
+* Kubernetes manifests (from Git repositories)
+
+* Helm charts (from chart repositories)
+
+Freight can therefore be thought of as a sort of meta-artifact. Freight is what
+Kargo seeks to progress from one stage to another.
+For detailed guidance on working with Freight, refer to
+[this guide](./30-how-to-guides/15-working-with-freight.md).
+
+### What is a Warehouse?
+
+A **warehouse** is a _source_ of freight. A warehouse subscribes to one or more:
+
+* Container image repositories
+
+* Git repositories
+
+* Helm charts repositories
+
+Anytime something new is discovered in any repository to which a warehouse
+subscribes, the warehouse produces a new piece of freight.
+
+### What is a Promotion?
+
+A **promotion** is a request to move a piece of freight into a specified stage.
+
+## Corresponding Resource Types
+
+Each of Kargo's fundamental concepts maps directly onto a custom Kubernetes
+resource type.
+
+### `Stage` Resources
+
+Each Kargo stage is represented by a Kubernetes resource of type `Stage`.
+
+A `Stage` resource's `spec` field decomposes into three main areas of concern:
+
+* Requested freight
+
+* Promotion template
+
+* Verification
+
+The following sections will explore each of these in greater detail.
+
+#### Requested Freight
+
+The `spec.requestedFreight` field is used to describe one or more "types" of
+`Freight`, as specified by an `origin`, that the `Stage`'s promotion process, as
+specified by `spec.promotionTemplate`, will operate on, and the acceptable
+sources from which to obtain that `Freight`. Those sources may include the
+origin itself (e.g. a `Warehouse`) and/or any number of "upstream" `Stage`
+resources.
+
+:::info
+`Warehouse`s are the only type of origin at present, but it is anticipated that
+future versions of Kargo will introduce additional origin types. This is why
+"types" of `Freight` are described by an `origin` field having `kind` and `name`
+subfields instead of being described only by the name of a `Warehouse`.
+:::
+
+For each `Stage`, the Kargo controller will periodically check for `Freight`
+resources that are newly available for promotion to that `Stage`.
+
+When a `Stage` accepts `Freight` directly from its origin, _all_ new `Freight`
+created by that origin (e.g. a `Warehouse` ) are immediately available for
+promotion to that `Stage`.
+
+When a `Stage` accepts `Freight` from one or more "upstream" `Stage` resources,
+`Freight` is considered available for promotion to that `Stage` only after being
+_verified_ in at least one of the upstream `Stage`s. Alternatively, users with
+adequate permissions may manually _approve_ `Freight` for promotion to any given
+`Stage` without requiring upstream verification.
+
+:::tip
+Explicit approvals are a useful method for applying the occasional "hotfix"
+without waiting for a `Freight` resource to traverse the entirety of a pipeline.
+:::
+
+In the following example, the `test` `Stage` requests `Freight` that has
+originated from the `my-warehouse` `Warehouse` and indicates that it will accept
+new `Freight` _directly_ from that origin:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Stage
+metadata:
+ name: test
+ namespace: kargo-demo
+spec:
+ requestedFreight:
+ - origin:
+ kind: Warehouse
+ name: my-warehouse
+ sources:
+ direct: true
+ # ...
+```
+
+In this example, the `uat` `Stage` requests `Freight` that has originated from
+the `my-warehouse` `Warehouse`, but indicates that it will accept such `Freight`
+only after it has been _verified_ in the `test` `Stage`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Stage
+metadata:
+ name: uat
+ namespace: kargo-demo
+spec:
+ requestedFreight:
+ - origin:
+ kind: Warehouse
+ name: my-warehouse
+ sources:
+ stages:
+ - test
+ # ...
+```
+
+Stages may also request `Freight` from multiple sources. The following example
+illustrates a `Stage` that requests `Freight` from both a `microservice-a` and
+`microservice-b` `Warehouse`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Stage
+metadata:
+ name: test
+ namespace: kargo-demo
+spec:
+ requestedFreight:
+ - origin:
+ kind: Warehouse
+ name: microservice-a
+ sources:
+ direct: true
+ - origin:
+ kind: Warehouse
+ name: microservice-b
+ sources:
+ direct: true
+ # ...
+```
+
+:::tip
+By requesting `Freight` from multiple sources, a `Stage` can effectively
+participate in _multiple pipelines_ that may each deliver different collections
+of artifacts independently of the others. At present, this is most useful for
+the delivery of microservices that are developed and deployed in parallel,
+although other uses of this feature are anticipated in the future.
+:::
+
+#### Promotion Templates
+
+The `spec.promotionTemplate` field is used to describe _how_ to transition
+`Freight` into the `Stage`. The `spec.promotionTemplate.spec.steps` field describes
+the discrete steps of a promotion process in detail.
+
+In the following, very common example, the `promotionTemplate` describes steps
+to:
+
+1. Clone a Git repository containing Kubernetes manifests and Kustomize
+ configuration, checking out two different branches to two different
+ directories.
+
+1. Clears the contents of one working tree, with intentions to fully replace its
+ contents.
+
+1. Runs the equivalent of `kustomize edit set image` to update a
+ `kustomization.yaml` file with a reference to an updated
+ `public.ecr.aws/nginx/nginx` container image.
+
+1. Renders the updated manifests using the equivalent of `kustomize build`.
+
+1. Commits the updated manifests and pushes them to the `stage/test` of the
+ remote repository.
+
+1. Forces Argo CD to sync the `kargo-demo-test` application to the latest commit
+ of the `stage/test` branch.
+
+```yaml
+promotionTemplate:
+ spec:
+ steps:
+ - uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - fromFreight: true
+ path: ./src
+ - branch: stage/test
+ create: true
+ path: ./out
+ - uses: git-clear
+ config:
+ path: ./out
+ - uses: kustomize-set-image
+ as: update-image
+ config:
+ path: ./src/base
+ images:
+ - image: public.ecr.aws/nginx/nginx
+ - uses: kustomize-build
+ config:
+ path: ./src/stages/test
+ outPath: ./out
+ - uses: git-commit
+ as: commit
+ config:
+ path: ./out
+ messageFromSteps:
+ - update-image
+ - uses: git-push
+ config:
+ path: ./out
+ targetBranch: stage/test
+ - uses: argocd-update
+ config:
+ apps:
+ - name: kargo-demo-test
+ sources:
+ - repoURL: https://github.com/example/repo.git
+ desiredCommitFromStep: commit
+```
+
+__For complete documentation of all of Kargo's built-in promotion steps, refer
+to the [Promotion Steps Reference](./35-references/10-promotion-steps.md).__
+
+#### Verifications
+
+The `spec.verification` field is used to describe optional verification
+processes that should be executed after a `Promotion` has successfully deployed
+`Freight` to a `Stage`, and if applicable, after the `Stage` has reached a
+healthy state.
+
+Verification processes are defined through _references_ to one or more
+[Argo Rollouts `AnalysisTemplate` resources](https://argoproj.github.io/argo-rollouts/features/analysis/)
+that reside in the same `Project`/`Namespace` as the `Stage` resource.
+
+:::info
+Argo Rollouts `AnalysisTemplate` resources (and the `AnalysisRun` resources that
+are spawned from them) were intentionally built to be re-usable in contexts
+other than Argo Rollouts. Re-using this resource type to define verification
+processes means those processes benefit from this rich and battle-tested feature
+of Argo Rollouts.
+:::
+
+The following example depicts a `Stage` resource that references an
+`AnalysisTemplate` named `kargo-demo` to validate the `test` `Stage` after any
+successful `Promotion`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Stage
+metadata:
+ name: test
+ namespace: kargo-demo
+spec:
+ # ...
+ verification:
+ analysisTemplates:
+ - name: kargo-demo
+```
+
+It is also possible to specify additional labels, annotations, and arguments
+that should be applied to `AnalysisRun` resources spawned from the referenced
+`AnalysisTemplate`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Stage
+metadata:
+ name: test
+ namespace: kargo-demo
+spec:
+ # ...
+ verification:
+ analysisTemplates:
+ - name: kargo-demo
+ analysisRunMetadata:
+ labels:
+ foo: bar
+ annotations:
+ bat: baz
+ args:
+ - name: foo
+ value: bar
+```
+
+An `AnalysisTemplate` could be as simple as the following, which merely executes
+a Kubernetes `Job` that is defined inline:
+
+```yaml
+apiVersion: argoproj.io/v1alpha1
+kind: AnalysisTemplate
+metadata:
+ name: kargo-demo
+ namespace: kargo-demo
+spec:
+ metrics:
+ - name: test
+ provider:
+ job:
+ metadata:
+ spec:
+ backoffLimit: 1
+ template:
+ spec:
+ containers:
+ - name: test
+ image: alpine:latest
+ command:
+ - sleep
+ - "10"
+ restartPolicy: Never
+```
+
+:::note
+Please consult the
+[relevant sections](https://argoproj.github.io/argo-rollouts/features/analysis/)
+of the Argo Rollouts documentation for comprehensive coverage of the full range
+of `AnalysisTemplate` capabilities.
+:::
+
+#### Status
+
+A `Stage` resource's `status` field records:
+
+* The current phase of the `Stage` resource's lifecycle.
+
+* Information about the last `Promotion` and any in-progress `Promotion`.
+
+* History of `Freight` that has been deployed to the `Stage` (from most to
+ least recent) along with the results of any associated verification processes.
+
+* The health status of any associated Argo CD `Application` resources.
+
+For example:
+
+```yaml
+status:
+ freightHistory:
+ - id: 101bca5b0e18ca7913978a1da956308d2544f741
+ items:
+ Warehouse/my-warehouse:
+ commits:
+ - healthCheckCommit: 111eaf55aa41f21bb9bb707ba1baa748b83ec51e
+ id: 961cfaedbc53aacdb65110028839a2c1c281290d
+ repoURL: https://github.com/example/kargo-demo.git
+ images:
+ - digest: sha256:b2487a28589657b318e0d63110056e11564e73b9fd3ec4c4afba5542f9d07d46
+ repoURL: public.ecr.aws/nginx/nginx
+ tag: 1.27.0
+ name: 666209fd9755a1e48bec6b27f5f447747410dd9e
+ origin:
+ kind: Warehouse
+ name: my-warehouse
+ verificationHistory:
+ - analysisRun:
+ name: test.01j2w7aknhf3j7jteyqs72hnbg.101bca5
+ namespace: kargo-demo-09
+ phase: Successful
+ finishTime: "2024-07-15T22:13:57Z"
+ id: 5535a484-bbd0-4f12-8cf4-be2c8e0041c9
+ phase: Successful
+ startTime: "2024-07-15T22:13:34Z"
+ health:
+ argoCDApps:
+ - healthStatus:
+ status: Healthy
+ name: kargo-demo-09-test
+ namespace: argocd
+ syncStatus:
+ revision: 111eaf55aa41f21bb9bb707ba1baa748b83ec51e
+ status: Synced
+ status: Healthy
+ lastPromotion:
+ finishedAt: "2024-07-15T22:13:25Z"
+ freight:
+ commits:
+ - healthCheckCommit: 111eaf55aa41f21bb9bb707ba1baa748b83ec51e
+ id: 961cfaedbc53aacdb65110028839a2c1c281290d
+ repoURL: https://github.com/example/kargo-demo.git
+ name: 666209fd9755a1e48bec6b27f5f447747410dd9e
+ origin:
+ kind: Warehouse
+ name: kargo-demo
+ name: test.01j2w7a15cxjjgejresfyw6ysp.666209f
+ status:
+ finishedAt: "2024-07-15T22:13:25Z"
+ freight:
+ commits:
+ - healthCheckCommit: 111eaf55aa41f21bb9bb707ba1baa748b83ec51e
+ id: 961cfaedbc53aacdb65110028839a2c1c281290d
+ repoURL: https://github.com/example/kargo-demo.git
+ name: 666209fd9755a1e48bec6b27f5f447747410dd9e
+ origin:
+ kind: Warehouse
+ name: kargo-demo
+ freightCollection:
+ id: 101bca5b0e18ca7913978a1da956308d2544f741
+ items:
+ Warehouse/kargo-demo:
+ commits:
+ - healthCheckCommit: 111eaf55aa41f21bb9bb707ba1baa748b83ec51e
+ id: 961cfaedbc53aacdb65110028839a2c1c281290d
+ repoURL: https://github.com/example/kargo-demo.git
+ name: 666209fd9755a1e48bec6b27f5f447747410dd9e
+ origin:
+ kind: Warehouse
+ name: kargo-demo
+ verificationHistory:
+ - analysisRun:
+ name: test.01j2w7aknhf3j7jteyqs72hnbg.101bca5
+ namespace: kargo-demo-09
+ phase: ""
+ id: 5535a484-bbd0-4f12-8cf4-be2c8e0041c9
+ phase: Pending
+ startTime: "2024-07-15T22:13:34Z"
+ phase: Succeeded
+ observedGeneration: 1
+ phase: Steady
+```
+
+### `Freight` Resources
+
+Each piece of Kargo freight is represented by a Kubernetes resource of type
+`Freight`. `Freight` resources are immutable except for their `alias` field
+and `status` subresource (mutable only by the Kargo controller).
+
+A single `Freight` resource references one or more versioned artifacts, such as:
+
+* Container images (from image repositories)
+
+* Kubernetes manifests (from Git repositories)
+
+* Helm charts (from chart repositories)
+
+A `Freight` resource's `metadata.name` field is a SHA1 hash of a canonical
+representation of the artifacts referenced by the `Freight` resource. (This is
+enforced by an admission webhook.) The `metadata.name` field is therefore a
+"fingerprint", deterministically derived from the `Freight`'s contents.
+
+To provide a human-readable identifier for a `Freight` resource, a `Freight`
+resource has an `alias` field. This alias is
+a human-readable string that is unique within the `Project` to which the
+`Freight` belongs. Kargo automatically generates unique aliases for all
+`Freight` resources, but users may update them to be more meaningful.
+
+:::tip
+Assigning meaningful and recognizable aliases to important pieces of `Freight`
+traversing your pipeline(s) can make it easier to track their progress from one
+`Stage` to another.
+:::
+
+:::note
+For more information on aliases, refer to the [aliases](./30-how-to-guides/15-working-with-freight.md#aliases)
+and [updating aliases](./30-how-to-guides/15-working-with-freight.md#updating-aliases)
+sections of the "Working with Freight" how-to guide.
+:::
+
+A `Freight` resource's `status` field records a list of `Stage` resources in
+which the `Freight` has been _verified_ and a separate list of `Stage` resources
+for which the `Freight` has been manually _approved_.
+
+`Freight` resources look similar to the following:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Freight
+metadata:
+ name: 47b33c0c92b54439e5eb7fb80ecc83f8626fe390
+ namespace: kargo-demo
+ labels:
+ kargo.akuity.io/alias: fruitful-ferret
+alias: fruitful-ferret
+images:
+- digest: sha256:b2487a28589657b318e0d63110056e11564e73b9fd3ec4c4afba5542f9d07d46
+ repoURL: public.ecr.aws/nginx/nginx
+ tag: 1.27.0
+commits:
+- repoURL: https://github.com/example/kargo-demo.git
+ id: 1234abc
+warehouse: my-warehouse
+status:
+ verifiedIn:
+ test: {}
+ approvedFor:
+ prod: {}
+```
+
+### `Warehouse` Resources
+
+Each Kargo warehouse is represented by a Kubernetes resource of type
+`Warehouse`.
+
+A `Warehouse` resource's most important field is its `spec.subscriptions` field,
+which is used to subscribe to one or more:
+
+* Container image repositories
+
+* Git repositories
+
+* Helm charts repositories
+
+The following example shows a `Warehouse` resource that subscribes to a
+container image repository and a Git repository:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Warehouse
+metadata:
+ name: my-warehouse
+ namespace: kargo-demo
+spec:
+ subscriptions:
+ - image:
+ repoURL: public.ecr.aws/nginx/nginx
+ semverConstraint: ^1.26.0
+ - git:
+ repoURL: https://github.com/example/kargo-demo.git
+```
+:::info
+Kargo uses [semver](https://github.com/masterminds/semver#checking-version-constraints) to handle semantic versioning constraints.
+:::
+
+#### Git Subscription Path Filtering
+
+In some cases, it may be necessary to constrain the paths within a Git
+repository that a `Warehouse` will consider as triggers for `Freight`
+production. This is especially useful for GitOps repositories that are
+"monorepos" containing configuration for multiple applications.
+
+The paths that may or must not trigger `Freight` production may be specified
+using a combination of the `includePaths` and `excludePaths` fields of a Git
+repository subscription.
+
+The following example demonstrates a `Warehouse` with a Git repository
+subscription that will only produce new `Freight` when the latest commit
+(selected by the applicable commit selection strategy) contains changes in the
+`apps/guestbook` directory since the last piece of `Freight` produced by the
+`Warehouse`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Warehouse
+metadata:
+ name: my-warehouse
+ namespace: kargo-demo
+spec:
+ subscriptions:
+ - git:
+ repoURL: https://github.com/example/kargo-demo.git
+ includePaths:
+ - apps/guestbook
+```
+
+The next example demonstrates the opposite: a `Warehouse` with a Git repository
+subscription that will only produce new `Freight` when the latest commit
+(selected by the applicable commit selection strategy) contains changes to paths
+_other than_ the repository's `docs/` directory:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Warehouse
+metadata:
+ name: my-warehouse
+ namespace: kargo-demo
+spec:
+ subscriptions:
+ - git:
+ repoURL: https://github.com/example/kargo-demo.git
+ excludePaths:
+ - docs
+```
+
+`includePaths` and `excludePaths` may be combined to include a broad set of
+paths and then exclude a subset of those. The following example demonstrates a
+`Warehouse` with a Git repository subscription that will only produce new
+`Freight` when the latest commit (selected by the applicable commit selection
+strategy) contains changes _within_ the `apps/guestbook` directory _other than_
+the `apps/guestbook/README.md`:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Warehouse
+metadata:
+ name: my-warehouse
+ namespace: kargo-demo
+spec:
+ subscriptions:
+ - git:
+ repoURL: https://github.com/example/kargo-demo.git
+ includePaths:
+ - apps/guestbook
+ excludePaths:
+ - apps/guestbook/README.md
+```
+
+:::note
+It is important to understand that new `Freight` will be produced when the
+latest commit (selected by the applicable commit selection strategy) contains
+_even a single change_ that is:
+
+1. Implicitly included via undefined `includePaths`.
+
+ OR
+
+ Explicitly included via `includePaths`.
+
+ AND
+
+2. Not explicitly excluded via `excludePaths`.
+:::
+
+:::info
+By default, the strings in the `includePaths` and `excludePaths` fields are
+treated as exact paths to files or directories. (Selecting a directory will
+implicitly select all paths within that directory.)
+
+Paths may _also_ be specified using glob patterns (by prefixing the string with
+`glob:`) or regular expressions (by prefixing the string with `regex:` or
+`regexp:`).
+:::
+
+### `Promotion` Resources
+
+Each Kargo promotion is represented by a Kubernetes resource of type
+`Promotion`.
+
+A `Promotion` resource's two most important fields are its `spec.freight` and
+`spec.stage` fields, which respectively identify a piece of `Freight` and a
+target `Stage` to which that `Freight` should be promoted.
+
+`Promotions` are, in some cases, created automatically by Kargo. In other cases,
+they are created manually by users. In either case, a `Promotion` resource
+resembles the following:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Promotion
+metadata:
+ name: 47b33c0c92b54439e5eb7fb80ecc83f8626fe390-to-test
+ namespace: kargo-demo
+spec:
+ stage: test
+ freight: 47b33c0c92b54439e5eb7fb80ecc83f8626fe390
+```
+
+:::info
+The name in a `Promotion`'s `metadata.name` field is inconsequential. Only
+the `spec` matters.
+:::
+
+When a `Promotion` has concluded -- whether successfully or unsuccessfully --
+the `Promotion`'s `status` field is updated to reflect the outcome. For example:
+
+```yaml
+status:
+ phase: Succeeded
+```
+
+## Role-Based Access Control
+
+As with all resource types in Kubernetes, permissions to perform various actions
+on resources of different types are governed by
+[RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/).
+
+For all Kargo resource types, Kubernetes RBAC functions exactly as one would
+expect, with one notable exception.
+
+Often, it is necessary to grant a user permission to create `Promotion`
+resources that reference certain `Stage` resources, but not others. To address
+this, Kargo utilizes an admission control webhook that conducts access reviews
+to determine if a user creating a `Promotion` resource has the virtual `promote`
+verb for the `Stage` referenced by the `Promotion` resource.
+
+:::info
+[This blog post](https://blog.aquasec.com/kubernetes-verbs) is an excellent
+primer on virtual verbs in Kubernetes RBAC.
+:::
+
+The following `Role` resource describes permissions to create `Promotion`
+references that reference the `uat` `Stage` only:
+
+```yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: uat-promoter
+ namespace: kargo-demo
+rules:
+- apiGroups:
+ - kargo.akuity.io
+ resources:
+ - promotions
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+- apiGroups:
+ - kargo.akuity.io
+ resources:
+ - stages
+ resourceNames:
+ - uat
+ verbs:
+ - promote
+```
+
+To grant a fictional user `alice`, in the QA department, the ability to promote
+to `uat` only, create a corresponding `RoleBinding`:
+
+```yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: alice-uat-promoter
+ namespace: kargo-demo
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: uat-promoter
+subjects:
+- kind: User
+ name: alice
+```
diff --git a/docs/versioned_docs/version-1.1/20-quickstart.md b/docs/versioned_docs/version-1.1/20-quickstart.md
new file mode 100644
index 000000000..f37187b65
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/20-quickstart.md
@@ -0,0 +1,980 @@
+---
+description: Learn about Kargo by progressing a change through multiple stages in a local Kubernetes cluster
+sidebar_label: Quickstart
+---
+
+# Kargo Quickstart
+
+This guide presents a basic introduction to Kargo. Together, we will:
+
+1. Install Kargo and its dependencies into an existing, local Kubernetes
+ cluster.
+
+ OR
+
+ Create a new local Kubernetes cluster with Kargo and its dependencies
+ already installed.
+
+1. Demonstrate how Kargo can progress changes through multiple stages by
+ interacting with your GitOps repository and Argo CD `Application` resources.
+
+1. Clean up.
+
+:::info
+If you're looking to contribute to Kargo, you may wish to consult the
+[contributor guide](./contributor-guide) instead.
+:::
+
+## Starting a Local Cluster
+
+Any of the following approaches require [Helm](https://helm.sh/docs/) v3.13.1 or
+greater to be installed.
+
+
+
+
+If you are a
+[Docker Desktop](https://www.docker.com/products/docker-desktop/)
+user, you can follow
+[these instructions](https://docs.docker.com/desktop/kubernetes/) to enable
+its built-in Kubernetes support.
+
+:::info
+Although this is one of the fastest paths to a local Kubernetes cluster, be
+aware that Docker Desktop supports only a _single_ Kubernetes cluster. If
+that cluster reaches a state you are dissatisfied with, resetting it will
+remove not just Kargo-related resources, but _all_ your workloads and data.
+:::
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/main/hack/quickstart/install.sh | sh
+```
+
+
+
+
+[OrbStack](https://orbstack.dev/) is a fast, lightweight, drop-in replacement
+for Docker Desktop for Mac OS only. You can follow
+[these instructions](https://docs.orbstack.dev/kubernetes/) to enable its
+built-in Kubernetes support.
+
+:::info
+Although this is one of the fastest paths to a local Kubernetes cluster, be
+aware that OrbStack supports only a _single_ Kubernetes cluster. If
+that cluster reaches a state you are dissatisfied with, resetting it will
+remove not just Kargo-related resources, but _all_ your workloads and data.
+:::
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/main/hack/quickstart/install.sh | sh
+```
+
+
+
+
+If you have any Docker-compatible container runtime installed (including native
+Docker, Docker Desktop, or OrbStack), you can easily launch a disposable cluster
+just for this quickstart using
+[kind](https://kind.sigs.k8s.io/#installation-and-usage).
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/main/hack/quickstart/kind.sh | sh
+```
+
+:::info
+While this option is a bit more complex than using Docker Desktop or OrbStack
+directly, it offers the advantage of being fully-disposable. If your cluster
+reaches a state you are dissatisfied with, you can simply destroy it and
+launch a new one.
+:::
+
+
+
+
+If you have any Docker-compatible container runtime installed (including native
+Docker, Docker Desktop, or OrbStack), you can easily launch a disposable cluster
+just for this quickstart using [k3d](https://k3d.io).
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/main/hack/quickstart/k3d.sh | sh
+```
+
+:::info
+While this option is a bit more complex than using Docker Desktop or OrbStack
+directly, it offers the advantage of being fully-disposable. If your cluster
+reaches a state you are dissatisfied with, you can simply destroy it and
+launch a new one.
+:::
+
+
+
+
+:::info
+If you are averse to piping a downloaded script directly into a shell, please
+feel free to download the applicable script and inspect its contents prior to
+execution.
+
+Any approach you select should only:
+
+1. Launch a new, local Kubernetes cluster, if applicable
+1. Install cert-manager
+1. Install Argo CD
+1. Install Argo Rollouts
+1. Install Kargo
+
+:::
+
+
+
+
+:::note
+If Kargo installation fails with a `401`, verify that you are using Helm v3.13.1
+or greater.
+
+If Kargo installation fails with a `403`, it is likely that Docker is configured
+to authenticate to `ghcr.io` with an expired token. The Kargo chart and images
+are accessible anonymously, so this issue can be resolved simply by logging out:
+
+```shell
+docker logout ghcr.io
+```
+
+:::
+
+At the end of this process:
+
+* The Argo CD dashboard will be accessible at [localhost:31443](https://localhost:31443).
+
+ The username and password are both `admin`.
+
+* The Kargo dashboard will be accessible at [localhost:31444](https://localhost:31444).
+
+ The admin password is `admin`.
+
+* You can safely ignore all cert errors for both of the above.
+
+## Create a GitOps Repository
+
+Let's begin by creating a repository on GitHub to house variations of our
+application manifests for three different stages of a sample application: test,
+UAT, and production.
+
+1. Visit https://github.com/akuity/kargo-demo and fork the repository into your
+ own GitHub account.
+
+1. You can explore the repository and see that the `main` branch contains common
+ configuration in a `base/` directory as well as stage-specific overlays in
+ paths of the form `stages//`.
+
+ :::note
+ This layout is typical of a GitOps repository using
+ [Kustomize](https://kustomize.io/) for configuration management and is not
+ at all Kargo-specific.
+
+ Kargo also works just as well with [Helm](https://helm.sh).
+ :::
+
+1. We'll be using it later, so save the location of your GitOps repository in an
+ environment variable:
+
+ ```shell
+ export GITOPS_REPO_URL=
+ ```
+
+## Create Argo CD Application Resources
+
+In this step, we will use an Argo CD `ApplicationSet` resource to create and
+manage three Argo CD `Application` resources that deploy the sample application
+at three different stages of its lifecycle, with three slightly different
+configurations, to three different namespaces in our local cluster:
+
+```shell
+cat <
+ export GITHUB_PAT=
+ ```
+
+1. Next, we'll create several Kargo resources:
+
+ * A `Project`, which, when reconciled, will effect all boilerplate project
+ initialization, including the creation of a specially-labeled `Namespace`
+ with the same name as the `Project`
+
+ * A `Secret` containing credentials for our GitOps repository
+
+ * A `Warehouse` that subscribes to a container image repository
+
+ * Three `Stage` resources -- `test`, `uat`, and `prod`
+
+ Although we will use Kargo's UI throughout most of this quickstart, with the
+ amount of configuration we're about to create, it is easiest to do it
+ declaratively using either `kubectl` or the `kargo` CLI.
+
+ :::info
+ For demo purposes, using `kubectl` is the quickest way to declaratively
+ define your first `Project`. The `kargo` CLI, however, does offer
+ Kargo-specific functionality, and for Kargo users who lack direct access to
+ the underlying cluster, it also offers authentication via OpenID Connect.
+ You might consider choosing this option below if you wish to become more
+ familiar with it.
+ :::
+
+
+
+
+ To create Kargo resources, use the following command:
+
+ ```shell
+ cat <
+
+
+
+ Install the Kargo CLI:
+
+
+
+
+ ```shell
+ arch=$(uname -m)
+ [ "$arch" = "x86_64" ] && arch=amd64
+ curl -L -o kargo https://github.com/akuity/kargo/releases/latest/download/kargo-"$(uname -s | tr '[:upper:]' '[:lower:]')-${arch}"
+ chmod +x kargo
+ ```
+
+ Then move `kargo` to a location in your file system that is included in the
+ value of your `PATH` environment variable.
+
+
+
+
+ ```shell
+ Invoke-WebRequest -URI https://github.com/akuity/kargo/releases/latest/download/kargo-windows-amd64.exe -OutFile kargo.exe
+ ```
+
+ Then move `kargo.exe` to a location in your file system that is included in the value
+ of your `PATH` environment variable.
+
+
+
+
+ Log in:
+
+ ```shell
+ kargo login https://localhost:31444 \
+ --admin \
+ --password admin \
+ --insecure-skip-tls-verify
+ ```
+
+ To create Kargo resources, use the following command:
+
+ ```shell
+ cat <
+
+
+1. Navigate to the [Kargo Dashboard](https://localhost:31444/):
+
+ 1. Log in using the password `admin`.
+
+ This will take you to a list of `Project`s. It currently includes only
+ the one created in the previous step.
+
+ ![Kargo-dashboard](./assets/kargo-projects.png)
+
+ 1. Select kargo-demo:
+
+ Here you can see a detailed overview of the `Project` we previously
+ created. It includes:
+
+ * An interactive, visual representation of your pipeline, composed of:
+ * A container image repository.
+ * A `Warehouse` that discovers new images as they are pushed to the
+ repository.
+ * Three `Stage`s representing distinct instances of our demo
+ application.
+
+ ![Kargo-dashboard-screenshot](./assets/kargo-dashboard-projects.png)
+
+ * An interactive Freight Timeline with `Freight` ordered
+ chronologically, with newer `Freight` to the left and older `Freight` to
+ the right.
+
+ ![Kargo-Freight-Timeline](./assets/kargo-frieght-timeline.png)
+
+1. After a few seconds, a piece of `Freight` should appear in the Freight
+ Timeline, if it isn't there already.
+
+ :::note
+ Note that the timeline _may_ not refresh automatically and you may need to
+ refresh the page to see new `Freight`.
+
+ This inconvenience will be addressed in a forthcoming update.
+ :::
+
+ :::info
+ `Freight` is a set of references to one or more versioned artifacts, which
+ may include:
+
+ * Container images (from image repositories)
+
+ * Kubernetes manifests (from Git repositories)
+
+ * Helm charts (from chart repositories)
+
+ This introductory example has `Freight` that references only a specific
+ version of the `public.ecr.aws/nginx/nginx` container image.
+ :::
+
+## Your First Promotion
+
+1. To promote `Freight` to the `test` `Stage`, select the target icon on the
+ left border of test:
+
+ ![Kargo-Promote](./assets/kargo-promote-option.png)
+
+ Next, select the `Freight` from the Freight Timeline and confirm
+ the promotion by selecting Yes:
+
+ ![Kargo-Promote](./assets/kargo-promote-option-2.png)
+
+ When promotion process is complete, you'll see a check mark next to
+ test, indicating that the promotion was successful.
+
+ ![Kargo-dashboard-screenshot](./assets/kargo-dashboard-promotion.png)
+
+ Following the promotion, health checks will run periodically. When a `Stage`
+ is in a healthy state, this will be reflected with a heart icon. You can
+ also verify the status by visiting the test instance of the demo application
+ at [localhost:30081](http://localhost:30081).
+
+ The Freight Timeline will also automatically update following the
+ promotion. It is color-coded to indicate which `Stage`s are actively using
+ each piece of `Freight`.
+
+1. Select the test to reveal additional details about the `Stage`
+ including its status, current `Freight`, and history.
+
+1. Select the `Freight` from the Freight Timeline to reveal
+ additional details. Importantly, you can see that (by virtue of the `test`
+ `Stage` having achieved a healthy state) the `Freight` is now _verified_ in
+ `test`, which designates it as eligible for promotion to the next `Stage` --
+ in our case, `uat`.
+
+ ![Kargo-Freight-Verified](./assets/kargo-freight-verified.png)
+
+ :::note
+ Although this example does not demonstrate it, it is also possible to verify
+ the `Freight` in a `Stage` using user-defined processes. See the
+ [relevant section](./15-concepts.md#verifications) of the concepts page to
+ learn more.
+ :::
+
+## Behind the Scenes
+
+So what has Kargo done behind the scenes?
+
+Visiting our fork of https://github.com/akuity/kargo-demo, we will see that
+Kargo has recently created a `stage/test` branch for us. It has taken the latest
+manifests from the `main` branch as a starting point, run `kustomize edit set
+image` and `kustomize build` within the `stages/test/` directory, and written
+the resulting manifests to a stage-specific branch -- the same branch referenced
+by the `test` Argo CD `Application`'s `targetRevision` field.
+
+:::info
+Although not required for all uses cases, using stage-specific branches is a
+practice highly recommended by the Kargo team.
+:::
+
+## Promote to UAT and then Production
+
+Unlike our `test` `Stage`, which subscribes directly to an image repository,
+our `uat` and `prod` `Stage`s both subscribe to other, _upstream_ `Stage`s,
+thereby forming a _pipeline_:
+
+1. `uat` subscribes to `test`
+1. `prod` subscribes to `uat`.
+
+We leave it as an exercise to the reader to use the dashboard to progress the
+`Freight` from `test` to `uat` and again from `uat` to `prod`.
+
+:::info
+The `uat` and `prod` instances of our site should be accessible at:
+
+* `uat`: [localhost:30082](http://localhost:30082)
+* `prod`: [localhost:30083](http://localhost:30083)
+:::
+
+:::info
+It is possible to automate promotion of new, qualified `Freight` for designated
+`Stage`s and also possible to used RBAC to limit who can trigger manual
+promotions for each `Stage`, however, both these topics are beyond the scope of
+this introduction.
+:::
+
+## Cleaning up
+
+Congratulations! You've just gotten hands on with Kargo for the first time!
+
+Now let's clean up!
+
+
+
+
+Docker Desktop supports only a _single_ Kubernetes cluster. If you are
+comfortable deleting not just just Kargo-related resources, but _all_ your
+workloads and data, the cluster can be reset from the Docker Desktop
+Dashboard.
+
+If, instead, you wish to preserve non-Kargo-related workloads and data, you
+will need to manually uninstall Kargo and its prerequisites:
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/main/hack/quickstart/uninstall.sh | sh
+```
+
+
+
+
+OrbStack supports only a _single_ Kubernetes cluster. If you are
+comfortable deleting not just just Kargo-related resources, but _all_ your
+workloads and data, you can destroy the cluster with:
+
+```shell
+orb delete k8s
+```
+
+If, instead, you wish to preserve non-Kargo-related workloads and data, you
+will need to manually uninstall Kargo and its prerequisites:
+
+```shell
+curl -L https://raw.githubusercontent.com/akuity/kargo/main/hack/quickstart/uninstall.sh | sh
+```
+
+
+
+
+Simply destroy the cluster:
+
+```shell
+kind delete cluster --name kargo-quickstart
+```
+
+
+
+
+Simply destroy the cluster:
+
+```shell
+k3d cluster delete kargo-quickstart
+```
+
+
+
diff --git a/docs/versioned_docs/version-1.1/30-how-to-guides/10-installing-kargo.md b/docs/versioned_docs/version-1.1/30-how-to-guides/10-installing-kargo.md
new file mode 100644
index 000000000..47fc77fe8
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/30-how-to-guides/10-installing-kargo.md
@@ -0,0 +1,90 @@
+---
+description: Learn how to install Kargo using this step-by-step guide
+sidebar_label: Installing Kargo
+---
+
+# Installing Kargo
+
+## Basic Installation
+
+Installing Kargo with default configuration is quick and easy.
+
+You will need:
+
+* [Helm](https://helm.sh/docs/): These instructions were tested with v3.13.1.
+* A Kubernetes cluster with [cert-manager](https://cert-manager.io/),
+ [Argo CD](https://argo-cd.readthedocs.io), and
+ [Argo Rollouts](https://argoproj.github.io/argo-rollouts/)
+ pre-installed. These instructions were tested with:
+ * Kubernetes: v1.27.4
+ * cert-manager: v1.11.5
+ * Argo CD: v2.9.3
+ * Argo Rollouts: v1.6.4
+
+:::info
+`cert-manager` is used for self-signing a certificate used to identify Kargo's
+webhook server to the Kubernetes API server. If you do not wish to use
+`cert-manager` for this purpose, you may provision your own certificate through
+other means. Refer to the advanced installation section for more information.
+:::
+
+:::info
+We are working toward transitioning Argo CD and Argo Rollouts from required
+dependencies to _suggested_ dependencies.
+:::
+
+:::note
+If your Argo CD control plane manages multiple Kubernetes clusters, be advised
+that Kargo is intended to be installed into the same cluster as the Argo CD
+control plane and _not_ into the individual clusters that Argo CD is managing.
+:::
+
+The following command will install Kargo with default configuration and a
+user-specified admin password:
+
+```shell
+helm install kargo \
+ oci://ghcr.io/akuity/kargo-charts/kargo \
+ --namespace kargo \
+ --create-namespace \
+ --set api.adminAccount.passwordHash='$2a$10$Zrhhie4vLz5ygtVSaif6o.qN36jgs6vjtMBdM6yrU1FOeiAAMMxOm' \
+ --set api.adminAccount.tokenSigningKey=iwishtowashmyirishwristwatch \
+ --wait
+```
+
+:::caution
+If deploying to an internet-facing cluster, be certain to do one of the
+following:
+
+* Disable the admin account with `--set api.adminAccount.enabled=false`
+
+* Choose your own strong password and signing key.
+:::
+
+## Advanced Installation
+
+1. Extract the default values from the Helm chart and save it to a convenient
+ location. In the example below, we save it to `~/kargo-values.yaml`
+
+ ```shell
+ helm inspect values \
+ oci://ghcr.io/akuity/kargo-charts/kargo > ~/kargo-values.yaml
+ ```
+
+1. Edit and save the values.
+
+ :::info
+ You will find this configuration file contains helpful comments for every
+ option, so specific options are not covered in detail here.
+ :::
+
+1. Proceed with installation, using your modified values:
+
+ ```shell
+ helm install kargo \
+ oci://ghcr.io/akuity/kargo-charts/kargo \
+ --namespace kargo \
+ --create-namespace \
+ --values ~/kargo-values.yaml \
+ --wait
+ ```
diff --git a/docs/versioned_docs/version-1.1/30-how-to-guides/11-working-with-projects.md b/docs/versioned_docs/version-1.1/30-how-to-guides/11-working-with-projects.md
new file mode 100644
index 000000000..7e3ca6e46
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/30-how-to-guides/11-working-with-projects.md
@@ -0,0 +1,110 @@
+---
+description: Learn how to work effectively with Projects
+sidebar_label: Working with Projects
+---
+
+# Working with Projects
+
+Each Kargo project is represented by a cluster-scoped Kubernetes resource of
+type `Project`. Reconciliation of such a resource effects all boilerplate
+project initialization, including the creation of a specially-labeled
+`Namespace` with the same name as the `Project`. All resources belonging to a
+given `Project` should be grouped together in that `Namespace`.
+
+A minimal `Project` resource looks like the following:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Project
+metadata:
+ name: example
+```
+
+:::note
+Deletion of a `Project` resource results in the deletion of the corresponding
+`Namespace`. For convenience, the inverse is also true -- deletion of a
+project's `Namespace` results in the deletion of the corresponding `Project`
+resource.
+:::
+
+:::info
+There are compelling advantages to using `Project` resources instead of
+permitting users to create `Namespace` resources directly:
+
+* The required label indicating a `Namespace` is a Kargo project cannot be
+forgotten or misapplied.
+
+* Users can be granted permission to indirectly create `Namespace` resources for
+Kargo projects _only_ without being granted more general permissions to create
+_any_ new `Namespace` directly.
+
+* Boilerplate configuration is automatically created at the time of `Project`
+creation. This includes things such as project-level RBAC resources and
+`ServiceAccount` resources.
+:::
+
+## Promotion Policies
+
+A `Project` resource can additionally define project-level configuration. At
+present, this only includes **promotion policies** that describe which `Stage`s
+are eligible for automatic promotion of newly available `Freight`.
+
+:::note
+Promotion policies are defined at the project-level because users with
+permission to update `Stage` resources in a given project `Namespace` may _not_
+have permission to create `Promotion` resources. Defining promotion policies at
+the project-level therefore restricts such users from enabling automatic
+promotions for a `Stage` to which they may lack permission to promote to
+manually. It leaves decisions about eligibility for auto-promotion squarely in
+the hands of someone like a "project admin."
+:::
+
+In the example below, the `test` and `uat` `Stage`s are eligible for automatic
+promotion of newly available `Freight`, but any other `Stage`s in the `Project`
+are not:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Project
+metadata:
+ name: example
+spec:
+ promotionPolicies:
+ - stage: test
+ autoPromotionEnabled: true
+ - stage: uat
+ autoPromotionEnabled: true
+```
+
+## Namespace Adoption
+
+At times, `Namespace`s may require specific configuration to
+comply with regulatory or organizational requirements. To
+account for this, Kargo supports the adoption of pre-existing
+`Namespace`s that are labeled with `kargo.akuity.io/project: "true"`.
+This enables pre-configuring such `Namespace`s according to your
+own requirements.
+
+:::info
+Requiring a `Namespace` to have the `kargo.akuity.io/project: "true"` label to be eligible for adoption by a new `Project` is intended to prevent accidental or willful hijacking of an existing `Namespace`.
+:::
+
+The following example demonstrates adoption of a `Namespace` that's been
+pre-configured with with a label unrelated to Kargo:
+
+```yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: example
+labels:
+ kargo.akuity.io/project: "true"
+ example.com/org: platform-eng
+---
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Project
+metadata:
+ name: example
+spec:
+ # ...
+```
diff --git a/docs/versioned_docs/version-1.1/30-how-to-guides/15-working-with-freight.md b/docs/versioned_docs/version-1.1/30-how-to-guides/15-working-with-freight.md
new file mode 100644
index 000000000..ac0c86a36
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/30-how-to-guides/15-working-with-freight.md
@@ -0,0 +1,209 @@
+---
+description: Learn how to work effectively with freight
+sidebar_label: Working with Freight
+---
+
+# Working With Freight
+
+**Freight** is an important Kargo concept. A single "piece of freight" is a set
+of references to one or more versioned artifacts, which may include one or more:
+
+* Container images (from image repositories)
+
+* Kubernetes manifests (from Git repositories)
+
+* Helm charts (from chart repositories)
+
+Freight can therefore be thought of as a sort of meta-artifact. Freight is what
+Kargo seeks to progress from one stage to another.
+
+:::info
+To learn the fundamentals of freight and the warehouses that produce freight,
+visit the [concepts doc](../concepts).
+:::
+
+The remainder of this page describes features of freight that will enable you
+to work more effectively.
+
+## Names
+
+Like all Kubernetes resources, Kargo `Freight` resources have a `metadata.name`
+field, which uniquely identifies each resource of that type within a given Kargo
+project (a specially labeled Kubernetes namespace). When a `Warehouse` produces
+a new `Freight` resource, it will compute a canonical representation of the
+artifacts referenced by that resource and use that, in turn, to compute a SHA-1
+hash. This becomes the value of the `metadata.name` field. The deterministic
+method of computing this value makes it a unique "fingerprint" of the
+collection of artifacts referenced by the `Freight` resource.
+
+## Aliases
+
+While the `metadata.name` field contains a predictably computed SHA-1 hash,
+such identifiers are, unarguably, not very user-friendly.
+To make `Freight` resources easier for human users to identify, `Warehouse`s
+automatically generate a human-friendly alias for every `Freight` resource they
+produce and apply it as the value of the `Freight` resource's
+`kargo.akuity.io/alias`
+[label](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/).
+
+:::info
+Generating aliases of the form `-` is a strategy borrowed
+from Docker, which generates similar names for containers not explicitly named
+by users.
+:::
+
+:::info
+Why a label?
+
+Kubernetes enforces the immutability of the `metadata.name` field for all
+resources.
+
+Kubernetes
+[labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/),
+by contrast, are both mutable and indexed, which makes them ideal for use as
+secondary identifiers.
+:::
+
+When using the Kargo CLI to query for `Freight` resources, the `alias` field is
+always displayed:
+
+```shell
+kargo get freight --project kargo-demo
+```
+
+Sample output:
+
+```shell
+NAME ALIAS AGE
+f5f87aa23c9e97f43eb83dd63768ee41f5ba3766 mortal-dragonfly 35s
+```
+
+It is also displayed when using `kubectl` to query for `Freight` resources:
+
+```shell
+kubectl get freight --namespace kargo-demo
+```
+
+Sample output:
+
+```shell
+NAME ALIAS AGE
+f5f87aa23c9e97f43eb83dd63768ee41f5ba3766 mortal-dragonfly 35s
+```
+
+:::info
+The Kargo UI, to make efficient use of screen real estate, displays aliases
+only, but a `Freight` resource's `name` can always be discovered by hovering
+over its alias.
+:::
+
+:::note
+Kargo CLI commands will accept `Freight` aliases as an alternative to a
+`Freight` name. Refer to the help text for the `kargo` command for more
+information.
+:::
+
+### Updating Aliases
+
+While every `Freight` resource is automatically assigned an alias, users may
+sometimes wish to override that alias with one of their own choosing. This can
+make it easier to identify a particularly important (or problematic) `Freight`
+resource as it progresses through the `Stage`s of a pipeline.
+
+This is conveniently accomplished via the Kargo CLI:
+
+```shell
+kargo update freight \
+ --project=kargo-demo \
+ --name=f5f87aa23c9e97f43eb83dd63768ee41f5ba3766 \
+ --new-alias=frozen-tauntaun
+```
+Alternatively, you can reference the `Freight` to which you want to assign a new alias using its existing alias:
+
+```shell
+kargo update freight \
+ --project=kargo-demo \
+ --old-alias=mortal-dragonfly \
+ --new-alias=frozen-tauntaun
+```
+
+This can also be accomplished via `kubectl` commands `apply`, `edit`, `patch`,
+etc. by updating the `alias` field of the `Freight` resource.
+
+:::info
+The `alias` field is a convenient way to update the `Freight` resource's
+`kargo.akuity.io/alias` label, which causes a webhook to sync the field value
+to the label value. The precedence rules for syncing between the field and
+label values are as follows:
+
+- If the field has a non-empty value, the label will assume the field's value.
+- If the field has an empty value, the field will assume the label's value.
+
+It's worth noting that removing an alias entirely requires clearing both the
+field and label values, but this is expected to be a rare occurrence.
+:::
+
+## Manual Approvals
+
+The [concepts doc](../concepts#verifications) describes the
+usual process by which `Freight` resources are _verified_ at each `Stage` in a
+pipeline before becoming available to the next `Stage` or `Stage`s. In brief, it
+typically requires the `Stage` to reach a healthy state _and_, if applicable,
+any user-defined verification processes to complete with favorable results.
+
+This is suitable for the average case wherein a new `Freight` resource is
+expected to traverse the entirety of a pipeline on its way to production,
+however, it is nearly inevitable that the occasional need for a "hotfix" will
+arise, in which case it may sometimes be desirable to bypass one or more
+`Stage`s in the pipeline.
+
+To enable this, Kargo provides the ability to manually approve a `Freight`
+resource for promotion to any given `Stage`. This is conveniently accomplished
+via the Kargo CLI:
+
+```shell
+kargo approve \
+ --freight f5f87aa23c9e97f43eb83dd63768ee41f5ba3766 \
+ --stage prod \
+ --project kargo-demo
+```
+
+:::note
+Manual approvals cannot be granted via `kubectl` due to technical factors
+preventing `kubectl` from updating `status` subresources of Kargo resources.
+:::
+
+:::note
+Manually granting approval for a `Freight` resource to be promoted to any given
+`Stage` requires the same level of permissions as would be required to carry out
+that promotion, although, granting manual approval does _not_ automatically
+create a corresponding `Promotion` resource.
+:::
+
+After successfully granting manual approval for a `Freight` resource to be
+promoted to a given `Stage`, the `Freight` resource's `status` field will
+reflect that approval.
+
+The following depicts a `Freight` resource that has been verified in a `test`
+`Stage` through the usual process, but has been manually approved for promotion
+to the `prod` `Stage`. i.e. Any `Stage`s between `test` and `prod` may be
+bypassed.
+
+```shell
+kargo get freight \
+ --project kargo-demo \
+ --output jsonpath-as-json={.status}
+```
+
+```shell
+[
+ {
+ "approvedFor": {
+ "prod": {}
+ },
+ "verifiedIn": {
+ "test": {}
+ }
+ }
+]
+```
diff --git a/docs/versioned_docs/version-1.1/30-how-to-guides/20-managing-credentials.md b/docs/versioned_docs/version-1.1/30-how-to-guides/20-managing-credentials.md
new file mode 100644
index 000000000..65601e9de
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/30-how-to-guides/20-managing-credentials.md
@@ -0,0 +1,630 @@
+---
+description: Find out how to manage repository credentials for use by Kargo
+sidebar_label: Managing Credentials
+---
+
+# Managing Credentials
+
+To manage the progression of Freight from Stage to Stage, Kargo will often
+require read/write permissions on private GitOps repositories and read-only
+permissions on private container image and/or Helm chart repositories.
+
+This section presents an overview of how these credentials can be managed.
+
+## Credentials as Kubernetes `Secret` Resources
+
+:::caution
+Kargo formerly borrowed its general credential-management approach from Argo CD,
+but has since diverged.
+:::
+
+Kargo expects any credentials it requires to have been stored as specially
+labeled Kubernetes `Secret` resources containing specially-formatted data. These
+`Secret`s take the following form:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name:
+ namespace:
+ labels:
+ kargo.akuity.io/cred-type: image
+stringData:
+ repoURL:
+ username:
+ password:
+```
+
+The `name` of such a `Secret` is inconsequential and may follow any convention
+preferred by the user.
+
+:::info
+Kargo uses Kubernetes `Namespace`s to mark project boundaries. `Secret`s
+representing credentials will typically exist in the same `Namespace` as the
+`Stage` resources that will require them. There are exceptions to this, which
+are covered in the next section.
+:::
+
+The label key `kargo.akuity.io/cred-type` and its value, one of `git`, `helm`,
+or `image`, is important, as it designates the `Secret` as representing
+credentials for a Git repository, a Helm chart repository, or a container image
+repository, respectively.
+
+The `Secret`'s `data` field (set above using plaintext in the `stringData`
+field), MUST contain the following keys:
+
+* `repoURL`: The full URL of the repository the credentials are for.
+
+* Either:
+
+ * `username`: The username to use when authenticating to the repository.
+
+ * `password`: A password or personal access token.
+
+ :::info
+ If the value of the `password` key is a personal access token, the value of
+ the `username` field may be inconsequential. You should consult your
+ repository's documentation for more information.
+ :::
+
+ OR:
+
+ * `sshPrivateKey`: A PEM-encoded SSH private key. Applicable to Git
+ repositories only.
+
+
+Optionally, the following keys may also be included:
+
+* `repoURLIsRegex`: Set this to `true` if the value of the `repoURL` key
+ is a regular expression. Any other value of this key or the absence of this
+ key is interpreted as `false`.
+
+:::note
+When Kargo searches for repository credentials in a project `Namespace`, it
+_first_ checks all appropriately labeled `Secret`s for a `repoURL` value
+matching the repository URL exactly. Only if no `Secret` is an exact match does
+it check all appropriately labeled `Secret`s for a `repoURL` value containing a
+regular expression matching the repository URL.
+
+When searching for an exact match, and again when searching for a pattern match,
+appropriately labeled `Secret`s are considered in lexical order by name.
+:::
+
+:::caution
+Only username/password (or personal access token) authentication is
+supported at this time. Others are likely to be added in the future.
+:::
+
+## Global Credentials
+
+In cases where one or more sets of credentials are needed widely across _all_
+Kargo projects, the administrator/operator installing Kargo may opt-in to
+designating one or more `Namespace`s as homes for "global" credentials using the
+`controller.globalCredentials.namespaces` setting in Kargo's Helm chart.
+Refer to
+[the advanced section of the installation guide](./10-installing-kargo.md#advanced-installation)
+for more details.
+
+:::note
+Operators must manually ensure Kargo controllers receive read-only access
+to `Secret`s in the designated namespaces. For example, if `kargo-global-creds`
+is designated as a global credentials namespace, the following `RoleBinding`
+should be created within that `Namespace`:
+
+```yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: kargo-controller-read-secrets
+ namespace: kargo-global-creds
+subjects:
+ - kind: ServiceAccount
+ name: kargo-controller
+ namespace: kargo
+roleRef:
+ kind: ClusterRole
+ name: kargo-controller-read-secrets
+ apiGroup: rbac.authorization.k8s.io
+```
+:::
+
+:::info
+By default, Kargo controllers lack cluster-wide permissions on `Secret`
+resources. Instead, the Kargo _management controller_ dynamically expands
+controller access to `Secret`s on a namespace-by-namespace basis as new
+`Project`s are created.
+
+_It is because this process does not account for "global" credential namespaces
+that these bindings must be created manually by an operator._
+:::
+
+:::warning
+Setting `controller.serviceAccount.clusterWideSecretReadingEnabled` setting to
+`true` during Kargo installation will grant Kargo controllers cluster-wide read
+permission on `Secret` resources.
+
+__This is highly discouraged, especially in sharded environments where this
+permission would have the undesirable effect of granting remote Kargo
+controllers read permissions on all `Secret`s throughout the Kargo control
+plane's cluster -- including `Secret`s having nothing to do with Kargo.__
+:::
+
+:::note
+Any matching credentials (exact match _or_ pattern match) found in a project's
+own `Namespace` take precedence over those found in any global credentials
+`Namespace`.
+
+When Kargo searches for repository credentials in global credentials
+`Namespace`s, it _first_ checks all appropriately labeled `Secret`s for a
+`repoURL` value matching the repository URL exactly. Only if no `Secret` is an
+exact match does it check all appropriately labeled `Secret`s for a
+`repoURL` value containing a regular expression matching the repository URL.
+
+When searching for an exact match, and again when searching for a pattern match,
+appropriately labeled `Secret`s are considered in lexical order by name.
+
+When Kargo is configured with multiple global credentials `Namespace`s, they are
+searched in lexical order by name. Only after no exact match _and_ no pattern
+match is found in one global credentials `Namespace` does Kargo search the next.
+:::
+
+## Managing Credentials with the CLI
+
+The Kargo CLI can be used to manage credentials in a project's `Namespace.`
+
+The following example creates credentials for a Git repository:
+
+```shell
+kargo create credentials --project kargo-demo my-credentials \
+ --git --repo-url https://github.com/example/kargo-demo.git \
+ --username my-username --password my-my-personal-access-token
+```
+
+```shell
+secret/my-credentials created
+```
+
+:::caution
+If you do not wish for your password or personal access token to be stored
+in your shell history, you may wish to omit the `--password` flag, in which
+case the CLI will prompt you to enter the password interactively.
+:::
+
+Credentials can be listed or viewed with `kargo get credentials`:
+
+```shell
+kargo get credentials --project kargo-demo my-credentials
+```
+
+```shell
+NAME TYPE REGEX REPO AGE
+my-credentials git false https://github.com/example/kargo-demo.git 8m25s
+```
+
+If requesting output as YAML or JSON, passwords and other potentially sensitive
+information will be redacted.
+
+```shell
+kargo get credentials --project kargo-demo my-credentials -o yaml
+```
+
+```shell
+apiVersion: v1
+kind: Secret
+metadata:
+ creationTimestamp: "2024-05-30T20:02:46Z"
+ labels:
+ kargo.akuity.io/cred-type: git
+ name: my-credentials
+ namespace: kargo-demo
+ resourceVersion: "17614"
+ uid: ca2660e4-867d-4709-b1a7-57fbb93fc6dc
+stringData:
+ password: '*** REDACTED ***'
+ repoURL: https://github.com/example/kargo-demo.git
+ username: my-username
+type: Opaque
+```
+
+Credentials can be updated using the `kargo update credentials` command and
+the flags corresponding to attributes of the credential that you wish to modify.
+Other attributes of the credentials will remain unchanged.
+
+The following example updates `my-credentials` with a regular expression for the
+repository URL:
+
+```shell
+kargo update credentials --project kargo-demo my-credentials \
+ --repo-url '^http://github.com/' --regex
+```
+
+```shell
+secret/my-credentials updated
+```
+
+And credentials can, of course, be deleted with `kargo delete credentials`:
+
+```shell
+kargo delete credentials --project kargo-demo my-credentials
+```
+
+```shell
+secret/my-credentials deleted
+```
+
+:::note
+While the CLI may be a fine way of managing project-level credentials whilst
+getting to know Kargo, it is unquestionably more secure to use other means to
+ensure the existence of these specially-formatted `Secret`s in the appropriate
+project `Namespace`s.
+:::
+
+## Git Provider-Specific Authentication Options
+
+This section provides Git provider-specific guidance on credential management.
+
+### GitHub
+
+#### Personal Access Token
+
+GitHub supports authentication using a
+[personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens),
+which can be used in place of a password. The corresponding username must be
+the GitHub handle of the user who created the token. These can be stored in
+the `username` and `password` fields of a `Secret` resource as described
+[in the first section](#credentials-as-kubernetes-secret-resources) of this
+document.
+
+:::info
+This method of authentication may be best when wishing to rigorously enforce
+the principle of least privilege, as personal access tokens can be scoped to
+specific permissions on specific repositories.
+
+A drawback to this method, however, is that the token is owned by a specific
+GitHub user, and if that user should lose their own access to the repositories
+in question, Kargo will also lose access.
+:::
+
+#### GitHub App Authentication
+
+[GitHub Apps](https://docs.github.com/en/apps) can be used
+[as an authentication method](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/about-authentication-with-a-github-app).
+
+1. [Create a GitHub App](https://github.com/settings/apps/new):
+
+ 1. In the GitHub App name field, specify a unique
+ name.
+ 1. Set the Homepage URL to any URL you like.
+ 1. Under Webhook, de-select
+ Active.
+ 1. Under Permissions → Repository
+ permissions → Contents, select whether
+ the App will require Read-only or Read
+ and write permissions. _The App will receive these
+ permissions on all repositories into which it is installed._
+ 1. Under Where can this GitHub App be installed?,
+ leave Only on this account selected.
+ 1. Click Create GitHub App.
+ 1. Take note of the App ID.
+ 1. Scroll to the bottom of the page and click Generate a private
+ key. The resulting key will be downloaded immediately. Store
+ it securely.
+ 1. On the left-hand side of the page, click Install
+ App.
+ 1. Choose an account to install the App into by clicking
+ Install.
+ 1. Select Only select repositories and choose the
+ repositories you wish to grant the App access to. Remember that the App
+ will receive the permissions you selected earlier on _all_ of these
+ repositories.
+ 1. Click Install.
+ 1. In your browser's address bar, take note of the numeric identifier at the
+ end of the current page's URL. This is the Installation
+ ID.
+
+2. Create a `Secret` resource with the following structure:
+
+ ```yaml
+ apiVersion: v1
+ kind: Secret
+ metadata:
+ name:
+ namespace:
+ labels:
+ kargo.akuity.io/cred-type: git
+ stringData:
+ githubAppID:
+ githubAppPrivateKey:
+ githubAppInstallationID:
+ repoURL:
+ repoURLIsRegex:
+ ```
+
+:::info
+Compared to personal access tokens, a benefit of authenticating with a GitHub
+App is that the App's permissions are not tied to a specific GitHub user.
+:::
+
+:::caution
+It is all too easy to violate the principle of least privilege when
+authenticating using this method.
+
+For convenience sake, it may be tempting to register a single GitHub App and
+select a broad set of repositories when installing that App into your
+organization. It may also be tempting to create a single set of
+[global credentials](#global-credentials) such that all Kargo projects can use
+them to access their repositories, _however_, this will have the undesirable
+effect of granting _all_ Kargo projects access to _all_ of the repositories
+selected when the App was installed.
+
+It is, instead, recommended to register a separate GitHub App for
+each Kargo project. When installing each App into your organization, only those
+repositories to which each Kargo project requires access should be selected.
+
+GitHub organizations are limited to registering 100 GitHub Apps, however, so
+this approach may not be feasible for organizations with many Kargo projects.
+:::
+
+:::caution
+A second way in which authentication using GitHub Apps may violate the principle
+of least privilege involves the fact that the same permissions are granted to
+the App on _all_ repositories that are selected when it is installed.
+
+If a Kargo project requires read-only access to one repository and read/write
+access to another, it is not possible to grant the App different permissions on
+the two. This may then lead to granting broader permissions than are strictly
+necessary.
+:::
+
+## Image Registry-Specific Authentication Options
+
+While many container image registries support authentication using long-lived
+credentials, such as a username and password (or personal access token), some
+either require or offer more secure options.
+
+This section provides registry-specific guidance on credential management and
+also covers options for gaining image repository access using workload identity
+on applicable platforms.
+
+### Amazon Elastic Container Registry (ECR)
+
+The authentication options described in this section are applicable only to
+container image repositories whose URLs indicate they are hosted in ECR.
+
+#### Long-Lived Credentials
+
+Elastic Container Registries do not _directly_ support long-lived credentials,
+however, an AWS access key ID and secret access key
+[can be used to obtain an authorization token](https://docs.aws.amazon.com/AmazonECR/latest/userguide/registry_auth.html#registry-auth-token)
+that is valid for 12 hours. Kargo can seamlessly obtain such a token and will
+cache it for a period of 10 hours.
+
+To use this option, your `Secret` should take the following form:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name:
+ namespace:
+ labels:
+ kargo.akuity.io/cred-type: image
+stringData:
+ awsAccessKeyID:
+ awsSecretAccessKey:
+ repoURL:
+```
+
+:::caution
+Following the principle of least privilege, the IAM user associated with the
+access key ID and secret access key should be limited only to read-only access
+to the required ECR repositories.
+:::
+
+:::caution
+This method of authentication is a "lowest common denominator" approach that
+will work regardless of where Kargo is deployed. i.e. if running Kargo outside EKS, this method will still work.
+
+If running Kargo within EKS, you may wish to either consider using EKS Pod Identity or IRSA
+instead.
+:::
+
+#### EKS Pod Identity or IAM Roles for Service Accounts (IRSA)
+
+If Kargo locates no `Secret` resources matching a repository URL and is deployed
+within an EKS cluster, it will attempt to use
+[EKS Pod Identity](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html)
+or
+[IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)
+to authenticate. Both of these rely upon some external setup. Leveraging either
+eliminates the need to store ECR credentials in a `Secret` resource.
+
+Follow
+[this overview](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html#pod-id-setup-overview)
+to set up EKS Pod Identity in your EKS cluster or
+[this one](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)
+to set up IRSA. For either, you will assign an IAM role to the
+`kargo-controller` `ServiceAccount` within the `Namespace` to which Kargo is (or
+will be) installed.
+
+:::note
+To use IRSA, you will additionally need to specify the
+[ARN](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html) of
+the controller's IAM role as the value of the
+`controller.serviceAccount.iamRole` setting in Kargo's Helm chart. Refer to
+[the advanced section of the installation guide](./10-installing-kargo.md#advanced-installation)
+for more details.
+:::
+
+
+At this point, an IAM role will be associated with the Kargo _controller_,
+however, that controller acts on behalf of multiple Kargo projects, each of
+which may require access to _different_ ECR repositories. To account for this,
+when Kargo attempts to access an ECR repository on behalf of a specific project,
+it will first attempt to
+[assume an IAM role](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html)
+specific to that project. The name of the role it attempts to assume will
+_always_ be of the form `kargo-project-`. It is this role that
+should be granted read-only access to applicable ECR repositories.
+
+:::info
+The name of the IAM role associated with each Kargo project is deliberately
+not configurable to prevent project admins from attempting to coerce Kargo into
+assuming arbitrary IAM roles.
+:::
+
+:::caution
+For optimal adherence to the principle of least permissions, the IAM role
+associated with the `kargo-controller` `ServiceAccount` should be limited only
+to the ability to assume project-specific IAM roles. Project-specific IAM roles
+should be limited only to read-only access to applicable ECR repositories.
+:::
+
+:::info
+If the Kargo controller is unable to assume a project-specific IAM role, it will
+fall back to using its own IAM role directly. For organizations without strict
+tenancy requirements, this can eliminate the need to manage a large number of
+project-specific IAM roles. While useful, this approach is not strictly
+recommended.
+:::
+
+Once Kargo is able to gain necessary permissions to access an ECR repository,
+it will follow a process similar to that described in the previous section to
+obtain a token that is valid for 12 hours and cached for 10.
+
+### Google Artifact Registry
+
+The authentication options described in this section are applicable only to
+container image repositories whose URLs indicate they are hosted in Google
+Artifact Registry.
+
+:::note
+Google Container Registry (GCR) has been deprecated in favor of Google Artifact
+Registry. For authentication to repositories with legacy GCR URLs, the same
+options outlined here may be applied.
+:::
+
+#### Long-Lived Credentials
+
+:::caution
+Google Artifact Registry does _directly_ support long-lived credentials
+[as described here](https://cloud.google.com/artifact-registry/docs/docker/authentication#json-key).
+The username `_json_key_base64` and the base64-encoded service account key
+may be stored in the `username` and `password` fields of a `Secret` resource as
+described [in the first section](#credentials-as-kubernetes-secret-resources) of
+this document. Kargo and Google both strongly discourage this method of
+authentication however.
+:::
+
+Google documentation recommends
+[using a service account key to obtain an access token](https://cloud.google.com/artifact-registry/docs/docker/authentication#token)
+that is valid for 60 minutes. Compared to the discouraged method of using the
+service account key to authenticate to the registry directly, this process does
+_not_ transmit the service account key over the wire. Kargo can seamlessly carry
+out this process and will cache the access token for a period of 40 minutes.
+
+To use this option, your `Secret` should take the following form:
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+ name:
+ namespace:
+ labels:
+ kargo.akuity.io/cred-type: image
+stringData:
+ gcpServiceAccountKey:
+ repoURL:
+```
+
+:::note
+Service account keys contain structured data, so it is important that the
+key be base64-encoded.
+:::
+
+:::caution
+Following the principle of least privilege, the service account associated with
+the service account key should be limited only to read-only access to the
+required Google Artifact Registry repositories.
+:::
+
+:::caution
+This method of authentication is a "lowest common denominator" approach that
+will work regardless of where Kargo is deployed. i.e. If running Kargo outside
+of GKE, this method will still work.
+
+If running Kargo within GKE, you may wish to consider using Workload Identity
+Federation instead.
+:::
+
+#### Workload Identity Federation
+
+If Kargo locates no `Secret` resources matching a repository URL, and if Kargo
+is deployed within a GKE cluster, it will attempt to use
+[Workload Identity Federation](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
+to authenticate, but this relies upon some external setup. Leveraging this
+option eliminates the need to store credentials in a `Secret` resource.
+
+First, follow
+[these directions](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#enable_on_cluster)
+to provision a new GKE cluster with Workload Identity Federation enabled or
+[these directions](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#enable-existing-cluster)
+to enable Workload Identity Federation on an existing GKE cluster.
+
+At this point, the `kargo-controller` `ServiceAccount` within the `Namespace` to
+which Kargo is (or will be) installed will be associated with an _IAM principal
+identifier_, which takes the following form:
+
+```plaintext
+principal://iam.googleapis.com/projects//locations/global/workloadIdentityPools/.svc.id.goog/subject/ns//sa/kargo-controller
+```
+
+Although associated with this _one_ principal, the Kargo controller acts on
+behalf of multiple Kargo projects, each of which may require access to
+_different_ Google Artifact Registry repositories. To account for this, when
+Kargo attempts to access a Google Artifact Registry repository on behalf of a
+specific project, it will first attempt to
+[impersonate a Google service account](https://cloud.google.com/iam/docs/service-account-impersonation)
+specific to that project. The name of the service account it attempts to
+impersonate will _always_ be of the form
+`kargo-project-@.iam.gserviceaccount.com`.
+It is this service account that should be granted read-only access to applicable
+Google Artifact Registry repositories.
+
+:::info
+The name of the Google service account associated with each Kargo project is
+deliberately not configurable to prevent Kargo project admins from attempting to
+coerce Kargo into impersonating arbitrary Google service accounts.
+:::
+
+Once Kargo is able to impersonate the appropriate Google service account for a
+given project, it will follow a process similar to that described in the
+previous section to obtain a token that is valid for 60 minutes and cached for
+40.
+
+:::caution
+Following the principle of least privilege, the IAM principal associated with
+the `kargo-controller` `ServiceAccount` should be limited only to the ability to
+impersonate project-specific Google service accounts. Project-specific Google
+service accounts should be limited only to read-only access to the applicable
+Google Artifact Registry repositories.
+:::
+
+### Azure Container Registry (ACR)
+
+Azure Container Registry directly supports long-lived credentials.
+
+It is possible to
+[create tokens with repository-scoped permissions](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-repository-scoped-permissions),
+with or without an expiration date. These tokens can be stored in the
+`username` and `password` fields of a `Secret` resource as described
+[in the first section](#credentials-as-kubernetes-secret-resources) of this
+document.
+
+:::info
+Support for authentication to ACR repositories using workload identity, on par
+with Kargo's support for ECR and Google Artifact Registry, is likely to be
+included in a future release of Kargo.
+:::
diff --git a/docs/versioned_docs/version-1.1/30-how-to-guides/25-argo-cd-integration.md b/docs/versioned_docs/version-1.1/30-how-to-guides/25-argo-cd-integration.md
new file mode 100644
index 000000000..20604f207
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/30-how-to-guides/25-argo-cd-integration.md
@@ -0,0 +1,66 @@
+---
+description: Learn how to integrate Kargo Stages with Argo CD Applications.
+sidebar_label: Argo CD Integration
+---
+
+# Argo CD Integration
+
+Argo CD excels at syncing Kubernetes clusters to desired state stored in
+a Git repository, but lacks any concept of a "promotion", i.e. updating
+the desired state of some application instance to reflect the validated
+state of some other application instance. Kargo was created to orchestrate
+such processes. Because such orchestration naturally entails some direct
+and indirect integration with Argo CD, this page details certain key
+elements of the interactions between the two systems.
+
+:::note
+This page is a work in progress. Thank you for your patience as as we work to add more details.
+:::
+
+## Updating Argo CD Applications
+
+In the course of orchestrating the transition of an application instance
+from one state to another, it is common for Kargo to updated Argo CD
+`Application` resources in some way. Such updates are enabled through the
+use of the
+[`argocd-update` promotion step](../35-references/10-promotion-steps.md#argocd-update).
+Often, these updates entail little more than modifying an `Application`'s
+`operation` field to force the `Application` to be synced to recently
+updated desired state.
+
+### Authorizing Updates
+
+Performing updates of any kind to an `Application` resource naturally
+requires Kargo to be _authorized_ to do so. Kargo controllers have the
+requisite RBAC permissions to perform such updates, but being a
+multi-tenant system, Kargo must also understand, internally, when it
+is acceptable to utilize those broad permissions to update a specific
+`Application` resource _on behalf of_ a given `Stage`.
+
+To enable Kargo controllers to update an Argo CD `Application` on behalf of
+a given `Stage`, that `Application` must be explicitly annotated as follows:
+
+```yaml
+kargo.akuity.io/authorized-stage: ":"
+```
+
+Because an annotation such as the one above could only be added to
+an `Application` by a user who, themselves, is authorized to update
+that `Application`, Kargo interprets the presence of such an annotation
+as delegation of that user's authority to do so.
+
+In the following example, an `Application` has been annotated to
+authorize Kargo to update it on behalf of a `Stage` named `test`
+in the `kargo-demo` `Project`:
+
+```yaml
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: kargo-demo-test
+ namespace: argocd
+ annotations:
+ kargo.akuity.io/authorized-stage: kargo-demo:test
+spec:
+ # Application Specifications
+```
diff --git a/docs/versioned_docs/version-1.1/30-how-to-guides/30-managing-user-permissions.md b/docs/versioned_docs/version-1.1/30-how-to-guides/30-managing-user-permissions.md
new file mode 100644
index 000000000..ff57fa38d
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/30-how-to-guides/30-managing-user-permissions.md
@@ -0,0 +1,308 @@
+---
+description: Learn how to manage user permissions
+sidebar_label: Managing User Permissions
+---
+
+# Managing User Permissions
+
+Kargo is typically configured to support single-sign-on (SSO) using an external
+identity provider that implements the
+[OpenID Connect](https://openid.net/developers/how-connect-works/) (OIDC)
+ protocol.
+
+:::info
+Refer to
+[the advanced section of the installation guide](./10-installing-kargo.md#advanced-installation)
+for more details on how to configure Kargo to use an external identity provider.
+:::
+
+Kargo also implements authorization of all user actions using pure Kubernetes
+[RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/). i.e.
+Permission to perform various actions on various Kargo resources is therefore
+granted via `RoleBinding` resources that associate users or `ServiceAccount`
+resources with `Role` resources.
+
+Because Kargo users log into the Kargo CLI or UI via SSO, their identifies are
+not known to Kargo's underlying Kubernetes cluster. This represents an
+impediment to using Kubernetes RBAC to authorize the actions of such users.
+
+Kargo answers this challenge through a scheme that permits users to be mapped
+to zero or more Kubernetes `ServiceAccount` resources. The remainder of this
+page describes how to create those mappings.
+
+## User to `ServiceAccount` Mappings
+
+Whether logged into the Kargo CLI or UI, Kargo users are interacting with Kargo
+via the Kargo API server. The Kargo API server authenticates users via a bearer
+token issued by the external identity provider. On every request, the Kargo
+API server validates and decodes the token to obtain trusted information about
+the user which, importantly, includes _claims_ such as username, email address,
+and group membership. The exact claims available depend on the identity provider
+and the configuration of the Kargo API server. (Refer again to
+[the advanced section of the installation guide](./10-installing-kargo.md#advanced-installation).)
+
+Also at the time of authentication, the Kargo API server queries the Kubernetes
+API server to obtain a list of all `ServiceAccount` resources to which the user
+has been mapped. Kargo typically restricts this search to `ServiceAccount` resources
+in Kargo project namespaces only (i.e. only those labeled with
+`kargo.akuity.io/project: "true"`). Refer to the next section for exceptions to
+this rule.
+
+ServiceAccount resources may be mapped to users through the use of annotations
+whose key begins with `rbac.kargo.akuity.io/claim.`. The value of the annotation
+may be a single value, or a comma-delimited list of values.
+
+In the following example, the `ServiceAccount` resource is mapped to all of:
+
+* Users identified as `alice` or `bob`.
+* A user with the email address `carl@example.com`.
+* All users in _either_ the `devops` or `kargo-admin` group.
+
+```yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: admin
+ namespace: kargo-demo
+ annotations:
+ rbac.kargo.akuity.io/claim.sub: alice,bob
+ rbac.kargo.akuity.io/claim.email: carl@example.com
+ rbac.kargo.akuity.io/claim.groups: devops,kargo-admin
+```
+
+A user may be mapped to multiple `ServiceAccount` resources. A user's effective
+permissions are therefore the union of the permissions associated with all such
+`ServiceAccount` resources.
+
+## Managing Project-Level "Kargo Roles" with the CLI
+
+The Kargo CLI offers several conveniences for working with "Kargo Roles," which
+are simplified abstractions over Kubernetes `ServiceAccount`, `Role`, and
+`RoleBinding` resources.
+
+A Kargo Role combines the "who" of a `ServiceAccount` (with the mapping
+annotations described in the previous section) with the "what" of a `Role`
+resource's policy rules.
+
+Creating a Kargo Role, therefore, effects creation of an underlying
+`ServiceAccount`/`Role`/`RoleBinding` trio. Similarly, deleting a Kargo Role
+deletes those same underlying resources. Updating a Kargo Role via `grant` or
+`revoke` commands updates the underlying `ServiceAccount` or `RoleBinding`
+accordingly.
+
+:::info
+Before diving into the commands for Kargo Role management, please note the
+following details:
+
+* A Kargo Role _exists_ as long as an underlying `ServiceAccount` resource with
+ the same name exists in the Project namespace.
+* If any `RoleBinding` resources in the Project namespace reference the
+ `ServiceAccount` resource, then all of the `Role` resources referenced by
+ those `RoleBinding` resources are also considered part of the Kargo Role, as
+ are the `RoleBinding` resources themselves.
+* Kargo can only _manage_ Kargo Roles that are:
+ * Comprised of precisely one `RoleBinding` and `Role` resource.
+ * Explicitly annotated as _being_ Kargo-managed.
+* Kargo also normalizes the representation of policy rules in any `Role`
+ resource it manages, which is necessary to ensure that `grant` and `revoke`
+ operations can modify policy rules accurately, without unintended side
+ effects.
+
+In practice, if you GitOps your Project-level `ServiceAccount`, `Role`, and
+`RoleBinding` resources, those resources should _not_ be annotated as being
+Kargo-managed. This will prevent modification of those resources through
+imperative Kargo CLI commands like `grant` and `revoke`.
+:::
+
+All Kargo Roles associated with a Project are listed using the `kargo get roles`
+command:
+
+```shell
+kargo get roles --project kargo-demo
+```
+
+```shell
+NAME KARGO MANAGED AGE
+default false 20m
+```
+
+Here we see that Kargo counts a Kargo Role as existing due to the existence of
+the `default` `ServiceAccount` resource that Kubernetes automatically creates in
+any new namespace, including Kargo Project namespaces. Because the `default`
+`ServiceAccount` lacks the necessary annotations, Kargo does not consider it
+Kargo-managed.
+
+We can create a new Kargo-manged Kargo role with the `kargo create role`
+command:
+
+```shell
+kargo create role developer --project kargo-demo
+```
+
+```shell
+role.rbac.kargo.akuity.io/developer created
+```
+
+If we list the Kargo Roles again, we see the new `developer` Kargo Role, and
+that it is Kargo-managed:
+
+```shell
+kargo get roles --project kargo-demo
+```
+
+```shell
+NAME KARGO MANAGED AGE
+default false 24m
+developer true 64s
+```
+
+We can view a YAML representation of the `developer` Kargo Role and see that
+it's not very interesting yet:
+
+```shell
+kargo get role developer --project kargo-demo -o yaml
+```
+
+```shell
+apiVersion: rbac.kargo.akuity.io/v1alpha1
+kargoManaged: true
+kind: Role
+metadata:
+ creationTimestamp: "2024-05-01T13:27:20Z"
+ name: developer
+ namespace: kargo-demo
+```
+
+To make things more interesting, we can grant the `developer` Kargo Role to
+a users having the value `developer` in their `groups` claim:
+
+```shell
+kargo grant --role developer --claim groups=developer --project kargo-demo
+```
+
+```shell
+role.rbac.kargo.akuity.io/developer updated
+```
+
+And we can grant broad permissions on `Stage` resources to the `developer` Kargo
+Role:
+
+```shell
+kargo grant --role developer \
+ --verb '*' --resource-type stages \
+ --project kargo-demo
+```
+
+```shell
+role.rbac.kargo.akuity.io/developer updated
+```
+
+We can view the updated `developer` Kargo Role and see that it is now
+considerably more interesting:
+
+```shell
+kargo get role developer --project kargo-demo -o yaml
+```
+
+```yaml
+apiVersion: rbac.kargo.akuity.io/v1alpha1
+claims:
+ - name: groups
+ values:
+ - developer
+kargoManaged: true
+kind: Role
+metadata:
+ creationTimestamp: "2024-05-01T13:27:20Z"
+ name: developer
+ namespace: kargo-demo
+rules:
+- apiGroups:
+ - kargo.akuity.io
+ resources:
+ - stages
+ verbs:
+ - create
+ - delete
+ - deletecollection
+ - get
+ - list
+ - patch
+ - update
+ - watch
+```
+
+We can also revoke the `developer` Kargo Role from the `developer` group or
+revoke any permissions from the `developer` Kargo Role using the `kargo revoke`
+command, which supports all the same flags as the `kargo grant` command.
+
+Last, it may sometimes be useful to view a Kargo Role's underlying
+`ServiceAccount`, `Role`, and `RoleBinding` resources. This may be useful, for
+instance, to users who have managed Project-level permissions imperatively up to
+a point and now wish to make the transition to GitOps'ing those permissions.
+
+```shell
+kargo get role developer --as-kubernetes-resources --project kargo-demo
+```
+
+```yaml
+NAME K8S SERVICE ACCOUNT K8S ROLE BINDINGS K8S ROLES AGE
+developer developer developer developer 13m
+```
+
+It is also possible to request alternative representations of the underlying
+resources:
+
+```shell
+kargo get role developer \
+ --as-kubernetes-resources -o yaml \
+ --project kargo-demo
+```
+
+:::note
+Output of the above command is not shown here due to its length.
+:::
+
+Last, it is, of course, possible to delete a Kargo Role:
+
+```shell
+kargo delete role developer --project kargo-demo
+```
+
+```shell
+role.rbac.kargo.akuity.io/developer deleted
+```
+
+## Kargo Role Matrix
+
+The table below outlines the maximum rules required based on the `kargo-admin` ClusterRole. When specifying verbs, it's recommended to apply the principle of least privilege, ensuring access is limited to what is necessary for the specific role.
+
+| **API Groups** | **Resources** | **Verbs** |
+|-----------------------------|------------------------------------------------|-----------------------------------------------------|
+| `""` | `events`, `namespaces`, `serviceaccounts` | `get`, `list`, `watch` |
+| `rbac.authorization.k8s.io` | `rolebindings`, `roles` | `get`, `list`, `watch` |
+| `kargo.akuity.io` | `freights`, `projects`, `stages`, `warehouses` | `*` |
+| `kargo.akuity.io` | `stages` | `promote` |
+| `kargo.akuity.io` | `promotions` | `create`, `delete`, `get`, `list`, `patch`, `watch` |
+| `kargo.akuity.io` | `freights/status` | `patch` |
+| `argoproj.io` | `analysisruns` | `delete`, `get`, `list`, `watch` |
+| `argoproj.io` | `analysistemplates` | `*` |
+
+## Global Mappings
+
+In cases where certain, broad sets of permissions may be required by a large
+numbers of users, the administrator/operator installing Kargo may opt-in to
+designating one or more namespaces as homes for "global" `ServiceAccount`
+resources using the `api.oidc.globalServiceAccounts` setting in Kargo's Helm
+chart. Refer to
+[the advanced section of the installation guide](./10-installing-kargo.md#advanced-installation)
+for more details.
+
+Note that `ServiceAccount` resources in designated namespaces are not _truly_
+global because they are _still_ mapped to users according to the rules described
+in the previous section.
+
+Making use of this feature could be, for instance, a convenient method of
+granting read-only access to all Kargo resources in all projects to all users
+within an organization. Additional permissions may then be granted to users on a
+project-by-project basis.
diff --git a/docs/versioned_docs/version-1.1/30-how-to-guides/_category_.json b/docs/versioned_docs/version-1.1/30-how-to-guides/_category_.json
new file mode 100644
index 000000000..5011e45cd
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/30-how-to-guides/_category_.json
@@ -0,0 +1,4 @@
+{
+ "label": "How-to Guides",
+ "link": null
+}
diff --git a/docs/versioned_docs/version-1.1/35-references/10-promotion-steps.md b/docs/versioned_docs/version-1.1/35-references/10-promotion-steps.md
new file mode 100644
index 000000000..a9b047539
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/35-references/10-promotion-steps.md
@@ -0,0 +1,1510 @@
+---
+sidebar_label: Promotion Steps Reference
+description: Learn about all of Kargo's built-in promotion steps
+---
+
+# Promotion Steps Reference
+
+Kargo's promotion steps are the building blocks of a promotion process. They
+perform the actions necessary to promote a piece of Freight into a Stage.
+Promotion steps are designed to be composable, allowing users to construct
+complex promotion processes from simple, reusable components.
+
+## Defining a Promotion Step
+
+A promotion step is a YAML object with at least one key, `uses`, whose value is
+the name of the step to be executed. The step's configuration is provided in a
+subsequent key, `config`. The `config` key's value is an object whose keys are
+the configuration options for the step.
+
+```yaml
+steps:
+- uses: step-name
+ config:
+ option1: value1
+ option2: value2
+```
+
+:::info
+For a list of built-in promotion steps and configuration options, see the
+[Built-in Steps](#built-in-steps) section.
+:::
+
+### Step Aliases
+
+A step can be given an alias by providing an `as` key in the step definition.
+The value of the `as` key is the alias to be used to reference the
+[step's output](#step-outputs).
+
+```yaml
+steps:
+- uses: step-name
+ as: alias
+```
+
+### Step Outputs
+
+A promotion step may produce output that can be referenced by subsequent steps,
+allowing the output of one step to be used as input to another. The output of a
+step is defined by the step itself and is typically documented in the step's
+reference.
+
+```yaml
+steps:
+- uses: step-name
+ as: alias
+- uses: another-step
+ config:
+ input: ${{ outputs.alias.someOutput }}
+```
+
+### Step Retries
+
+When a step fails for any reason, it can be retried instead of immediately
+failing the entire `Promotion`. An _error threshold_ specifies the number of
+_consecutive_ failures required for retry attempts to be abandoned and the
+`Promotion` to fail.
+
+Independent of the error threshold, steps are also subject to a _timeout_. Any
+step that doesn't achieve its goal within that interval will cause the
+`Promotion` to fail. For steps that exhibit any kind of polling behavior, the
+timeout can cause a `Promotion` to fail with no _other_ failure having occurred.
+
+System-wide, the default error threshold is 1 and the default timeout is
+indefinite. Thus, default behavior is effectively no retries when a step fails
+for any reason and steps with any kind of polling behavior will poll
+indefinitely _as long a no other failure occurs._
+
+The implementations of individual steps can override these defaults. Users also
+may override these defaults through configuration. In the following example, the
+`git-wait-for-pr` step is configured not to fail the `Promotion` until three
+consecutive failed attempts to execute it. It is also configured to wait a
+maximum of 48 hours for the step to complete successfully (i.e. for the PR to be
+merged).
+
+```yaml
+steps:
+# ...
+- uses: wait-for-pr
+ retry:
+ errorThreshold: 3
+ timeout: 48h
+ config:
+ prNumber: ${{ outputs['open-pr'].prNumber }}
+```
+
+:::info
+This feature was introduced in Kargo v1.1.0, and is still undergoing refinements
+and improvements to better distinguish between transient and non-transient
+errors, and to provide more control over retry behavior like backoff strategies
+or time limits.
+:::
+
+## Built-in Steps
+
+This section describes the promotion steps that are built directly into Kargo.
+Steps are presented roughly in the order in which they might appear in a typical
+promotion process. Similarly, configuration options for each step are laid out
+in order of their applicability to typical use cases.
+
+:::info
+Promotion steps support the use of [expr-lang] expressions in their
+configuration. Many examples in this reference document will include expressions
+to demonstrate their use. For more information on expressions, refer to our
+[Expression Language Reference](./20-expression-language.md).
+:::
+
+### `git-clone`
+
+`git-clone` is often the first step in a promotion process. It creates a
+[bare clone](https://git-scm.com/docs/git-clone#Documentation/git-clone.txt-code--barecode)
+of a remote Git repository, then checks out one or more branches, tags, or
+commits to working trees at specified paths. Checking out different revisions to
+different paths is useful for the common scenarios of combining content from
+multiple sources or rendering Stage-specific manifests to a Stage-specific
+branch.
+
+:::note
+It is a noteworthy limitation of Git that one branch cannot be checked out in
+multiple working trees.
+:::
+
+#### `git-clone` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `repoURL` | `string` | Y | The URL of a remote Git repository to clone. |
+| `insecureSkipTLSVerify` | `boolean` | N | Whether to bypass TLS certificate verification when cloning (and for all subsequent operations involving this clone). Setting this to `true` is highly discouraged in production. |
+| `checkout` | `[]object` | Y | The commits, branches, or tags to check out from the repository and the paths where they should be checked out. At least one must be specified. |
+| `checkout[].branch` | `string` | N | A branch to check out. Mutually exclusive with `commit`, `tag`, and `fromFreight=true`. If none of these is specified, the default branch will be checked out. |
+| `checkout[].create` | `boolean` | N | In the event `branch` does not already exist on the remote, whether a new, empty, orphaned branch should be created. Default is `false`, but should commonly be set to `true` for Stage-specific branches, which may not exist yet at the time of a Stage's first promotion. |
+| `checkout[].commit` | `string` | N | A specific commit to check out. Mutually exclusive with `branch`, `tag`, and `fromFreight=true`. If none of these is specified, the default branch will be checked out. |
+| `checkout[].tag` | `string` | N | A tag to check out. Mutually exclusive with `branch`, `commit`, and `fromFreight=true`. If none of these is specified, the default branch will be checked out. |
+| `checkout[].fromFreight` | `boolean` | N | Whether a commit to check out should be obtained from the Freight being promoted. A value of `true` is mutually exclusive with `branch`, `commit`, and `tag`. If none of these is specified, the default branch will be checked out. Default is `false`, but is often set to `true`.
__Deprecated: Use `commit` with an expression instead. Will be removed in v1.3.0.__ |
+| `checkout[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins).
__Deprecated: Use `commit` with an expression instead. Will be removed in v1.3.0.__ |
+| `checkout[].path` | `string` | Y | The path for a working tree that will be created from the checked out revision. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+
+#### `git-clone` Examples
+
+
+
+
+
+The most common usage of this step is to check out a commit specified by the
+Freight being promoted as well as a Stage-specific branch. Subsequent steps are
+likely to perform actions that revise the contents of the Stage-specific branch
+using the commit from the Freight as input.
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo) }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+# Prepare the contents of ./out ...
+# Commit, push, etc...
+```
+
+
+
+
+
+For this more advanced example, consider a Stage that requests Freight from two
+Warehouses, where one provides Kustomize "base" configuration, while the other
+provides a Stage-specific Kustomize overlay. Rendering the manifests intended
+for such a Stage will require combining the base and overlay configurations
+with the help of a [`copy`](#copy) step. For this case, a `git-clone` step may be
+configured similarly to the following:
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo, warehouse("base")).ID }}
+ path: ./src
+ - commit: ${{ commitFrom(vars.gitRepo, warehouse(ctx.stage + "-overlay")).ID }}
+ path: ./overlay
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: copy
+ config:
+ inPath: ./overlay/stages/${{ ctx.stage }}/kustomization.yaml
+ outPath: ./src/stages/${{ ctx.stage }}/kustomization.yaml
+- uses: kustomize-build
+ config:
+ path: ./src/stages/${{ ctx.stage }}
+ outPath: ./out
+# Commit, push, etc...
+```
+
+
+
+
+
+### `git-clear`
+
+`git-clear` deletes the _the entire contents_ of a specified Git working tree
+(except for the `.git` file). It is equivalent to executing
+`git add . && git rm -rf --ignore-unmatch .`. This step is useful for the common
+scenario where the entire content of a Stage-specific branch is to be replaced
+with content from another branch or with content rendered using some
+configuration management tool.
+
+#### `git-clear` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a Git working tree whose entire contents are to be deleted. |
+
+#### `git-clear` Example
+
+```yaml
+steps:
+- uses: git-clone
+ config:
+ repoURL: https://github.com/example/repo.git
+ checkout:
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+# Prepare the contents of ./out ...
+# Commit, push, etc...
+```
+
+### `copy`
+
+`copy` copies files or the contents of entire directories from one specified
+location to another.
+
+#### `copy` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `inPath` | `string` | Y | Path to the file or directory to be copied. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `outPath` | `string` | Y | Path to the destination. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+
+#### `copy` Example
+
+The most common (though still advanced) usage of this step is to combine content
+from two working trees to use as input to a subsequent step, such as one that
+renders Stage-specific manifests.
+
+Consider a Stage that requests Freight from two Warehouses, where one provides
+Kustomize "base" configuration, while the other provides a Stage-specific
+Kustomize overlay. Rendering the manifests intended for such a Stage will
+require combining the base and overlay configurations:
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo, warehouse("base")).ID }}
+ path: ./src
+ - commit: ${{ commitFrom(vars.gitRepo, warehouse(ctx.stage + "-overlay")).ID }}
+ path: ./overlay
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: copy
+ config:
+ inPath: ./overlay/stages/${{ ctx.stage }}/kustomization.yaml
+ outPath: ./src/stages/${{ ctx.stage }}/kustomization.yaml
+# Render manifests to ./out, commit, push, etc...
+```
+
+### `kustomize-set-image`
+
+`kustomize-set-image` updates the `kustomization.yaml` file in a specified
+directory to reflect a different revision of a container image. It is equivalent
+to executing `kustomize edit set image`. This step is commonly followed by a
+[`kustomize-build`](#kustomize-build) step.
+
+#### `kustomize-set-image` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a directory containing a `kustomization.yaml` file. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `images` | `[]object` | Y | The details of changes to be applied to the `kustomization.yaml` file. At least one must be specified. |
+| `images[].image` | `string` | Y | Name/URL of the image being updated. |
+| `images[].tag` | `string` | N | A tag naming a specific revision of `image`. Mutually exclusive with `digest` and `useDigest=true`. If none of these are specified, the tag specified by a piece of Freight referencing `image` will be used as the value of this field. |
+| `images[].digest` | `string` | N | A digest naming a specific revision of `image`. Mutually exclusive with `tag` and `useDigest=true`. If none of these are specified, the tag specified by a piece of Freight referencing `image` will be used as the value of `tag`. |
+| `images[].useDigest` | `boolean` | N | Whether to update the `kustomization.yaml` file using the container image's digest instead of its tag. Mutually exclusive with `digest` and `tag`. If none of these are specified, the tag specified by a piece of Freight referencing `image` will be used as the value of `tag`.
__Deprecated: Use `digest` with an expression instead. Will be removed in v1.3.0.__ |
+| `images[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins).
__Deprecated: Use `digest` or `tag` with an expression instead. Will be removed in v1.3.0.__ |
+| `images[].newName` | `string` | N | A substitution for the name/URL of the image being updated. This is useful when different Stages have access to different container image repositories (assuming those different repositories contain equivalent images that are tagged identically). This may be a frequent consideration for users of Amazon's Elastic Container Registry. |
+
+#### `kustomize-set-image` Examples
+
+
+
+
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+- name: imageRepo
+ value: my/image
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo).ID }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: kustomize-set-image
+ config:
+ path: ./src/base
+ images:
+ - image: ${{ vars.imageRepo }}
+ tag: ${{ imageFrom(vars.imageRepo).Tag }}
+# Render manifests to ./out, commit, push, etc...
+```
+
+
+
+
+
+For this example, consider the promotion of Freight containing a reference to
+some revision of the container image
+`123456789012.dkr.ecr.us-east-1.amazonaws.com/my-image`. This image exists in the
+`us-east-1` region of Amazon's Elastic Container Registry. However, assuming the
+Stage targeted by the promotion is backed by environments in the `us-west-2`
+region, it will be necessary to make a substitution when updating the
+`kustomization.yaml` file. This can be accomplished like so:
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo).ID }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: kustomize-set-image
+ config:
+ path: ./src/base
+ images:
+ - image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-image
+ newName: 123456789012.dkr.ecr.us-west-2.amazonaws.com/my-image
+# Render manifests to ./out, commit, push, etc...
+```
+
+
+
+
+
+#### `kustomize-set-image` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `commitMessage` | `string` | A description of the change(s) applied by this step. Typically, a subsequent [`git-commit`](#git-commit) step will reference this output and aggregate this commit message fragment with other like it to build a comprehensive commit message that describes all changes. |
+
+### `kustomize-build`
+
+`kustomize-build` renders manifests from a specified directory containing a
+`kustomization.yaml` file to a specified file or to many files in a specified
+directory. This step is useful for the common scenario of rendering
+Stage-specific manifests to a Stage-specific branch. This step is commonly
+preceded by a [`git-clear`](#git-clear) step and followed by
+[`git-commit`](#git-commit) and [`git-push`](#git-push) steps.
+
+#### `kustomize-build` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a directory containing a `kustomization.yaml` file. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `outPath` | `string` | Y | Path to the file or directory where rendered manifests are to be written. If the path ends with `.yaml` or `.yml` it is presumed to indicate a file and is otherwise presumed to indicate a directory. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `plugin.helm.apiVersions` | `[]string` | N | Optionally specifies a list of supported API versions to be used when rendering manifests using Kustomize's Helm chart plugin. This is useful for charts that may contain logic specific to different Kubernetes API versions. |
+| `plugin.helm.kubeVersion` | `string` | N | Optionally specifies a Kubernetes version to be assumed when rendering manifests using Kustomize's Helm chart plugin. This is useful for charts that may contain logic specific to different Kubernetes versions. |
+
+#### `kustomize-build` Examples
+
+
+
+
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo).ID }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: kustomize-build
+ config:
+ path: ./src/stages/${{ ctx.stage }}
+ outPath: ./out/manifests.yaml
+# Commit, push, etc...
+```
+
+
+
+
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo).ID }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: kustomize-build
+ config:
+ path: ./src/stages/${{ ctx.stage }}
+ outPath: ./out
+# Commit, push, etc...
+```
+
+
+
+
+
+### `helm-update-image`
+
+`helm-update-image` updates the values of specified keys in a specified Helm
+values file (e.g. `values.yaml`) to reflect a new version of a container image.
+This step is useful for the common scenario of updating such a `values.yaml`
+file with new version information which is referenced by the Freight being
+promoted. This step is commonly followed by a [`helm-template`](#helm-template)
+step.
+
+__Deprecated: Use the generic `yaml-update` step instead. Will be removed in v1.3.0.__
+
+#### `helm-update-image` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to Helm values file (e.g. `values.yaml`). This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `images` | `[]object` | Y | The details of changes to be applied to the values file. At least one must be specified. |
+| `images[].image` | `string` | Y | Name/URL of the image being updated. The Freight being promoted presumably contains a reference to a revision of this image. |
+| `images[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins) |
+| `images[].key` | `string` | Y | The key to update within the values file. See Helm documentation on the [format and limitations](https://helm.sh/docs/intro/using_helm/#the-format-and-limitations-of---set) of the notation used in this field. |
+| `images[].value` | `string` | Y | Specifies how the value of `key` is to be updated. Possible values for this field are limited to:
`ImageAndTag`: Replaces the value of `key` with a string in form `:`
`Tag`: Replaces the value of `key` with the image's tag
`ImageAndDigest`: Replaces the value of `key` with a string in form `@`
`Digest`: Replaces the value of `key` with the image's digest
|
+
+#### `helm-update-image` Example
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo).ID }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: helm-update-image
+ config:
+ path: ./src/charts/my-chart/values.yaml
+ images:
+ - image: my/image
+ key: image.tag
+ value: Tag
+# Render manifests to ./out, commit, push, etc...
+```
+
+#### `helm-update-image` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `commitMessage` | `string` | A description of the change(s) applied by this step. Typically, a subsequent [`git-commit`](#git-commit) step will reference this output and aggregate this commit message fragment with other like it to build a comprehensive commit message that describes all changes. |
+
+### `yaml-update`
+
+`yaml-update` updates the values of specified keys in any YAML file. This step
+most often used to update image tags or digests in a Helm values and is commonly
+followed by a [`helm-template`](#helm-template) step.
+
+#### `yaml-update` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a YAML file. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `updates` | `[]object` | Y | The details of changes to be applied to the file. At least one must be specified. |
+| `updates[].key` | `string` | Y | The key to update within the file. For nested values, use a YAML dot notation path. |
+| `updates[].value` | `string` | Y | The new value for the key. Typically specified using an expression. |
+
+#### `yaml-update` Example
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo).ID }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: yaml-update
+ config:
+ path: ./src/charts/my-chart/values.yaml
+ updates:
+ - key: image.tag
+ value: ${{ imageFrom("my/image").Tag }}
+# Render manifests to ./out, commit, push, etc...
+```
+
+#### `yaml-update` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `commitMessage` | `string` | A description of the change(s) applied by this step. Typically, a subsequent [`git-commit`](#git-commit) step will reference this output and aggregate this commit message fragment with other like it to build a comprehensive commit message that describes all changes. |
+
+### `helm-update-chart`
+
+`helm-update-chart` performs specified updates on the `dependencies` section of
+a specified Helm chart's `Chart.yaml` file. This step is useful for the common
+scenario of updating a chart's dependencies to reflect new versions of charts
+referenced by the Freight being promoted. This step is commonly followed by a
+[`helm-template`](#helm-template) step.
+
+#### `helm-update-chart` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a Helm chart (i.e. to a directory containing a `Chart.yaml` file). This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `charts` | `[]string` | Y | The details of dependency (subschart) updates to be applied to the chart's `Chart.yaml` file. |
+| `charts[].repository` | `string` | Y | The URL of the Helm chart repository in the `dependencies` entry whose `version` field is to be updated. Must _exactly_ match the `repository` field of that entry. |
+| `charts[].name` | `string` | Y | The name of the chart in in the `dependencies` entry whose `version` field is to be updated. Must exactly match the `name` field of that entry. |
+| `charts[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins).
__Deprecated: Use `version` with an expression instead. Will be removed in v1.3.0.__ |
+| `charts[].version` | `string` | N | The version to which the dependency should be updated. If left unspecified, the version specified by a piece of Freight referencing this chart will be used. |
+
+#### `helm-update-chart` Examples
+
+
+
+
+
+Given a `Chart.yaml` file such as the following:
+
+```yaml
+apiVersion: v2
+name: example
+type: application
+version: 0.1.0
+appVersion: 0.1.0
+dependencies:
+- repository: https://example-chart-repo
+ name: some-chart
+ version: 1.2.3
+```
+
+The `dependencies` can be updated to reflect the version of `some-chart`
+referenced by the Freight being promoted like so:
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+- name: chartRepo
+ value: https://example-chart-repo
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo).ID }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: helm-update-chart
+ config:
+ path: ./src/charts/my-chart
+ charts:
+ - repository: ${{ chartRepo }}
+ name: some-chart
+ version: ${{ chartFrom(chartRepo).Version }}
+# Render manifests to ./out, commit, push, etc...
+```
+
+
+
+
+
+:::caution
+Classic (HTTP/HTTPS) Helm chart repositories can contain many differently named
+charts. A specific chart, therefore, can be identified by a repository URL and
+a chart name.
+
+OCI repositories, on the other hand, are organizational constructs within OCI
+_registries._ Each OCI repository is presumed to contain versions of only a
+single chart. As such, a specific chart can be identified by a repository URL
+alone.
+
+Kargo Warehouses understand this distinction well, so a subscription to an OCI
+chart repository will utilize its URL only, _without_ specifying a chart name.
+For example:
+
+```yaml
+apiVersion: kargo.akuity.io/v1alpha1
+kind: Warehouse
+metadata:
+ name: my-warehouse
+ namespace: kargo-demo
+spec:
+ subscriptions:
+ - chart:
+ repoURL: oci://example-chart-registry/some-chart
+ semverConstraint: ^1.0.0
+```
+
+Helm deals with this difference somewhat more awkwardly, however. When a Helm
+chart references a chart in an OCI repository, it must reference the _registry_
+by URL in the `repository` field and _still_ specify a chart name in the name
+field. For example:
+
+```yaml
+apiVersion: v2
+name: example
+type: application
+version: 0.1.0
+appVersion: 0.1.0
+dependencies:
+- repository: oci://example-chart-registry
+ name: some-chart
+ version: 1.2.3
+```
+
+__When using `helm-update-chart` to update the dependencies in a `Chart.yaml`
+file, you must play by Helm's rules and use the _registry_ URL in the
+`repository` field and the _repository_ name (chart name) in the `name` field.__
+:::
+
+:::info
+As a general rule, when configuring Kargo to update something, observe the
+conventions of the thing being updated, even if those conventions differ from
+Kargo's own. Kargo is aware of such differences and will adapt accordingly.
+:::
+
+Given a `Chart.yaml` file such as the following:
+
+```yaml
+apiVersion: v2
+name: example
+type: application
+version: 0.1.0
+appVersion: 0.1.0
+dependencies:
+- repository: oci://example-chart-registry
+ name: some-chart
+ version: 1.2.3
+```
+
+The `dependencies` can be updated to reflect the version of
+`oci://example-chart-registry/some-chart` referenced by the Freight being
+promoted like so:
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+- name: chartReg
+ value: oci://example-chart-registry
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo).ID }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: helm-update-chart
+ config:
+ path: ./src/charts/my-chart
+ charts:
+ - repository: ${{ chartReg }}
+ name: some-chart
+ version: ${{ chartFrom(chartReg + "/some-chart").Version }}
+# Render manifests to ./out, commit, push, etc...
+```
+
+
+
+
+
+#### `helm-update-chart` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `commitMessage` | `string` | A description of the change(s) applied by this step. Typically, a subsequent [`git-commit`](#git-commit) step will reference this output and aggregate this commit message fragment with other like it to build a comprehensive commit message that describes all changes. |
+
+### `helm-template`
+
+`helm-template` renders a specified Helm chart to a specified directory or to
+many files in a specified directory. This step is useful for the common scenario
+of rendering Stage-specific manifests to a Stage-specific branch. This step is
+commonly preceded by a [`git-clear`](#git-clear) step and followed by
+[`git-commit`](#git-commit) and [`git-push`](#git-push) steps.
+
+#### `helm-template` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a Helm chart (i.e. to a directory containing a `Chart.yaml` file). This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `outPath` | `string` | Y | Path to the file or directory where rendered manifests are to be written. If the path ends with `.yaml` or `.yml` it is presumed to indicate a file and is otherwise presumed to indicate a directory. |
+| `releaseName` | `string` | N | Optional release name to use when rendering the manifests. This is commonly omitted. |
+| `namespace` | `string` | N | Optional namespace to use when rendering the manifests. This is commonly omitted. GitOps agents such as Argo CD will generally ensure the installation of manifests into the namespace specified by their own configuration. |
+| `valuesFiles` | `[]string` | N | Helm values files (apart from the chart's default `values.yaml`) to be used when rendering the manifests. |
+| `includeCRDs` | `boolean` | N | Whether to include CRDs in the rendered manifests. This is `false` by default. |
+| `kubeVersion` | `string` | N | Optionally specifies a Kubernetes version to be assumed when rendering manifests. This is useful for charts that may contain logic specific to different Kubernetes versions. |
+| `apiVersions` | `[]string` | N | Allows a manual set of supported API versions to be specified. |
+
+#### `helm-template` Examples
+
+
+
+
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo).ID }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: helm-template
+ config:
+ path: ./src/charts/my-chart
+ valuesFiles:
+ - ./src/charts/my-chart/${{ ctx.stage }}-values.yaml
+ outPath: ./out/manifests.yaml
+# Commit, push, etc...
+```
+
+
+
+
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo).ID }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: helm-template
+ config:
+ path: ./src/charts/my-chart
+ valuesFiles:
+ - ./src/charts/my-chart/${{ ctx.stage }}-values.yaml
+ outPath: ./out
+# Commit, push, etc...
+```
+
+
+
+
+
+### `git-commit`
+
+`git-commit` commits all changes in a working tree to its checked out branch.
+This step is often used after previous steps have put the working tree into the
+desired state and is commonly followed by a [`git-push`](#git-push) step.
+
+#### `git-commit` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a Git working tree containing changes to be committed. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. |
+| `message` | `string` | N | The commit message. Mutually exclusive with `messageFromSteps`. |
+| `messageFromSteps` | `[]string` | N | References the `commitMessage` output of previous steps. When one or more are specified, the commit message will be constructed by concatenating the messages from individual steps. Mutually exclusive with `message`. |
+| `author` | `[]object` | N | Optionally provider authorship information for the commit. |
+| `author.name` | `string` | N | The committer's name. |
+| `author.email` | `string` | N | The committer's email address. |
+
+#### `git-commit` Example
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - commit: ${{ commitFrom(vars.gitRepo).ID }}
+ path: ./src
+ - branch: stage/${{ ctx.stage }}
+ create: true
+ path: ./out
+- uses: git-clear
+ config:
+ path: ./out
+- uses: kustomize-set-image
+ as: update-image
+ config:
+ images:
+ - image: my/image
+- uses: kustomize-build
+ config:
+ path: ./src/stages/${{ ctx.stage }}
+ outPath: ./out
+- uses: git-commit
+ config:
+ path: ./out
+ messageFromSteps:
+ - update-image
+# Push, etc...
+```
+
+#### `git-commit` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `commit` | `string` | The ID (SHA) of the commit created by this step. If the step short-circuited and did not create a new commit because there were no differences from the current head of the branch, this value will be the ID of the existing commit at the head of the branch instead. Typically, a subsequent [`argocd-update`](#argocd-update) step will reference this output to learn the ID of the commit that an applicable Argo CD `ApplicationSource` should be observably synced to under healthy conditions. |
+
+### `git-push`
+
+`git-push` pushes the committed changes in a specified working tree to a
+specified branch in the remote repository. This step typically follows a
+`git-commit` step and is often followed by a `git-open-pr` step.
+
+This step also implements its own, internal retry logic. If a push fails, with
+the cause determined to be the presence of new commits in the remote branch that
+are not present in the local branch, the step will attempt to rebase before
+retrying the push. Any merge conflict requiring manual resolution will
+immediately halt further attempts.
+
+:::info
+This step's internal retry logic is helpful in scenarios when concurrent
+Promotions to multiple Stages may all write to the same branch of the same
+repository.
+
+Because conflicts requiring manual resolution will halt further attempts, it is
+recommended to design your Promotion processes such that Promotions to multiple
+Stages that write to the same branch do not write to the same files.
+:::
+
+#### `git-push` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `path` | `string` | Y | Path to a Git working tree containing committed changes. |
+| `targetBranch` | `string` | N | The branch to push to in the remote repository. Mutually exclusive with `generateTargetBranch=true`. If neither of these is provided, the target branch will be the same as the branch currently checked out in the working tree. |
+| `maxAttempts` | `int32` | N | The maximum number of attempts to make when pushing to the remote repository. Default is 50. |
+| `generateTargetBranch` | `boolean` | N | Whether to push to a remote branch named like `kargo///promotion`. If such a branch does not already exist, it will be created. A value of 'true' is mutually exclusive with `targetBranch`. If neither of these is provided, the target branch will be the currently checked out branch. This option is useful when a subsequent promotion step will open a pull request against a Stage-specific branch. In such a case, the generated target branch pushed to by the `git-push` step can later be utilized as the source branch of the pull request. |
+
+#### `git-push` Examples
+
+
+
+
+
+```yaml
+steps:
+# Clone, prepare the contents of ./out, etc...
+- uses: git-commit
+ config:
+ path: ./out
+ message: rendered updated manifests
+- uses: git-push
+ config:
+ path: ./out
+```
+
+
+
+
+
+```yaml
+steps:
+# Clone, prepare the contents of ./out, etc...
+- uses: git-commit
+ config:
+ path: ./out
+ message: rendered updated manifests
+- uses: git-push
+ as: push
+ config:
+ path: ./out
+ generateTargetBranch: true
+# Open a PR and wait for it to be merged or closed...
+```
+
+
+
+
+
+#### `git-push` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `branch` | `string` | The name of the remote branch pushed to by this step. This is especially useful when the `generateTargetBranch=true` option has been used, in which case a subsequent [`git-open-pr`](#git-open-pr) will typically reference this output to learn what branch to use as the head branch of a new pull request. |
+| `commit` | `string` | The ID (SHA) of the commit pushed by this step. |
+
+### `git-open-pr`
+
+`git-open-pr` opens a pull request in a specified remote repository using
+specified source and target branches. This step is often used after a `git-push`
+and is commonly followed by a `git-wait-for-pr` step.
+
+At present, this feature only supports GitHub pull requests and GitLab merge
+requests.
+
+#### `git-open-pr` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `repoURL` | `string` | Y | The URL of a remote Git repository. |
+| `provider` | `string` | N | The name of the Git provider to use. Currently only `github` and `gitlab` are supported. Kargo will try to infer the provider if it is not explicitly specified. |
+| `insecureSkipTLSVerify` | `boolean` | N | Indicates whether to bypass TLS certificate verification when interfacing with the Git provider. Setting this to `true` is highly discouraged in production. |
+| `sourceBranch` | `string` | N | Specifies the source branch for the pull request. Mutually exclusive with `sourceBranchFromStep`. |
+| `sourceBranchFromStep` | `string` | N | Indicates the source branch should be determined by the `branch` key in the output of a previous promotion step with the specified alias. Mutually exclusive with `sourceBranch`.
__Deprecated: Use `sourceBranch` with an expression instead. Will be removed in v1.3.0.__ |
+| `targetBranch` | `string` | N | The branch to which the changes should be merged. |
+| `createTargetBranch` | `boolean` | N | Indicates whether a new, empty orphaned branch should be created and pushed to the remote if the target branch does not already exist there. Default is `false`. |
+
+#### `git-open-pr` Example
+
+```yaml
+steps:
+# Clone, prepare the contents of ./out, commit, etc...
+- uses: git-push
+ as: push
+ config:
+ path: ./out
+ generateTargetBranch: true
+- uses: git-open-pr
+ as: open-pr
+ config:
+ repoURL: https://github.com/example/repo.git
+ createTargetBranch: true
+ sourceBranch: ${{ outputs.push.branch }}
+ targetBranch: stage/${{ ctx.stage }}
+# Wait for the PR to be merged or closed...
+```
+
+#### `git-open-pr` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `prNumber` | `number` | The numeric identifier of the pull request opened by this step. Typically, a subsequent [`git-wait-for-pr`](#git-wait-for-pr) step will reference this output to learn what pull request to monitor. |
+
+### `git-wait-for-pr`
+
+`git-wait-for-pr` waits for a specified open pull request to be merged or
+closed. This step commonly follows a `git-open-pr` step and is commonly followed
+by an `argocd-update` step.
+
+#### `git-wait-for-pr` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `repoURL` | `string` | Y | The URL of a remote Git repository. |
+| `provider` | `string` | N | The name of the Git provider to use. Currently only `github` and `gitlab` are supported. Kargo will try to infer the provider if it is not explicitly specified. |
+| `insecureSkipTLSVerify` | `boolean` | N | Indicates whether to bypass TLS certificate verification when interfacing with the Git provider. Setting this to `true` is highly discouraged in production. |
+| `prNumber` | `string` | N | The number of the pull request to wait for. Mutually exclusive with `prNumberFromStep`. |
+| `prNumberFromStep` | `string` | N | References the `prNumber` output from a previous step. Mutually exclusive with `prNumber`.
__Deprecated: Use `prNumber` with an expression instead. Will be removed in v1.3.0.__ |
+
+#### `git-wait-for-pr` Output
+
+| Name | Type | Description |
+|------|------|-------------|
+| `commit` | `string` | The ID (SHA) of the new commit at the head of the target branch after merge. Typically, a subsequent [`argocd-update`](#argocd-update) step will reference this output to learn the ID of the commit that an applicable Argo CD `ApplicationSource` should be observably synced to under healthy conditions. |
+
+#### `git-wait-for-pr` Example
+
+```yaml
+steps:
+# Clone, prepare the contents of ./out, commit, etc...
+- uses: git-push
+ as: push
+ config:
+ path: ./out
+ generateTargetBranch: true
+- uses: git-open-pr
+ as: open-pr
+ config:
+ repoURL: https://github.com/example/repo.git
+ createTargetBranch: true
+ sourceBranch: ${{ outputs.push.branch }}
+ targetBranch: stage/${{ ctx.stage }}
+- uses: git-wait-for-pr
+ as: wait-for-pr
+ config:
+ repoURL: https://github.com/example/repo.git
+ prNumber: ${{ outputs['open-pr'].prNumber }}
+```
+
+### `argocd-update`
+
+`argocd-update` updates one or more Argo CD `Application` resources in various
+ways. Among other scenarios, this step is useful for the common one of forcing
+an Argo CD `Application` to sync after previous steps have updated a remote
+branch referenced by the `Application`. This step is commonly the last step in a
+promotion process.
+
+:::note
+For an Argo CD `Application` resource to be managed by a Kargo `Stage`,
+the `Application` _must_ have an annotation of the following form:
+
+```yaml
+kargo.akuity.io/authorized-stage: ":"
+```
+
+Such an annotation offers proof that a user who is themselves authorized
+to update the `Application` in question has consented to a specific
+`Stage` updating the `Application` as well.
+
+The following example shows how to configure an Argo CD `Application`
+manifest to authorize the `test` `Stage` of the `kargo-demo` `Project`:
+
+```yaml
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+ name: kargo-demo-test
+ namespace: argocd
+ annotations:
+ kargo.akuity.io/authorized-stage: kargo-demo:test
+spec:
+ # Application specifications go here
+```
+:::
+
+:::info
+Enforcement of Argo CD
+[sync windows](https://argo-cd.readthedocs.io/en/stable/user-guide/sync_windows/)
+was improved substantially in Argo CD v2.11.0. If you wish for the `argocd-update`
+step to honor sync windows, you must use Argo CD v2.11.0 or later.
+
+_Additionally, it is recommended that if a promotion process is expected to
+sometimes encounter an active deny window, the `argocd-update` step should be
+configured with a timeout that is at least as long as the longest expected deny
+window. (The step's default timeout is five minutes.)_
+:::
+
+#### `argocd-update` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `apps` | `[]object` | Y | Describes Argo CD `Application` resources to update and how to update them. At least one must be specified. |
+| `apps[].name` | `string` | Y | The name of the Argo CD `Application`. __Note:__ A small technical restriction on this field is that any [expressions](./20-expression-language.md) used therein are limited to accessing `ctx` and `vars` and may not access `secrets` or any Freight. This is because templates in this field are, at times, evaluated outside the context of an actual `Promotion` for the purposes of building an index. In practice, this restriction does not prove to be especially limiting. |
+| `apps[].namespace` | `string` | N | The namespace of the Argo CD `Application` resource to be updated. If left unspecified, the namespace will be the Kargo controller's configured default -- typically `argocd`. __Note:__ This field is subject to the same restrictions as the `name` field. See above. |
+| `apps[].sources` | `[]object` | N | Describes Argo CD `ApplicationSource`s to update and how to update them. |
+| `apps[].sources[].repoURL` | `string` | Y | The value of the target `ApplicationSource`'s own `repoURL` field. This must match exactly. |
+| `apps[].sources[].chart` | `string` | N | Applicable only when the target `ApplicationSource` references a Helm chart repository, the value of the target `ApplicationSource`'s own `chart` field. This must match exactly. |
+| `apps[].sources[].desiredRevision` | `string` | N | Specifies the desired revision for the source. i.e. The revision to which the source must be observably synced when performing a health check. This field is mutually exclusive with `desiredCommitFromStep`. Prior to v1.1.0, if both were left undefined, the desired revision was determined by Freight (if possible). Beginning with v1.1.0, if both are left undefined, Kargo will not require the source to be observably synced to any particular source to be considered healthy. Note that the source's `targetRevision` will not be updated to this revision unless `updateTargetRevision=true` is also set. |
+| `apps[].sources[].desiredCommitFromStep` | `string` | N | Applicable only when `repoURL` references a Git repository, this field references the `commit` output from a previous step and uses it as the desired revision for the source. i.e. The revision to which the source must be observably synced when performing a health check. This field is mutually exclusive with `desiredRevisionFromStep`. Prior to v1.1.0, if both were left undefined, the desired revision was determined by Freight (if possible). Beginning with v1.1.0, if both are left undefined, Kargo will not require the source to be observably synced to any particular source to be considered healthy. Note that the source's `targetRevision` will not be updated to this commit unless `updateTargetRevision=true` is also set.
__Deprecated: Use `desiredRevision` with an expression instead. Will be removed in v1.3.0.__ |
+| `apps[].sources[].updateTargetRevision` | `boolean` | Y | Indicates whether the target `ApplicationSource` should be updated such that its `targetRevision` field points directly at the desired revision. A `true` value in this field requires exactly one of `desiredCommitFromStep` or `desiredRevision` to be specified. |
+| `apps[].sources[].kustomize` | `object` | N | Describes updates to an Argo CD `ApplicationSource`'s Kustomize-specific properties. |
+| `apps[].sources[].kustomize.images` | `[]object` | Y | Describes how to update an Argo CD `ApplicationSource`'s Kustomize-specific properties to reference specific versions of container images. |
+| `apps[].sources[].kustomize.images[].repoURL` | `string` | Y | URL of the image being updated. |
+| `apps[].sources[].kustomize.images[].tag` | `string` | N | A tag naming a specific revision of the image specified by `repoURL`. Mutually exclusive with `digest` and `useDigest=true`. One of `digest`, `tag`, or `useDigest=true` must be specified. |
+| `apps[].sources[].kustomize.images[].digest` | `string` | N | A digest naming a specific revision of the image specified by `repoURL`. Mutually exclusive with `tag` and `useDigest=true`. One of `digest`, `tag`, or `useDigest=true` must be specified. |
+| `apps[].sources[].kustomize.images[].useDigest` | `boolean` | N | Whether to use the container image's digest instead of its tag. |
+| `apps[].sources[].kustomize.images[].newName` | `string` | N | A substitution for the name/URL of the image being updated. This is useful when different Stages have access to different container image repositories (assuming those different repositories contain equivalent images that are tagged identically). This may be a frequent consideration for users of Amazon's Elastic Container Registry. |
+| `apps[].sources[].kustomize.images[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). If not specified, may inherit a value from `apps[].sources[].kustomize.fromOrigin`.
__Deprecated: Use `digest` or `tag` with an expression instead. Will be removed in v1.3.0.__ |
+| `apps[].sources[].kustomize.fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). If not specified, may inherit a value from `apps[].sources[].fromOrigin`.
__Deprecated: Will be removed in v1.3.0.__ |
+| `apps[].sources[].helm` | `object` | N | Describes updates to an Argo CD `ApplicationSource`'s Helm parameters. |
+| `apps[].sources[].helm.images` | `[]object` | Y | Describes how to update an Argo CD `ApplicationSource`'s Helm parameters to reference specific versions of container images. |
+| `apps[].sources[].helm.images[].repoURL` | `string` | N | URL of the image being updated. __Deprecated: Use `value` with an expression instead. Will be removed in v1.3.0.__ |
+| `apps[].sources[].helm.images[].key` | `string` | Y | The key to update within the target `ApplicationSource`'s `helm.parameters` map. See Helm documentation on the [format and limitations](https://helm.sh/docs/intro/using_helm/#the-format-and-limitations-of---set) of the notation used in this field. |
+| `apps[].sources[].helm.images[].value` | `string` | Y | Specifies how the value of `key` is to be updated. When `repoURL` is non-empty, possible values for this field are limited to:
`ImageAndTag`: Replaces the value of `key` with a string in form `:`
`Tag`: Replaces the value of `key` with the image's tag
`ImageAndDigest`: Replaces the value of `key` with a string in form `@`
`Digest`: Replaces the value of `key` with the image's digest
When `repoURL` is empty, use an expression in this field to describe the new value. |
+| `apps[].sources[].helm.images[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). If not specified, may inherit a value from `apps[].sources[].helm.fromOrigin`.
__Deprecated: Use `value` with an expression instead. Will be removed in v1.3.0.__ |
+| `apps[].sources[].helm.fromOrigin` | `object` | N | See [specifying origins].(#specifying-origins). If not specified, may inherit a value from `apps[].sources[]`.
__Deprecated: Will be removed in v1.3.0.__ |
+| `apps[].sources[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). If not specified, may inherit a value from `apps[].fromOrigin`.
__Deprecated: Will be removed in v1.3.0.__ |
+| `apps[].fromOrigin` | `object` | N | See [specifying origins](#specifying-origins). If not specified, may inherit a value from `fromOrigin`.
__Deprecated: Will be removed in v1.3.0.__ |
+| `fromOrigin` | `object` | N | See [specifying origins](#specifying-origins).
__Deprecated: Will be removed in v1.3.0.__ |
+
+#### `argocd-update` Examples
+
+
+
+
+
+```yaml
+steps:
+# Clone, render manifests, commit, push, etc...
+- uses: git-commit
+ as: commit
+ config:
+ path: ./out
+ messageFromSteps:
+ - update-image
+- uses: git-push
+ config:
+ path: ./out
+- uses: argocd-update
+ config:
+ apps:
+ - name: my-app
+ sources:
+ - repoURL: https://github.com/example/repo.git
+ desiredRevision: ${{ outputs.commit.commit }}
+```
+
+
+
+
+
+:::caution
+Without making any modifications to a Git repository, this example simply
+updates a "live" Argo CD `Application` resource to point its `targetRevision`
+field at a specific version of a Helm chart, which Argo CD will pull directly
+from the chart repository.
+
+While this can be a useful technique, it should be used with caution. This is
+not "real GitOps" since the state of the `Application` resource is not backed
+up in a Git repository. If the `Application` resource were deleted, there would
+be no remaining record of its desired state.
+:::
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: argocd-update
+ config:
+ apps:
+ - name: my-app
+ sources:
+ - repoURL: ${{ chartRepo }}
+ chart: my-chart
+ targetRevision: ${{ chartFrom(chartRepo, "my-chart").Version }}
+```
+
+
+
+
+
+:::caution
+Without making any modifications to a Git repository, this example simply
+updates Kustomize-specific properties of a "live" Argo CD `Application`
+resource.
+
+While this can be a useful technique, it should be used with caution. This is
+not "real GitOps" since the state of the `Application` resource is not backed up
+in a Git repository. If the `Application` resource were deleted, there would be
+no remaining record of its desired state.
+:::
+
+```yaml
+vars:
+- name: gitRepo
+ value: https://github.com/example/repo.git
+steps:
+- uses: argocd-update
+ config:
+ apps:
+ - name: my-app
+ sources:
+ - repoURL: https://github.com/example/repo.git
+ kustomize:
+ images:
+ - repoURL: ${{ vars.imageRepo }}
+ tag: ${{ imageFrom(vars.imageRepo).Tag }}
+```
+
+
+
+
+
+:::caution
+Without making any modifications to a Git repository, this example simply
+updates Helm-specific properties of a "live" Argo CD `Application` resource.
+
+While this can be a useful technique, it should be used with caution. This is
+not "real GitOps" since the state of the `Application` resource is not backed
+up in a Git repository. If the `Application` resource were deleted, there would
+be no remaining record of its desired state.
+:::
+
+```yaml
+steps:
+- uses: argocd-update
+ config:
+ apps:
+ - name: my-app
+ sources:
+ - repoURL: https://github.com/example/repo.git
+ helm:
+ images:
+ - key: image.tag
+ value: ${{ imageFrom("my/image").Tag }}
+```
+
+
+
+
+
+#### `argocd-update` Health Checks
+
+The `argocd-update` step is unique among all other built-in promotion steps in
+that, on successful completion, it will register health checks to be performed
+upon the target Stage on an ongoing basis. This health check configuration is
+_opaque_ to the rest of Kargo and is understood only by health check
+functionality built into the step. This permits Kargo to factor the health and
+sync state of Argo CD `Application` resources into the overall health of a Stage
+without requiring Kargo to understand `Application` health directly.
+
+:::info
+Although the `argocd-update` step is the only promotion step to currently
+utilize this health check framework, we anticipate that future built-in and
+third-party promotion steps will take advantage of it as well.
+:::
+
+### `http`
+
+`http` is a generic step that makes an HTTP/S request to enable basic integration
+with a wide variety of external services.
+
+#### `http` Configuration
+
+| Name | Type | Required | Description |
+|------|------|----------|-------------|
+| `method` | `string` | Y | The HTTP method to use. |
+| `url` | `string` | Y | The URL to which the request should be made. |
+| `headers` | `[]object` | N | A list of headers to include in the request. |
+| `headers[].name` | `string` | Y | The name of the header. |
+| `headers[].value` | `string` | Y | The value of the header. |
+| `queryParams` | `[]object` | N | A list of query parameters to include in the request. |
+| `queryParams[].name` | `string` | Y | The name of the query parameter. |
+| `queryParams[].value` | `string` | Y | The value of the query parameter. The provided value will automatically be URL-encoded if necessary. |
+| `body` | `string` | N | The body of the request. __Note:__ As this field is a `string`, take care to utilize [`quote()`](./20-expression-language.md#quote) if the body is a valid JSON `object`. Refer to the example below of posting a message to a Slack channel. |
+| `insecureSkipTLSVerify` | `boolean` | N | Indicates whether to bypass TLS certificate verification when making the request. Setting this to `true` is highly discouraged. |
+| `timeout` | `string` | N | A string representation of the maximum time interval to wait for a request to complete. _This is the timeout for an individual HTTP request. If a request is retried, each attempt is independently subject to this timeout._ See Go's [`time` package docs](https://pkg.go.dev/time#ParseDuration) for a description of the accepted format. |
+| `successExpression` | `string` | N | An [expr-lang] expression that can evaluate the response to determine success. If this is left undefined and `failureExpression` _is_ defined, the default success criteria will be the inverse of the specified failure criteria. If both are left undefined, success is `true` when the HTTP status code is `2xx`. If `successExpression` and `failureExpression` are both defined and both evaluate to `true`, the failure takes precedence. Note that this expression should _not_ be offset by `${{` and `}}`. See examples for more details. |
+| `failureExpression` | `string` | N | An [expr-lang] expression that can evaluate the response to determine failure. If this is left undefined and `successExpression` _is_ defined, the default failure criteria will be the inverse of the specified success criteria. If both are left undefined, failure is `true` when the HTTP status code is _not_ `2xx`. If `successExpression` and `failureExpression` are both defined and both evaluate to `true`, the failure takes precedence. Note that this expression should _not_ be offset by `${{` and `}}`. See examples for more details. |
+| `outputs` | `[]object` | N | A list of rules for extracting outputs from the HTTP response. These are only applied to responses deemed successful. |
+| `outputs[].name` | `string` | Y | The name of the output. |
+| `outputs[].fromExpression` | `string` | Y | An [expr-lang] expression that can extract a value from the HTTP response. Note that this expression should _not_ be offset by `${{` and `}}`. See examples for more details. |
+
+:::note
+An HTTP response that is not conclusively determined to have succeeded or failed
+will result in the step reporting a result of `Running`. Kargo will
+[retry](#step-retries) such a step on its next attempt at reconciling the
+`Promotion` resource. This will continue until the step succeeds, fails,
+exhausts the configured maximum number of retries, or a configured timeout has
+elapsed.
+:::
+
+#### `http` Expressions
+
+The `successExpression`, `failureExpression`, and `outputs[].fromExpression`
+fields all support [expr-lang] expressions.
+
+:::note
+The expressions included in the `successExpression`, `failureExpression`, and
+`outputs[].fromExpression` fields should _not_ be offset by `${{` and `}}`. This
+is to prevent the expressions from being evaluated by Kargo during
+pre-processing of step configurations. The `http` step itself will evaluate
+these expressions.
+:::
+
+A `response` object (a `map[string]any`) is available to these expressions. It
+is structured as follows:
+
+| Field | Type | Description |
+|-------|------|-------------|
+| `status` | `int` | The HTTP status code of the response. |
+| `headers` | `http.Header` | The headers of the response. See applicable [Go documentation](https://pkg.go.dev/net/http#Header). |
+| `header` | `func(string) string` | `headers` can be inconvenient to work with directly. This function allows you to access a header by name. |
+| `body` | `map[string]any` | The body of the response, if any, unmarshaled into a map. If the response body is empty, this map will also be empty. |
+
+#### `http` Examples
+
+
+
+
+
+This examples configuration makes a `GET` request to the
+[Cat Facts API.](https://www.catfacts.net/api/) and uses the default
+success/failure criteria.
+
+```yaml
+steps:
+# ...
+- uses: http
+ as: cat-facts
+ config:
+ method: GET
+ url: https://www.catfacts.net/api/
+ outputs:
+ - name: status
+ fromExpression: response.status
+ - name: fact1
+ fromExpression: response.body.facts[0]
+ - name: fact2
+ fromExpression: response.body.facts[1]
+```
+
+Assuming a `200` response with the following JSON body:
+
+```json
+{
+ "facts": [
+ {
+ "fact_number": 1,
+ "fact": "Kittens have baby teeth, which are replaced by permanent teeth around the age of 7 months."
+ },
+ {
+ "fact_number": 2,
+ "fact": "Each day in the US, animal shelters are forced to destroy 30,000 dogs and cats."
+ }
+ ]
+}
+```
+
+The step would succeed and produce the following outputs:
+
+```yaml
+| Name | Type | Value |
+|----------|------|-------|
+| `status` | `int` | `200` |
+| `fact1` | `string` | `Kittens have baby teeth, which are replaced by permanent teeth around the age of 7 months.` |
+| `fact2` | `string` | `Each day in the US, animal shelters are forced to destroy 30,000 dogs and cats.` |
+```
+
+
+
+
+
+Building on the basic example, this configuration defines explicit success and
+failure criteria. Any response meeting neither of these criteria will result in
+the step reporting a result of `Running` and being retried. Note the use of
+[retry](#step-retries) configuration to set a timeout for the step.
+
+```yaml
+steps:
+# ...
+- uses: http
+ as: cat-facts
+ retry:
+ timeout: 10m
+ config:
+ method: GET
+ url: https://www.catfacts.net/api/
+ successExpression: response.status == 200
+ failureExpression: response.status == 404
+ outputs:
+ - name: status
+ fromExpression: response.status
+ - name: fact1
+ fromExpression: response.body.facts[0]
+ - name: fact2
+ fromExpression: response.body.facts[1]
+```
+
+Our request is considered:
+
+- Successful if the response status is `200`.
+- A failure if the response status is `404`.
+- Running if the response status is anything else. i.e. Any other status code
+ will result in a retry.
+
+
+
+
+
+This examples is adapted from
+[Slack's own documentation](https://api.slack.com/tutorials/tracks/posting-messages-with-curl):
+
+```yaml
+vars:
+- name: slackChannel
+ value: C123456
+steps:
+# ...
+- uses: http
+ config:
+ method: POST
+ url: https://slack.com/api/chat.postMessage
+ headers:
+ - name: Authorization
+ value: Bearer ${{ secrets.slack.token }}
+ - name: Content-Type
+ value: application/json
+ body: |
+ ${{ quote({
+ "channel": vars.slackChannel,
+ "blocks": [
+ {
+ "type": "section",
+ "text": {
+ "type": "mrkdwn",
+ "text": "Hi I am a bot that can post *_fancy_* messages to any public channel."
+ }
+ }
+ ]
+ }) }}
+```
+
+
+
+
+
+#### `http` Outputs
+
+The `http` step only produces the outputs described by the `outputs` field of
+its configuration.
+
+[expr-lang]: https://expr-lang.org/
diff --git a/docs/versioned_docs/version-1.1/35-references/20-expression-language.md b/docs/versioned_docs/version-1.1/35-references/20-expression-language.md
new file mode 100644
index 000000000..a1f78cb48
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/35-references/20-expression-language.md
@@ -0,0 +1,288 @@
+---
+sidebar_label: Expression Language Reference
+description: Learn about expression language support in promotion step configurations
+---
+
+# Expression Language Reference
+
+The steps of a user-defined promotion process may take advantage of expressions
+in their configuration.
+
+:::info
+The documentation on this page assumes a general familiarity with the concept of
+Promotions and some knowledge of how a promotion process is defined as a
+sequence of discrete steps.
+
+For an overview of Promotions, refer to the
+[concepts doc](../concepts#promotions).
+
+For detailed coverage of individual promotion steps, refer to the
+[Promotion Steps Reference](./10-promotion-steps.md).
+:::
+
+## Syntax
+
+All steps in a user-defined promotion processes (i.e. those described by a
+`Stage` resource's `spec.promotionTemplate.spec.steps` field) support the use of
+[expr-lang](https://expr-lang.org/) as a means of dynamically resolving values
+in their configuration at promotion time.
+
+All expressions must be enclosed within the `${{` and `}}` delimiters. This is
+not universally true for all applications of expr-lang. Kargo selected these
+specific delimiters to mimic GitHub Actions expression syntax, which many users
+will already be familiar with.
+
+Basic example:
+
+```yaml
+config:
+ message: ${{ "Hello, world!" }}
+```
+
+The above example will be evaluated as the following:
+
+```yaml
+config:
+ message: Hello, world!
+```
+
+The
+[expr-lang language definition docs](https://expr-lang.org/docs/language-definition)
+provide a comprehensive overview of the language's syntax and capabilities, so
+this reference will continue to focus only on Kargo-specific extensions and
+usage.
+
+## Behavior
+
+Kargo will evaluate expressions just-in-time as each step of a promotion process
+is executed. It will _only_ evaluate expressions within _values_ of a
+configuration block and will _not_ evaluate expressions within keys. Expressions
+in values are evaluated recursively, so expressions may be nested any number of
+levels deep within a configuration block.
+
+### Validation
+
+Kargo parses configuration blocks _before_ evaluating expressions, so any
+configuration containing expressions _must_ be well-formed YAML even prior to
+evaluation. Further validation (e.g. for adherence to a step-specific schema) is
+performed only _after_ expressions are evaluated.
+
+### Types
+
+Due to the requirement that configuration blocks be well-formed YAML, all fields
+containing expressions must be `string`s. Internally, all expressions will also
+evaluate to `string`s, however, Kargo will attempt to coerce the results to
+other valid JSON types (YAML is a superset of JSON) including `object`, `array`,
+`number`, `boolean`, and `null` before concluding that the evaluated expression
+should continue to be treated as a `string`.
+
+This behavior should be unsurprising and perhaps even familiar to experienced
+YAML users, as YAML parsers behave in the same way. `42`, for example, is
+interpreted as a JSON `number` unless it is explicitly quoted (i.e. `"42"`) to
+specify that it should be interpreted as a `string`.
+
+In practice, this means care should be taken to use Kargo's built-in `quote()`
+function in cases where an evaluated expression may appear to be a `number` or
+`boolean`, for instance, but should be treated as a `string`.
+
+For example:
+
+```yaml
+config:
+ numField: ${{ 40 + 2 }} # Will be treated as a number
+ strField: ${{ quote(40 + 2) }} # Will be treated as a string
+```
+
+The above example will be evaluated to the following:
+
+```yaml
+config:
+ numField: 42
+ strField: "42"
+```
+
+## Pre-Defined Variables
+
+Kargo provides a number of pre-defined variables that are accessible within
+expressions. This section enumerates these variables, their structure, and use.
+
+| Name | Type | Description |
+|------|------|-------------|
+| `ctx` | `object` | `string` fields `project`, `stage`, and `promotion` provide convenient access to details of a `Promotion`. |
+| `outputs` | `object` | A map of output from previous promotion steps indexed by step aliases. |
+| `secrets` | `object` | A map of maps indexed by the names of all Kubernetes `Secret`s in the `Promotion`'s `Project` and the keys within the `Data` block of each. |
+| `vars` | `object` | A user-defined map of variable names to static values of any type. The map is derived from a `Promotion`'s `spec.promotionTemplate.spec.vars` field. Variable names must observe standard Go variable-naming rules. Variables values may, themselves, be defined using an expression. `vars` (contains previously defined variables) and `ctx` are available to expressions defining the values of variables, however, `outputs` and `secrets` are not. |
+
+:::info
+Expect other useful variables to be added in the future.
+:::
+
+The following example promotion process clones a repository and checks out
+two branches to different directories, uses Kustomize with source from one
+branch to render some Kubernetes manifests that it commits to the other branch,
+and pushes back to the repository. These steps make extensive use of the
+pre-defined variables `ctx`, `outputs`, and `vars`.
+
+```yaml
+promotionTemplate:
+ spec:
+ vars:
+ - name: gitRepo
+ value: https://github.com/example/repo.git
+ - name: srcPath
+ value: ./src
+ - name: outPath
+ value: ./out
+ - name: targetBranch
+ value: stage/${{ ctx.stage }}
+ steps:
+ - uses: git-clone
+ config:
+ repoURL: ${{ vars.gitRepo }}
+ checkout:
+ - fromFreight: true
+ path: ${{ vars.srcPath }}
+ - branch: ${{ vars.targetBranch }}
+ create: true
+ path: ${{ vars.outPath }}
+ - uses: git-clear
+ config:
+ path: ${{ vars.outPath }}
+ - uses: kustomize-set-image
+ as: update-image
+ config:
+ path: ${{ vars.srcPath }}/base
+ images:
+ - image: public.ecr.aws/nginx/nginx
+ - uses: kustomize-build
+ config:
+ path: ${{ vars.srcPath }}/stages/${{ ctx.stage }}
+ outPath: ${{ vars.outPath }}
+ - uses: git-commit
+ as: commit
+ config:
+ path: ${{ vars.outPath }}
+ messageFromSteps:
+ - update-image
+ - uses: git-push
+ config:
+ path: ${{ vars.outPath }}
+ targetBranch: ${{ vars.targetBranch }}
+ - uses: argocd-update
+ config:
+ apps:
+ - name: example-${{ ctx.stage }}
+ sources:
+ - repoURL: ${{ vars.gitRepo }}
+ desiredRevision: ${{ outputs.commit.commit }}
+```
+
+:::info
+Since the usage of expressions and pre-defined variables effectively
+parameterizes the promotion process, the same promotion process can be reused in
+other `Projects` or `Stages` with few, if any, modifications (other than the
+definition of the static variables).
+
+At present, such re-use can be achieved only through manual copy/paste, but
+support for a new, top-level `PromotionTemplate` resource type is planned for an
+upcoming release.
+:::
+
+## Functions
+
+Several functions are built-in to Kargo's expression language. This section
+describes each of them.
+
+### `quote()`
+
+The `quote()` function takes a single argument of any type and returns a string
+representation. This is useful for scenarios where an expression evaluates to a
+non-`string` JSON type, but you wish to treat it as a `string` regardless.
+
+Example:
+
+```yaml
+config:
+ numField: ${{ 40 + 2 }} # Will be treated as a number
+ strField: ${{ quote(40 + 2) }} # Will be treated as a string
+```
+
+### `warehouse()`
+
+The `warehouse()` function takes a single argument of type `string`, which is the
+name of a `Warehouse` resource in the same `Project` as the `Promotion` being
+executed. It returns a `FreightOrigin` object representing that `Warehouse`.
+
+The `FreightOrigin` object can be used as an optional argument to the
+`commitFrom()`, `imageFrom()`, or `chartFrom()` functions to disambiguate the
+desired source of an artifact when necessary.
+
+See the next sections for examples.
+
+### `commitFrom()`
+
+The `commitFrom()` function takes the URL of a Git repository as its first
+argument and returns a corresponding `GitCommit` object from the `Promotion`'s
+`FreightCollection`.
+
+In the event that a `Stage` requests `Freight` from multiple origins
+(`Warehouse`s) and more than one of those can provide a `GitCommit` object from
+the specified repository, a `FreightOrigin` may be used as a second argument to
+disambiguate the desired source.
+
+Example:
+
+```yaml
+config:
+ commitID: ${{ commitFrom("https://github.com/example/repo.git", warehouse("my-warehouse")).ID }}
+```
+
+### `imageFrom()`
+
+The `imageFrom()` function takes the URL of a container image repository as its
+first argument and returns a corresponding `Image` object from the `Promotion`'s
+`FreightCollection`.
+
+In the event that a `Stage` requests `Freight` from multiple origins
+(`Warehouse`s) and more than one of those can provide an `Image` object from the
+specified repository, a `FreightOrigin` may be used as a second argument to
+disambiguate the desired source.
+
+Example:
+
+```yaml
+config:
+ imageTag: ${{ imageFrom("public.ecr.aws/nginx/nginx", warehouse("my-warehouse")).Tag }}
+```
+
+### `chartFrom()`
+
+The `chartFrom()` function takes the URL of a Helm chart repository as its first
+argument and returns a corresponding `Chart` object from the `Promotion`'s
+`FreightCollection`.
+
+For Helm charts stored in OCI registries, the URL should be the full path to the
+repository within that registry.
+
+For Helm charts stored in classic (http/s) repositories, which can store
+multiple different charts within a single repository, a second argument should
+be used to specify the name of the chart within the repository.
+
+In the event that a `Stage` requests `Freight` from multiple origins
+(`Warehouse`s) and more than one of those can provide a `Chart` object from the
+specified repository, a `FreightOrigin` may be used as a final argument to
+disambiguate the desired source.
+
+OCI registry example:
+
+```yaml
+config:
+ chartVersion: ${{ chartFrom("oci://example.com/my-chart", warehouse("my-warehouse")).Version }}
+```
+
+Classic repository example:
+
+```yaml
+config:
+ chartVersion: ${{ chartFrom("https://example.com/charts", "my-chart", warehouse("my-warehouse")).Version }}
+```
diff --git a/docs/versioned_docs/version-1.1/35-references/_category_.json b/docs/versioned_docs/version-1.1/35-references/_category_.json
new file mode 100644
index 000000000..bf7735e44
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/35-references/_category_.json
@@ -0,0 +1,4 @@
+{
+ "label": "Reference Docs",
+ "link": null
+}
diff --git a/docs/versioned_docs/version-1.1/40-contributor-guide/10-hacking-on-kargo.md b/docs/versioned_docs/version-1.1/40-contributor-guide/10-hacking-on-kargo.md
new file mode 100644
index 000000000..6788c824f
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/40-contributor-guide/10-hacking-on-kargo.md
@@ -0,0 +1,467 @@
+---
+description: Learn how to set up a development environment to begin contributing to Kargo
+sidebar_label: Hacking on Kargo
+---
+
+# Hacking on Kargo
+
+Kargo is implemented in Go. For maximum productivity in your text editor or IDE,
+it is recommended that you have installed the latest stable releases of Go and
+applicable editor/IDE extensions, however, this is not strictly required to be
+successful.
+
+## Running Tests
+
+In order to minimize the setup required to apply small changes and to reduce the
+incidence of tests passing locally, but failing during the continuous
+integration process due to environmental differences, we've made it easy to
+execute tests within a container that is maximally similar to those used in CI.
+
+To take advantage of this, you only need `make` and
+[Docker](https://docs.docker.com/engine/install/) (or a Docker-compatible
+container-runtime).
+
+To run all unit tests:
+
+```shell
+make hack-test-unit
+```
+
+:::info
+If you wish to opt-out of executing the tests within a container (for
+performance reasons, perhaps), drop the `hack-` prefix from the target:
+
+```shell
+make test-unit
+```
+
+This will require Go to be installed locally.
+:::
+
+## Running Linters
+
+It is also possible to execute a variety of different linters that perform
+static code analysis, detect code hygiene issues, assert adherence to project
+standards, etc. As with unit tests, we've made it easy to execute linters within
+a container that is maximally similar to those used in CI.
+
+To lint Go code only:
+
+```shell
+make hack-lint-go
+```
+
+To lint generated protobuf definitions only:
+
+```shell
+make hack-lint-proto
+```
+
+To lint Helm charts only:
+
+```shell
+make hack-lint-charts
+```
+
+To run _all_ linters with one command:
+
+```shell
+make hack-lint
+```
+
+:::info
+If you wish to opt-out of executing any or all linters within a container (for
+performance reasons, perhaps), drop the `hack-` prefix from the desired target.
+
+This will require quite a variety of tools to be installed locally, so we do not
+recommend this if you can avoid it.
+:::
+
+## Executing Code Generation
+
+Anytime the contents of the `api/` directory have been modified, a code
+generation process must be manually executed. As with tests and linters, this
+process is easy to execute within a container, which eliminates the need to
+install various tools or specific versions thereof:
+
+```shell
+make hack-codegen
+```
+
+:::info
+If you wish to opt-out of executing code-generation within a container (for
+performance reasons, perhaps), drop the `hack-` prefix from the target:
+
+```shell
+make codegen
+```
+
+This will require quite a variety of tools to be installed locally, so we do not
+recommend this if you can avoid it.
+:::
+
+## Building the Image
+
+To build source into a Docker image that will be tagged as `kargo:dev`,
+execute the following:
+
+```shell
+make hack-build
+```
+
+:::info
+There is seldom a need to do this, as the next section will cover a better
+option for rapidly building and deploying Kargo from source.
+:::
+
+:::tip
+The [Docker buildx](https://github.com/docker/buildx) machine required by the
+build process has to be created with the `--driver-opt network=host` option to
+allow it to access the (temporary) local image registry used for the base image.
+
+If you encounter an error during the build process (e.g. `failed to resolve
+source metadata for localhost:5001/kargo-base:latest-arm64` or `granting
+entitlement network.host is not allowed by build daemon configuration`), you
+may need to (re)create the machine using `docker buildx create` with this
+option set.
+:::
+
+## Iterating Quickly
+
+This section focuses on the best approaches for gaining rapid feedback on
+changes you make to Kargo's code base.
+
+The fastest path to learning whether changes you have applied work as desired is
+to execute unit tests as described in previous sections. If the changes you are
+applying are complex, it can also be advantageous to exercise them, end-to-end,
+as a user would. Because Kargo is dependent on a Kubernetes cluster, this raises
+the question of how Kargo can not only be built from source, but also deployed
+to a live Kubernetes cluster efficiently enough to enable a tight feedback loop
+as you continue iterating on your changes.
+
+The remainder of this section covers the approaches we recommend for enabling
+this.
+
+:::info
+We may eventually provide convenient methods of running _some_ Kargo components
+as native processes.
+:::
+
+1. Launch or re-use an existing local Kubernetes cluster.
+
+ Any of the following options are viable:
+
+
+
+
+ If you are a
+ [Docker Desktop](https://www.docker.com/products/docker-desktop/)
+ user, you can follow
+ [these instructions](https://docs.docker.com/desktop/kubernetes/) to enable
+ its built-in Kubernetes support.
+
+ :::info
+ A specific benefit of this option is that nothing special is required in
+ terms of creating a local image registry connected to the cluster.
+ Additionally, this approach requires no specific port-forwarding rules to be
+ defined.
+ :::
+ :::info
+ Although this is one of the fastest paths to a local Kubernetes cluster, be
+ aware that Docker Desktop supports only a _single_ Kubernetes cluster. If
+ that cluster reaches a state you are dissatisfied with, resetting it will
+ remove not just Kargo-related resources, but _all_ your workloads and data.
+ :::
+
+ To install Kargo's prerequisites, you will need
+ [Helm](https://helm.sh/docs/intro/install/) installed first, and can then
+ execute a convenient `make` target:
+
+ ```shell
+ make hack-install-prereqs
+ ```
+
+
+
+
+ [OrbStack](https://orbstack.dev/) is a fast, lightweight, drop-in replacement
+ for Docker Desktop for Mac OS only. You can follow
+ [these instructions](https://docs.docker.com/desktop/kubernetes/) to enable
+ its built-in Kubernetes support.
+
+ :::info
+ A specific benefit of this option is that nothing special is required in
+ terms of creating a local image registry connected to the cluster.
+ Additionally, this approach requires no specific port-forwarding rules to be
+ defined.
+ :::
+ :::info
+ Although this is one of the fastest paths to a local Kubernetes cluster, be
+ aware that OrbStack supports only a _single_ Kubernetes cluster. If
+ that cluster reaches a state you are dissatisfied with, resetting it will
+ remove not just Kargo-related resources, but _all_ your workloads and data.
+ :::
+
+ To install Kargo's prerequisites, you will need
+ [Helm](https://helm.sh/docs/intro/install/) installed first, and can then
+ execute a convenient `make` target:
+
+ ```shell
+ make hack-install-prereqs
+ ```
+
+
+
+
+ If you have any Docker-compatible container runtime installed (including
+ native Docker, Docker Desktop, or OrbStack), you can easily launch a
+ disposable cluster to facilitate Kargo development using
+ [kind](https://kind.sigs.k8s.io/#installation-and-usage).
+
+ This option also requires
+ [ctlptl](https://github.com/tilt-dev/ctlptl#how-do-i-install-it) and
+ [Helm](https://helm.sh/docs/intro/install/) to be installed.
+
+ The following `make` target will launch a kind cluster with a local image
+ registry wired into it, various port-forwarding rules pre-configured, and
+ Kargo's prerequisites installed:
+
+ ```shell
+ make hack-kind-up
+ ```
+
+ :::info
+ While this option is a bit more complex than using Docker Desktop or OrbStack
+ directly, it offers the advantage of being fully-disposable. If your cluster
+ reaches a state you are dissatisfied with, you can simply destroy it and
+ launch a new one.
+ :::
+
+
+
+
+ If you have any Docker-compatible container runtime installed (including
+ native Docker, Docker Desktop, or OrbStack), you can easily launch a
+ disposable cluster to facilitate Kargo development using
+ [k3d](https://k3d.io).
+
+ This option also requires
+ [ctlptl](https://github.com/tilt-dev/ctlptl#how-do-i-install-it) and
+ [Helm](https://helm.sh/docs/intro/install/) to be installed.
+
+ The following `make` target will launch a kind cluster with a local image
+ registry wired into it, various port-forwarding rules pre-configured, and
+ Kargo's prerequisites installed:
+
+ ```shell
+ make hack-k3d-up
+ ```
+
+ :::info
+ While this option is a bit more complex than using Docker Desktop or OrbStack
+ directly, it offers the advantage of being fully-disposable. If your cluster
+ reaches a state you are dissatisfied with, you can simply destroy it and
+ launch a new one.
+ :::
+
+
+
+
+ Whichever approach you choose, your cluster will end up with recent, stable
+ versions of [cert-manager](https://cert-manager.io/) and
+ [Argo CD](https://argoproj.github.io/cd/) installed.
+
+ :::info
+ The Argo CD dashboard will be exposed at
+ [localhost:30080](https://localhost:30080).
+
+ The username and password are both `admin`.
+
+ You may safely ignore any certificate warnings.
+ :::
+
+1. Build and deploy Kargo from source:
+
+ [Tilt](https://docs.tilt.dev/#macoslinux) is a convenient tool that builds
+ container images from source and seamlessly deploys them to a local
+ Kubernetes cluster. More importantly, it enables developers to rapidly
+ rebuild and replace running components with the click of a button.
+
+ :::warning
+ If using OrbStack, be advised it is only compatible with Tilt as of Tilt
+ v0.33.6. Please use that version or greater.
+ :::
+
+ ```shell
+ tilt up
+ ```
+
+ Tilt will also launch a web-based UI running at
+ [http://localhost:10350](http://localhost:10350). Visit this in your web
+ browser to view the build and deployment status of each Kargo component as
+ well as the logs from each component.
+
+ :::info
+ Tilt is often configured to watch files and automatically rebuild and replace
+ running components when their source code is changed. This is deliberately
+ disabled for Kargo since the Docker image takes long enough to build that
+ it’s better to conserve system resources by only rebuilding when you choose.
+ The web UI makes it easy to identify components whose source has been
+ altered. They can be rebuilt and replaced with a single click.
+ :::
+
+1. If necessary, build the CLI from source:
+
+ ```shell
+ make hack-build-cli
+ ```
+
+ This will produce an executable at `bin/kargo--`.
+
+ You can log in using:
+
+ ```shell
+ bin/kargo-- login http://localhost:30081 \
+ --admin \
+ --password admin \
+ --insecure-skip-tls-verify
+ ```
+
+1. If necessary, access the Kargo UI at
+ [localhost:30082](http://localhost:30082).
+
+ The admin account password is `admin`.
+
+ You may safely ignore any certificate warnings.
+
+1. When you are done with Tilt, interrupt the running `tilt up` process with
+ `ctrl + c`. Components _will remain running in the cluster_, but Tilt will no
+ longer be in control. If Tilt is restarted later, it will retake control of
+ the already-running components.
+
+ If you wish to undeploy everything Tilt has deployed for you, use `tilt
+ down`.
+
+1. Clean up your local Kubernetes cluster.
+
+
+
+
+ Docker Desktop supports only a _single_ Kubernetes cluster. If you are
+ comfortable deleting not just just Kargo-related resources, but _all_ your
+ workloads and data, the cluster can be reset from the Docker Desktop
+ Dashboard.
+
+ If, instead, you wish to preserve non-Kargo-related workloads and data, you
+ will need to manually uninstall Kargo's prerequisites:
+
+ ```
+ make hack-uninstall-prereqs
+ ```
+
+
+
+
+ OrbStack supports only a _single_ Kubernetes cluster. If you are
+ comfortable deleting not just just Kargo-related resources, but _all_ your
+ workloads and data, you can destroy the cluster with:
+
+ ```shell
+ orb delete k8s
+ ```
+
+ If, instead, you wish to preserve non-Kargo-related workloads and data, you
+ will need to manually uninstall Kargo's prerequisites:
+
+ ```
+ make hack-uninstall-prereqs
+ ```
+
+
+
+
+ To destroy the cluster, use:
+
+ ```shell
+ make hack-kind-down
+ ```
+
+ :::info
+ This command deliberately leaves your local image registry running so that if
+ you resume work later, you are doing so with a local registry that’s already
+ primed with most layers of Kargo’s image.
+
+ If you wish to stop the registry, use:
+
+ ```shell
+ docker stop kargo-dev-registry
+ ```
+
+ To destroy it, use:
+
+ ```shell
+ docker rm -f kargo-dev-registry
+ ```
+ :::
+
+
+
+
+ To destroy the cluster, use:
+
+ ```shell
+ make hack-k3d-down
+ ```
+
+ :::info
+ This command deliberately leaves your local image registry running so that if
+ you resume work later, you are doing so with a local registry that’s already
+ primed with most layers of Kargo’s image.
+
+ If you wish to stop the registry, use:
+
+ ```shell
+ docker stop kargo-dev-registry
+ ```
+
+ To destroy it, use:
+
+ ```shell
+ docker rm -f kargo-dev-registry
+ ```
+ :::
+
+
+
+
+## Contributing to Documentation
+
+Contributors should ensure that their changes are accompanied by relevant documentation
+updates. This helps maintain the project's sustainability. Pull requests with
+corresponding documentation updates are more likely to be merged faster.
+
+To make this process smoother, you can refer to [Docusaurus](https://docusaurus.io/docs)
+for guidance on writing and maintaining docs effectively.
+
+### Previewing Doc Changes Locally
+
+After making your changes, preview the documentation locally to ensure everything renders
+correctly. You can either run it in a container or natively on your system.
+
+To build and serve the docs inside a container:
+
+```shell
+make hack-serve-docs
+```
+
+:::info
+If you wish to opt-out of executing code-generation within a container (for
+performance reasons, perhaps), drop the `hack-` prefix from the target to run the docs natively on your system:
+
+```shell
+make serve-docs
+```
+
+This will require quite a variety of tools to be installed locally, so we do not
+recommend this if you can avoid it.
+:::
diff --git a/docs/versioned_docs/version-1.1/40-contributor-guide/15-release-procedures.md b/docs/versioned_docs/version-1.1/40-contributor-guide/15-release-procedures.md
new file mode 100644
index 000000000..fe017ed7b
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/40-contributor-guide/15-release-procedures.md
@@ -0,0 +1,170 @@
+---
+description: Steps required by Kargo maintainers to orchestrate a minor or major release of Kargo.
+sidebar_label: Release Procedures
+---
+
+# Release Procedures
+
+This document outlines the few manual steps that Kargo maintainers must follow
+to orchestrate a minor or major release of Kargo.
+
+## Conventions
+
+Throughout this document, we will use:
+
+* `M` and `m` to denote the major and minor version numbers of the upcoming
+ release (i.e. the one being performed), respectively.
+
+* `M-1` and `m-1` to denote the _previous_ major and minor version numbers,
+ respectively.
+
+* `M+1` and `m+1` to denote the _next_ major and minor version numbers,
+ respectively.
+
+* `L` to denote the latest minor version of the `M-1` line.
+
+## Timeline
+
+The steps outlined below should be started on the Monday preceding the expected
+release date -- which is always a Friday.
+
+## Steps
+
+1. Open a PR [similar to this one](https://github.com/akuity/kargo/pull/1932)
+ to revise the roadmap.
+
+ * The roadmap should be updated to reflect that work for the `vM.m.0`
+ release is complete.
+ * Planned work that was not completed should be moved to a future release.
+ * The next release (`vM.m+1.0` or `vM+1.0.0`) should be updated to reflect
+ that work is in-progress, along with the expected release date.
+
+ :::note
+ "Edge" documentation at
+ [main.kargo.akuity.io](https://main.docs.kargo.io) is continuously
+ published from the `main` branch and production documentation at
+ [kargo.akuity.io](https://docs.kargo.io) is continuously published from
+ the previous release branch (`release-M.m-1` or `release-M-1.L`). There
+ are two consequences of this:
+
+ * The production documentation will _not_ immediately reflect changes made
+ to the `main` branch, nor will it reflect changes made to the release branch
+ for the upcoming release. (Which does not exist yet. See next step.)
+
+ * This step should ideally be performed _prior_ to the creation of the
+ release branch (see next step) in order to avoid the need for two separate
+ PRs to update both branches.
+ :::
+
+1. Create a release branch of the form `release-M.m`.
+
+ This can be done locally by a maintainer. Presuming `upstream` is a remote
+ pointing to the main Kargo repository:
+
+ ```shell
+ git checkout main
+ git pull upstream main
+ git checkout -b release-M.m
+ git push upstream release-M.m
+ ```
+
+ :::note
+ After the creation of this branch, anything merged to `main` is excluded
+ from the upcoming release unless explicitly cherry-picked into the
+ `release-M.m branch`. As such, this step should ideally be performed
+ _after_ the majority of work for the upcoming release is complete.
+
+ In some cases, this may be performed early to:
+
+ * Un-block work on the next release.
+ * Facilitate the creation of a release candidate for use by non-engineers
+ while work on the upcoming release continues.
+ :::
+
+1. Merge any release-specific upgrade logic into the `release-M.m` branch.
+
+ :::info
+ Pre-`v1.0.0`, we are making a best effort to automatically compensate for
+ breaking changes between minor releases for users upgrading _directly_ from
+ any release in the `v0.m-1` line. This means release-specific upgrade
+ logic does not need to be merged into `main`.
+ :::
+
+1. Open a PR [similar to this one](https://github.com/akuity/kargo/pull/1925)
+ against the previous release branch (`release-M.m-1` or `release-M-1.L`) to
+ lock production documentation (e.g. for download and installation procedures)
+ into permanently reflecting the latest stable release.
+
+ :::note
+ Production documentation is continuously published from the previous
+ release branch, so this step is necessary to ensure that the production
+ documentation is not inadvertently broken by any subsequent steps.
+
+ This step will also ensure that when the current production documentation
+ is archived, it will reflect the latest release to which that documentation
+ was applicable.
+ :::
+
+1. Cut `vM.m.0-rc.1` from the Kargo
+ [release page](https://github.com/akuity/kargo/releases/new).
+
+ * The release process itself is fully-automated.
+ * Be certain to reference the head of the `release-M.m` branch and _not_ `main`.
+ * Be sure to check the __"Set as a pre-release"__ box.
+ * Wait for the
+ [automated release process](https://github.com/akuity/kargo/actions/workflows/release.yaml)
+ to complete.
+
+1. Open a PR [like this one](https://github.com/akuity/kargo/pull/1926) against
+ `main` to make the edge documentation (e.g. for download and installation
+ procedures) reflect the recently built release candidate.
+
+ :::info
+ The edge documentation is continuously published from the `main` branch, so
+ this step makes it easy for non-engineers to test the release candidate by
+ adhering to instructions in the edge documentation, without any need to
+ compensate for the release candidate not being counted as "latest" on
+ account of being a pre-release.
+ :::
+
+1. Alert non-engineer stakeholders to the availability of the release candidate.
+
+1. Bug fixes and last minute features should be merged to `main` and backported
+ to the `release-M.m` (in bulk, when possible).
+
+1. Repeat steps 5-8 as necessary until the release candidate is deemed stable
+ by relevant stakeholders.
+
+1. Draft release notes for the upcoming release.
+
+ :::info
+ This can be done concurrently with the previous steps.
+
+ Some stakeholders may desire early access to these notes to inform blog
+ posts, marketing materials, etc.
+ :::
+
+1. Cut `vM.m.0` from the Kargo
+ [release page](https://github.com/akuity/kargo/releases/new).
+
+ * Be certain to reference the head of the `release-M.m` branch and _not_ `main`.
+ * Be certain to include the final draft of the release notes.
+ * Be sure to check the __"Set as the latest release"__ box.
+ * Wait for the
+ [automated release process](https://github.com/akuity/kargo/actions/workflows/release.yaml)
+ to complete.
+
+1. Mark the release branch (`release-M.m`) as the __"Production branch"__
+ [in Netlify](https://app.netlify.com/sites/docs-kargo-akuity-io/configuration/deploys#branches-and-deploy-contexts).
+
+ * Also add the previous release branch (`release-M.m-1` or
+ `release-M-1.L`) to __"Branch deploys"__.
+ * After changing the __"Production branch"__, it will be necessary to
+ [manually trigger a deployment](https://app.netlify.com/sites/docs-kargo-io/deploys)
+ of the production documentation.
+
+1. Open a PR to revert the changes from step 6.
+
+1. Inform relevant stakeholders that the release is complete.
+
+1. 🎉 Celebrate!
diff --git a/docs/versioned_docs/version-1.1/40-contributor-guide/20-signing-commits.md b/docs/versioned_docs/version-1.1/40-contributor-guide/20-signing-commits.md
new file mode 100644
index 000000000..d9f580933
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/40-contributor-guide/20-signing-commits.md
@@ -0,0 +1,73 @@
+---
+description: Find out how to sign commits when contributing to Kargo
+sidebar_label: Signing Commits
+---
+
+# Signing Commits
+
+All commits merged into Kargo's main branch MUST bear a DCO (Developer
+Certificate of Origin) sign-off. This is a line placed at the end of a commit
+message containing a contributor’s “signature.” In adding this, the contributor
+certifies that they have the right to contribute the material in question.
+
+Here are the steps to sign your work:
+
+1. Verify the contribution in your commit complies with the
+ [terms of the DCO](https://developercertificate.org/).
+
+1. Add a line like the following to your commit message:
+
+ ```
+ Signed-off-by: Joe Smith
+ ```
+
+ You MUST use your legal name -- handles or other pseudonyms are not
+ permitted.
+
+ While you could manually add DCO sign-off to every commit, there is an easier
+ way:
+
+ 1. Configure your git client appropriately. This is one-time setup.
+
+ ```shell
+ git config user.name
+ git config user.email
+ ```
+
+ If you work on multiple projects that require a DCO sign-off, you can
+ configure your git client to use these settings globally instead of only
+ for Kargo:
+
+ ```shell
+ git config --global user.name
+ git config --global user.email
+ ```
+
+ 1. Use the --signoff or -s (lowercase) flag when making each commit. For
+ example:
+
+ ```shell
+ git commit --message "" --signoff
+ ```
+
+ If you ever make a commit and forget to use the `--signoff` flag, you can
+ amend your commit with this information before pushing:
+
+ ```shell
+ git commit --amend --signoff
+ ```
+
+ 1. You can verify the above worked as expected using `git log`. Your latest
+ commit should look similar to this one:
+
+ ```shell
+ Author: Joe Smith
+ Date: Thu Feb 2 11:41:15 2018 -0800
+
+ Update README
+
+ Signed-off-by: Joe Smith
+ ```
+
+ Notice the `Author` and `Signed-off-by` lines match. If they do not, the
+ PR will be rejected by the automated DCO check.
diff --git a/docs/versioned_docs/version-1.1/40-contributor-guide/30-code-of-conduct.md b/docs/versioned_docs/version-1.1/40-contributor-guide/30-code-of-conduct.md
new file mode 100644
index 000000000..ac3901b34
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/40-contributor-guide/30-code-of-conduct.md
@@ -0,0 +1,137 @@
+---
+sidebar_label: Code of Conduct
+description: Contributor Code of Conduct for the open source Kargo project
+---
+
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual
+identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall
+ community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or advances of
+ any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email address,
+ without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+[kent@akuity.io](mailto:kent@akuity.io).
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series of
+actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
+ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within the
+community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
+[https://www.contributor-covenant.org/translations][translations].
+
+[homepage]: https://www.contributor-covenant.org
+[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
diff --git a/docs/versioned_docs/version-1.1/40-contributor-guide/5-debugging-kargo.md b/docs/versioned_docs/version-1.1/40-contributor-guide/5-debugging-kargo.md
new file mode 100644
index 000000000..f606be7fb
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/40-contributor-guide/5-debugging-kargo.md
@@ -0,0 +1,63 @@
+---
+description: Steps to help you debug Kargo when you run into issues.
+sidebar_label: Debugging Kargo
+---
+
+# Debugging Kargo
+
+From time to time, you may need to debug Kargo. This document outlines options
+to help you achieve a better understanding of what Kargo (internally) is doing,
+especially when you are running into issues which are not immediately obvious
+by just reading the code.
+
+As a Kargo user, you may not need to debug Kargo itself, but this document may
+serve you when a Kargo maintainer asks you to provide additional information
+about an issue you are facing.
+
+## Enabling pprof endpoints
+
+Kargo components can be configured to expose [`pprof` endpoints](https://golang.org/pkg/net/http/pprof/).
+These endpoints can be used to profile the components when they are running,
+and can be useful to understand what the components are doing and where they
+are spending time.
+
+To enable the `pprof` endpoint on a component, you can set the
+`PPROF_BIND_ADDRESS` environment variable to the address where the component
+should listen for `pprof` requests. For example, to enable the `pprof` endpoint
+on port `6060` of the controller, you can set the `PPROF_BIND_ADDRESS`
+environment variable to `:6060`.
+
+```yaml
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: kargo-controller
+spec:
+ # ...omitted for brevity
+ template:
+ spec:
+ containers:
+ - name: kargo-controller
+ env:
+ - name: PPROF_BIND_ADDRESS
+ value: ":6060"
+```
+
+After setting the `PPROF_BIND_ADDRESS` environment variable, the `pprof`
+endpoints will be available at `http://:6060/debug/pprof/`.
+
+### Collecting a profile
+
+To collect a profile, you can port-forward the `pprof` address to your local
+machine and collect the data from an endpoint of choice. For example, to
+collect a heap profile, you can run:
+
+```console
+$ kubectl port-forward -n deployment/ 6060
+$ curl -Sk -v http://localhost:6060/debug/pprof/heap > heap.out
+```
+
+This will collect a heap profile in the `heap.out` file, which you can then
+[analyze using `go`](https://go.dev/blog/pprof), or share with a Kargo
+maintainer.
diff --git a/docs/versioned_docs/version-1.1/40-contributor-guide/index.md b/docs/versioned_docs/version-1.1/40-contributor-guide/index.md
new file mode 100644
index 000000000..45d0c8252
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/40-contributor-guide/index.md
@@ -0,0 +1,16 @@
+---
+description: A comprehensive introduction for developers who are looking to get involved with contributing directly to the Kargo project
+sidebar_label: Contributor Guide
+---
+
+# Kargo Contributor Guide
+
+This contributor guide is intended as a comprehensive introduction for
+developers who are looking to get involved with contributing directly to the
+Kargo project.
+
+This guide is decomposed into the following, high-level topics:
+
+* [Hacking on Kargo](./10-hacking-on-kargo.md)
+* [Signing Commits](./20-signing-commits.md)
+* [Code of Conduct](./30-code-of-conduct.md)
diff --git a/docs/versioned_docs/version-1.1/45-resources.md b/docs/versioned_docs/version-1.1/45-resources.md
new file mode 100644
index 000000000..6da6a651a
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/45-resources.md
@@ -0,0 +1,50 @@
+---
+description: Learn about Kargo through our talks from conferences
+sidebar_label: Resources
+---
+
+# Resources
+
+Learn more about Kargo through talks and webinars presented at conferences like KubeCon, ArgoCon, GitOpsCon, etc!
+
+## Kargo GA Webinar 🎉
+By Kelsey Hightower & Jesse Suen
+
+
+
+
+
+
+
+## Streamlining Kubernetes with Kargo
+By Christian Hernandez | GitHub OpenSourceFriday 2024
+
+
+
+
+
+
+
+---
+
+## GitOps Pipelines: Everything Everywhere All at Once
+By Christian Hernandez | GitOpsCon North America 2024
+
+
+
+
+
+
+
+---
+
+## Multi-Stage Deployment Pipelines the GitOps Way
+By Jesse Suen & Kent Rancourt | GitOpsCon Europe 2023
+
+
+
+
+
+
+
+---
\ No newline at end of file
diff --git a/docs/versioned_docs/version-1.1/50-roadmap.md b/docs/versioned_docs/version-1.1/50-roadmap.md
new file mode 100644
index 000000000..d6070f705
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/50-roadmap.md
@@ -0,0 +1,126 @@
+---
+sidebar_label: Roadmap
+Description: See what's on the roadmap of Kargo and find out more about the latest releases
+---
+
+# Kargo Roadmap
+
+Over a series of releases, Kargo's maintainers have settled into a cadence of a
+minor release roughly every five weeks, with two or three major features
+completed per release.
+
+:::caution
+This roadmap tracks only _major_ features and is subject to change at any time,
+for the most up-to-date information, please see the [GitHub
+Project](https://github.com/akuity/kargo/milestones)
+:::
+
+## In Progress
+
+### v1.1.0
+
+__Expected:__ 22 November 2024
+
+This release will focus on improving the flexibility of the promotion steps
+introduced in v0.9.0 through the addition of support for an expression language.
+
+This release also kicks off a three phase plan with the end goal of enabling
+custom/third-party promotion steps.
+
+## Upcoming
+
+### v1.2.0
+
+This release is to be the second phase of three advancing Kargo toward support
+for custom/third-party promotion steps, with a focus on ensuring a secure and
+isolated execution environment for those steps.
+
+### v1.3.0
+
+The third and final phase of the three advancing Kargo toward support for
+custom/third-party promotion steps will focus on:
+
+* Establishing a formal specification for developers wishing to implement their
+ own promotion steps.
+
+* Building the mechanisms whereby operators may install and users may leverage
+ versioned, custom/third-party promotion steps.
+
+### v1.4.0 and Beyond
+
+* Packaging common workflows as pre-defined, composite promotion steps.
+* TBD
+
+## Completed
+
+### v1.0.0
+
+v1.0.0 was our long-anticipated GA release containing only small features,
+bug fixes, stability improvements, and the final removal of the legacy
+promotion mechanisms that were deprecated in v0.9.0.
+
+### v0.9.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| [Promotion Steps](https://github.com/akuity/kargo/issues/2219) | strategic refactor | Transitioned from opinionated promotion mechanisms to an ordered lists of more finely-grained promotion directives steps reminiscent of GitHub Actions. These enable greater flexibility in addressing outlying use cases and have left us with a clear path forward for to eventually enable third-party integrations. |
+| Production Readiness | chore |
Prioritized stability of existing features.
Paid down technical debt.
**This does not mean v0.9.0 is production-ready. It means it is several steps closer to it.**
|
+
+### v0.8.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| Auth via [GitHub Apps](https://docs.github.com/en/apps) | feature | Support GitHub Apps as an authentication option for GitHub repositories. |
+| Multiple `Freight` per `Stage` | feature | Permit `Stage`s to host multiple pieces of `Freight` from different `Warehouse`s. Different artifacts, or sets of artifacts, can be promoted through parallel pipelines with different/independent cadence. |
+| Production Readiness | chore |
Prioritized stability of existing features.
Paid down technical debt.
**This does not mean v0.8.0 is production-ready. It means it is several steps closer to it.**
|
+
+### v0.7.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| Multiple `Warehouse`s | feature | Improved UI support for displaying Freight from multiple `Warehouse`s. |
+| Manual `Freight` Creation | feature | Added UI feature for manual `Freight` creation. |
+| ECR/GAR Support | feature | Added multiple options for authenticating to image repositories in ECR and Google Artifact Registry, including support for EKS Pod Identity and GKE Workload Identity Federation. |
+| [Patch Promotions](https://github.com/akuity/kargo/issues/1250) | poc | Support a generalized option to promote arbitrary configuration (e.g. strings, files, and directories) to other paths of a GitOps repository. |
+| Production Readiness | chore | Prioritized stability of existing features. **This does not mean v0.7.0 is production-ready. It means it is several steps closer to it.** |
+
+### v0.6.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| Project Management | feature | Added user / role / permission management capabilities to the CLI and UI. |
+| Events | feature | Kargo emits noteworthy events as Kubernetes events. Events are also viewable in the UI. |
+| Production Readiness | chore | Prioritized stability of existing features. **This does not mean v0.6.0 is production-ready. It means it is several steps closer to it.** |
+
+### v0.5.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `Warehouse` Rules/Filters | feature | Introduced optional path-based constraints on Git repository subscriptions. |
+| Credential Storage | refactor | Simplified and streamlined format and storage of repository credentials. |
+| Credential Management | feature | Added credential management capabilities to the CLI and UI. |
+| CLI Improvements | refactor | Overhauled the CLI to make the tree of sub-commands more intuitive, with improved consistency in usage and documentation from command to command. |
+| UI Improvements | feature | Achieved near-parity with CLI features. |
+
+### v0.4.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `Warehouse` Rules/Filters | feature | Introduced optional tag-based constraints on Git repository subscriptions. |
+| Project Management | feature |
Introduced `Project` CRD to simplify project initialization.
Removed `PromotionPolicy` CRD and folded its functionality directly into the `Project` CRD.
|
+
+### v0.3.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| GitHub PR-Based Promotion | feature | Pull request-based promotions are now supported on GitHub. |
+| Verifications | feature | `Stage` resources can now execute a user-defined verification process after a promotion. These can be defined using Argo Rollouts `AnalysisTemplate` resources, and executions take the form of `AnalysisRun` resources. |
+| Improved RBAC | feature | SSO user identities can now be mapped to Kubernetes `ServiceAccount` resources using annotations. |
+
+### v0.2.0
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `Freight` CRD | feature | Freight changed from being a property of a `Stage`, to being its own `Freight` CRD. |
+| `Warehouse` CRD | feature | `Freight` production was decoupled from a pipeline's first `Stage` and now comes from a `Warehouse`. |
+| Kargo Render | breaking change | The Bookkeeper project was rebranded as Kargo Render -- a Kargo sub-project for rendering manifests. |
diff --git a/docs/versioned_docs/version-1.1/assets/architecture.png b/docs/versioned_docs/version-1.1/assets/architecture.png
new file mode 100644
index 000000000..e4baba6d3
Binary files /dev/null and b/docs/versioned_docs/version-1.1/assets/architecture.png differ
diff --git a/docs/versioned_docs/version-1.1/assets/argo-dashboard.png b/docs/versioned_docs/version-1.1/assets/argo-dashboard.png
new file mode 100644
index 000000000..fcdee7a1f
Binary files /dev/null and b/docs/versioned_docs/version-1.1/assets/argo-dashboard.png differ
diff --git a/docs/versioned_docs/version-1.1/assets/kargo-dashboard-projects.png b/docs/versioned_docs/version-1.1/assets/kargo-dashboard-projects.png
new file mode 100644
index 000000000..3d6df83f7
Binary files /dev/null and b/docs/versioned_docs/version-1.1/assets/kargo-dashboard-projects.png differ
diff --git a/docs/versioned_docs/version-1.1/assets/kargo-dashboard-promotion.png b/docs/versioned_docs/version-1.1/assets/kargo-dashboard-promotion.png
new file mode 100644
index 000000000..4087592de
Binary files /dev/null and b/docs/versioned_docs/version-1.1/assets/kargo-dashboard-promotion.png differ
diff --git a/docs/versioned_docs/version-1.1/assets/kargo-freight-verified.png b/docs/versioned_docs/version-1.1/assets/kargo-freight-verified.png
new file mode 100644
index 000000000..d9e7f8d07
Binary files /dev/null and b/docs/versioned_docs/version-1.1/assets/kargo-freight-verified.png differ
diff --git a/docs/versioned_docs/version-1.1/assets/kargo-frieght-timeline.png b/docs/versioned_docs/version-1.1/assets/kargo-frieght-timeline.png
new file mode 100644
index 000000000..7ae78a0c5
Binary files /dev/null and b/docs/versioned_docs/version-1.1/assets/kargo-frieght-timeline.png differ
diff --git a/docs/versioned_docs/version-1.1/assets/kargo-projects.png b/docs/versioned_docs/version-1.1/assets/kargo-projects.png
new file mode 100644
index 000000000..6f4737479
Binary files /dev/null and b/docs/versioned_docs/version-1.1/assets/kargo-projects.png differ
diff --git a/docs/versioned_docs/version-1.1/assets/kargo-promote-option-2.png b/docs/versioned_docs/version-1.1/assets/kargo-promote-option-2.png
new file mode 100644
index 000000000..fe37f0d95
Binary files /dev/null and b/docs/versioned_docs/version-1.1/assets/kargo-promote-option-2.png differ
diff --git a/docs/versioned_docs/version-1.1/assets/kargo-promote-option.png b/docs/versioned_docs/version-1.1/assets/kargo-promote-option.png
new file mode 100644
index 000000000..1532d4136
Binary files /dev/null and b/docs/versioned_docs/version-1.1/assets/kargo-promote-option.png differ
diff --git a/docs/versioned_docs/version-1.1/assets/kargo.png b/docs/versioned_docs/version-1.1/assets/kargo.png
new file mode 100644
index 000000000..67bd6ad0a
Binary files /dev/null and b/docs/versioned_docs/version-1.1/assets/kargo.png differ
diff --git a/docs/versioned_docs/version-1.1/assets/logo.svg b/docs/versioned_docs/version-1.1/assets/logo.svg
new file mode 100644
index 000000000..9db6d0d06
--- /dev/null
+++ b/docs/versioned_docs/version-1.1/assets/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/versioned_docs/version-1.1/assets/screenshot.png b/docs/versioned_docs/version-1.1/assets/screenshot.png
new file mode 100644
index 000000000..d059fd67e
Binary files /dev/null and b/docs/versioned_docs/version-1.1/assets/screenshot.png differ
diff --git a/docs/versioned_sidebars/version-1.0-sidebars.json b/docs/versioned_sidebars/version-1.0-sidebars.json
new file mode 100644
index 000000000..cd411e376
--- /dev/null
+++ b/docs/versioned_sidebars/version-1.0-sidebars.json
@@ -0,0 +1,13 @@
+{
+ "tutorialSidebar": [
+ {
+ "type": "autogenerated",
+ "dirName": "."
+ },
+ {
+ "type": "link",
+ "label": "CRD Reference",
+ "href": "https://doc.crds.dev/github.com/akuity/kargo"
+ }
+ ]
+}
diff --git a/docs/versioned_sidebars/version-1.1-sidebars.json b/docs/versioned_sidebars/version-1.1-sidebars.json
new file mode 100644
index 000000000..cd411e376
--- /dev/null
+++ b/docs/versioned_sidebars/version-1.1-sidebars.json
@@ -0,0 +1,13 @@
+{
+ "tutorialSidebar": [
+ {
+ "type": "autogenerated",
+ "dirName": "."
+ },
+ {
+ "type": "link",
+ "label": "CRD Reference",
+ "href": "https://doc.crds.dev/github.com/akuity/kargo"
+ }
+ ]
+}
diff --git a/docs/versions.json b/docs/versions.json
new file mode 100644
index 000000000..a74314cd1
--- /dev/null
+++ b/docs/versions.json
@@ -0,0 +1,4 @@
+[
+ "1.1",
+ "1.0"
+]