From 2edb6e588ab7ac3763edc29e61580e93b7cc959a Mon Sep 17 00:00:00 2001
From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com>
Date: Fri, 29 May 2026 10:54:01 +0000
Subject: [PATCH 1/4] docs: document download-only content-as-code scope for
editors
---
references/workspace/custom-roles.mdx | 18 ++++++++++++++++++
references/workspace/roles.mdx | 6 ++++--
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/references/workspace/custom-roles.mdx b/references/workspace/custom-roles.mdx
index 6941f46c..84d7737e 100644
--- a/references/workspace/custom-roles.mdx
+++ b/references/workspace/custom-roles.mdx
@@ -103,6 +103,24 @@ Custom roles are assigned at the project level to provide granular access contro
## Scope reference
+### Content-as-code scopes
+
+Two scopes control access to [content as code](/guides/developer/dashboards-as-code), the CLI workflow for managing charts and dashboards as YAML files.
+
+**Download content as code** (`view:ContentAsCode`) lets a user pull existing charts and dashboards as YAML via `lightdash download`. It does not allow pushing changes back.
+
+**Download and upload content as code** (`manage:ContentAsCode`) grants both download and upload. Users with this scope can run `lightdash upload` to overwrite charts and dashboards in the project.
+
+Use **download-only** to let a user pull production YAML for local development, diffing, or inspection without giving them the ability to overwrite production content. Combine with a controlled promotion path (e.g., CI/CD running with a service account that holds the manage scope) so writes only land via the pipeline.
+
+For example, to protect a production project from accidental `lightdash upload` overwrites:
+
+1. Downgrade the user's org role to **Member** or **Viewer** so they don't inherit `manage:ContentAsCode` from their org role.
+2. Create a custom project role with only **Download content as code** enabled (plus whatever else they need).
+3. Assign the custom role to the user on the production project.
+
+The user can now run `lightdash download` against production but will get a `403` on `lightdash upload`.
+
### SQL-related scopes
Three scopes control different SQL-authoring features. They are independent — granting one does not grant the others.
diff --git a/references/workspace/roles.mdx b/references/workspace/roles.mdx
index 0f1f2985..f5119486 100644
--- a/references/workspace/roles.mdx
+++ b/references/workspace/roles.mdx
@@ -35,7 +35,8 @@ Project Admins can invite users to their project and assign users or [groups](/r
| Manage project access and permissions | | | | | |
| Delete project | | | | | |
| Create a preview project | | | | | |
-| Use dashboards as code (CLI) | | | | | |
+| Download content as code (CLI) | | | | | |
+| Upload content as code (CLI) | | | | | |
| Rename models, dimensions, and metrics (CLI and UI) | | | | | |
@@ -54,7 +55,8 @@ Organization Admins can assign roles to organization members, which gives access
| Admin for **all** projects | | | | | | |
| Invite users to organization | | | | | | |
| Manage organization access and permissions | | | | | | |
-| Use dashboards as code (CLI) | | | | | |
+| Download content as code (CLI) | | | | | |
+| Upload content as code (CLI) | | | | | |
| Rename models, dimensions, and metrics (CLI and UI) | | | | | |
From 3033b958ac9a9f2f1621b7db11d142337e7b5214 Mon Sep 17 00:00:00 2001
From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com>
Date: Tue, 9 Jun 2026 11:42:54 +0000
Subject: [PATCH 2/4] docs: document manage:ContentAsCode@self scope for
own-preview uploads
---
references/workspace/custom-roles.mdx | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/references/workspace/custom-roles.mdx b/references/workspace/custom-roles.mdx
index 84d7737e..6e84a122 100644
--- a/references/workspace/custom-roles.mdx
+++ b/references/workspace/custom-roles.mdx
@@ -105,21 +105,27 @@ Custom roles are assigned at the project level to provide granular access contro
### Content-as-code scopes
-Two scopes control access to [content as code](/guides/developer/dashboards-as-code), the CLI workflow for managing charts and dashboards as YAML files.
+Three scopes control access to [content as code](/guides/developer/dashboards-as-code), the CLI workflow for managing charts and dashboards as YAML files. They form a read → write → narrow-write ladder.
-**Download content as code** (`view:ContentAsCode`) lets a user pull existing charts and dashboards as YAML via `lightdash download`. It does not allow pushing changes back.
+**Download content as code** (`view:ContentAsCode`) lets a user pull existing charts and dashboards as YAML via `lightdash download`. It does not allow pushing changes back. This is the common "let people pull templates" grant.
-**Download and upload content as code** (`manage:ContentAsCode`) grants both download and upload. Users with this scope can run `lightdash upload` to overwrite charts and dashboards in the project.
+**Upload content as code to own previews** (`manage:ContentAsCode@self`) is a narrow upload right: users can run `lightdash upload` only against preview projects they created themselves. This is the intended day-to-day scope for non-Developer users in CI/CD-style workflows where they need to validate their own preview but shouldn't push to shared projects. Pair it with `view:ContentAsCode` so they can still pull from shared projects.
+
+**Download and upload content as code** (`manage:ContentAsCode`) grants both download and upload across any project the role applies to. Users with this scope can run `lightdash upload` to overwrite charts and dashboards in the project. This implies `view:ContentAsCode` and the `@self` upload right.
Use **download-only** to let a user pull production YAML for local development, diffing, or inspection without giving them the ability to overwrite production content. Combine with a controlled promotion path (e.g., CI/CD running with a service account that holds the manage scope) so writes only land via the pipeline.
-For example, to protect a production project from accidental `lightdash upload` overwrites:
+For example, to protect a production project from accidental `lightdash upload` overwrites while still letting users iterate on previews:
1. Downgrade the user's org role to **Member** or **Viewer** so they don't inherit `manage:ContentAsCode` from their org role.
-2. Create a custom project role with only **Download content as code** enabled (plus whatever else they need).
+2. Create a custom project role with **Download content as code** and **Upload content as code to own previews** enabled (plus whatever else they need).
3. Assign the custom role to the user on the production project.
-The user can now run `lightdash download` against production but will get a `403` on `lightdash upload`.
+The user can now run `lightdash download` against production and `lightdash upload` against their own preview projects, but will get a `403` on `lightdash upload` to production.
+
+
+ A custom role cloned from **Developer** can drop the full **Upload content as code** scope while keeping **Upload content as code to own previews** — this mirrors built-in Developer behavior for the own-preview case while removing write access to shared projects.
+
### SQL-related scopes
From 8e10c2e43eb1be4514ba4ddf0cc4c880ac728636 Mon Sep 17 00:00:00 2001
From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com>
Date: Tue, 9 Jun 2026 12:01:13 +0000
Subject: [PATCH 3/4] docs: expand agentic development workflow for
content-as-code scopes
---
references/workspace/custom-roles.mdx | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/references/workspace/custom-roles.mdx b/references/workspace/custom-roles.mdx
index 6e84a122..cd659174 100644
--- a/references/workspace/custom-roles.mdx
+++ b/references/workspace/custom-roles.mdx
@@ -115,17 +115,26 @@ Three scopes control access to [content as code](/guides/developer/dashboards-as
Use **download-only** to let a user pull production YAML for local development, diffing, or inspection without giving them the ability to overwrite production content. Combine with a controlled promotion path (e.g., CI/CD running with a service account that holds the manage scope) so writes only land via the pipeline.
-For example, to protect a production project from accidental `lightdash upload` overwrites while still letting users iterate on previews:
+#### Restrict developers to preview uploads (agentic development workflow)
-1. Downgrade the user's org role to **Member** or **Viewer** so they don't inherit `manage:ContentAsCode` from their org role.
-2. Create a custom project role with **Download content as code** and **Upload content as code to own previews** enabled (plus whatever else they need).
-3. Assign the custom role to the user on the production project.
+A common pattern for agentic development of dashboards and content as code is to let developers iterate freely on their own preview projects while preventing direct `lightdash upload` to production. Promotion to production then happens through a reviewed CI/CD pipeline instead of an individual's CLI.
-The user can now run `lightdash download` against production and `lightdash upload` against their own preview projects, but will get a `403` on `lightdash upload` to production.
+To set this up:
-
- A custom role cloned from **Developer** can drop the full **Upload content as code** scope while keeping **Upload content as code to own previews** — this mirrors built-in Developer behavior for the own-preview case while removing write access to shared projects.
-
+1. **Clone the built-in Developer role** to create a custom role (for example, `Developer (no prod upload)`).
+2. **Remove** the **Download and upload content as code** (`manage:ContentAsCode`) scope from the cloned role.
+3. **Add** the **Download content as code** (`view:ContentAsCode`) and **Upload content as code to own previews** (`manage:ContentAsCode@self`) scopes.
+4. **Assign the custom role to the user at the project level** on the production project.
+
+
+ Custom project roles can only narrow scopes the user would otherwise inherit. If the user is an **Organization Admin** or **Organization Developer**, they will inherit `manage:ContentAsCode` from their org role and the project-level custom role will not block them. For this pattern to work, the user's organization role must be **Viewer**, **Interactive Viewer**, or **Member**.
+
+
+With this setup, the user can:
+
+- Run `lightdash download` against the production project to pull YAML for local editing.
+- Run `lightdash preview` and `lightdash upload` against their own preview projects to validate changes.
+- Receive a `403` when attempting `lightdash upload` against the production project — production writes must go through the promotion pipeline.
### SQL-related scopes
From 28c38b797be82b763e2035f556b7e3fbb86f8f6b Mon Sep 17 00:00:00 2001
From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com>
Date: Tue, 9 Jun 2026 12:04:25 +0000
Subject: [PATCH 4/4] docs: mention UI promote-content as alternative prod
promotion path
---
references/workspace/custom-roles.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/references/workspace/custom-roles.mdx b/references/workspace/custom-roles.mdx
index cd659174..1d8eaf8c 100644
--- a/references/workspace/custom-roles.mdx
+++ b/references/workspace/custom-roles.mdx
@@ -117,7 +117,7 @@ Use **download-only** to let a user pull production YAML for local development,
#### Restrict developers to preview uploads (agentic development workflow)
-A common pattern for agentic development of dashboards and content as code is to let developers iterate freely on their own preview projects while preventing direct `lightdash upload` to production. Promotion to production then happens through a reviewed CI/CD pipeline instead of an individual's CLI.
+A common pattern for agentic development of dashboards and content as code is to let developers iterate freely on their own preview projects while preventing direct `lightdash upload` to production. Promotion to production then happens through a reviewed CI/CD pipeline instead of an individual's CLI, or through [promoting content](/guides/how-to-promote-content) in the UI.
To set this up: