Skip to main content

Overview

Tool Name

Purpose

The apps_tools (also called GenesisApps) let agents create, deploy, and manage lightweight web applications that run inside the Genesis platform. These apps are accessible to users via the Apps panel in the Genesis UI — no external hosting, Docker knowledge, or DevOps pipeline required. GenesisApps are ideal for turning one-off analyses into living, shareable deliverables: interactive dashboards, operational CRUD tools, and narrated slide decks.

Key Features

Scaffold from Templates

Instantly generate a working application skeleton using built-in templates for Dash dashboards, Flask apps, or presentation decks.

Full Lifecycle Management

Create → Scaffold → Write Files → Start → Verify → Capture Screenshot → Review → Stop — all from chat.

Reverse-Proxy Serving

Each app is served through Genesis’s reverse proxy at /api/apps/<app_id>/proxy/, with automatic port management and base-path injection.

Dataset Integration

Dash dashboards connect to data via the Datasets fast layer — cached SQLite snapshots that avoid hitting your warehouse on every page load.

Access Control

Grant view, edit, or manage privileges to roles and individual users. Publish or keep apps in draft mode.

Branding

Apps inherit organization branding (logos, colors, design guidance) automatically from genesis_branding.json.

Chat Embedding

Embed any running app directly in a chat message with ```app my-app-id```.

Architecture

Each GenesisApp is a standard Python web application (Dash or Flask) running in its own subprocess. Genesis manages: On Linux, unconfined app processes run under per-run cleanup. STOP and RESTART stop processes the app started, including detached descendants. If the Genesis server exits unexpectedly, an app’s reaper detects the parent exit and starts cleanup. Dashboard render workers and dependency-installation commands also stop processes they started when the operation completes or times out. When a versioned app’s runtime moves to separate storage, Genesis removes its obsolete copy under bot_storage during cleanup passes, unless that storage is stage-backed. These passes run at startup and hourly by default, with no setting to enable; active or otherwise referenced runtime paths are left alone.
GenesisApps do not have direct database credentials. All data flows through the Genesis API layer. This ensures security, auditing, and connection reuse.
Genesis also runs an auxiliary LLM security review on selected WRITE_FILE / WRITE_FILES payloads before they are saved — for example Python that may probe the host filesystem, launch subprocesses, or reach outside documented Genesis API usage. When that review cannot run because the active chat provider is misconfigured, unreachable, or returns an empty response, Genesis blocks the write with success: false, error: "GenesisApp security review is unavailable; blocking file.", and a security_findings entry with rule_id: "llm_app_code_guard" and severity: "block". The finding message includes the failure kind (not_configured, provider_exception, or empty_response). Fix the provider in Config → AI Providers and retry the write rather than treating the failure as a policy denial on the code itself.

Functions Available

apps_action

The primary function for all GenesisApp operations. Dispatches based on the action parameter.

Actions Reference

START returns start_outcome so callers can distinguish a transition this call performed from a live runtime it found and left in place. A new start returns {"started": true, "reason": "started"}. When the runtime was already running or starting, the response returns started: false, the reason, running_since when available, code_reloaded: false, and restart_with. restart_with names the literal call the caller that received it can make — an apps_action(...) invocation for the tool, an HTTP endpoint for the REST route. START does not reload app.py or requirements.txt on that reuse path; use RESTART, or the call named by restart_with, when the code must be reloaded.
apps_action(action="LIST") returns success: true with an apps array. Each entry is the same status-shaped payload as STATUS when lookup succeeds. When status lookup fails for one app (for example a legacy non-canonical registry key or a corrupted workspace record), that entry is still included with status: "unknown" and an error string so the rest of the list remains usable. Inspect error and call STATUS or EXPLAIN_BLOCKING on the affected app_id before mutating it.Genesis stores app_id in canonical form: lowercase letters, numbers, and hyphens, 1–64 characters, starting and ending with a letter or digit. On registry load, legacy keys that differ only by casing or punctuation are renormalized to the canonical id; duplicates after renormalization are skipped.
Registry changes from CREATE, DELETE, replace_existing, and app metadata updates take effect only after the app registry is saved. If that save is unavailable during replacement or DELETE, the tool returns success: false, error_code: "app.registry_unavailable", and retryable: true; retry the operation later. A refused replacement leaves the existing app registered. For metadata changes, a refused save reports failure and leaves the previous metadata in place. After CREATE, saving the requested or derived display name is best-effort: if that separate save is refused, the app remains created with its previous name.

presentation_deck_generate_tts

Generate MP3 narration audio for a running presentation deck app using OpenAI TTS. Use use_genesis=true (default) to rely on the platform OpenAI credential. For fallback auth, set use_genesis=false and pass api_key as either a raw OpenAI key or a stored secret_* reference. See the full parameter reference below for format, slides, voice_match, use_genesis, and timeout_seconds.
Narration is read only from the canonical n field in presentation_deck.json. If a slide uses alias keys such as narration, speaker_notes, notes, voiceover, or script without n, TTS skips that slide and validation reports a warning. If no selected slides contain n, presentation_deck_generate_tts returns success=false with diagnostic hints instead of generating empty output.

Scaffold Templates

Call apps_action(action="TEMPLATES") to see the latest list. Built-in templates:
Best for: Interactive data dashboards with Plotly charts and AG Grid tables.Generates: app.py, requirements.txt, assets/style.cssIncludes server-side Dash callbacks, null-safe filter patterns, Genesis API integration, and CSS styling. KPI cards are data-driven from the bound dataset (row count plus column-derived totals or distinct counts) rather than hardcoded demo labels. This is the recommended default for dashboard-style apps.Aliases: dash_dashboard
Best for: Comparing performance of direct /api/query calls vs. the Datasets fast layer.Generates: app.py, requirements.txt, assets/style.cssMeasures and displays latency benchmarks so you can validate the Datasets caching benefit.Aliases: dash_dataset_benchmark
Best for: Operational CRUD applications — forms, tables, import/export workflows.Generates: app.py, requirements.txt, static/style.css, templates/*.htmlLocal-first design with SQLite under MICROAPP_STATE_DIR for persistent state. Includes a connectivity check endpoint but no data sync by default.Aliases: flask_ops_crud, flask_enhancement_inbox
Best for: Minimal starting point for custom Flask apps.Generates: app.py, requirements.txt, static/style.cssPrefix-safe with /healthz endpoint. Includes genesis_llm_call(...) and genesis_llm_direct(...) helpers for server-side app LLM calls. Add your own routes as needed.
Best for: Narrated slide presentations with splash screens, transitions, and optional AI voice-over.Generates: app.py, requirements.txt, presentation_deck.json, presentation.js, presentation_styles.css, slide generators under presentation_slides/, and example images under presentation_images/.A stdlib-only HTTP server (no Dash/Flask) that renders slides from a JSON definition. app.py loads the scaffolded presentation.js and presentation_styles.css runtime assets; edit those files with WRITE_FILE when you need custom deck chrome or client behavior. Supports OpenAI TTS narration via presentation_deck_generate_tts.Aliases: presentation, deck

Typical Workflow

Building a Dashboard

1

Create the app

2

Scaffold the template

If you already have a dataset, SCAFFOLD can bind it immediately with dataset_id="sales_dashboard_data". That writes genesis_datasets.json using default read + ssrm actions unless you override them with dataset_actions. Use DATASETS_SETUP instead when Genesis still needs to create or refresh the dataset first.
3

Set up datasets (recommended)

This creates the dataset, refreshes it, writes genesis_datasets.json, and restarts the app.To bind existing datasets without creating new ones, call:
The binding shortcut writes genesis_datasets.json, preserves the existing datasets, and restarts the app. You can also put actions inside the shortcut payload; when omitted, Genesis defaults to both read and ssrm.Use kind="materialized_dataset" for larger single-source dashboard snapshots. query_cache_dataset is capped at max_rows <= 10000; if you stay on that lightweight cache path, reduce the cached result with filters or aggregation first.
4

Customize app.py

Edit the SQL queries, chart definitions, and layout. Use WRITE_FILE for a single full app.py replacement, and WRITE_FILES when updating app.py plus requirements or assets in one batch.
5

Record dashboard attestation

New dashboard scaffolds can require typed proof before the first review and start sequence can complete.
6

Clear the first-start review gate

REVIEW runs health checks, captures a screenshot, tails logs, reports diagnostic hints, and can pass even before the first runtime is started so the initial dashboard gate can clear.
7

Start or restart the runtime

Use RESTART after later code or dependency changes. Add auto_capture_after_start=true when you want START to return screenshot/render diagnostics immediately.
8

Self-audit before sharing

Compare the rendered dashboard against the original request or REQUIREMENTS.md. Confirm that required KPIs, filters, grid columns, chart labels, units, and time ranges are present and plausible. If gaps remain, update the app, RESTART, and re-run the audit. Limit this loop to 3 audit cycles; if gaps still remain, call them out explicitly in the handoff instead of treating the dashboard as complete.
9

Publish and share

The final dashboard handoff should include the self-audit gap list, the deployed URL, the runtime env vars used (at minimum GENESIS_API_BASE_URL and GENESIS_REFRESH_SECONDS), verification evidence snippets, the final screenshot artifact path, and any known remaining gaps.

Versioned Publishing (Safe Edit → Promote)

Versioning actions apply only to genesis-versioned apps. Git-backed apps (managed remote / Git source) must use FORK_TO_STANDALONE first; otherwise ENABLE_VERSIONING, CREATE_VERSION, PROMOTE_VERSION, and related calls return an ARTIFACT_IS_GIT_BACKED error.
CREATE_VERSION and PROMOTE_VERSION are user-gated. Edit and preview the working draft, then stop and report the preview URL. Do not snapshot or promote on your own initiative after a successful preview. Phrases such as “looks good”, “thanks”, or “that worked” do not authorize publication — wait for explicit requests like “publish it”, “promote it”, “make it live”, “push to production”, or “save and publish”.
The agent owns edit and preview. Save and promote run only when the user explicitly asks (in chat or via the Apps UI Promote control).
1

Enable versioning (when the user wants safe iteration)

Creates Version 1 from the current files. When assign_production is true (default) on an already-published app, v1 is pinned as production so live users keep seeing the pre-change state. Do not enable versioning on your own initiative.
2

Edit the working draft

Changes go to the working draft — production is unaffected.
3

Preview the draft

The draft runs at /api/apps/<id>/working-copy/proxy/. Production stays on the promoted version until the user publishes.
4

Stop and report

Tell the user the working-draft preview URL and which production version is still live (for example, “Preview is at /api/apps/sales-dashboard/working-copy/proxy/; production is still on v3. Say if you want me to save and publish, or promote from App History.”). Also include the --working-copy chat embed from the tool’s reminders response (see Embedding Apps in Chat) so the user can review unpublished draft changes inline. Do not call CREATE_VERSION or PROMOTE_VERSION yet.
5

Save a version (only when the user asks)

6

Promote to production (only when the user asks)

7

Roll back (only when the user asks)

Genesis also records file-level checkpoints. In the dashboard UI these appear inside App History, and for versioned apps the checkpoints are grouped beneath their parent saved version as dot releases such as v2.1. LIST_CHANGE_HISTORY also returns a compact summary for each checkpoint so agents can scan rollback candidates quickly. For app-tool behavior after a Databricks restart, see Databricks working-copy recovery.

Building a Presentation

1

Create and scaffold

2

Edit presentation_deck.json

Define slides, titles, narration text, and images in the JSON file. Use t for visible slide title, s for visible subtitle/body HTML, and n for narration. t accepts either a plain string, {"text":"Plain title"} for escaped text, or {"html":"<span>Styled</span>"} for explicit safe title markup. When you use the object form, include exactly one key: html or text. Keep title styling in s when the title does not need inline markup. Export/publish validation rejects slides that store visible text only in alias fields such as title, subtitle, body, body_text, bullets, left_content, right_content, or two_column, and it also rejects slides with no visible content. Non-text slides should still provide visible img, plotly, py, or staged label/sub content. When you update presentation_deck.json through WRITE_FILE or WRITE_FILES, Genesis also returns warnings and hints when it detects long-form alias keys without the canonical short fields.
3

Validate the deck workspace

Run this before export or before a gated first START / RESTART to catch missing presentation_images/* paths, slide/stage URL targets, slide_range selection errors, stage-sweep gaps, visual-coverage gaps, and audio/captions issues early. validate_check_images and validate_check_audio both default to true. Use slide_range="1-6" to validate only part of a deck, and add stage_sweep=true when those targeted slides must already expose staged content. When narration intent is explicit via deck metadata or presentation_deck.json audio.format, missing fallback narration clips become blocking errors instead of warnings. For kind="python" slides or stages, py / python must point to a file under presentation_slides/*.py that defines callable render(ctx). Those renderer files are loaded as standalone workspace scripts, so prefer absolute imports such as from presentation_slides.utils import helper instead of relative imports.
4

First start: clear the deck gate and launch

The first START / RESTART is blocked until both flags succeed once. Genesis runs structured deck validation before launch, then auto-captures slide 1 (the first authored content slide) rather than the splash gate shell. The gate clears only when that capture shows real slide content instead of an empty, loading, error, or broken-asset state. Font-only subresource failures are tolerated; other broken deck assets block the gate. After the gate is cleared, later START / RESTART calls remain warning-only.
5

Generate narration (optional)

The app must already be running. If the selected slides do not contain narration in n, the tool returns success=false with hints telling you to move narration text into n. If the Genesis-configured TTS path returns invalid_api_key, retry with use_genesis=false and a valid direct api_key value or stored secret_* reference.
6

Import an existing deck (optional)

Native Google Slides import now reads the deck in place through the Slides API, so large decks no longer depend on a Drive .pptx export succeeding.
7

Publish a snapshot export (optional)

Export is snapshot-first: it freezes the rendered Genesis app state into a PowerPoint-ready artifact and can publish that .pptx back into Google Slides.

Remote Deployment

GenesisApps can also run outside the Genesis host on supported remote backends. Use LIST_DEPLOY_TARGETS first to discover saved target_env and security_profile names. Then call DEPLOY with dataset_definition={"target_env":"<name>","security_profile":"<name>"} to reuse stored backend defaults such as cluster, region, namespace, and runtime identity settings. If target_env already declares the backend, runtime_type is optional; otherwise set it explicitly to eks, railway, docker, or databricks_apps. For versioned apps, add version_id="<saved_version_id>" to deploy a specific saved version remotely; omit version_id to deploy Production.
For EKS, DEPLOY now defaults service_type to LoadBalancer so REMOTE_STATUS usually reports a browser-reachable URL. Set service_type="ClusterIP" only when you intentionally want a cluster-internal URL instead. User-facing app links such as apps_action(action="URL") prefer these explicit public-base overrides before falling back to inferred hostnames: GENESIS_MCP_PUBLIC_URL, GENESIS_PUBLIC_URL, GENESIS_PUBLIC_BASE_URL, GENESIS_EXTERNAL_URL, SERVICE_BASE_URL, NGROK_BASE_URL, and FRONTEND_BASE_URL. Set one of them in hosted deployments when Genesis cannot infer the browser-facing hostname cleanly.
Remote deployment requires confirm_identity_delegation="true". For container backends, the caller must acknowledge that the app uses their delegated Genesis identity and permissions. A Databricks App instead runs as its own service principal and receives no Genesis app token.

Databricks Apps

runtime_type="databricks_apps" runs the app as a Databricks App on the workspace of the Databricks connection named in dataset_definition.databricks_connection_id. Genesis uploads the app’s source files to /Workspace/Users/<you>/genesis_apps/<app_name>. It leaves out local runtime state such as the app’s virtual environment, its logs and genesis_datasets.json. It then creates or reuses the app, starts its compute, and deploys a snapshot. Optional settings are warehouse_id (the SQL warehouse the app queries; defaults to the connection’s), grant_schema (catalog.schema on which the app’s service principal is granted USE CATALOG, USE SCHEMA and SELECT), and app_name (at most 30 lowercase letters, digits and hyphens).Genesis ships a runner, genesis_databricks_main.py, beside the app and makes it the app’s command. The runner serves the app’s app.py: a Flask app, or a Dash app through its app.server, at the root path /. Most GenesisApps then run unchanged, because the runner answers the app’s Genesis data calls itself. It starts a local stand-in for the Genesis API, and points the app’s GENESIS_API_* settings and app token at it:
  • POST /api/query (the templates’ genesis_query_rows()) runs the statement on the SQL warehouse, in the catalog and schema of the Genesis connection the app names. Only one read statement runs: anything after a ; is refused, and so is a WITH that writes.
  • /api/datasets/<id>, .../tables and .../tables|views/<name>/rows (the dataset fast layer) are served from a local SQLite snapshot. The snapshot is rebuilt from the dataset’s own source queries on the warehouse when it is first read, and again after an hour, or after the dataset’s TTL if it has one. It is built with Genesis’s own dataset store and query code, so dataset views run as they do in Genesis.
  • GET /api/health and /api/healthcheck return a local health response, and POST /api/apps/<id>/app-token/rotate returns the stand-in’s current per-process token.
  • A module-level query_rows(sql, max_rows=...), such as the one in the foundry_workshop_app template, is replaced by a direct statement on the warehouse.
The runner is never placed in the GenesisApp workspace, because it reads Databricks credentials, which a GenesisApp may not.Before anything is created on Databricks, a preflight reads the app’s source and refuses the deploy, listing every reason, when the app:
  • calls the Genesis LLM (genesis_llm_call, genesis_llm_direct, /llm/call, /llm/direct). An LLM feature whose function first checks that the LLM URL is set, as the dashboard scaffold’s AI insight does, is not refused. It reports itself unavailable, and the deploy result says so in notes.
  • calls another Genesis endpoint beyond the query, dataset, health-check, and token rotation routes above, such as /api/tts/speech, /api/apps/<id>/files/... or the dataset SSRM endpoint /api/datasets/<id>/datasource.
  • names a connection that is not a Databricks connection on the deploy workspace, or that Genesis cannot find. An app whose app.py defines a module-level query_rows (the foundry_workshop_app contract) is not refused for this: the runner replaces that function with a direct statement on the warehouse, and the deploy result notes the connection instead.
  • is bound to a dataset with a source other than SQL or inline data, a source whose SQL lives in a repository file (sql_path), or a source on such a connection.
  • has no module-level app in app.py.
The scaffolds dash_dashboard, flask_basic, flask_enhancement_inbox and foundry_workshop_app pass as shipped. presentation_deck is refused. The deploy result lists the packaged connections and datasets in config.packaged_connections and config.packaged_datasets.Unlike the other backends, a Databricks App does not call back into Genesis. No Genesis app token is minted for it, and it queries Unity Catalog as its own service principal. The returned URL is the app’s own: it is opened with a Databricks login, which the Genesis remote proxy cannot pass. A first deployment takes several minutes, while the app’s compute starts and the deployment builds.

Environment Variables

These are injected automatically into each app process at START / RESTART:
Never hardcode ports. Always bind to MICROAPP_HOST / MICROAPP_PORT.Be proxy-prefix safe. Dash apps must set requests_pathname_prefix and routes_pathname_prefix to MICROAPP_BASE_PATH. Flask apps should mount routes under url_prefix=MICROAPP_BASE_PATH.

App-scoped LLM calls

When app code needs model output, call the app-scoped Genesis routes with X-Genesis-App-Token rather than embedding third-party LLM API keys in the workspace:
  • POST /api/apps/{app_id}/llm/call runs one chat turn through a Genesis agent. Body fields: bot_id, prompt, optional thread_id, model_tier, provider, execution_lane, and timeout_seconds. Omit thread_id to create a new thread; when model_tier and provider are also omitted, Genesis seeds that new thread from the app authoring thread when available.
  • POST /api/apps/{app_id}/llm/direct runs a direct base completion without agent orchestration. Body fields: prompt, optional model_tier, provider, and timeout_seconds. Omit model_tier and provider to inherit the app authoring thread defaults when available; otherwise Genesis falls back to main tier plus the deployment’s configured main provider.
  • Dash and Flask Basic scaffolds expose genesis_llm_call(...) and genesis_llm_direct(...), and Genesis injects GENESIS_API_APP_LLM_URL, GENESIS_API_APP_LLM_DIRECT_URL, GENESIS_LLM_BOT_ID, GENESIS_LLM_MODEL_TIER, and optional GENESIS_LLM_PROVIDER for that contract.

Data Access Patterns

Dashboard Default Path

For dashboard-style GenesisApps, use datasets first:
  1. CREATE
  2. SCAFFOLD
  3. DATASETS_SETUP
  4. ATTEST_CHECKLIST
  5. REVIEW
  6. START
Use direct /api/query only as an explicit fallback for prototypes, tiny result sets, debugging, or true realtime needs, and run DEV_QUERY_PREFLIGHT before relying on it for an interactive dashboard. Preflight now inspects both scaffold helper calls (genesis_query_rows() / genesis_query_df()) and direct requests.post(..., json={...}) /api/query payloads. If the workspace defines DEFAULT_CONNECTION_ID, preflight reuses that value for inferred query paths that do not set connection_id inline. If preflight reports query_health: "unknown", it means the tool still could not infer a concrete connection_id from the current app code, not that the query itself failed. This still commonly happens when the app reads the connection from GENESIS_CONNECTION_ID or another runtime-only source. Provide preflight_connection_id (or make the connection literal in code) before treating it as a live-query error. Prefer profile_mode="both" on DEV_QUERY_PREFLIGHT for dashboards so the same call returns latency plus structural findings such as grain mismatches, missing latest periods, and raw-vs-dedup deltas. When structural profiling runs, responses can also include structural_profiles, structural_findings, structural_query_profiles, and structural_summary. When a workspace has saved preflight state, apps_action(action="STATUS") also returns a compact preflight block. Genesis reuses cached health inside APPS_STATUS_PREFLIGHT_MAX_AGE_SECONDS (default 60) and otherwise runs a lightweight SELECT 1 smoke check against the saved connection before returning status.

Template-backed writes

Use COPY_FILE or source-backed WRITE_FILE / WRITE_FILES with substitutions when you want large templates to stay in a repo instead of expanding them in chat context.
When apps_action is invoked through hosted MCP or POST /api/tool_call, Genesis allows raw HTML/CSS/JS/SVG content only for workspace-relative destinations under templates/, static/, or assets/ ending in .html, .htm, .css, .js, .mjs, or .svg. Other destinations keep normal string sanitization.

Dashboard readiness v2

New dashboard scaffolds can require the dashboard_readiness_v2 contract before the first meaningful start:
  • Call ATTEST_CHECKLIST with checklist_attestation, not checklist_answers, on v2 workspaces.
  • Each item in checklist_attestation.items must include id, answer, decision, and evidence.
  • data_plausibility_checklist.questions[*].override_supported marks checklist items that accept checklist_attestation.structural_overrides.
  • checklist_attestation.structural_overrides is optional and uses {item_id, justification, verified_by} entries for eligible items grain, time_range, magnitude, and consistency. justification must be at least 20 characters, and verified_by must be one of DEV_QUERY_PREFLIGHT, dataset_query_tool, or external_check.
  • query_result evidence must include inline result rows or data, and time_range evidence accepts ISO dates plus year (2015), year-month (2015-04), and year-quarter (2015-Q2) last_period_end values.
  • tool_result_ref resolves the current workspace state by label, or by structural identifiers such as finding_type, finding_id, or check_id.
  • data_plausibility_checklist also exposes structural_overrides_help and dry_run_supported=true; pass top-level dry_run=true to ATTEST_CHECKLIST to validate evidence shape without persisting the attestation.
  • For demos and prototypes, pass attestation_mode="sample" or sample_dashboard=true to use the explicit sample contract. Sample mode still requires source_choice, grain, and dataset_strategy, while magnitude, consistency, and time_range are reported as non-blocking validation details.
  • Sample-mode failures can return attempted_attestation_context with the attempted attestation_mode, whether sample_dashboard was requested, and the required question ids checked for that attempt. attestation_status continues to describe the last persisted workspace attestation until a non-dry_run submission succeeds.
  • In sample mode, grain can also be satisfied by a current auto_profile_ref structural profile, including heuristic sample-dashboard profiles, when that saved profile still matches the current workspace fingerprints.
  • For additive KPI dashboards, exact grain proof can come from a fresh structural grain_check / raw_vs_dedup result with exact confidence, or from inline query_result evidence whose summary rows include total_rows and distinct_entities aligned with the grain decision.
  • Known bundled demo connections such as formula_1_sqlite, baseball_sqlite, credit_card_sqlite, asset_mgmt_sqlite, or workspace_sqlite may trigger an advisory suggesting sample mode; Genesis never switches modes automatically.
  • Invalid v2 submissions default to compact responses. Genesis may still repeat the checklist schema when the thread has not seen it yet unless you explicitly force compact=true. In compact failures, inspect failing_item_ids, compact_item_errors, corrected_minimal_examples / corrected_example_items, attempted_attestation_context, and schema_followup. Use compact=false when you need the full checklist schema again, including item_validation_details, submission_rules, structural_overrides_help, and the example command. After the checklist schema has already been emitted in a thread, repeated compact failures can suppress data_plausibility_checklist.questions[*] and keep only the machine-correctable fields.
  • When time_range.decision.covers_expected_period contradicts evidence, item_validation_details.time_range.resolution_hints[] explains whether to refresh the dataset/source or record the observed stale last_period_end.
  • attestation_status.time_range_summary surfaces last_period_end, expected_end, covers_expected_period, and days_behind when available so app chrome can display freshness state without parsing raw evidence. When the latest period still lags the expected period, app advisories can also include freshness_banner with a ready-to-display warning message.
  • If genesis_datasets.json is already bound, dataset_strategy can auto-satisfy.
  • For dashboard_readiness_v2, freshness is scoped to the data proof fingerprint rather than ordinary app.py edits. attestation_status.code_changed_since_attestation still flags code drift for visibility.
  • Genesis computes a workspace source fingerprint from primary config files (app.py, requirements.txt, genesis_datasets.json, genesis-microapp.json, genesis_branding.json, presentation_deck.json, and for presentation decks presentation.js and presentation_styles.css when present), asset directories (templates, static, assets), and every authored .py module in the workspace (excluding build/cache directories such as .venv, node_modules, and __pycache__). Edits to helper modules or deck runtime assets therefore invalidate cached first-start REVIEW results tied to an older fingerprint. START / RESTART also treat changes to presentation.js or presentation_styles.css as restart-relevant, just like app.py and requirements.txt.
  • The first START or RESTART is blocked until attestation is fresh and REVIEW passes once. START and RESTART normally attempt that REVIEW automatically and surface any blocking findings so you can fix them and retry. A standalone passing REVIEW may start and stop a temporary preview runtime; call START next to launch the persistent runtime.
The Datasets fast layer pre-materializes query results into SQLite snapshots. This avoids hitting your data warehouse on every dashboard page load.
  1. Define a dataset with DATASETS_SETUP or the dataset_create_tool.
  2. Bind it to the app via genesis_datasets.json:
  3. Restart the app so dataset bindings and dataset env vars are refreshed.
  4. GET /api/datasets/<id> also returns top-level freshness helpers for app code: active_snapshot_id, last_refresh_at, snapshot_built_at, row_counts, and table_name_mapping.
  5. In your app code, fetch data from /api/datasets/<id>/tables/<table>/rows using GENESIS_APP_TOKEN:
    POST /api/datasets/<id>/datasource also accepts table or view in the SSRM request body (or query string) when the dashboard should target a specific dataset table or view instead of the dataset default target.
GENESIS_APP_TOKEN is the app’s server-side Genesis API credential. genesis_datasets.json adds dataset scopes/bindings and populates dataset env vars; it is not the sole reason the token exists.
GENESIS_APP_TOKEN authenticates API requests as the app’s delegated Genesis user identity. Genesis rejects app tokens whose delegated identity is empty, so keep this token server-side and send it only from backend app code via X-Genesis-App-Token.
When genesis_datasets.json is present, proxied browser requests can also include an incoming X-Genesis-App-Token header that Genesis minted for the current viewer. Request handlers that need the active viewer’s dataset or /api/query scope should prefer that incoming header when present; background jobs and startup code should keep using GENESIS_APP_TOKEN.

Direct Query (Fallback)

For small, ad-hoc queries you can call /api/query directly:
The Dash scaffold already includes genesis_query_rows() / genesis_query_df() helpers around this pattern. Reuse those helpers when possible instead of hand-parsing the response. Read the response as body["data"]["rows"], not body["data"] as a list. DEV_QUERY_PREFLIGHT can inspect both the scaffold helpers and direct json={...} payloads for /api/query. Keep query and connection_id literal when possible so preflight can auto-profile the live-query path. If multiple inferred queries share one connection, set DEFAULT_CONNECTION_ID in the workspace so preflight can reuse it automatically. DEV_QUERY_PREFLIGHT does not execute PRAGMA ... statements. For schema discovery, use SELECT * FROM <table> LIMIT 1 and inspect the returned columns. If Genesis detects more live-query call sites than the latest preflight covered, the response can include coverage_gap and may add a blocking finding for dashboard apps with a large gap. Re-run preflight with preflight_queries covering the actual query paths before relying on the result.
Do not pass a dataset-prefixed connection_id such as dataset.my_dataset to /api/query. That route expects a real database connection. For dataset-backed reads, use the scaffold helpers genesis_dataset_df(), genesis_dataset_frame_with_meta(), or dataset_read_or_query_fallback(), which call /api/datasets/{id}/{tables|views}/{name}/rows.
There is no SQL-style POST /api/datasets/{id}/query endpoint. If an app calls it, Genesis returns a structured 400 with suggested dataset rows and datasource endpoints. Use /api/datasets/{id}/tables/{table}/rows, /api/datasets/{id}/views/{view}/rows, or /api/datasets/{id}/datasource instead.
Use Datasets for production dashboards (performance + caching). Use /api/query only for preflight-approved prototypes or truly real-time needs.

Access Control

GenesisApps support four privilege levels: Common patterns:

Published vs. Draft

  • Draft (default): Only the owner can see the app in the Apps panel.
  • Published: The app appears in the Apps panel for anyone with view access.

Embedding Apps in Chat

Embed a running GenesisApp directly in a chat message using a fenced code block:
For genesis-versioned apps, use the --working-copy flag when you want the user to preview unpublished draft changes instead of production:
After WRITE_FILE or WRITE_FILES on a versioned app, apps_action returns this embed block in the reminders array — include it verbatim in your next reply so the user can review the draft inline. This renders the app inline in the conversation — great for presenting results to stakeholders without them needing to navigate to the Apps panel.

Diagnostics and Troubleshooting

REVIEW (One-Stop Diagnostics)

The REVIEW action combines verification, screenshot, and log analysis:
For new dashboard workspaces, REVIEW also clears the one-time first-start gate and can block when ATTEST_CHECKLIST proof is missing, contradictions remain between decision and evidence, or structural findings are still unresolved. When a review runtime is already running but its last_started_fingerprint no longer matches current_source_fingerprint, Genesis stops the stale runtime and provisions a fresh one so REVIEW evaluates the current working copy. If the app was already serving that runtime, the replacement runtime is kept running after REVIEW completes instead of being torn down like a throwaway preview. For truly static/no-data Dash apps, pass no_data_declared=true on REVIEW only when the workspace has no Genesis dataset binding, live-query path, or /api/datasets call. If the source scan agrees, the response sets no_data_attestation_bypass=true and clears the attestation gate from health plus rendered-content evidence instead of checklist proof. When START or RESTART reports a blocking gate and you want the safest next move, call apps_action(action="EXPLAIN_BLOCKING", app_id="my-app"). It summarizes the active blocker and recommends the next apps_action call instead of making you infer it from raw state. For apps that render charts or other content asynchronously, pass wait_for_render_signals such as {"chart_data_detected": true} or {"plotly_chart_count": {"gte": 2}} so capture waits for semantic readiness instead of a fixed delay. Prefer semantic signals over exact counts when you can. Capture-style responses echo both render_signals and wait_signals so you can see which semantic wait condition completed. Setting include_visual_description=true adds extra latency because Genesis runs a follow-up vision pass after the screenshot is taken. Genesis Desktop’s first-use browser-tools download during app capture or runtime inspection is described under Browser Tools. The durable chat uploads guide also covers screenshot persistence for CAPTURE and automatic capture after START or RESTART. For Dash dashboards, Genesis does not switch into presentation-deck review logic just because capture payloads include empty genesis_export_* fields. Presentation handling applies only when the app runtime is actually presentation_deck or capture data contains a real presentation value such as genesis_export_slide_kind or genesis_export_blockers, so dashboard-first review can still clear from positive render signals like chart_data_detected, ag_grid_row_count, and non-zero KPI values. [GENESIS_QUERY_OK] and [GENESIS_DATASET_OK] app log markers are useful diagnostics, but REVIEW does not require them as the only proof. For dataset-backed dashboards, Genesis also inspects bound dataset metadata and readable snapshot rows. If neither markers, dataset readiness, nor populated capture evidence are available, REVIEW returns hints for the agent: bind or refresh a materialized dataset, keep/add a live-query marker, make populated runtime data visible to capture, rerun after async callbacks finish, and inspect dataset/query/callback errors. For narrated decks, use SWEEP_CAPTURE when you want a whole-deck audit instead of a single screenshot. If both slide and slide_range are omitted, Genesis captures the full presentation_deck.json range automatically, stage_sweep defaults to true, and the response returns summary, per-slide slides[], failed_slides, slides_with_error_banners, and recommended_next_steps.

Interactive browser flows

For multi-step validation on a running GenesisApp, use Browser Tools alongside apps_action instead of relying only on CAPTURE or REVIEW. This is the preferred path when you need to click buttons, fill forms, move between pages, or confirm post-click UI state. Open the app proxy URL with browser_open, for example browser_open(url="/api/apps/<app_id>/proxy/"), then use browser_snapshot, browser_click, and browser_type within the same session. Because that proxy path resolves to the local Genesis backend, browser_open automatically adds the X-Genesis-Internal-Token header for that local origin. Finish with browser_close when you are done. It returns:
  • verify: Health check results (proxy reachability, healthz status, Dash layout validation)
  • capture: Screenshot of the app
  • logs: Recent log output
  • findings: Auto-detected issues (callback 500s, query errors, shape mismatches)
  • hints: Actionable fix suggestions

Common Issues

For WRITE_FILE and WRITE_FILES, history placeholders are refused rather than written as file content. See the file-write placeholder guidance.

Best Practices

Use Datasets for Dashboards

Avoid hammering your warehouse. The Datasets fast layer caches data in SQLite snapshots — dashboards load in milliseconds.

Restart After Code Changes

Code and dependency changes only take effect after RESTART. Use restart_after_write=true to combine write + restart.

Read the Skill First

The apps-build-basics skill contains the canonical GenesisApps workflow. Build and runtime actions require an active app skill in thread context; CREATE may register the app first, then CHECK_PREREQUISITES shows the activation step before scaffold/write/start work. For hosted MCP or other stateless callers, use the gateway read_skill or list_skill_files actions instead of relying on manage_context(action="ADD_CONTEXT", ...), then retry apps_action.

Verify Before Sharing

Always run REVIEW before publishing. It catches proxy issues, callback errors, and data-loading failures automatically.

Parameters Reference

apps_action Parameters

presentation_deck_generate_tts Parameters