Imported from databricks-solutions/vibe-coding-workshop-template (
skills/genie-code-environment/SKILL.md). Install upstream withnpx skills add databricks-solutions/vibe-coding-workshop-template --skill genie-code-environment. Copyright stays with the author.
Genie Code Environment — session-start manifest
Confidence tags.
[DOC]= Databricks documentation;[TESTED]= observed directly in a probe (probe IDsP1–P18);[CONTESTED]= probes once conflicted — now resolved, see §"Resolved vs. open";[INFERENCE]= reasoned, unverified. Every behavioral claim below carries a tag + a citation.
Why this skill exists
The single highest-leverage fix for working in Genie Code is to begin each session knowing how it
behaves, instead of re-discovering it live in front of the user (field guide §6.8 — the meta-fix for
every other gap). This skill is that durable manifest. skills/vibecoding-state detects which client
is active and writes the capability block; this skill explains how the Genie Code client behaves —
detection vs. explanation, no duplication. If client_context == ide_cli, you do not need this skill.
Record the load (G3 manifest-load gate). The moment you have read this manifest in the current thread, set
environment_capabilities.genie_code_manifest_loaded: truein the live state file. This skill is the owner of thegenie_code_manifest_loadedpreflight check (skills/vibecoding-state§ Preflight Check Registry): on Genie Code, the first deploy / client-divergent prompt'senterhalts until this flag istrue, so the deploy machinery (allow-list tiers, CWD pin, FUSE gap, App scaffold/deploy, OAuth-session verify) is in context before you act. The check is inert onide_cli.
The one operating rule (read this first)
Match the surface to the task. If a path is blocked, try the next of the three execution paths. Never conclude "impossible" from one path or one page. Every operation that was hard-blocked on one path in the probes had a working alternative on another. [TESTED, recurring P1–P18]
Don't fabricate state — report unverified facts as
unknown. Never claim a page, surface, deploy state, or capability you did not actually observe (e.g. "I'm on the Apps page" when you never navigated there, or "the deploy succeeded" without readingdeployment.state). If you haven't verified it this turn, say so and probe it. TherunDatabricksCliallow-list is non-deterministic (a verb blocked on one attempt can be allowed on the next), so "blocked once" is not "impossible" — and "worked once" is not "always works." [TESTED P32]
1. What Genie Code is, and why the surface matters
Genie Code is Databricks' context-aware AI assistant embedded throughout the workspace — notebooks, SQL
editor, jobs, AI/BI dashboards, the file editor, and bundle folders. It runs on serverless compute and
is pre-authenticated to the workspace (no auth login, no token export). [DOC; TESTED P-runtime]
The defining fact: Genie Code adapts its available tools to the surface (page/asset) you are
currently on. [DOC] A dashboard page exposes dashboard tools; a notebook page exposes code execution; a
bundle folder exposes bundle operations. This surface-scoping is the single most important thing to
understand — the same request can succeed on one page and be "not in the allow-list" on another. The first
move when a capability seems missing is to navigate to the right surface, not to conclude it's
impossible. [TESTED P10 — apps deploy blocked on a file-editor page]
2. The three execution paths
Genie Code can act on Databricks three independent ways, in order of preference:
runDatabricksCli— a pre-authenticated, API-routed CLI path with a per-command allow-list and safety guardrails. The primary path. [TESTED]- Python SDK —
from databricks.sdk import WorkspaceClientviaexecuteCode; auto-authenticated; full REST surface. This is the most capable path: it bypasses the CLI allow-list and is the reliable way tow.apps.deploy(...), obtain a runtime bearer viaw.config.authenticate()(note:w.config.tokenisNoneon serverless — see §7), and poll deployment/run state. Caveat: the SDK has no bundle-deploy equivalent —bundle deployis a composite client-side operation (readdatabricks.yml, resolve templates, sync files, Terraform state), so it stays onrunDatabricksCli. [TESTED] - Native workspace tools —
createAsset,editAsset,openAsset,readTable,tableSearch,findReferencesTool,checkPermissions,renderChart,askDataroom, … operating on governed APIs. [TESTED]
A fourth, raw shell (executeCode language sh calling the databricks binary), is blocked by a
trampoline unless ENABLE_DATABRICKS_CLI=true — an escape hatch, not an intended path. [TESTED]
Discipline: try path 1 → if blocked, path 2 → if still blocked, path 3.
Full per-command allow-list tiers and the deploy/CWD/FUSE detail live in references/allow-list-and-commands.md — load on demand.
3. Bundle deploy reality (the spine, on Genie Code)
The deploy contract is identical to the IDE — bundle deploy --target dev, run through
runDatabricksCli (see databricks-asset-bundles for the canonical contract). The Genie-specific facts:
--target devis mandatory — a targetlessbundle deployis rejected by a content safety guardrail ("could affect staging/production"); it is not a page block.--help/validate/summaryare pre-approved from any bundle-context page. [TESTED P4/P5/P6]- CWD is pinned to the current page's bundle root — be on the page of the bundle you are deploying.
There is no
cd, no--bundle-rootflag; you can only validate/deploy the bundle tied to the current page. [TESTED P2] - How to GET on the bundle page: open the bundle editor. As soon as a folder contains a
databricks.yml, the Databricks workspace file browser shows an "Open in bundle editor" affordance for that folder (and an "Open in editor" button at the top of the folder view). Click it to enter the Bundle UI, whose page CWD IS that bundle root — this is the reliable way to satisfy the CWD pin above, and Genie Code operates more predictably (deploy/run pre-approved) from inside the bundle editor than from a generic file page. So the canonical sequence is: writedatabricks.ymlunderdp_bundle_root→ open that folder's bundle editor → runbundle validate/deploy/runthere. Adatabricks.yml not founderror means you are NOT on the bundle page — open the bundle editor for thedp_bundle_rootfolder; never fall back to direct SQL. [TESTED — user-observed] - Bundle recognition requires a git working tree — this is why
artifact_rootis a git clone. A 3x2 workspace probe settled the rule: a folder'sdatabricks.ymlshows the "Open in bundle editor" affordance (and a working Deploy surface) only when it sits inside a git working tree. A webgit clone(a plain workspace "Folder" containing.git) is sufficient — recognized at the root AND in nested subfolders (so<artifact_root>/<use_case_slug>_dab/databricks.ymlis recognized whenartifact_rootis the clone); a managed Databricks Repos object is NOT required (it is the documented fallback). A plainmkdirdirectory (no.git), even with a validdatabricks.yml, is NOT recognized. This is the whole reason the kickstartgit clones the workshop repo INTOartifact_root(and merely copies the tree to the.assistant/skillsdiscovery path). [TESTED — 3x2 workspace probe] - Surface a clickable bundle-editor link — don't make the operator hunt for the icon. With the
pre-authenticated
WorkspaceClient(w):host = w.config.host;o = w.get_workspace_id();file_id = w.workspace.get_status("<dp_bundle_root>/databricks.yml").object_id;folder_id = w.workspace.get_status("<dp_bundle_root>").object_id. Then the bundle-editor URL is{host}/editor/files/{file_id}?o={o}&contextId=folder%3A{folder_id}(the plain folder is{host}/browse/folders/{folder_id}?o={o}). Print the bundle-editor link and tell the operator to open it before deploy. [TESTED — user-observed] - 🛑 Blocked
bundlecommand ⇒ navigate, don't improvise. If still blocked, STOP.bundle deploy/runare page-context-gated: BLOCKED on a generic file/notebook page, but they work normally from the bundle editor — CONFIRMED in the field, the samebundle deploythat returned "blocked by safety guardrails" from a file page returned "Deployment complete!" andbundle run … SUCCESSonce the operator opened the bundle editor. So a "blocked" /databricks.yml not foundmessage is a wrong-page signal, not a dead end: open the bundle-editor link and retry. Only if it still fails from the bundle editor do you STOP and report the blocker. Do NOT fall back to the Jobs/Pipelines REST API (jobs/create,/api/2.0/pipelines), the SDK, or direct SQL to "get the tables created" — that silently defeats version control andbundle destroycleanup and is the exact regression this spine prevents. The REST/SDK route is an escape hatch available only on explicit operator authorization. [TESTED — user-observed] - Edit the existing on-page
databricks.yml. Files newly written viacreateAsset/the workspace API do not reach the CLI's FUSE mount in the same session, so "create a new bundle then validate it" fails — edit the bundle already on the page. [TESTED P3] - Use
bundle validate/bundle summaryas safe pre-flight (pre-approved, any page). [TESTED P4]
4. AppKit / Node reality
apps initneeds--output-dir— it defaults to the workspace root (/Workspace/<name>), ignoring the page CWD. Pass--output-dir .(page folder) or an explicit/Workspace/Users/<email>/<repo>. [TESTED P14]- No local
npm/npx/corepackin the shell (onlynodeis present), but the Apps runtime builds server-side: a SNAPSHOT deploy runsnpm install+npm run build(Vite) from un-built source. A Genie-Code participant can editclient/src/*.tsxdirectly and redeploy with no local Node toolchain. [TESTED P9/P11/P18 — verified: an edited string appeared in the server-built JS bundle] apps deployviarunDatabricksCliis unreliable — the allow-list is non-deterministic (blocked on one attempt, allowed on the next on the same page type — not cleanly page-gated) and CWD-defeated (the enhanced build flow only fires when CWD = the project root, which never held in probes → it demandsAPP_NAMEand falls through to the build-skipping API-direct path; the enhanced flow also runs a local build/typecheck/lint that needsnpm, which is absent). The reliable cross-context path is the SDK:w.apps.deploy(<name>, AppDeployment(source_code_path=…, mode=SNAPSHOT))viaexecuteCode, which bypasses the allow-list and runs the build server-side. Prefer the SDK SNAPSHOT path; treat a blockedapps deploy/apps initas transient — retry or setENABLE_DATABRICKS_CLI=true, never declare it impossible. [TESTED P10/P11/P32]- Python toolchain IS present (Track A agent apps are Python, not Node). Unlike npm, the
uvbinary (/usr/local/bin/uv),pip25.0.1, and Python 3.12 in a writable ephemeral venv ARE available in the shell —uv pip install -e ./python -m pip install -e .against apyproject.tomlcomplete in-session. The venv is ephemeral (no persistence across sessions/cluster restarts), so treat installs as per-session. (The field guide only tested the Node toolchain; this closes the Python side.) [TESTED P19] - A
uv-based FastAPI app builds server-side on a SNAPSHOT deploy, exactly like Node/Vite. Theagent-openai-advancedTrack A template (pyproject.toml+app.yamlwith auv run …command) deploys via the SDKw.apps.deploy(<name>, AppDeployment(source_code_path=…, mode=SNAPSHOT)): the platform resolves deps withuvand starts the process server-side, reachingSUCCEEDED("App started successfully") — no local build. So Track A agent apps follow the same SDK-SNAPSHOT deploy path as AppKit, and the agent app can live at a clone-rooted top-level root (SNAPSHOT copies the source). [TESTED P20]- SDK ergonomics (carry into the deploy code):
w.apps.deploy(...)returns aWaitobject — readwait.response/wait.deployment_id, then pollw.apps.get_deployment(app_name, deployment_id)→dep.status.state.value(IN_PROGRESS→SUCCEEDED) /dep.status.message. TheAppobject has no.statusattribute — useapp.compute_status,app.active_deployment,app.pending_deployment,app.url. [TESTED P20]
- SDK ergonomics (carry into the deploy code):
- AppKit build failures trace to two import specifiers — preserve the scaffold. A pristine
apps initshipsclient/src/index.csswith@import "@databricks/appkit-ui/styles.css";and.tsximporting from@databricks/appkit-ui/react. Hand-regenerating these from memory reintroduces the bare@databricks/appkit-ui(no React export) and extension-less…/styles(unresolvable) — the dominant first-deploy failure. EditApp.tsx/index.cssincrementally; keepErrorBoundary.tsx. [TESTED P24/P25] - There is no local typecheck — a regex pre-flight is the only static gate.
npm/npx/corepackare dangling symlinks andtsccannot resolve@databricks/appkit-ui/vite/clientwithoutnode_modules, so the import-specifier failure is not catchable locally. Before a (~50s) deploy, scanclient/src/**viaexecuteCode+regex for the two bad specifiers and fix hits first. [TESTED P30] - The static gate catches more than import paths; author with literal characters. A round-2 run still
burned deploy cycles on classes the path-only gate missed, so the regex pre-flight now also blocks an
empty Radix
<SelectItem value="">(runtime crash on menu open), an escaped single-quote in a JSX attribute (Vite/rolldown parse crash), and a stray\uXXXXescape artifact, and flags for review any unused named import (noUnusedLocals→ hardTS6133build failure). Because you author.tsxthrough Pythonopen().write(...), prefer triple-quoted raw strings and write the real'/"characters — double-escaping is what produces the\u0027-style artifacts the gate flags. [TESTED P33] - Build logs are unreadable from compute — escalate to
/logzin a browser.deployment.status.message- REST only say "check /logz";
databricks apps logs <name>→ OAuth error;/logzover raw HTTP → 401. OnFAILED, hand the operator<app-url>/logz(already authenticated) to read the exacterror TS…line; no-browser fallback = the 2–3-file batch ladder (redeploy small batches; the batch that flips green→FAILED holds the break). [TESTED P26/P27/P28]
- REST only say "check /logz";
package-lock.jsonis a hard requirement on SNAPSHOT. Deleting it hard-fails the source-export phase in ~10s (RESOURCE_DOES_NOT_EXIST), beforenpm install. Never delete it as a reset. [TESTED P29]- A green deploy does NOT mean a working app. A server boot crash →
FAILED(agent-visible); a client runtime crash compiles and deploysSUCCEEDED/ACTIVEbut renders blank — invisible to the agent. Require a human render check in the browser (the scaffoldErrorBoundarysurfaces the stack). [TESTED P31]
5. Agent-Skills install
databricks aitools install (and the legacy experimental aitools install) is hard-blocked via
runDatabricksCli — the whole aitools verb family is not allow-listed. [TESTED P12] The working path is
git clone of databricks/databricks-agent-skills (git present, github.com reachable). [TESTED P13]
npx @databricks/appkit docs is unavailable (no npm); fetch AppKit docs via WebFetch instead. [TESTED P13]
6. Genie Spaces
Use the RULE_8 three tiers from databricks-asset-bundles ("Genie Spaces — three deploy tiers"):
Tier 1 native genie_spaces resource (preferred, landing ~this month), Tier 2 provisioning-job (active
fallback, both clients), Tier 3 createAsset({assetType:"genie", …}) + REST PATCH — the Genie-Code
hybrid dev-authoring loop. [TESTED P8] createAsset returns a live Space ID but builds only a shell
(tables registered; 0 instructions, 0 benchmarks, and metric views miscategorized under
data_sources.tables). Populate the FULL serialized_space with PATCH /api/2.0/genie/spaces/{id},
then PERSIST that JSON into the bundle so a job reproduces it — Tier 3 is sanctioned for dev iteration
only when the JSON is persisted (an orphan Space with no file is the regression). The Space title
always carries the per-user prefix. See §6c for the create→extract-back→persist mechanics. Point to the
spine for the canonical recipe; do not restate it.
Genie API gotchas (TESTED). Find Spaces with
searchAssets(assetTypes=["datarooms"]), but the ONLY supported mutation isPATCH /api/2.0/genie/spaces/{id}with a full body — NEVERPATCH /api/2.0/data-rooms/{id}(it silently wipesserialized_spaceto{}). Export config only viaGET /api/2.0/genie/spaces/{id}?include_serialized_space=true(there is no/exportendpoint — it 404s).readAssetById(assetType="genie")is unsupported — use the REST GET. Every text field inserialized_spaceisList[str];data_sources.tables/metric_viewsentries carry NOid; all IDs areuuid4().hex. The canonical contract +_assert_sql_arraysvalidator live insemantic-layer/04-genie-space-export-import-api/SKILL.md.
6b. Knowledge Assistants (Agent Bricks)
A Knowledge Assistant is not a bundle resource (no knowledge_assistant DABs type) — like Genie Spaces
it is an authoring-discipline exception created via the Agent Bricks REST API. The Genie-Code gotcha:
the bundled databricks-sdk 0.67.0 has no w.knowledge_assistants wrapper (hasattr → False), even
though the REST API is live. Call it through the generic SDK escape hatch w.api_client.do(<verb>, <path>, body=…) — no SDK upgrade needed (an uv pip install -U databricks-sdk would be ephemeral and is
unnecessary). Verified contract (mirrors the newer SDK's KnowledgeAssistantsAPI): [TESTED P22]
| Operation | Verb + path |
|---|---|
| list | GET /api/2.1/knowledge-assistants |
| create | POST /api/2.1/knowledge-assistants (body requires ≥1 knowledge source) |
| get / update / delete | GET / PATCH / DELETE /api/2.1/{name} |
| list / create sources | GET / POST /api/2.1/{parent}/knowledge-sources |
| sync sources | POST /api/2.1/{name}/knowledge-sources:sync |
GET /api/2.1/knowledge-assistants returned a live KA under Genie Code runtime auth. Some verbs also answer
on the older /api/2.0/... prefix (the API is mid-migration) — prefer 2.1, fall back to 2.0 only if a
2.1 verb 404s. Readiness polls via serving-endpoints get / WorkspaceClient.serving_endpoints (both
available). [TESTED P22]
6c. Semantic-layer authoring — native create + extract-back (TVF / Metric View / Dashboard)
The semantic layer (TVFs, Metric Views, Genie Spaces, AI/BI Dashboards) uses a hybrid model distinct from the lakehouse table-DDL discipline in §8 (schemas/tables remain bundle-job-only): author the definition file FIRST, apply it natively for a fast dev loop, extract the live asset back and diff it against the file, then keep the Asset Bundle as the version-controlled source of truth and the non-dev deploy mechanism. The invariant: persisted file + live matches file + bundle validates + job ran once in dev. An orphan asset (no file) or drift (live ≠ file) is the regression.
| Artifact | Create natively (dev) | Extract definition back | Persist to bundle | Notes / blocked |
|---|---|---|---|---|
| TVF | executeCode SQL CREATE OR REPLACE FUNCTION … RETURNS TABLE(…); INVOKE-test SELECT * FROM fn(…) |
DESCRIBE FUNCTION EXTENDED + information_schema.routines.routine_definition |
.sql with ${catalog}/${gold_schema} placeholders |
SHOW CREATE FUNCTION blocked (PARSE_SYNTAX_ERROR) |
| Metric View | executeCode SQL CREATE OR REPLACE VIEW … WITH METRICS LANGUAGE YAML AS $$…$$; validate with a MEASURE() query |
readTable → metadata.view_query_text (or UC REST GET /api/2.1/unity-catalog/tables/{full_name}.view_definition) |
.yaml with placeholders |
SHOW CREATE TABLE blocked for METRIC_VIEW; appears in information_schema.tables (type METRIC_VIEW), NOT .views |
| Genie Space | createAsset(assetType="genie", tableIdentifiers=[…]) shell → PATCH /api/2.0/genie/spaces/{id} full serialized_space (run _assert_sql_arrays first) |
GET /api/2.0/genie/spaces/{id}?include_serialized_space=true (assert non-zero instructions/benchmarks/sql_functions; MV under metric_views) |
full serialized_space JSON |
see §6 gotchas; never PATCH /data-rooms/{id} |
| AI/BI Dashboard | createAsset(assetType="dashboard") then AUTO-NAVIGATE openAsset(assetType="dashboard", assetId=<uuid>) + print a clickable link; author widgets on the canvas |
readAssetById(assetType="dashboard", assetId=<uuid>) → full .lvdash.json (UUID=published; treeNodeId=draft+path) |
.lvdash.json |
widget editing requires the canvas page; no remote widget edit |
Native authoring competence: TVFs and Metric Views are FULLY native — use the native using-metric-views
and writing-sql skills (more accurate than the workshop 01/02, which are CI/validation references
only). Genie Spaces need the workshop 04 (JSON schema + _assert_sql_arrays validator) — load it.
Dashboards are authored by navigation, then the extracted .lvdash.json feeds the existing
deploy_dashboard.py bundle job for persistence + cross-env redeploy.
7. Verifying a deployed app
A deployed App sits behind the Databricks Apps OAuth gate — a raw Authorization: Bearer token (even
SDK w.config.token) is rejected (/api/health → 401). [TESTED P16] Two working ways:
- Browser (simplest manual verify) — open
w.apps.get(<name>).url; the OAuth flow establishes the session. Useapps logs <name>for backend assertions. - Programmatic — replay the 3-hop Apps OAuth handshake in one
requests.Session()so the CSRF cookie persists through the callback (PKCE match), then reuse the session for all/api/*calls. [TESTED P17] Reusable snippet in references/app-verification.md.
Serverless token nuance (decisive — captured live). On serverless compute
w.config.tokenisNone; the runtime bearer that the OIDC authorize endpoint (Hop 2) accepts comes fromw.config.authenticate()["Authorization"](a shortdkea…token). Use that for Hop 2 — a missing/raw token bounces Hop 2 to/login.html. After Hop 3 the__Host-databricksappssession cookie authenticates everything; noAuthorizationheader is needed post-handshake. The 3-hop handshake is confirmed not just for static apps but against a Track A Agent App/invocations(FastAPI host, not Model Serving):POST /invocationscarrying only the session cookie →200+ a valid ChatCompletion body. [TESTED P21]
8. How a Genie Code session actually operates (operating model)
This is how a session runs — distilled from the field forks (someone ran this workshop on Genie Code):
- A pre-authenticated
WorkspaceClientis available viaexecuteCode(no auth step). Run Python/SQL on serverless directly. - Read and write workspace files, not
/tmp—/tmpis not durable and is not where artifacts belong. Build artifacts in memory or write to a project/workspace path. - Anchor every relative artifact path to
artifact_root, never the page CWD or your home dir.artifact_rootis the workshop PROJECT root thatskills/vibecoding-statecaptures into the## Environment Capabilitiesblock (= the local repo root onide_cli; the USER PROJECT path/Workspace/Users/<email>/<repo>ongenie_code, which is a git clone of the workshop repo — a git working tree, so generated bundles/apps/docs are recognized as Databricks Asset Bundles). The skill tree is copied fromartifact_roottoskills_install_root=/Workspace/Users/<email>/.assistant/skills/<repo>(the read-only discovery path); artifacts build inartifact_root, skills load fromskills_install_root. A baredocs/design_prd.mdis unsafe here because Genie Code's CWD is page-type-dependent (the bundle root on a bundle page, the workspace home otherwise — see §"Resolved vs. open"), so the same relative path resolves to different places. Write deliverables to<ARTIFACT_ROOT>/<relpath>(e.g.<ARTIFACT_ROOT>/docs/design_prd.md), filling<ARTIFACT_ROOT>from the capturedartifact_root./tmpremains forbidden. The kickstartgit clones the workshop repo INTOartifact_root(the workspace path), making it a git working tree where bundles are recognized — a baremkdirdoes NOT (TESTED, §3). Confirm<artifact_root>/.gitis present before the first write (vibecoding-state'sresolve_root/bootstrapstep 0 do this;git cloneif absent, then confirm withos.path.existsto clear the FUSE create-then-validate gap; a Repos-managed Git folder is the documented fallback). [TESTED P2] - The data-product bundle anchors to
dp_bundle_root, a dedicated subdir — not the bareartifact_rootroot.skills/vibecoding-statecapturesdp_bundle_root = <artifact_root>/<use_case_slug>_dab(e.g.…/vibe-coding-workshop/booking_app_dab). The whole DP pipeline (bronze→silver→gold→semantic) writes itsdatabricks.yml/src//resources/UNDER<DP_BUNDLE_ROOT>. Writing them at the bareartifact_rootroot (the framework clone itself) is the observed "one level too high" bug — the bundle then has no clean page-context root to deploy from. Becausebundle deploy's CWD is pinned to the current page's bundle root,<DP_BUNDLE_ROOT>is ALSO the page you deploy from: be on that folder's page, then runbundle validate/deploy/run. Adatabricks.yml not founderror means you are on the wrong page — navigate to<DP_BUNDLE_ROOT>; never fall back to direct SQL. - Load every workshop skill by its clone-rooted
readSkillFilepath, never a bare repo-relative path or@-mention. Genie Code loads skills throughreadSkillFile, which has no repo-root-relative resolution: a file under.assistant/skills/is loadable only asskills/{path-after-.assistant/skills/}. Because the skill tree is copied to.assistant/skills/<clone-folder>/, a repo-relative skill pathX/Y/SKILL.mdmust be loaded asreadSkillFile("<skill_ref_root>/X/Y/SKILL.md")whereskill_ref_rootis captured byskills/vibecoding-state(="skills/" + basename(skills_install_root), defaultskills/vibe-coding-workshop; empty onide_cli, where@-mentions resolve from the workspace root). Noteskill_ref_rootis anchored toskills_install_root(the.assistant/skills/<repo>copy), NOTartifact_root(the git-cloned user project) — so skills keep loading from the.assistant/skillscopy even though artifacts build in the project. Nesting depth is irrelevant — e.g.data_product_accelerator/skills/bronze/00-bronze-layer-setup/SKILL.mdloads asskills/vibe-coding-workshop/data_product_accelerator/skills/bronze/00-bronze-layer-setup/SKILL.md. A bare@data_product_accelerator/…sends Genie Code on a goose chase.AGENTS.mddoes not help here — it is read once at the clone root and does not propagate across Agent threads, so each prompt must name the skill by itsskill_ref_root-prefixed path (thegenie-codeprompt forks do exactly this). [TESTED — user-observed] - The forks evolved a small helper shape —
w,read_file/write_file,run_sql,run_job_by_name. These are session conveniences for inspection and orchestration, NOT artifact-creation channels.
SUPERSEDED — do not resurrect. The forks also carried ad-hoc SDK-creation primitives (
create_job,create_pipeline_idempotent,make_job_notebook). Those created un-versioned workspace state that diverged from the IDE's bundle output — that divergence was itself the regression. They are superseded by the bundle-deploy spine (databricks-asset-bundles): every artifact is a bundle resource brought to life bybundle deploy, identically on both clients. The only sanctioned in-session creation is RULE_8 Tier 3 Genie-SpacecreateAsset(last-resort). [decision #6/#8; M3 §2a Bucket C]This explicitly includes data-product table DDL. Creating Bronze/Silver/Gold schemas and tables —
CREATE SCHEMA,CREATE TABLE,DEEP CLONE,ALTER TABLE … SET TBLPROPERTIES,CLUSTER BY, and the data load — directly viaexecuteCode/spark.sqlis the SAME regression: it produces live tables with no versioned bundle behind them. Those statements are the body of a bundle job notebook, executed bybundle run, not run by hand. The frictionlessexecuteCodepath is the trap (it "works" and the tables appear, so the gate passes) — but it bypasses the spine. Ifbundle deployis blocked, FIX the page context (open thedp_bundle_rootbundle editor, §"bundle-deploy reality"); do not fall back to direct SQL, the Jobs/Pipelines REST API (jobs/create,/api/2.0/pipelines), or the SDK — those are an escape hatch only on explicit operator authorization, and the field-confirmed fix is the bundle editor, not the API. Read-only inspection (SHOW TABLES,DESCRIBE,SELECT COUNT(*)) viaexecuteCodeis fine.
This section is the canonical home for the session operating model — the RULE_0 client_context
preamble and the PRE-REQUISITES Genie branch point here rather than re-inlining it.
9. Why the portability rules exist (rationale)
The single-body portability rules (authored elsewhere) exist because of these Genie behaviors — kept here as the explanation, not the rule:
- No
--varresolver at the page. Asset Bundle variables resolve at deploy time; you cannot "pass a var" interactively. The agnostic body states the concrete-value requirement once. /tmpis not durable and is not the place to write deliverables — write to a workspace/project path.- CWD is page-type-dependent, so a bare relative path (
docs/design_prd.md) is unstable across pages. Theartifact_rootrule above exists for this reason: resolve relative artifacts against the captured clone root, not the page CWD. The agnostic body keeps a single anchored form (<ARTIFACT_ROOT>/…). - No repo-root-relative skill resolution and no cross-thread
AGENTS.md.readSkillFileonly resolvesskills/{path-after-.assistant/skills/}, andAGENTS.mdis read once at the clone root without propagating to later Agent threads. Theskill_ref_rootrule above exists for this reason: prompts (and thegenie-codeforks) name each skill by itsskill_ref_root-prefixed path so it loads regardless of thread. - Don't rely on
jq/ raw shell for control flow — build and inspect artifacts in-memory via the SDK.
10. Session ergonomics — parallel skill reads, file-write tiers, and executeCode timeouts
Three behaviors that materially change session speed and reliability. All [TESTED — user-observed, Gold-design run].
- Read every skill a phase needs in ONE batched turn.
readSkillFilecalls run in parallel — issuing all of a phase's skill reads in a single turn returned every file successfully, whereas serializing them costs one full turn each. When a step's Step-1 list (or an orchestrator's "Mandatory Skill Dependencies") names several skills with no inter-dependency, load them together, not one per turn. [TESTED] - File writes — two paths, choose by situation (there is NO single-call, compute-free file-creation
tool):
executeCodewithopen(path,"w").write(...)— one call; creates and writes any workspace file directly; but needs warm serverless compute (see cold-start below). Best for creating many files or large content — once compute is warm.createAsset→readFile→workspaceUpdateFile— a compute-free trio (no cold-start risk), but with two field-proven constraints:workspaceUpdateFilecannot create a new file (the file must already exist) and requires the file to have been read in the current thread first. So:createAsset(withassetType: file) makes the empty file →readFilesatisfies the read-first guard →workspaceUpdateFilepopulates it. Three calls, zero compute. Best for updating a single already-read file, or writing a few files before compute is warm. [TESTED]
- Verify file writes with
os.path.exists/os.listdir, NOTlistFiles. After writing a file viaexecuteCodeopen(...), confirm it landed withos.path.exists(path)(oros.listdir(dir)) in the sameexecuteCodeblock. Do NOT uselistFilesto confirm a just-written file: the workspace REST API that backslistFileslags files written through the FUSE mount, so it returns false "missing-file" negatives — and you waste turns recreating files that already exist. [TESTED — a live run sawlistFiles=7 whileos.listdir=12 for the same directory immediately after writing] executeCodecold start & timeout — never starve the first call. The firstexecuteCodein a session pays a serverless cold start of ~3–5 minutes before any code runs; subsequent calls are warm (~0 s).timeoutMinutesdefaults to 15 (minimum 5). Never settimeoutMinutesbelow 15 — the only thing a smaller budget buys is a cold-start timeout and a wasted retry (the retry then "succeeds" only because the failed first attempt warmed the compute). For heavy phases (e.g. Gold design — CSV parsing, per-table YAML generation, cross-table validation) set it higher (≥ 20), and/or send a trivialprint("ready")warm-up call first so the cold start is paid once, up front. [TESTED — two 5-min timeouts on cold first calls; identical code on warm compute ran instantly]
Resolved vs. open
The field guide flagged several items [CONTESTED]/[INCOMPLETE]. The session-2/3 probes closed them
— do not re-import stale doubt:
| Field-guide open item | Status now |
|---|---|
Does the Apps runtime run npm run build server-side from un-built source? [INCOMPLETE] |
RESOLVED — yes. [TESTED P18 / field guide §6.2] |
Is bundle deploy page-context-gated or safety-guardrail-gated? [CONTESTED] |
Practical rule settled (formally still [CONTESTED]): --help/validate/summary always run; a real deploy needs an explicit non-prod --target dev (targetless → content guardrail). Operate on that rule; don't re-litigate the why. [TESTED P4–P6] |
Is the runDatabricksCli CWD the page's bundle root or the workspace home? [CONTESTED] |
Page-type-dependent: = the bundle root on a bundle page (proven), = workspace home on non-bundle pages (notebook/AppKit). Be on the bundle's page to deploy it. [TESTED P2] |
Is FUSE-invisibility of new files latency or a hard boundary? [OPEN] |
Unresolved upstream — treat as a boundary in-session: edit the on-page file. [TESTED P3] |
Does any allow-listed path reach the AppKit enhanced (apps deploy) build in-session? [OPEN] |
Not demonstrated — use the SDK SNAPSHOT path (build still runs server-side). [TESTED P11/P18] |
Does a uv/FastAPI (non-Node) app also build server-side on SNAPSHOT? (not in field guide) |
RESOLVED — yes. uv-based Track A agent apps install deps + start server-side → SUCCEEDED. [TESTED P20] |
Does the 3-hop OAuth handshake work against a Track A Agent App /invocations, and what token does Hop 2 need on serverless? (extends P16/P17) |
RESOLVED — yes; Hop 2 uses w.config.authenticate() (not w.config.token, which is None on serverless). [TESTED P21] |
| Does the Knowledge Assistant API work on Genie Code's SDK 0.67.0? (agents track) | RESOLVED — REST yes, SDK wrapper no. w.knowledge_assistants absent in 0.67.0; call /api/2.1/knowledge-assistants via w.api_client.do (no upgrade). [TESTED P22] |
Is the full mlflow.genai eval stack on the Genie runtime? |
RESOLVED — yes. mlflow 3.8.1 has scorers, evaluate, and optimize_prompts (GEPA). [TESTED P23] |
AppKit hardening ledger (P24–P37)
Live Genie-Code probes from the AppKit hardening sessions (2026-06-03), distilling an ~11-deploy booking-app failure (P24–P32) plus a round-2 deploy of the hardened skills (P33) and the Lakebase fork probes (P34–P37d) into preventable causes. These extend the P1–P23 ledger; the §4 AppKit facts cite these rows.
| # | Finding | Result |
|---|---|---|
| P24 | Root cause of the original build failures (reproduce-then-bisect) | Green only when BOTH fixed: index.css @import "@databricks/appkit-ui/styles" → styles.css; component imports from "@databricks/appkit-ui" → /react. Neither alone. |
| P25 | Scaffold defaults are correct | Pristine apps init ships styles.css + /react; the agent had overwritten correct files with hallucinated specifiers (regenerating from memory). |
| P26 | Build logs unreadable from compute | SDK/REST return only generic "check /logz"; apps logs → OAuth error; programmatic /logz → PKCE/401. No agent-visible build error. |
| P27 | /logz is human-readable in a browser |
Authenticated <app-url>/logz shows the exact App.tsx(L,C): error TS… + full Vite/tsc pipeline. Escalation = hand the operator the link. |
| P28 | Deploy ladder localizes a break; cost = the deploy loop | 2–3-file batches localize a break; deploy ≈ 50s cold / 30s warm; file writes ≈ 0.15s → deploy loop is the bottleneck, not file I/O. |
| P29 | package-lock.json is a hard deploy requirement |
Deleting it fails at the source-export phase in ~10s (RESOURCE_DOES_NOT_EXIST), before npm install. |
| P30 | No functional npm; local full typecheck impossible | node present; npm/npx/corepack dangling symlinks; tsc can't resolve appkit-ui/vite without node_modules. → grep/regex pre-flight is the only static gate. |
| P31 | Green deploy ≠ working app | Server boot crash → FAILED (visible); client runtime crash → SUCCEEDED/ACTIVE but blank (invisible) → human render check required; keep ErrorBoundary. |
| P32 | CLI allow-list non-deterministic; agent fabricated page-state | apps init blocked once then allowed on the same page type; agent reported an "Apps page" it never navigated to. SDK deploy bypasses the guardrail → reliable. Don't-fabricate-state. |
| P33 | Round-2 run of the hardened skills — residual static-but-uncaught classes | Import-specifier gate + lockfile rule + human render gate all held. New misses: deploy #1 FAILED on an unused import (TS6133/noUnusedLocals); a green deploy then crashed at runtime on <SelectItem value=""> (Radix needs a non-empty value) — the 02-build skill's own gotcha had prescribed value="". Also external Unsplash hotlinks went blank (browser egress) and \u0027 artifacts appeared from Python-written source. → extend the regex gate (empty value, escaped quote, \uXXXX blocking + unused-import review), fix the harmful gotcha, mandate an onError data-URI image fallback. |
| P34 | Dependencies edit package.json directly (no local install) |
Adding a dependency by editing package.json works — the server-side install at deploy reconciles it; the lockfile must stay in place (P29). The Lakebase setup fork edits package.json rather than shelling a local install. |
| P35 | databricks.yml resources are inert on the SDK SNAPSHOT path |
A postgres_projects declared in databricks.yml never materializes via the SNAPSHOT deploy (it is the Terraform spine, not applied here) → provision Lakebase over REST (POST /api/2.0/postgres/projects) + PATCH /api/2.0/apps/{name} to bind, instead of declaring bundle resources. |
| P36 | databricks apps validate is blocked / page-dependent |
Not reliably runnable from the agent on Genie Code → substitute a local YAML structural check (parse app.yaml + package.json, assert valueFrom: postgres + DB_SCHEMA + the dependency). |
| P37b/d | Canonical Lakebase wiring boots straight to RUNNING when bound | The supported wiring shape is the onPluginsReady(appkit) hook on createApp + appkit.server.extend(...) — NOT server({ autoStart: false }) + a manual AppKit.server.start() (the listener double-listen()s → boot crash; the earlier "autoStart:false broken" read was self-inflicted by omitting/duplicating start()). The lakebase plugin imports from the framework entrypoint (@databricks/appkit), not from the driver package (@databricks/lakebase). Binding the postgres resource BEFORE the first plugin-bearing deploy → RUNNING with no CRASHED hop; an unbound app carrying valueFrom: postgres boots CRASHED. |
Reference files
- allow-list-and-commands.md — the full
runDatabricksCliallow-list tiers (per-command, probe-cited), deploy/CWD/FUSE detail,apps init --output-dir,postgres list-*, the git-clone install path. - app-verification.md — the 3-hop OAuth
requests.Session()snippet and the server-side build evidence.
Related skills
databricks-asset-bundles— the canonical deploy contract + Genie-Space tiers (this skill points there; it does not restate deploy mechanics).databricks-expert-agent— surface-scoping + path-fallback discipline (cross-references this skill).skills/vibecoding-state— detects the client and writes the capability block; points here for the behavioral detail.