Vibecoding State — Workshop Runtime Contract
This skill is the single source of truth for how every prompt in the repo-root Instructions.md workshop and its worked instantiations (e.g. example/skyloyalty/WALKTHROUGH.md) interacts with the shared per-user state file and the async per-prompt retrospective file.
Prompts do not re-state the "Vibecoding state contract / Preamble / Postamble / Pathway Applicability guard / Retrospective contract" prose. They invoke this skill with typed parameters and this skill owns the behavior.
When to Use
Invoke this skill — always — when executing any vibecoding workshop prompt. Specifically:
- Every prompt in
Instructions.md (Prompt 0.1 through 8.24).
- Every prompt in
example/<use_case>/WALKTHROUGH.md (e.g. SkyLoyalty's 22 prompts).
- Every post-workshop per-prompt retro + the single session rollup.
Do not invoke for: one-off terminal commands, ad-hoc debugging, or anything outside the workshop flow.
Candidate future skills that this skill deliberately does not absorb (they stay inline in prompts for now): workspace-preflight (databricks compute-policies list, databricks current-user me), llm-endpoint-health (databricks serving-endpoints get <endpoint>), bundle-deploy (databricks bundle validate/deploy/run), derive-app-name (email + use_case_slug → APP_NAME), prd-reader. If you end up duplicating any of those across prompts, extract them next.
Operations
All thirteen operations take a typed parameter bag. The prompt invokes the operation by name (e.g. vibecoding-state.enter) and passes only the dynamic values. Everything else (file paths, log schema, gate rules, pathway matrix, resolved spec) is owned by this skill.
Operation: bootstrap
When: Once per workshop run, at Prompt 0.1 (Instructions.md) or Prompt 1 (WALKTHROUGH.md). Only runs if no live state file exists.
Inputs:
| Param |
Type |
Required |
Description |
use_case_slug |
string |
required |
Short hyphenated lowercase slug, ≤ 26 chars. Drives the bootstrap path. |
workspace_url |
string |
required |
The only value the operator provides by hand. Every subsequent prompt reads it from state. |
pathway |
A | B | C | D |
required |
|
track |
A | B | C | n/a |
required |
n/a for pathways A, B. |
prd_path |
string |
required |
e.g. example/<use_case_slug>/docs/design_prd.md. |
llm_endpoint |
string |
required |
e.g. databricks-claude-sonnet-4-6. |
dabs_bundle_path |
string | n/a |
required |
|
Behavior:
- Detect environment & write the
## Environment Capabilities block (RULE_0 / RULE_1 enabling). Before any other step, resolve the active coding client and write the capability block (schema in references/state-template.md § Environment Capabilities) as section 0 of the state file. This is the block every prompt and the enter / exit operations read to resolve the deploy verb, CLI channel, and state-file root — so no skill or prompt body assumes a local IDE. Detection signal [inference — pending the live Genie Code probe]: if a Databricks-managed CLI channel is present in-session (the runDatabricksCli tool / Genie serverless markers), set client_context: genie_code, cli_channel: runDatabricksCli, bundle_deploy.page_context_required: true, both state_file_root and artifact_root to the user project workspace path (/Workspace/Users/<email>/<repo> — a git clone of the workshop repo, so it is a git working tree and generated bundles are recognized), and skills_install_root to the skills copy path (/Workspace/Users/<email>/.assistant/skills/<repo>, a copy of the tree for discovery, no git required); otherwise set client_context: ide_cli, cli_channel: local_shell, bundle_deploy.page_context_required: false, and state_file_root, artifact_root, and skills_install_root all to the local repo path. Ensure artifact_root (and thus state_file_root, which equals it) is a git-backed working tree — the kickstart git clones the workshop repo into it; if <artifact_root>/.git is absent, git clone <workshop remote> into it before writing the ## Environment Capabilities block (a bare mkdir leaves generated bundles unrecognized — TESTED; a Repos-managed Git folder is the documented fallback). On genie_code operate via the workspace path / executeCode, mindful of the FUSE create-then-validate gap (clone, then confirm os.path.exists(<artifact_root>/.git) before writing); a non-PRD-first flow may reach bootstrap before the clone exists. (artifact_root defaults equal to state_file_root; it is where relative artifact paths resolve as <ARTIFACT_ROOT>/<relpath> — see skills/genie-code-environment §8. skills_install_root is the read-side anchor: a copy of the clone on genie_code, the same repo on ide_cli.) Also set skill_ref_root — the prefix that makes a repo-relative skill path loadable: on genie_code it is the readSkillFile prefix "skills/" + basename(skills_install_root) (e.g. skills/vibe-coding-workshop, because the skills copy lives under .assistant/skills/<repo> and any file there loads as skills/{path-after-.assistant/skills/}); on ide_cli it is empty (repo-relative skill paths / @-mentions resolve as-is). See skills/genie-code-environment §8 for how prompts use it. Also set dp_bundle_root = <artifact_root>/{user_schema_prefix}_<use_case_slug>_dab (the use_case_slug bootstrap param is available here; {user_schema_prefix} is the SAME username-derived prefix used for the {user_schema_prefix}_bronze/_silver/_gold schemas — companion app on genie_code, authenticated-user derivation on ide_cli, e.g. jane_d) — the self-contained Databricks Asset Bundle project directory the whole data-product pipeline (bronze→silver→gold→semantic) writes its databricks.yml / src/ / resources/ into, and the bundle deploy page-context root on genie_code. The username prefix disambiguates concurrent users in a shared workspace; the bundle name: inside databricks.yml MUST match this prefixed folder name (bundle: { name: {user_schema_prefix}_<use_case_slug>_dab }). It is the same shape on both clients (a dedicated subdir of the repo/clone root, NOT the bare root and NOT inside a read-only framework dir); see skills/genie-code-environment §8. Also set app_root = <artifact_root>/<app_name> — the AppKit application track's analog of dp_bundle_root: a TOP-LEVEL sibling of <use_case_slug>_dab (NOT nested under apps_lakebase/) that holds the scaffolded app (app.yaml / databricks.yml / server/ / client/ + <app_root>/.vibecoding-state.md) on BOTH clients, so the app's root folder has parity regardless of client. It is the apps init --output-dir target on genie_code, deploys via apps deploy (no bundle page-context pin), and is <pending> until APP_NAME is resolved (Module 1 / prompt 04); n/a for Pathway D. Also set agent_app_root = <artifact_root>/<agent_app_name> — the Track A custom-agent track's analog of app_root: a TOP-LEVEL sibling of <app_name> and <use_case_slug>_dab (NOT nested under apps_lakebase/) that holds the cloned agent framework (app.yaml / pyproject.toml / databricks.yml / server/ + <agent_app_root>/.vibecoding-state.md) on BOTH clients, so the agent app's root folder has parity regardless of client. On genie_code it is the apps init --output-dir target and the uv/FastAPI server builds server-side via apps deploy (mode=SNAPSHOT) — there is no local uv run dev loop. It is <pending> until AGENT_APP_NAME is resolved (Track A clone / prompt 43); n/a for Pathways A/B. The remaining fields are client-invariant: bundle_deploy.verb is always bundle deploy --target dev, app_deploy is always { verb: "apps deploy", gated: true }, and destructive_ops is always confirm_required. Also seed genie_code_manifest_loaded (G3): n/a on ide_cli (the check is inert there), false on genie_code — on Genie Code the first deploy/divergent prompt's enter halts until the skills/genie-code-environment manifest is read in-thread and flips it true (see references/spec-schema.md § Genie Code manifest-load gate). Record the detection signal that fired in a trailing # detected_via: comment so a later live probe can confirm or correct it. For how the detected genie_code client actually behaves — the runDatabricksCli allow-list tiers, the bundle-deploy CWD pin and FUSE create-then-validate gap, the App-scaffold output-dir rule, and the deployed-app OAuth session pattern — see the genie-code-environment skill (this skill detects the client; that skill explains it).
- Workspace URL normalization & placeholder refusal. Trim any trailing slash from
workspace_url and normalize the scheme to https://. Refuse any literal placeholder — <your-workspace-url>, the empty string, or https://<...> — by halting with a remediation hint pointing the operator at Workshop Choices. Record the normalized value in bootstrap_preflight.workspace_url_normalized and the placeholder check in workspace_url_was_placeholder.
- Profile selection & host match. Run
databricks auth profiles and select the profile whose host equals the normalized workspace host. Store it in bootstrap_preflight.workspace_profile. If no profile matches, set workspace_host_auth_status: wrong_host and halt; if the matching profile fails databricks current-user me, set unauthenticated and halt; on success set authenticated.
- CLI version preflight (client-branched — Gap-1). On
ide_cli: capture databricks --version into bootstrap_preflight.databricks_cli_version, compare against bootstrap_preflight.databricks_cli_min_version (default 0.295.0, may be raised by workshop config), and halt with an upgrade hint if the installed version is older. On genie_code: databricks --version is hard-blocked (no local CLI binary — the managed runDatabricksCli channel does not expose a version string; CONFIRMED P1), so set bootstrap_preflight.databricks_cli_version: unknown_on_genie_code and skip the numeric comparison and the version halt entirely. Any later decision that would have keyed off the numeric version (the databricks_cli_min_version registry check, and skill_helper_resolution's CLI-version gate) falls back to the behavior probe — databricks bundle validate accepting the field/deploy without stripping — instead of a version number. The managed channel always tracks a current CLI, so the only real risk a version gate guards against (a stale local install) cannot occur on Genie Code.
- Apps quota preflight. Before any
databricks apps create happens (Pathways A/B/C), run databricks apps list --output json and record current_count, max_count, and free_slots in bootstrap_preflight.apps_quota. If free_slots < 1, halt with a clean-up hint listing the apps the operator can delete.
- First state file path. Write the bootstrap live file to
example/<use_case_slug>/.vibecoding-state.md (used in this repo's example/ examples) or workshops/<use_case_slug>/.vibecoding-state.md (used by external adopters that follow the workshops/ convention). Whichever path is chosen, record it verbatim in bootstrap_preflight.first_state_file_path so migrate_canonical knows exactly which file to move once $APP_NAME is resolved. Set bootstrap_preflight.app_name_known_at_bootstrap = false — $APP_NAME is resolved later by Module 1 / Prompt 2.
- Copy the template. Copy
references/state-template.md to bootstrap_preflight.first_state_file_path.
- Replace
<USE_CASE_SLUG> in the title and both <ISO timestamp> placeholders with the current ISO timestamp.
- Write all
Workshop Choices from the params above.
- Run
databricks auth profiles + databricks current-user me to capture PROFILE, Workspace host, User email into Global Variables. (PROFILE is the same value already stored as bootstrap_preflight.workspace_profile.)
- Run the serverless-only preflight (
databricks compute-policies list) and set workspace_serverless_only.
- DAB dev-mode schema-prefix detection. If
dabs_bundle_path is a real path (not n/a), shell out to databricks bundle validate --target dev --output json from that path and inspect every UC schema resource. If any resource has dev-mode prefixing applied (a name shaped like dev_${user}_<schema> instead of the unprefixed <schema>), set bootstrap_preflight.bundle_dev_mode_schema_prefix_detected = true. Every downstream prompt that passes agent_schema, ops_schema, or uc_schema into a job/notebook MUST read the resolved (prefixed) schema name from state — never the unprefixed variable name.
- Verify-job summary semantics. Set
bootstrap_preflight.verify_summary_semantics from the merged workshop config. Default pass_field/warn_field/fail_field are "pass", "warn", "fail" (matching 05_verify_infrastructure.py's notebook.exit payload). warning_policy defaults to allow_with_notes; set to block_if_load_bearing for use cases whose verify-job emits warnings that must block the gate. When warning_policy == block_if_load_bearing, any warning whose name matches an entry in the workshop's gate_load_bearing_checks[] list blocks the first verify gate (PASS only when fail == 0 AND no load-bearing warning is present).
- Derive
variant_id from pathway + track using the deterministic derivation table in references/resolver-prompt.md § Variant-ID Derivation Table.
- Invoke
resolve_spec (see below) to parse the PRD at prd_path and populate the six spec sections (## Variant, ## Resources, ## UI, ## Agent, ## Governance, ## Spec Provenance). This is a hard step: if resolve_spec halts, bootstrap halts.
Outputs: Path of the bootstrap state file (also stored as bootstrap_preflight.first_state_file_path), populated with ## Environment Capabilities (section 0), ## Bootstrap Preflight, Workshop Choices, Global Variables (partial), and fully resolved Variant / Resources / UI / Agent / Governance / Provenance spec sections (schema v2.0). The workshop continues with this path until migrate_canonical runs.
Errors: If the bootstrap path already exists, abort — do not overwrite. The operator must remove or migrate the stale file. Any of the four halt rules in references/spec-schema.md § Bootstrap Preflight (steps 1–4 above) abort before the template is copied. If resolve_spec fails validation twice, abort and surface the validation errors; the operator must fix the PRD before re-running.
DAB dev-mode schema-prefix rule (consumer-side). If Databricks Asset Bundle dev mode prefixes UC schema resource names, notebook/job parameters must receive the resolved prefixed schema name, not the unprefixed variable. Bootstrap captures bundle_dev_mode_schema_prefix_detected; any prompt that passes agent_schema, ops_schema, or uc_schema to a job reads the resolved value from state.
Operation: resolve_root
When: Any prompt that writes an artifact before bootstrap has run (e.g. the PRD-generation prompt produces docs/design_prd.md before the PRD exists to bootstrap from). It is the minimal, gate-free way to learn where relative artifact paths must land so a bare docs/… does not resolve against a page-dependent CWD on Genie Code. Idempotent — safe to call repeatedly; a later bootstrap supersedes it as the persistence owner.
Inputs: none required. (Optional state_file_path — if the caller already knows where a state file lives.)
Behavior:
- Read-if-present. If a state file with a
## Environment Capabilities block (section 0) already exists (the live file, or the bootstrap path example/<use_case_slug>/.vibecoding-state.md / workshops/<use_case_slug>/.vibecoding-state.md), read client_context, artifact_root, skills_install_root, and skill_ref_root from it and return them. Do not re-detect or rewrite.
- Else detect fresh (bootstrap step-0 detection ONLY). Run just the client/root detection from
bootstrap step 0 — no URL/profile/CLI/quota preflights, no template copy, no resolve_spec, no gates: if a Databricks-managed CLI channel is present (runDatabricksCli / Genie serverless markers) ⇒ client_context: genie_code, artifact_root = the user project workspace path (e.g. /Workspace/Users/<email>/<repo>, a git clone of the workshop repo), skills_install_root = the skills copy path (e.g. /Workspace/Users/<email>/.assistant/skills/<repo>, a copy for discovery), skill_ref_root = "skills/" + basename(skills_install_root) (e.g. skills/vibe-coding-workshop); otherwise ⇒ client_context: ide_cli, artifact_root = skills_install_root = the local repo root, skill_ref_root = empty.
- Ensure
artifact_root is a git-backed working tree. The kickstart git clones the workshop repo into artifact_root; if <artifact_root>/.git is missing, git clone <workshop remote> into it so the caller's first relative write (e.g. the PRD at <ARTIFACT_ROOT>/docs/design_prd.md, produced before bootstrap) lands in a real, git-backed directory where generated bundles are recognized (a bare mkdir leaves them unrecognized — TESTED; a Repos-managed Git folder is the documented fallback). On genie_code operate via the workspace path / executeCode, mindful of the FUSE create-then-validate gap (clone, then confirm with os.path.exists(<artifact_root>/.git) before writing). This clone/check is the only filesystem side effect of resolve_root.
- Echo, do not persist. Return
client_context + artifact_root + skills_install_root + skill_ref_root for the caller to use immediately and to echo the project-root + skill-load rules to the operator. No state file is written — bootstrap step 0 remains the sole writer of section 0, so there is no "abort if path exists" conflict and no half-initialized state file.
Outputs: { client_context, artifact_root, skills_install_root, skill_ref_root } (ephemeral). The calling prompt resolves its relative artifact path as <ARTIFACT_ROOT>/<relpath>, loads any repo-relative skill path X/Y/SKILL.md as <skill_ref_root>/X/Y/SKILL.md via readSkillFile (§8), and echoes: "artifacts resolve under the workshop project root (artifact_root, the git-cloned user project on Genie Code — not the skills copy) and skills load under skill_ref_root (= skills/<clone-folder> = skills/ + basename of skills_install_root on Genie Code), never the page CWD."
Errors: None that halt — resolve_root is fail-soft. If detection is ambiguous, default to ide_cli / repo-root and note the assumption; the later bootstrap step 0 is authoritative.
Operation: resolve_spec
When: Called automatically as the final step of bootstrap. May also be re-invoked manually if the PRD changes mid-workshop (rare; prefer restarting from bootstrap).
Inputs:
| Param |
Type |
Required |
Description |
prd_path |
string |
required |
Path to the PRD. Read from Workshop Choices.prd_path if omitted. |
llm_endpoint |
string |
required |
LLM endpoint used to synthesize the spec. Read from Workshop Choices.llm_endpoint if omitted. Must be a Databricks Model Serving endpoint reachable from the workspace. |
Behavior:
- Read the PRD contents from
prd_path and compute prd_sha256.
- Load the schema from
references/spec-schema.md and the prompt from references/resolver-prompt.md.
- Derive
variant_id deterministically from Workshop Choices (pathway, track) per the resolver prompt's Variant-ID Derivation Table. Inject it into the user prompt.
- Call
llm_endpoint with the system + user prompts. Expect a single YAML document with exactly six top-level keys: variant_id, resources, ui, agent, governance, spec_provenance.
- Run the deterministic guards listed in the resolver prompt's "Post-resolution Guards" section:
- YAML parses cleanly into a dict with the expected top-level keys.
- Every validation rule in
references/spec-schema.md §"Validation Rules" passes.
- Consumer cross-check: each
agent.tools[].name of kind: function with language: python reconciles with the PRD Tools Table.
- Placeholder guard: no resource-ID-shaped strings leaked through.
- Variant-ID echo check: emitted
variant_id equals the one passed in.
- MCP ref resolution: every
agent.tools[].mcp_server_ref (kind=mcp) maps to an agent.mcp_servers[].name.
- If any guard fails, retry once with the validation errors appended to the user prompt. Second failure halts bootstrap.
- Split the validated YAML by top-level key and write each block into its matching state-file section (
## Variant, ## Resources, ## UI, ## Agent, ## Governance, ## Spec Provenance), replacing the <pending> placeholder body with a fenced ```yaml block containing the resolved content.
- Stamp
## Spec Provenance with resolved_at, resolver_version: "2.0", schema_version: "2.0", prd_sha256, and llm_endpoint.
Outputs: No return value; mutates the live state file.
Errors: Validation failure (after one retry), missing PRD file, unreachable llm_endpoint, or any LLM response that is not parseable YAML with the six expected keys — all halt bootstrap.
Downstream contract: Every consuming skill declares which fields it reads via a machine-parseable fields_read: YAML list in its frontmatter (see § Field Consumer Contract below and references/spec-schema.md §"Field Consumer Contract"). Prompts in Instructions.md and WALKTHROUGH.md reference resolved content by dotted path (e.g. ui.user_journeys, agent.tools, governance.scorer_suite.guidelines) instead of inlining domain-specific content. This is what makes the workshops use-case-agnostic.
Operation: hydrate_from_files
When: Called once per workshop, before any prompt that reads state://AgentSpec, state://AppSpec, or state://DataSpec. The Agents Accelerator visible path calls it from prompt uc_resources_foundation (input_id 200, order 40), right after op enter succeeds and before any UC schema/volume creation.
Purpose: The Agents Accelerator design pair (docs/agent_spec.yaml from prompt 38, docs/agent_tool_plan.yaml from prompt 39) becomes the source of truth for the agent's intent. hydrate_from_files lifts those file values into the live state file so every downstream consumer (Track A build prompts, MLflow SDLC suite at prompts 50-56) keeps reading from state://AgentSpec, state://AppSpec, and state://Spec Provenance without an additional visible-path step. This is additive to resolve_spec: PRD-only LLM-driven workflows that never produce the docs/*.yaml files continue to work unchanged.
Inputs:
| Param |
Type |
Required |
Description |
agent_spec_yaml |
string |
required |
Path to the docs/agent_spec.yaml produced by prompt 38 (agent_spec_design). |
agent_tool_plan_yaml |
string |
required |
Path to the docs/agent_tool_plan.yaml produced by prompt 39 (agent_tool_selection). |
ui_design_md |
string |
required |
Path to the docs/ui_design.md produced by prompt 04 (cursor_copilot_ui_design). |
prd_path |
string |
required |
Path to docs/design_prd.md from prompt 03 (prd_generation); used for source_prd provenance. |
state_path |
string |
required |
Path to the live state file (Pathways A/B/C: apps_lakebase/$APP_NAME/.vibecoding-state.md; Pathway D: agents/$AGENT_NAME/.vibecoding-state.md). |
Behavior:
Read agent_spec_yaml. Copy scalar/list agent.* fields directly into the state file's ## Agent section as a fenced yaml block: model, capabilities, personas, system_prompt, benchmark_seeds, must_do, must_not_do. File values override any prior resolve_spec LLM output silently; the file is the source of truth.
Tool projection rule (preserves the v2.0 fields_read: agent.tools contract without rewriting any consumer). The Agent Spec produced by step 38 follows the 00b schema (tool_recommendations, NOT agent.tools). Hydration MUST project tools into state://AgentSpec.agent.tools[] using these three sub-rules:
a. Seed state://AgentSpec.agent.tools[] from docs/agent_spec.yaml.tool_recommendations.managed_databricks[] plus tool_recommendations.external[]. Map each entry to the v2.0 tool discriminated-union shape: populate kind (hosted | function | mcp), name, surface, io_contract, readonly, plus the kind-specific fields (hosted_type + resource_ref, or language, or mcp_server_ref). Carry selected_by_default forward to pre-mark entries.
b. Overlay docs/agent_tool_plan.yaml.selected_tools[] on top. Any Tool Plan entry with the same name REPLACES the spec recommendation — binding selection wins over loose recommendation. Tool Plan entries with no matching spec recommendation are appended.
c. Tool families absent from BOTH the spec and the Tool Plan are NOT written into agent.tools[]. Skipped families are recorded as skipped, not failed (consistent with step 44 semantics).
The projection is the only legitimate way state://AgentSpec.agent.tools[] becomes populated on the Agents Accelerator visible path. Step 38 does NOT and MUST NOT write agent.tools[] directly into docs/agent_spec.yaml; downstream prompts that still cite agent.tools[] (e.g. step 44's prerequisite block before Pass 3.5) MUST be updated to read tool_recommendations (loose) plus selected_tools (binding) instead.
Read agent_tool_plan_yaml. Merge selected_tools[], selected_mcp_servers[], runtime_config.llm, and resource_grants into ## Agent under new keys selected_tools, selected_mcp_servers, runtime_config, and resource_grants. Tools selected by the user in the Tool Plan win over the Agent Spec's recommendations.
Read ui_design_md. Parse loose markdown headings into ## UI (pages[], personas[], user_journeys[]) on a best-effort basis. If the document is structured differently or only contains free-form prose, write the verbatim markdown into ## UI.raw_markdown and emit a non-fatal warning so downstream SDLC prompts can still find personas/journeys textually.
Stamp ## Spec Provenance. Compute prd_sha256 from prd_path and write resolved_at (current UTC ISO timestamp), resolver_version: "3.0" (new tag distinguishing file-based hydration from LLM resolve_spec's "2.0"), schema_version: "2.0", prd_sha256, and hydrated_from_files: true.
Optional ## Resources (DataSpec). If the PRD declares a Lakehouse/Resources section (Bronze tables, Genie Spaces, Vector Search indexes, etc.) and ## Resources is already populated by an earlier resolve_spec run, leave it untouched. Otherwise write ## Resources as optional: true with tables: [], mark_skipped: "no Lakehouse track", signalling downstream prompts that state://DataSpec.* lookups should fall back gracefully (e.g. KA branch C in prompt 42 reads from docs/design_prd.md + docs/agent_spec.yaml.agent.capabilities instead of state://DataSpec.glossary).
Idempotency. Re-running with the same inputs is a no-op: each section is regenerated from the file values, sha256 is stable, and the state file ends in the same byte sequence (modulo the resolved_at timestamp, which is allowed to drift). Re-running with newer docs/*.yaml files overwrites cleanly.
Outputs: { hydrated: true, sections_written: ["## Agent", "## UI", "## Resources", "## Spec Provenance"] }. The Agents Accelerator step 40 records hydrated_from_files: true and resolver_version: "3.0" in its op exit captured map.
Errors:
- Missing required input file → halt with an explicit pointer to the producing prompt:
agent_spec_yaml → 38, agent_tool_plan_yaml → 39, ui_design_md → 04, prd_path → 03, state_path → bootstrap.
agent_spec.yaml missing agent.model → halt with a pointer to prompt 38's model selection rule (Pass 1 / Pass 2 of the Agents Accelerator cleanup).
agent_tool_plan.yaml.runtime_config.llm.endpoint equals the literal YAML-path string docs/agent_spec.yaml.agent.model → halt with the Pass 2 placeholder rule citation. This is defense-in-depth; prompt 39's generated prompt already forbids this.
- Any value at a documented Agent Spec / Tool Plan path is still wrapped in
{...} (e.g. {agent_sql_catalog}) → halt with the Pass 2 placeholder-handling rule. The user must rerun prompt 39 with real values.
Downstream contract: After hydrate_from_files runs, every prompt that consumes state://AgentSpec.agent.*, state://AppSpec.ui.*, or state://Spec Provenance.* sees the file-derived values. state://DataSpec.* is <pending> or optional: true unless the Lakehouse track produced one. SDLC prompts (50-56) MUST handle the optional/pending DataSpec case gracefully — they already do (the Agents Accelerator visible path no longer requires Lakehouse outputs), but the optional: true flag makes the contract explicit.
LLM driver prompt: See references/hydrator-prompt.md for the actual prompt that an LLM-driven implementation runs to execute this operation. That file is to hydrate_from_files what references/resolver-prompt.md is to resolve_spec.
Operation: enter
When: At the top of every workshop prompt, before any domain skill or command runs.
Inputs:
| Param |
Type |
Required |
Description |
prompt_id |
string |
required |
e.g. 0.1, 3.2, 5.A4, 7.22.5, or 20c. Matches the heading the prompt will log under. |
require_prior_gate |
{prompt_id: string, gate: string} |
optional |
Assert the listed prompt's Gate equals the listed string. If it does not match, enter stops the workshop and surfaces the mismatch. |
Behavior:
Locate the live state file:
- First, resolve
state_file_root from the ## Environment Capabilities block (section 0). Every path below is relative to it — the local repo root for client_context: ide_cli, the git-folder workspace path for genie_code. On a pre-capability state file (no section 0), default state_file_root to the repo root and proceed without assuming a deploy channel.
- If
$APP_NAME is known (Pathways A/B/C), use <app_root>/.vibecoding-state.md (= <state_file_root>/<app_name>/.vibecoding-state.md, the TOP-LEVEL app dir — NOT apps_lakebase/<app_name>/).
- Else if
$AGENT_APP_NAME is known (Track A agent app, Pathways C/D), use <agent_app_root>/.vibecoding-state.md (= <state_file_root>/<agent_app_name>/.vibecoding-state.md, the TOP-LEVEL agent app dir — NOT apps_lakebase/<agent_app_name>/).
- Else if
dp_bundle_root is resolved (a data-product / lakehouse run with no app or agent app — e.g. the Gold-design→Bronze→Silver→Gold→semantic pipeline), use <dp_bundle_root>/.vibecoding-state.md (= <state_file_root>/{user_schema_prefix}_<use_case_slug>_dab/.vibecoding-state.md). This is the canonical DP-track live file — the data-product analog of <app_root> / <agent_app_root>. The FIRST data-product prompt to run (Gold design, step 09 — or Bronze, step 10, if design was skipped) bootstrap-creates it from references/state-template.md if absent (a real create, copying the template + filling Workshop Choices from the prior example/ bootstrap file if present — not just resolve_root); every later DP step appends to it. Do NOT leave data-product state in the temporary example/ bootstrap path — that path carries no durable record and was the root cause of "state survived only in chat summary."
- Else fall back to the bootstrap path
<state_file_root>/example/<use_case_slug>/.vibecoding-state.md (pre-bootstrap only — once dp_bundle_root/app_root/agent_app_root is known, migrate/bootstrap-create the canonical file above).
- If none of these exists yet: for the
dp_bundle_root/app_root/agent_app_root canonical paths, bootstrap-create the file from the template (this is the first prompt of that track); only stop and tell the operator to run bootstrap first if even use_case_slug/Workshop Choices are unknown.
Schema v2.0 gate (hard fail). Parse the ## Spec Provenance YAML block. If schema_version != "2.0", halt with:
State file uses schema v<X> — this repo is strictly v2.0.
Run: python scripts/migrate-spec-v1-to-v2.py <path-to-state-file>
Then re-run this prompt.
No best-effort reads against older shapes.
Read end-to-end. Treat Workshop Choices, Global Variables, and Captured Resource IDs as authoritative. Never ask the operator for a value that already exists in state.
Multi-file resolution via state_file_set. Parse the ## State File Set block.
- If
state_file_set.secondary.path is <pending> or null, treat the located file as the only source — done.
- If
secondary is declared and prompt_id is in secondary.required_for_prompts, read the secondary file too. Halt if it does not exist (remediation: run bootstrap for the missing side or correct secondary.path).
- Walk both files following
lookup_order (e.g. ["primary", "secondary"]). For each canonical field requested by the prompt, the first hit wins.
- For any canonical field present in both files with different values: halt unless
conflict_policy: primary_wins is set explicitly. With primary_wins, use the primary value and append the conflict to ## State Contract Audit (fields_read_but_never_produced / captured_fields_with_no_consumer are unaffected; conflicts get their own audit row).
Apply canonical_names aliasing on read. Parse the ## Canonical Names block. Whenever the prompt reads an env var, HTTP header, jq path, or state field listed as a legacy/incorrect spelling on the left of a canonical_names map, resolve to the canonical name on the right. If the map's value is null (e.g. http_headers.x-forwarded-user-info: null), the name does not exist; halt and surface a hint pointing at the canonical alternatives. state_contract_audit performs the same checks at audit time.
Enforce the prior gate if require_prior_gate is set. On mismatch, halt unless a matching entry exists in state_overrides[] (see step 7). Mismatches that are NOT covered by an override stop the workshop.
Apply state_overrides[] (fail-closed escape hatch). Parse ## State Overrides. An override entry covers a failing gate when ALL of the following hold: prompt_id matches the current prompt; gate_type matches the failing gate (require_prior_gate for step 6, hard_assert / preflight_check for step 9 below, pathway_applicability for step 8); and expires_at is in the future relative to the current ISO timestamp. A covered failure is treated as satisfied and the override is logged in the prompt's Resolved issues / workarounds Per-Step Log entry. Expired or missing entries DO NOT cover the failure — enter halts. Cross-session continuity (e.g. resuming from a previous run's state file) is recorded as a state_override whose reason cites the earlier run's evidence; it is NOT a prose exception.
Consult the Pathway Applicability Matrix (below). If the prompt does not apply for this pathway/track and no state_override with gate_type: pathway_applicability covers it, synthesize a ## Prompt <prompt_id> — Skipped (N/A for pathway <X>) section with Gate: Skipped — N/A for pathway <X>, append it, and return a skipped: true signal so the prompt body short-circuits. With a covering override, proceed (the override reason is logged in the prompt's Per-Step Log entry).
Enforce deferred_actions[]. Parse ## Deferred Actions. Halt if the current prompt's role is in any open deferred_action's target_prompt_roles[] and its divergence_check evaluates to false (or fails to parse under the divergence-check grammar in references/spec-schema.md § Deferred Actions). Halt is suppressed only when a state_override with gate_type: hard_assert (or preflight_check) on the current prompt_id exists AND its references[] contains "deferred_action:<id>" matching the action's id. If divergence_check returns true, flip status to resolved and proceed. Entries with status: waived are skipped without evaluation.
Enforce mlflow_eval_known_quality_issues[]. Parse ## MLflow Eval Known Quality Issues. If the current prompt's role appears in any open issue's target_prompt_roles_blocked[], halt with a remediation hint citing id, source_prompt_role, and error_signature — unless a state_override exists on the current prompt_id whose references[] contains "known_issue:<id>" matching the issue's id. The issue's error_signature SHOULD be a name from gate_load_bearing_checks[] so audits and verify summaries align, but enter halts purely on target_prompt_roles_blocked[] membership and status: open — it does NOT consult gate_load_bearing_checks[] directly (that list drives state_contract_audit and the verify-job warning_policy: block_if_load_bearing rule per § Gate Load Bearing Checks in references/spec-schema.md).
Enforce preflight_check_registry. Parse ## Preflight Check Registry. For each registry entry, if the current prompt's role appears in blocks_prompt_roles[], evaluate the matching state field per the State-field mapping table in references/spec-schema.md § Preflight Check Registry. If the pass condition is not met (the field is <pending>, missing, or fails the predicate), halt with a remediation hint pointing at owner. The halt is suppressed only when a matching state_override with gate_type: preflight_check exists on the current prompt_id whose affected_state_field matches the check's state field. For reflection_lm_large_context_probe, the check is treated as passing only when a synchronous ≥80000-character probe has been run against the currently bound llm_role_endpoints.reflection_lm.endpoint and endpoint_guardrail_audit[<reflection_lm.endpoint>].long_context_ok == true AND accepted_min_context_chars >= 80000 — the generic bootstrap endpoint guardrail pass is NOT sufficient on its own. The owning skill (instruction_iteration) MUST invoke the probe synchronously before any 08b diff-summary helper or iteration helper call. For genie_code_manifest_loaded (G3, the one client-conditional check), evaluate it only when environment_capabilities.client_context == 'genie_code' — it is inert on ide_cli — and on Genie Code halt the deploy roles until environment_capabilities.genie_code_manifest_loaded == true (the agent has read skills/genie-code-environment in-thread); see references/spec-schema.md § Genie Code manifest-load gate.
Resolve variables. Return the subset of state the prompt body needs (it is declared in the prompt's enter invocation — e.g. APP_NAME, PROFILE, warehouse_id). Always also return the environment-capability set so any deploy/run instruction the prompt emits uses the resolved verb + channel instead of assuming a local IDE: bundle_deploy.verb (always `bund
…(truncated)
1---2name: vibecoding-state3description: Vibecoding State — Workshop Runtime Contract4---56# Vibecoding State — Workshop Runtime Contract78This skill is the single source of truth for how every prompt in the repo-root [`Instructions.md`](../../Instructions.md) workshop and its worked instantiations (e.g. [`example/skyloyalty/WALKTHROUGH.md`](../../example/skyloyalty/WALKTHROUGH.md)) interacts with the shared per-user **state file** and the async per-prompt **retrospective file**.910Prompts do **not** re-state the "Vibecoding state contract / Preamble / Postamble / Pathway Applicability guard / Retrospective contract" prose. They invoke this skill with typed parameters and this skill owns the behavior.1112---1314## When to Use1516Invoke this skill — always — when executing any vibecoding workshop prompt. Specifically:1718- **Every** prompt in [`Instructions.md`](../../Instructions.md) (Prompt 0.1 through 8.24).19- **Every** prompt in `example/<use_case>/WALKTHROUGH.md` (e.g. SkyLoyalty's 22 prompts).20- **Every** post-workshop per-prompt retro + the single session rollup.2122Do not invoke for: one-off terminal commands, ad-hoc debugging, or anything outside the workshop flow.2324Candidate future skills that this skill deliberately does **not** absorb (they stay inline in prompts for now): `workspace-preflight` (`databricks compute-policies list`, `databricks current-user me`), `llm-endpoint-health` (`databricks serving-endpoints get <endpoint>`), `bundle-deploy` (`databricks bundle validate/deploy/run`), `derive-app-name` (email + use_case_slug → APP_NAME), `prd-reader`. If you end up duplicating any of those across prompts, extract them next.2526---2728## Operations2930All thirteen operations take a typed parameter bag. The prompt invokes the operation by name (e.g. `vibecoding-state.enter`) and passes only the dynamic values. Everything else (file paths, log schema, gate rules, pathway matrix, resolved spec) is owned by this skill.3132### Operation: `bootstrap`3334**When:** Once per workshop run, at Prompt 0.1 (`Instructions.md`) or Prompt 1 (`WALKTHROUGH.md`). Only runs if no live state file exists.3536**Inputs:**3738| Param | Type | Required | Description |39|---|---|---|---|40| `use_case_slug` | string | required | Short hyphenated lowercase slug, ≤ 26 chars. Drives the bootstrap path. |41| `workspace_url` | string | required | The only value the operator provides by hand. Every subsequent prompt reads it from state. |42| `pathway` | `A` \| `B` \| `C` \| `D` | required | |43| `track` | `A` \| `B` \| `C` \| `n/a` | required | `n/a` for pathways A, B. |44| `prd_path` | string | required | e.g. `example/<use_case_slug>/docs/design_prd.md`. |45| `llm_endpoint` | string | required | e.g. `databricks-claude-sonnet-4-6`. |46| `dabs_bundle_path` | string \| `n/a` | required | |4748**Behavior:**49500. **Detect environment & write the `## Environment Capabilities` block (RULE_0 / RULE_1 enabling).** Before any other step, resolve the active coding client and write the capability block (schema in [`references/state-template.md`](references/state-template.md) § *Environment Capabilities*) as **section 0** of the state file. This is the block every prompt and the `enter` / `exit` operations read to resolve the deploy verb, CLI channel, and state-file root — so no skill or prompt body assumes a local IDE. Detection signal **[inference — pending the live Genie Code probe]**: if a Databricks-managed CLI channel is present in-session (the `runDatabricksCli` tool / Genie serverless markers), set `client_context: genie_code`, `cli_channel: runDatabricksCli`, `bundle_deploy.page_context_required: true`, both `state_file_root` and `artifact_root` to the **user project workspace path** (`/Workspace/Users/<email>/<repo>` — a **git clone** of the workshop repo, so it is a git working tree and generated bundles are recognized), and `skills_install_root` to the **skills copy path** (`/Workspace/Users/<email>/.assistant/skills/<repo>`, a copy of the tree for discovery, no git required); otherwise set `client_context: ide_cli`, `cli_channel: local_shell`, `bundle_deploy.page_context_required: false`, and `state_file_root`, `artifact_root`, and `skills_install_root` all to the local repo path. **Ensure `artifact_root` (and thus `state_file_root`, which equals it) is a git-backed working tree** — the kickstart `git clone`s the workshop repo into it; if `<artifact_root>/.git` is absent, `git clone <workshop remote>` into it before writing the `## Environment Capabilities` block (a bare `mkdir` leaves generated bundles unrecognized — TESTED; a Repos-managed Git folder is the documented fallback). On `genie_code` operate via the workspace path / `executeCode`, mindful of the FUSE create-then-validate gap (clone, then confirm `os.path.exists(<artifact_root>/.git)` before writing); a non-PRD-first flow may reach `bootstrap` before the clone exists. (`artifact_root` defaults equal to `state_file_root`; it is where relative artifact paths resolve as `<ARTIFACT_ROOT>/<relpath>` — see `skills/genie-code-environment` §8. `skills_install_root` is the read-side anchor: a copy of the clone on `genie_code`, the same repo on `ide_cli`.) **Also set `skill_ref_root`** — the prefix that makes a repo-relative *skill* path loadable: on `genie_code` it is the `readSkillFile` prefix `"skills/" + basename(skills_install_root)` (e.g. `skills/vibe-coding-workshop`, because the skills copy lives under `.assistant/skills/<repo>` and any file there loads as `skills/{path-after-.assistant/skills/}`); on `ide_cli` it is empty (repo-relative skill paths / `@`-mentions resolve as-is). See `skills/genie-code-environment` §8 for how prompts use it. **Also set `dp_bundle_root`** = `<artifact_root>/{user_schema_prefix}_<use_case_slug>_dab` (the `use_case_slug` bootstrap param is available here; `{user_schema_prefix}` is the SAME username-derived prefix used for the `{user_schema_prefix}_bronze`/`_silver`/`_gold` schemas — companion app on `genie_code`, authenticated-user derivation on `ide_cli`, e.g. `jane_d`) — the self-contained Databricks Asset Bundle project directory the whole data-product pipeline (bronze→silver→gold→semantic) writes its `databricks.yml` / `src/` / `resources/` into, and the `bundle deploy` page-context root on `genie_code`. The username prefix disambiguates concurrent users in a shared workspace; the bundle `name:` inside `databricks.yml` MUST match this prefixed folder name (`bundle: { name: {user_schema_prefix}_<use_case_slug>_dab }`). It is the same shape on both clients (a dedicated subdir of the repo/clone root, NOT the bare root and NOT inside a read-only framework dir); see `skills/genie-code-environment` §8. **Also set `app_root`** = `<artifact_root>/<app_name>` — the AppKit application track's analog of `dp_bundle_root`: a TOP-LEVEL sibling of `<use_case_slug>_dab` (NOT nested under `apps_lakebase/`) that holds the scaffolded app (`app.yaml` / `databricks.yml` / `server/` / `client/` + `<app_root>/.vibecoding-state.md`) on BOTH clients, so the app's root folder has parity regardless of client. It is the `apps init --output-dir` target on `genie_code`, deploys via `apps deploy` (no `bundle` page-context pin), and is `<pending>` until `APP_NAME` is resolved (Module 1 / prompt 04); `n/a` for Pathway D. **Also set `agent_app_root`** = `<artifact_root>/<agent_app_name>` — the Track A custom-agent track's analog of `app_root`: a TOP-LEVEL sibling of `<app_name>` and `<use_case_slug>_dab` (NOT nested under `apps_lakebase/`) that holds the cloned agent framework (`app.yaml` / `pyproject.toml` / `databricks.yml` / `server/` + `<agent_app_root>/.vibecoding-state.md`) on BOTH clients, so the agent app's root folder has parity regardless of client. On `genie_code` it is the `apps init --output-dir` target and the `uv`/FastAPI server builds server-side via `apps deploy` (`mode=SNAPSHOT`) — there is no local `uv run dev` loop. It is `<pending>` until `AGENT_APP_NAME` is resolved (Track A clone / prompt 43); `n/a` for Pathways A/B. The remaining fields are client-invariant: `bundle_deploy.verb` is always `bundle deploy --target dev`, `app_deploy` is always `{ verb: "apps deploy", gated: true }`, and `destructive_ops` is always `confirm_required`. **Also seed `genie_code_manifest_loaded` (G3):** `n/a` on `ide_cli` (the check is inert there), `false` on `genie_code` — on Genie Code the first deploy/divergent prompt's `enter` halts until the `skills/genie-code-environment` manifest is read in-thread and flips it `true` (see `references/spec-schema.md` § *Genie Code manifest-load gate*). Record the detection signal that fired in a trailing `# detected_via:` comment so a later live probe can confirm or correct it. For *how* the detected `genie_code` client actually behaves — the `runDatabricksCli` allow-list tiers, the bundle-deploy CWD pin and FUSE create-then-validate gap, the App-scaffold output-dir rule, and the deployed-app OAuth session pattern — see the **`genie-code-environment`** skill (this skill *detects* the client; that skill *explains* it).511. **Workspace URL normalization & placeholder refusal.** Trim any trailing slash from `workspace_url` and normalize the scheme to `https://`. Refuse any literal placeholder — `<your-workspace-url>`, the empty string, or `https://<...>` — by halting with a remediation hint pointing the operator at Workshop Choices. Record the normalized value in `bootstrap_preflight.workspace_url_normalized` and the placeholder check in `workspace_url_was_placeholder`.522. **Profile selection & host match.** Run `databricks auth profiles` and select the profile whose host equals the normalized workspace host. Store it in `bootstrap_preflight.workspace_profile`. If no profile matches, set `workspace_host_auth_status: wrong_host` and halt; if the matching profile fails `databricks current-user me`, set `unauthenticated` and halt; on success set `authenticated`.533. **CLI version preflight (client-branched — Gap-1).** **On `ide_cli`:** capture `databricks --version` into `bootstrap_preflight.databricks_cli_version`, compare against `bootstrap_preflight.databricks_cli_min_version` (default `0.295.0`, may be raised by workshop config), and halt with an upgrade hint if the installed version is older. **On `genie_code`:** `databricks --version` is **hard-blocked** (no local CLI binary — the managed `runDatabricksCli` channel does not expose a version string; CONFIRMED P1), so set `bootstrap_preflight.databricks_cli_version: unknown_on_genie_code` and **skip the numeric comparison and the version halt entirely**. Any later decision that would have keyed off the numeric version (the `databricks_cli_min_version` registry check, and `skill_helper_resolution`'s CLI-version gate) falls back to the **behavior probe** — `databricks bundle validate` accepting the field/deploy without stripping — instead of a version number. The managed channel always tracks a current CLI, so the only real risk a version gate guards against (a stale local install) cannot occur on Genie Code.544. **Apps quota preflight.** Before any `databricks apps create` happens (Pathways A/B/C), run `databricks apps list --output json` and record `current_count`, `max_count`, and `free_slots` in `bootstrap_preflight.apps_quota`. If `free_slots < 1`, halt with a clean-up hint listing the apps the operator can delete.555. **First state file path.** Write the bootstrap live file to `example/<use_case_slug>/.vibecoding-state.md` (used in this repo's `example/` examples) or `workshops/<use_case_slug>/.vibecoding-state.md` (used by external adopters that follow the `workshops/` convention). Whichever path is chosen, record it verbatim in `bootstrap_preflight.first_state_file_path` so `migrate_canonical` knows exactly which file to move once `$APP_NAME` is resolved. Set `bootstrap_preflight.app_name_known_at_bootstrap = false` — `$APP_NAME` is resolved later by Module 1 / Prompt 2.566. **Copy the template.** Copy [`references/state-template.md`](references/state-template.md) to `bootstrap_preflight.first_state_file_path`.577. Replace `<USE_CASE_SLUG>` in the title and both `<ISO timestamp>` placeholders with the current ISO timestamp.588. Write all `Workshop Choices` from the params above.599. Run `databricks auth profiles` + `databricks current-user me` to capture `PROFILE`, `Workspace host`, `User email` into `Global Variables`. (`PROFILE` is the same value already stored as `bootstrap_preflight.workspace_profile`.)6010. Run the serverless-only preflight (`databricks compute-policies list`) and set `workspace_serverless_only`.6111. **DAB dev-mode schema-prefix detection.** If `dabs_bundle_path` is a real path (not `n/a`), shell out to `databricks bundle validate --target dev --output json` from that path and inspect every UC schema resource. If any resource has dev-mode prefixing applied (a name shaped like `dev_${user}_<schema>` instead of the unprefixed `<schema>`), set `bootstrap_preflight.bundle_dev_mode_schema_prefix_detected = true`. Every downstream prompt that passes `agent_schema`, `ops_schema`, or `uc_schema` into a job/notebook MUST read the resolved (prefixed) schema name from state — never the unprefixed variable name.6212. **Verify-job summary semantics.** Set `bootstrap_preflight.verify_summary_semantics` from the merged workshop config. Default `pass_field`/`warn_field`/`fail_field` are `"pass"`, `"warn"`, `"fail"` (matching `05_verify_infrastructure.py`'s `notebook.exit` payload). `warning_policy` defaults to `allow_with_notes`; set to `block_if_load_bearing` for use cases whose verify-job emits warnings that must block the gate. When `warning_policy == block_if_load_bearing`, any warning whose name matches an entry in the workshop's `gate_load_bearing_checks[]` list blocks the first verify gate (PASS only when `fail == 0` AND no load-bearing warning is present).6313. **Derive `variant_id`** from `pathway` + `track` using the deterministic derivation table in [`references/resolver-prompt.md`](references/resolver-prompt.md) § *Variant-ID Derivation Table*.6414. **Invoke `resolve_spec`** (see below) to parse the PRD at `prd_path` and populate the six spec sections (`## Variant`, `## Resources`, `## UI`, `## Agent`, `## Governance`, `## Spec Provenance`). This is a hard step: if `resolve_spec` halts, `bootstrap` halts.6566**Outputs:** Path of the bootstrap state file (also stored as `bootstrap_preflight.first_state_file_path`), populated with `## Environment Capabilities` (section 0), `## Bootstrap Preflight`, Workshop Choices, Global Variables (partial), and fully resolved Variant / Resources / UI / Agent / Governance / Provenance spec sections (schema v2.0). The workshop continues with this path until `migrate_canonical` runs.6768**Errors:** If the bootstrap path already exists, abort — do not overwrite. The operator must remove or migrate the stale file. Any of the four halt rules in `references/spec-schema.md` § Bootstrap Preflight (steps 1–4 above) abort before the template is copied. If `resolve_spec` fails validation twice, abort and surface the validation errors; the operator must fix the PRD before re-running.6970**DAB dev-mode schema-prefix rule (consumer-side).** If Databricks Asset Bundle dev mode prefixes UC schema resource names, notebook/job parameters must receive the resolved prefixed schema name, not the unprefixed variable. Bootstrap captures `bundle_dev_mode_schema_prefix_detected`; any prompt that passes `agent_schema`, `ops_schema`, or `uc_schema` to a job reads the resolved value from state.7172### Operation: `resolve_root`7374**When:** Any prompt that writes an artifact **before `bootstrap` has run** (e.g. the PRD-generation prompt produces `docs/design_prd.md` *before* the PRD exists to bootstrap from). It is the minimal, gate-free way to learn *where relative artifact paths must land* so a bare `docs/…` does not resolve against a page-dependent CWD on Genie Code. Idempotent — safe to call repeatedly; a later `bootstrap` supersedes it as the persistence owner.7576**Inputs:** none required. (Optional `state_file_path` — if the caller already knows where a state file lives.)7778**Behavior:**79801. **Read-if-present.** If a state file with a `## Environment Capabilities` block (section 0) already exists (the live file, or the bootstrap path `example/<use_case_slug>/.vibecoding-state.md` / `workshops/<use_case_slug>/.vibecoding-state.md`), read `client_context`, `artifact_root`, `skills_install_root`, and `skill_ref_root` from it and return them. Do **not** re-detect or rewrite.812. **Else detect fresh (bootstrap step-0 detection ONLY).** Run just the client/root detection from `bootstrap` step 0 — no URL/profile/CLI/quota preflights, no template copy, no `resolve_spec`, no gates: if a Databricks-managed CLI channel is present (`runDatabricksCli` / Genie serverless markers) ⇒ `client_context: genie_code`, `artifact_root` = the **user project workspace path** (e.g. `/Workspace/Users/<email>/<repo>`, a **git clone** of the workshop repo), `skills_install_root` = the **skills copy path** (e.g. `/Workspace/Users/<email>/.assistant/skills/<repo>`, a copy for discovery), `skill_ref_root` = `"skills/" + basename(skills_install_root)` (e.g. `skills/vibe-coding-workshop`); otherwise ⇒ `client_context: ide_cli`, `artifact_root` = `skills_install_root` = the local repo root, `skill_ref_root` = empty.823. **Ensure `artifact_root` is a git-backed working tree.** The kickstart `git clone`s the workshop repo into `artifact_root`; if `<artifact_root>/.git` is missing, `git clone <workshop remote>` into it so the caller's first relative write (e.g. the PRD at `<ARTIFACT_ROOT>/docs/design_prd.md`, produced *before* `bootstrap`) lands in a real, git-backed directory where generated bundles are recognized (a bare `mkdir` leaves them unrecognized — TESTED; a Repos-managed Git folder is the documented fallback). On `genie_code` operate via the workspace path / `executeCode`, mindful of the FUSE create-then-validate gap (clone, then confirm with `os.path.exists(<artifact_root>/.git)` before writing). This clone/check is the **only** filesystem side effect of `resolve_root`.834. **Echo, do not persist.** Return `client_context` + `artifact_root` + `skills_install_root` + `skill_ref_root` for the caller to use immediately and to echo the project-root + skill-load rules to the operator. **No state file is written** — `bootstrap` step 0 remains the sole writer of section 0, so there is no "abort if path exists" conflict and no half-initialized state file.8485**Outputs:** `{ client_context, artifact_root, skills_install_root, skill_ref_root }` (ephemeral). The calling prompt resolves its relative artifact path as `<ARTIFACT_ROOT>/<relpath>`, loads any repo-relative skill path `X/Y/SKILL.md` as `<skill_ref_root>/X/Y/SKILL.md` via `readSkillFile` (§8), and echoes: "artifacts resolve under the workshop project root (`artifact_root`, the git-cloned user project on Genie Code — not the skills copy) and skills load under `skill_ref_root` (= `skills/<clone-folder>` = `skills/` + basename of `skills_install_root` on Genie Code), never the page CWD."8687**Errors:** None that halt — `resolve_root` is fail-soft. If detection is ambiguous, default to `ide_cli` / repo-root and note the assumption; the later `bootstrap` step 0 is authoritative.8889### Operation: `resolve_spec`9091**When:** Called automatically as the final step of `bootstrap`. May also be re-invoked manually if the PRD changes mid-workshop (rare; prefer restarting from bootstrap).9293**Inputs:**9495| Param | Type | Required | Description |96|---|---|---|---|97| `prd_path` | string | required | Path to the PRD. Read from `Workshop Choices.prd_path` if omitted. |98| `llm_endpoint` | string | required | LLM endpoint used to synthesize the spec. Read from `Workshop Choices.llm_endpoint` if omitted. Must be a Databricks Model Serving endpoint reachable from the workspace. |99100**Behavior:**1011021. Read the PRD contents from `prd_path` and compute `prd_sha256`.1032. Load the schema from [`references/spec-schema.md`](references/spec-schema.md) and the prompt from [`references/resolver-prompt.md`](references/resolver-prompt.md).1043. Derive `variant_id` deterministically from Workshop Choices (`pathway`, `track`) per the resolver prompt's *Variant-ID Derivation Table*. Inject it into the user prompt.1054. Call `llm_endpoint` with the system + user prompts. Expect a single YAML document with exactly six top-level keys: `variant_id`, `resources`, `ui`, `agent`, `governance`, `spec_provenance`.1065. Run the deterministic guards listed in the resolver prompt's "Post-resolution Guards" section:107 - YAML parses cleanly into a dict with the expected top-level keys.108 - Every validation rule in [`references/spec-schema.md`](references/spec-schema.md) §"Validation Rules" passes.109 - Consumer cross-check: each `agent.tools[].name` of `kind: function` with `language: python` reconciles with the PRD Tools Table.110 - Placeholder guard: no resource-ID-shaped strings leaked through.111 - Variant-ID echo check: emitted `variant_id` equals the one passed in.112 - MCP ref resolution: every `agent.tools[].mcp_server_ref` (kind=mcp) maps to an `agent.mcp_servers[].name`.1136. If any guard fails, retry **once** with the validation errors appended to the user prompt. Second failure halts bootstrap.1147. Split the validated YAML by top-level key and write each block into its matching state-file section (`## Variant`, `## Resources`, `## UI`, `## Agent`, `## Governance`, `## Spec Provenance`), replacing the `<pending>` placeholder body with a fenced ```yaml block containing the resolved content.1158. Stamp `## Spec Provenance` with `resolved_at`, `resolver_version: "2.0"`, `schema_version: "2.0"`, `prd_sha256`, and `llm_endpoint`.116117**Outputs:** No return value; mutates the live state file.118119**Errors:** Validation failure (after one retry), missing PRD file, unreachable `llm_endpoint`, or any LLM response that is not parseable YAML with the six expected keys — all halt bootstrap.120121**Downstream contract:** Every consuming skill declares which fields it reads via a machine-parseable `fields_read:` YAML list in its frontmatter (see § *Field Consumer Contract* below and [`references/spec-schema.md`](references/spec-schema.md) §"Field Consumer Contract"). Prompts in `Instructions.md` and `WALKTHROUGH.md` reference resolved content by dotted path (e.g. `ui.user_journeys`, `agent.tools`, `governance.scorer_suite.guidelines`) instead of inlining domain-specific content. This is what makes the workshops use-case-agnostic.122123### Operation: `hydrate_from_files`124125**When:** Called once per workshop, before any prompt that reads `state://AgentSpec`, `state://AppSpec`, or `state://DataSpec`. The Agents Accelerator visible path calls it from prompt `uc_resources_foundation` (input_id 200, order 40), right after `op enter` succeeds and before any UC schema/volume creation.126127**Purpose:** The Agents Accelerator design pair (`docs/agent_spec.yaml` from prompt 38, `docs/agent_tool_plan.yaml` from prompt 39) becomes the source of truth for the agent's intent. `hydrate_from_files` lifts those file values into the live state file so every downstream consumer (Track A build prompts, MLflow SDLC suite at prompts 50-56) keeps reading from `state://AgentSpec`, `state://AppSpec`, and `state://Spec Provenance` without an additional visible-path step. This is additive to `resolve_spec`: PRD-only LLM-driven workflows that never produce the `docs/*.yaml` files continue to work unchanged.128129**Inputs:**130131| Param | Type | Required | Description |132|---|---|---|---|133| `agent_spec_yaml` | string | required | Path to the `docs/agent_spec.yaml` produced by prompt 38 (`agent_spec_design`). |134| `agent_tool_plan_yaml` | string | required | Path to the `docs/agent_tool_plan.yaml` produced by prompt 39 (`agent_tool_selection`). |135| `ui_design_md` | string | required | Path to the `docs/ui_design.md` produced by prompt 04 (`cursor_copilot_ui_design`). |136| `prd_path` | string | required | Path to `docs/design_prd.md` from prompt 03 (`prd_generation`); used for `source_prd` provenance. |137| `state_path` | string | required | Path to the live state file (Pathways A/B/C: `apps_lakebase/$APP_NAME/.vibecoding-state.md`; Pathway D: `agents/$AGENT_NAME/.vibecoding-state.md`). |138139**Behavior:**1401411. **Read `agent_spec_yaml`.** Copy scalar/list `agent.*` fields directly into the state file's `## Agent` section as a fenced ```yaml``` block: `model`, `capabilities`, `personas`, `system_prompt`, `benchmark_seeds`, `must_do`, `must_not_do`. File values override any prior `resolve_spec` LLM output silently; the file is the source of truth.142143 **Tool projection rule (preserves the v2.0 `fields_read: agent.tools` contract without rewriting any consumer).** The Agent Spec produced by step 38 follows the 00b schema (`tool_recommendations`, NOT `agent.tools`). Hydration MUST project tools into `state://AgentSpec.agent.tools[]` using these three sub-rules:144145 a. Seed `state://AgentSpec.agent.tools[]` from `docs/agent_spec.yaml.tool_recommendations.managed_databricks[]` plus `tool_recommendations.external[]`. Map each entry to the v2.0 tool discriminated-union shape: populate `kind` (`hosted` | `function` | `mcp`), `name`, `surface`, `io_contract`, `readonly`, plus the kind-specific fields (`hosted_type` + `resource_ref`, or `language`, or `mcp_server_ref`). Carry `selected_by_default` forward to pre-mark entries.146 b. Overlay `docs/agent_tool_plan.yaml.selected_tools[]` on top. Any Tool Plan entry with the same `name` REPLACES the spec recommendation — binding selection wins over loose recommendation. Tool Plan entries with no matching spec recommendation are appended.147 c. Tool families absent from BOTH the spec and the Tool Plan are NOT written into `agent.tools[]`. Skipped families are recorded as skipped, not failed (consistent with step 44 semantics).148149 The projection is the only legitimate way `state://AgentSpec.agent.tools[]` becomes populated on the Agents Accelerator visible path. Step 38 does NOT and MUST NOT write `agent.tools[]` directly into `docs/agent_spec.yaml`; downstream prompts that still cite `agent.tools[]` (e.g. step 44's prerequisite block before Pass 3.5) MUST be updated to read `tool_recommendations` (loose) plus `selected_tools` (binding) instead.1502. **Read `agent_tool_plan_yaml`.** Merge `selected_tools[]`, `selected_mcp_servers[]`, `runtime_config.llm`, and `resource_grants` into `## Agent` under new keys `selected_tools`, `selected_mcp_servers`, `runtime_config`, and `resource_grants`. Tools selected by the user in the Tool Plan win over the Agent Spec's recommendations.1513. **Read `ui_design_md`.** Parse loose markdown headings into `## UI` (`pages[]`, `personas[]`, `user_journeys[]`) on a best-effort basis. If the document is structured differently or only contains free-form prose, write the verbatim markdown into `## UI.raw_markdown` and emit a non-fatal warning so downstream SDLC prompts can still find personas/journeys textually.1524. **Stamp `## Spec Provenance`.** Compute `prd_sha256` from `prd_path` and write `resolved_at` (current UTC ISO timestamp), `resolver_version: "3.0"` (new tag distinguishing file-based hydration from LLM `resolve_spec`'s `"2.0"`), `schema_version: "2.0"`, `prd_sha256`, and `hydrated_from_files: true`.1535. **Optional `## Resources` (DataSpec).** If the PRD declares a Lakehouse/Resources section (Bronze tables, Genie Spaces, Vector Search indexes, etc.) and `## Resources` is already populated by an earlier `resolve_spec` run, leave it untouched. Otherwise write `## Resources` as `optional: true` with `tables: []`, `mark_skipped: "no Lakehouse track"`, signalling downstream prompts that `state://DataSpec.*` lookups should fall back gracefully (e.g. KA branch C in prompt 42 reads from `docs/design_prd.md` + `docs/agent_spec.yaml.agent.capabilities` instead of `state://DataSpec.glossary`).1546. **Idempotency.** Re-running with the same inputs is a no-op: each section is regenerated from the file values, sha256 is stable, and the state file ends in the same byte sequence (modulo the `resolved_at` timestamp, which is allowed to drift). Re-running with newer `docs/*.yaml` files overwrites cleanly.155156**Outputs:** `{ hydrated: true, sections_written: ["## Agent", "## UI", "## Resources", "## Spec Provenance"] }`. The Agents Accelerator step 40 records `hydrated_from_files: true` and `resolver_version: "3.0"` in its `op exit` `captured` map.157158**Errors:**159160- Missing required input file → halt with an explicit pointer to the producing prompt: `agent_spec_yaml` → 38, `agent_tool_plan_yaml` → 39, `ui_design_md` → 04, `prd_path` → 03, `state_path` → bootstrap.161- `agent_spec.yaml` missing `agent.model` → halt with a pointer to prompt 38's model selection rule (Pass 1 / Pass 2 of the Agents Accelerator cleanup).162- `agent_tool_plan.yaml.runtime_config.llm.endpoint` equals the literal YAML-path string `docs/agent_spec.yaml.agent.model` → halt with the Pass 2 placeholder rule citation. This is defense-in-depth; prompt 39's generated prompt already forbids this.163- Any value at a documented Agent Spec / Tool Plan path is still wrapped in `{...}` (e.g. `{agent_sql_catalog}`) → halt with the Pass 2 placeholder-handling rule. The user must rerun prompt 39 with real values.164165**Downstream contract:** After `hydrate_from_files` runs, every prompt that consumes `state://AgentSpec.agent.*`, `state://AppSpec.ui.*`, or `state://Spec Provenance.*` sees the file-derived values. `state://DataSpec.*` is `<pending>` or `optional: true` unless the Lakehouse track produced one. SDLC prompts (50-56) MUST handle the optional/pending DataSpec case gracefully — they already do (the Agents Accelerator visible path no longer requires Lakehouse outputs), but the `optional: true` flag makes the contract explicit.166167**LLM driver prompt:** See [`references/hydrator-prompt.md`](references/hydrator-prompt.md) for the actual prompt that an LLM-driven implementation runs to execute this operation. That file is to `hydrate_from_files` what [`references/resolver-prompt.md`](references/resolver-prompt.md) is to `resolve_spec`.168169### Operation: `enter`170171**When:** At the **top** of every workshop prompt, before any domain skill or command runs.172173**Inputs:**174175| Param | Type | Required | Description |176|---|---|---|---|177| `prompt_id` | string | required | e.g. `0.1`, `3.2`, `5.A4`, `7.22.5`, or `20c`. Matches the heading the prompt will log under. |178| `require_prior_gate` | `{prompt_id: string, gate: string}` | optional | Assert the listed prompt's Gate equals the listed string. If it does not match, `enter` stops the workshop and surfaces the mismatch. |179180**Behavior:**1811821. **Locate the live state file:**183 - **First, resolve `state_file_root`** from the `## Environment Capabilities` block (section 0). Every path below is relative to it — the local repo root for `client_context: ide_cli`, the git-folder workspace path for `genie_code`. On a pre-capability state file (no section 0), default `state_file_root` to the repo root and proceed without assuming a deploy channel.184 - If `$APP_NAME` is known (Pathways A/B/C), use `<app_root>/.vibecoding-state.md` (= `<state_file_root>/<app_name>/.vibecoding-state.md`, the TOP-LEVEL app dir — NOT `apps_lakebase/<app_name>/`).185 - Else if `$AGENT_APP_NAME` is known (Track A agent app, Pathways C/D), use `<agent_app_root>/.vibecoding-state.md` (= `<state_file_root>/<agent_app_name>/.vibecoding-state.md`, the TOP-LEVEL agent app dir — NOT `apps_lakebase/<agent_app_name>/`).186 - **Else if `dp_bundle_root` is resolved (a data-product / lakehouse run with no app or agent app — e.g. the Gold-design→Bronze→Silver→Gold→semantic pipeline), use `<dp_bundle_root>/.vibecoding-state.md`** (= `<state_file_root>/{user_schema_prefix}_<use_case_slug>_dab/.vibecoding-state.md`). This is the **canonical DP-track live file** — the data-product analog of `<app_root>` / `<agent_app_root>`. The FIRST data-product prompt to run (Gold design, step 09 — or Bronze, step 10, if design was skipped) **bootstrap-creates** it from [`references/state-template.md`](references/state-template.md) if absent (a real create, copying the template + filling Workshop Choices from the prior `example/` bootstrap file if present — not just `resolve_root`); every later DP step appends to it. Do NOT leave data-product state in the temporary `example/` bootstrap path — that path carries no durable record and was the root cause of "state survived only in chat summary."187 - Else fall back to the bootstrap path `<state_file_root>/example/<use_case_slug>/.vibecoding-state.md` (pre-bootstrap only — once `dp_bundle_root`/`app_root`/`agent_app_root` is known, migrate/bootstrap-create the canonical file above).188 - If none of these exists yet: for the **`dp_bundle_root`/`app_root`/`agent_app_root` canonical paths, bootstrap-create the file from the template** (this is the first prompt of that track); only stop and tell the operator to run `bootstrap` first if even `use_case_slug`/Workshop Choices are unknown.1892. **Schema v2.0 gate (hard fail).** Parse the `## Spec Provenance` YAML block. If `schema_version != "2.0"`, halt with:190191 ```192 State file uses schema v<X> — this repo is strictly v2.0.193 Run: python scripts/migrate-spec-v1-to-v2.py <path-to-state-file>194 Then re-run this prompt.195 ```196197 No best-effort reads against older shapes.1983. **Read end-to-end.** Treat `Workshop Choices`, `Global Variables`, and `Captured Resource IDs` as authoritative. **Never ask the operator for a value that already exists in state.**1994. **Multi-file resolution via `state_file_set`.** Parse the `## State File Set` block.200 - If `state_file_set.secondary.path` is `<pending>` or null, treat the located file as the only source — done.201 - If `secondary` is declared and `prompt_id` is in `secondary.required_for_prompts`, read the secondary file too. Halt if it does not exist (remediation: run `bootstrap` for the missing side or correct `secondary.path`).202 - Walk both files following `lookup_order` (e.g. `["primary", "secondary"]`). For each canonical field requested by the prompt, the first hit wins.203 - For any canonical field present in **both** files with different values: halt unless `conflict_policy: primary_wins` is set explicitly. With `primary_wins`, use the primary value and append the conflict to `## State Contract Audit` (`fields_read_but_never_produced` / `captured_fields_with_no_consumer` are unaffected; conflicts get their own audit row).2045. **Apply `canonical_names` aliasing on read.** Parse the `## Canonical Names` block. Whenever the prompt reads an env var, HTTP header, jq path, or state field listed as a legacy/incorrect spelling on the left of a `canonical_names` map, resolve to the canonical name on the right. If the map's value is `null` (e.g. `http_headers.x-forwarded-user-info: null`), the name does not exist; halt and surface a hint pointing at the canonical alternatives. `state_contract_audit` performs the same checks at audit time.2056. **Enforce the prior gate** if `require_prior_gate` is set. On mismatch, halt unless a matching entry exists in `state_overrides[]` (see step 7). Mismatches that are NOT covered by an override stop the workshop.2067. **Apply `state_overrides[]` (fail-closed escape hatch).** Parse `## State Overrides`. An override entry covers a failing gate when ALL of the following hold: `prompt_id` matches the current prompt; `gate_type` matches the failing gate (`require_prior_gate` for step 6, `hard_assert` / `preflight_check` for step 9 below, `pathway_applicability` for step 8); and `expires_at` is in the future relative to the current ISO timestamp. A covered failure is treated as satisfied and the override is logged in the prompt's `Resolved issues / workarounds` Per-Step Log entry. Expired or missing entries DO NOT cover the failure — `enter` halts. Cross-session continuity (e.g. resuming from a previous run's state file) is recorded as a `state_override` whose `reason` cites the earlier run's evidence; it is NOT a prose exception.2078. **Consult the Pathway Applicability Matrix** (below). If the prompt does not apply for this `pathway`/`track` and no `state_override` with `gate_type: pathway_applicability` covers it, synthesize a `## Prompt <prompt_id> — Skipped (N/A for pathway <X>)` section with `Gate: Skipped — N/A for pathway <X>`, append it, and return a `skipped: true` signal so the prompt body short-circuits. With a covering override, proceed (the override `reason` is logged in the prompt's Per-Step Log entry).2089. **Enforce `deferred_actions[]`.** Parse `## Deferred Actions`. Halt if the current prompt's role is in any open `deferred_action`'s `target_prompt_roles[]` and its `divergence_check` evaluates to false (or fails to parse under the divergence-check grammar in `references/spec-schema.md` § *Deferred Actions*). Halt is suppressed only when a `state_override` with `gate_type: hard_assert` (or `preflight_check`) on the current `prompt_id` exists AND its `references[]` contains `"deferred_action:<id>"` matching the action's `id`. If `divergence_check` returns true, flip `status` to `resolved` and proceed. Entries with `status: waived` are skipped without evaluation.20910. **Enforce `mlflow_eval_known_quality_issues[]`.** Parse `## MLflow Eval Known Quality Issues`. If the current prompt's role appears in any open issue's `target_prompt_roles_blocked[]`, halt with a remediation hint citing `id`, `source_prompt_role`, and `error_signature` — unless a `state_override` exists on the current `prompt_id` whose `references[]` contains `"known_issue:<id>"` matching the issue's `id`. The issue's `error_signature` SHOULD be a name from `gate_load_bearing_checks[]` so audits and verify summaries align, but `enter` halts purely on `target_prompt_roles_blocked[]` membership and `status: open` — it does NOT consult `gate_load_bearing_checks[]` directly (that list drives `state_contract_audit` and the verify-job `warning_policy: block_if_load_bearing` rule per § *Gate Load Bearing Checks* in `references/spec-schema.md`).21011. **Enforce `preflight_check_registry`.** Parse `## Preflight Check Registry`. For each registry entry, if the current prompt's role appears in `blocks_prompt_roles[]`, evaluate the matching state field per the *State-field mapping* table in `references/spec-schema.md` § *Preflight Check Registry*. If the pass condition is not met (the field is `<pending>`, missing, or fails the predicate), halt with a remediation hint pointing at `owner`. The halt is suppressed only when a matching `state_override` with `gate_type: preflight_check` exists on the current `prompt_id` whose `affected_state_field` matches the check's state field. For `reflection_lm_large_context_probe`, the check is treated as passing only when a synchronous ≥80000-character probe has been run against the currently bound `llm_role_endpoints.reflection_lm.endpoint` and `endpoint_guardrail_audit[<reflection_lm.endpoint>].long_context_ok == true` AND `accepted_min_context_chars >= 80000` — the generic bootstrap endpoint guardrail pass is NOT sufficient on its own. The owning skill (`instruction_iteration`) MUST invoke the probe synchronously before any 08b diff-summary helper or iteration helper call. For `genie_code_manifest_loaded` (G3, the one **client-conditional** check), evaluate it **only when `environment_capabilities.client_context == 'genie_code'`** — it is inert on `ide_cli` — and on Genie Code halt the deploy roles until `environment_capabilities.genie_code_manifest_loaded == true` (the agent has read `skills/genie-code-environment` in-thread); see `references/spec-schema.md` § *Genie Code manifest-load gate*.21112. **Resolve variables.** Return the subset of state the prompt body needs (it is declared in the prompt's `enter` invocation — e.g. `APP_NAME`, `PROFILE`, `warehouse_id`). **Always also return the environment-capability set** so any deploy/run instruction the prompt emits uses the resolved verb + channel instead of assuming a local IDE: `bundle_deploy.verb` (always `bund212213…(truncated)