Skip to content

Commit 5e66e32

Browse files
OwenKephartclaude
authored andcommitted
Update state-backed component skill reference docs for clarity and accuracy (#22134)
Reorganize and expand state-backed component reference documentation in the dagster-expert skill to reflect actual Dagster+ behavior and operational details. The original docs were written from an OSS-first perspective and omitted critical information about how the system works in production on Dagster+. ## Key Changes - Fixed DbtProjectComponent description to accurately explain `shutil.copytree` behavior instead of misleading "writes manifest, reads with dbt's manifest parser" text - Reorganized VERSIONED_STATE_STORAGE into Dagster+ (automatic S3) and OSS/self-hosted (manual configuration) distinct sections - Added state storage availability section clarifying all processes require DefsStateStorage access - Added programmatic state refresh pattern showing how to trigger state updates independently of deploys via custom jobs - Added code location reload behavior section distinguishing Dagster+ (pinned versions, needs explicit refresh) from OSS (reads latest on reload) with GraphQL mutation example <details> <summary>Files Changed</summary> ### Modified (4 files) - `public/skills/skills/dagster-expert/skills/dagster-expert/references/asset-selection.md` - Formatting improvement (blank line) - `public/skills/skills/dagster-expert/skills/dagster-expert/references/components/state-backed/creating.md` - Fixed DbtProjectComponent description accuracy - `public/skills/skills/dagster-expert/skills/dagster-expert/references/components/state-backed/using.md` - Clarified Dagster+ vs OSS paths, added storage availability, programmatic refresh, and reload behavior sections - `public/skills/skills/dagster-expert/skills/dagster-expert/references/components/subclassing-components.md` - Added trailing newline </details> <details> <summary>original-plan</summary> # Update state-backed component skill reference docs ## Context The dagster-expert skill's state-backed component reference docs led to several wrong/misleading answers in a Q&A evaluation. The root cause is that the docs are written from an OSS-first perspective, but state-backed components are primarily used on Dagster+ where the experience is simpler (automatic storage, managed infra). Several operational details are also missing or inaccurate. ## Files to edit - `public/skills/skills/dagster-expert/skills/dagster-expert/references/components/state-backed/creating.md` - `public/skills/skills/dagster-expert/skills/dagster-expert/references/components/state-backed/using.md` ## Changes ### creating.md — 1 edit **Fix DbtProjectComponent description** in the "Tool's native format" section. Current text says it "writes dbt manifest, reads it with dbt's manifest parser." Actually it copies the entire project directory into the state path (via `shutil.copytree`), including running `dbt deps` if necessary. `build_defs_from_state` then reads the manifest from within that full project copy. ### using.md — 5 edits **A. Rewrite VERSIONED_STATE_STORAGE to lead with Dagster+** - Update strategy table: note that Dagster+ provides this automatically - Split the section into "Dagster+ (automatic)" and "OSS/self-hosted (manual config)" - The dagster.yaml config block should be clearly labeled as OSS-only - Dagster+ uploads/downloads state to an S3 bucket managed by Dagster Labs — no user config needed **B. Add error handling note** (new short subsection after LEGACY_CODE_SERVER_SNAPSHOTS) - If DefsStateStorage is unreachable during code location load → hard failure (not graceful degradation) - In Dagster+ this is not a practical concern since the bucket is managed by Dagster Labs **C. Add programmatic state refresh pattern** (new subsection under CI/CD State Refresh) - A component can produce a job with an op that calls its own `write_state_to_path` - That job can be triggered via manual runs, schedules, sensors, or GraphQL - This decouples state refresh from the deploy cycle entirely **D. Add "Code Location Reloads and Versioned State" section** (new, before Common Components) - Dagster+: each code location load is pinned to specific defs state versions; normal reload does NOT update them; separate GraphQL query needed to pull in latest versions - OSS: no version tracking; every reload pulls latest state - This explains when definition changes from a state refresh become visible **E. Add migration guidance** (new short section, before Common Components) - Straightforward: swap management_type, rebuild state, verify - Start with one component as proof of concept, then migrate the rest - No data migration needed — refresh rebuilds from external systems ## Verification After making edits, re-read both files to verify accuracy and that they're not overly long (these load into LLM context). The docs should answer these questions correctly: - "Does Dagster+ Cloud provide DefsStateStorage automatically?" → Yes - "What happens if storage is unreachable during load?" → Hard failure - "Can I refresh state without redeploying?" → Yes, via job pattern - "Does a normal code location reload pick up new state?" → In Dagster+ no, in OSS yes </details> <!-- WARNING: Machine-generated. Manual edits may break erk tooling. --> <!-- erk:metadata-block:plan-header --> <details> <summary>plan-header</summary> ```yaml schema_version: '2' created_at: '2026-03-27T13:43:11.547466+00:00' created_by: OwenKephart plan_comment_id: null last_dispatched_run_id: null last_dispatched_node_id: null last_dispatched_at: null last_local_impl_at: '2026-03-27T20:47:36.979490+00:00' last_local_impl_event: ended last_local_impl_session: f7a9a515-e9d4-423a-81c9-26917f9311eb last_local_impl_user: owen last_remote_impl_at: null last_remote_impl_run_id: null last_remote_impl_session_id: null branch_name: plnd/update-state-backed-docs-03-27-1343 created_from_session: 2d3d5cfe-d06c-476e-a35e-0eb02f4b6cc2 lifecycle_stage: impl last_session_branch: planned-pr-context/22134 last_session_id: f7a9a515-e9d4-423a-81c9-26917f9311eb last_session_at: '2026-03-27T13:47:41.425071+00:00' last_session_source: local worktree_name: erk-slot-04 ``` </details> <!-- /erk:metadata-block:plan-header --> --- To replicate this PR locally, run: ``` erk pr teleport 22134 ``` --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Internal-RevId: 88546ea5a41bfe90ff121fb0b24a2713d83b6f32
1 parent 27af24b commit 5e66e32

4 files changed

Lines changed: 78 additions & 9 deletions

File tree

skills/dagster-expert/skills/dagster-expert/references/asset-selection.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ sel = dg.AssetSelection.from_coercible("tag:priority=high and kind:dbt")
8989
### Parsing Selection Strings
9090

9191
`dg.AssetSelection.from_coercible()` converts a selection string (or other coercible types) into an `AssetSelection` object. It accepts:
92+
9293
- A selection string (parsed using the same grammar as the UI and CLI)
9394
- An existing `AssetSelection` instance (returned as-is)
9495
- A sequence of strings (each parsed and unioned together)

skills/dagster-expert/skills/dagster-expert/references/components/state-backed/creating.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ class MyComponent(dg.StateBackedComponent, dg.Model, dg.Resolvable):
160160

161161
### Tool's native format (for tools with existing artifacts)
162162

163-
Write tool artifacts directly and read them with the tool's own parser. Best when the tool already produces a well-defined artifact format. Used by DbtProjectComponent (writes dbt manifest, reads it with dbt's manifest parser).
163+
Write tool artifacts directly and read them with the tool's own parser. Best when the tool already produces a well-defined artifact format. Used by DbtProjectComponent (copies the entire dbt project directory into the state path via `shutil.copytree`, including running `dbt deps` if necessary; `build_defs_from_state` then reads the manifest from within that full project copy).
164164

165165
```python nocheckundefined
166166
class MyToolComponent(dg.StateBackedComponent, dg.Resolvable):

skills/dagster-expert/skills/dagster-expert/references/components/state-backed/using.md

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ The framework controls when refresh happens based on the configured management s
1717

1818
## State Management Strategies
1919

20-
| Strategy | Storage | Refresh Mechanism | Best For |
21-
| ------------------------------ | ----------------------------------- | ------------------------------------------------------------ | ------------------------------------------ |
22-
| `LOCAL_FILESYSTEM` | `.local_defs_state/` in project dir | `dg utils refresh-defs-state` in CI before building artifact | Most deployments |
23-
| `VERSIONED_STATE_STORAGE` | Cloud storage (S3/GCS/Azure) | `dg utils refresh-defs-state` or independent of deploys | Decoupling state updates from image builds |
24-
| `LEGACY_CODE_SERVER_SNAPSHOTS` | In-memory | Auto-refresh on every code server load | Not recommended; changing in 1.13.0 |
20+
| Strategy | Storage | Refresh Mechanism | Best For |
21+
| ------------------------------ | ----------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------- |
22+
| `LOCAL_FILESYSTEM` | `.local_defs_state/` in project dir | `dg utils refresh-defs-state` in CI before building artifact | Most deployments |
23+
| `VERSIONED_STATE_STORAGE` | Cloud storage (S3 on Dagster+, or S3/GCS/Azure) | `dg utils refresh-defs-state` or independent of deploys | Dagster+ (automatic); decoupling state from builds |
24+
| `LEGACY_CODE_SERVER_SNAPSHOTS` | In-memory | Auto-refresh on every code server load | Not recommended; changing in 1.13.0 |
2525

2626
### LOCAL_FILESYSTEM
2727

@@ -41,10 +41,18 @@ my_project/
4141

4242
### VERSIONED_STATE_STORAGE
4343

44-
State is stored in cloud storage with UUID-based versioning. Enables state updates without rebuilding deployment artifacts. Requires `dagster.yaml` configuration:
44+
State is stored in cloud storage with UUID-based versioning. Enables state updates without rebuilding deployment artifacts.
45+
46+
#### Dagster+ (automatic)
47+
48+
On Dagster+, `VERSIONED_STATE_STORAGE` works automatically with no user configuration. Dagster+ uploads and downloads state to an S3 bucket managed by Dagster Labs. Simply set `management_type: VERSIONED_STATE_STORAGE` on your component and Dagster+ handles the rest.
49+
50+
#### OSS / self-hosted (manual configuration)
51+
52+
For OSS or self-hosted deployments, you must configure `dagster.yaml` with a storage backend:
4553

4654
```yaml
47-
# dagster.yaml
55+
# dagster.yaml (OSS / self-hosted only — not needed on Dagster+)
4856
defs_state_storage:
4957
module: dagster._core.storage.defs_state.blob_storage_state_storage
5058
class: UPathDefsStateStorage
@@ -56,6 +64,10 @@ defs_state_storage:
5664
5765
In-memory state that auto-refreshes on every code server load. This is the current default for backwards compatibility but is **not recommended**. The default will change in version 1.13.0. Explicitly set `management_type` to `LOCAL_FILESYSTEM` or `VERSIONED_STATE_STORAGE` instead.
5866

67+
### State Storage Availability
68+
69+
All code location loads and run processes require access to the configured `DefsStateStorage`, as state is downloaded in all of these cases. The configured storage must be high-availability.
70+
5971
## Configuring State-Backed Components
6072

6173
Each state-backed component accepts a `defs_state` field in its YAML configuration:
@@ -132,6 +144,62 @@ Or scaffold a complete CI/CD workflow with state refresh included:
132144
uv run dg scaffold github-actions
133145
```
134146

147+
### Programmatic State Refresh (Without Redeploying)
148+
149+
A component can produce a job that calls `self.refresh_state(project_root)`, decoupling state refresh from the deploy cycle entirely. This job can be triggered via manual runs, schedules, sensors, or the GraphQL API.
150+
151+
```python nocheckundefined
152+
import asyncio
153+
import dagster as dg
154+
155+
156+
class MyApiComponent(dg.StateBackedComponent, dg.Model, dg.Resolvable):
157+
api_url: str
158+
159+
# ... defs_state_config, write_state_to_path, build_defs_from_state ...
160+
161+
def build_defs_from_state(
162+
self, context: dg.ComponentLoadContext, state_path: Path | None
163+
) -> dg.Definitions:
164+
assets = ... # build assets from state
165+
op_name = f"refresh_state_{hash(self.defs_state_config.key) % 10**8}"
166+
167+
@dg.op(name=op_name)
168+
def refresh_my_api_state():
169+
asyncio.run(self.refresh_state(context.project_root))
170+
171+
@dg.job(name="refresh_my_api_component_state")
172+
def refresh_job():
173+
refresh_my_api_state()
174+
175+
return dg.Definitions(assets=assets, jobs=[refresh_job])
176+
```
177+
178+
After the job runs, the new state is persisted. On Dagster+, use "Refresh definitions state" in the UI or the `refreshDefsState` GraphQL mutation to pick up the new versions (see below). On OSS, the next code location reload automatically uses the latest state.
179+
180+
## Code Location Reloads and Versioned State
181+
182+
How state updates become visible depends on the deployment model:
183+
184+
- **Dagster+**: Each code location load is pinned to specific defs state versions. A normal code location reload does **not** automatically pick up new state versions. To pull in the latest versions, use the "Refresh definitions state" option in the code location dropdown menu in the Dagster UI, or call the `refreshDefsState` GraphQL mutation:
185+
186+
```graphql
187+
mutation RefreshDefsStateMutation($locationName: String!) {
188+
refreshDefsState(locationName: $locationName) {
189+
... on WorkspaceEntry {
190+
locationName
191+
}
192+
... on RefreshDefsStateError {
193+
message
194+
}
195+
}
196+
}
197+
```
198+
199+
- **OSS / self-hosted**: There is no version pinning. Every code location reload reads the latest state from the configured storage backend. State updates are visible immediately after reload.
200+
201+
This distinction matters when using programmatic refresh or CI/CD pipelines that update state independently of deploys — on Dagster+, you must explicitly request the new versions; on OSS, a reload is sufficient.
202+
135203
## Common State-Backed Components
136204

137205
- **Tableau** — `dagster_tableau.TableauComponent`

skills/dagster-expert/skills/dagster-expert/references/components/subclassing-components.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,4 @@ class CustomComponent(ExistingStateBackedComponent):
7676
sensors=[my_custom_sensor],
7777
resources=base_defs.resources,
7878
)
79-
```
79+
```

0 commit comments

Comments
 (0)