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
Full Lifecycle Management
Reverse-Proxy Serving
/api/apps/<app_id>/proxy/, with automatic port management and base-path injection.Dataset Integration
Access Control
Branding
genesis_branding.json.Chat Embedding
```app my-app-id```.Architecture
Each GenesisApp is a standard Python web application (Dash or Flask) running in its own subprocess. Genesis manages: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.
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.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.
format, slides, voice_match, use_genesis, and timeout_seconds.
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
Callapps_action(action="TEMPLATES") to see the latest list. Built-in templates:
dash_dashboard_server_callbacks
dash_dashboard_server_callbacks
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_dashboarddash_benchmark_query_vs_datasets
dash_benchmark_query_vs_datasets
/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_benchmarkflask_scaffold
flask_scaffold
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_inboxflask_basic
flask_basic
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.presentation_deck
presentation_deck
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, deckTypical Workflow
Building a Dashboard
Create the app
Scaffold the template
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.Set up datasets (recommended)
genesis_datasets.json, and restarts the app.To bind existing datasets without creating new ones, call: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.Customize app.py
WRITE_FILE for a single full app.py replacement, and WRITE_FILES when updating app.py plus requirements or assets in one batch.Record dashboard attestation
Clear the first-start review gate
Start or restart the runtime
RESTART after later code or dependency changes. Add auto_capture_after_start=true when you want START to return screenshot/render diagnostics immediately.Self-audit before sharing
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.Publish and share
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)
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).Enable versioning (when the user wants safe iteration)
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.Edit the working draft
Preview the draft
/api/apps/<id>/working-copy/proxy/. Production stays on the
promoted version until the user publishes.Stop and report
/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.Save a version (only when the user asks)
Promote to production (only when the user asks)
Roll back (only when the user asks)
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
Create and scaffold
Edit presentation_deck.json
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.Validate the deck workspace
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.First start: clear the deck gate and launch
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.Generate narration (optional)
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.Import an existing deck (optional)
.pptx export succeeding.Publish a snapshot export (optional)
.pptx back into Google Slides.Remote Deployment
GenesisApps can also run outside the Genesis host on supported remote backends. UseLIST_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.
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.
Environment Variables
These are injected automatically into each app process at START / RESTART:App-scoped LLM calls
When app code needs model output, call the app-scoped Genesis routes withX-Genesis-App-Token rather than embedding third-party LLM API keys in the
workspace:
POST /api/apps/{app_id}/llm/callruns one chat turn through a Genesis agent. Body fields:bot_id,prompt, optionalthread_id,model_tier,provider,execution_lane, andtimeout_seconds. Omitthread_idto create a new thread; whenmodel_tierandproviderare also omitted, Genesis seeds that new thread from the app authoring thread when available.POST /api/apps/{app_id}/llm/directruns a direct base completion without agent orchestration. Body fields:prompt, optionalmodel_tier,provider, andtimeout_seconds. Omitmodel_tierandproviderto inherit the app authoring thread defaults when available; otherwise Genesis falls back tomaintier plus the deployment’s configured main provider.- Dash and Flask Basic scaffolds expose
genesis_llm_call(...)andgenesis_llm_direct(...), and Genesis injectsGENESIS_API_APP_LLM_URL,GENESIS_API_APP_LLM_DIRECT_URL,GENESIS_LLM_BOT_ID,GENESIS_LLM_MODEL_TIER, and optionalGENESIS_LLM_PROVIDERfor that contract.
Data Access Patterns
Dashboard Default Path
For dashboard-style GenesisApps, use datasets first:CREATESCAFFOLDDATASETS_SETUPATTEST_CHECKLISTREVIEWSTART
/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
UseCOPY_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.
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 thedashboard_readiness_v2 contract before the first meaningful start:
- Call
ATTEST_CHECKLISTwithchecklist_attestation, notchecklist_answers, on v2 workspaces. - Each item in
checklist_attestation.itemsmust includeid,answer,decision, andevidence. data_plausibility_checklist.questions[*].override_supportedmarks checklist items that acceptchecklist_attestation.structural_overrides.checklist_attestation.structural_overridesis optional and uses{item_id, justification, verified_by}entries for eligible itemsgrain,time_range,magnitude, andconsistency.justificationmust be at least 20 characters, andverified_bymust be one ofDEV_QUERY_PREFLIGHT,dataset_query_tool, orexternal_check.query_resultevidence must include inlineresultrows or data, andtime_rangeevidence accepts ISO dates plus year (2015), year-month (2015-04), and year-quarter (2015-Q2)last_period_endvalues.tool_result_refresolves the current workspace state bylabel, or by structural identifiers such asfinding_type,finding_id, orcheck_id.data_plausibility_checklistalso exposesstructural_overrides_helpanddry_run_supported=true; pass top-leveldry_run=truetoATTEST_CHECKLISTto validate evidence shape without persisting the attestation.- For demos and prototypes, pass
attestation_mode="sample"orsample_dashboard=trueto use the explicit sample contract. Sample mode still requiressource_choice,grain, anddataset_strategy, whilemagnitude,consistency, andtime_rangeare reported as non-blocking validation details. - Sample-mode failures can return
attempted_attestation_contextwith the attemptedattestation_mode, whethersample_dashboardwas requested, and the required question ids checked for that attempt.attestation_statuscontinues to describe the last persisted workspace attestation until a non-dry_runsubmission succeeds. - In sample mode,
graincan also be satisfied by a currentauto_profile_refstructural 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_dedupresult with exact confidence, or from inlinequery_resultevidence whose summary rows includetotal_rowsanddistinct_entitiesaligned with thegraindecision. - Known bundled demo connections such as
formula_1_sqlite,baseball_sqlite,credit_card_sqlite,asset_mgmt_sqlite, orworkspace_sqlitemay 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, inspectfailing_item_ids,compact_item_errors,corrected_minimal_examples/corrected_example_items,attempted_attestation_context, andschema_followup. Usecompact=falsewhen you need the full checklist schema again, includingitem_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 suppressdata_plausibility_checklist.questions[*]and keep only the machine-correctable fields. - When
time_range.decision.covers_expected_periodcontradicts evidence,item_validation_details.time_range.resolution_hints[]explains whether to refresh the dataset/source or record the observed stalelast_period_end. attestation_status.time_range_summarysurfaceslast_period_end,expected_end,covers_expected_period, anddays_behindwhen 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 includefreshness_bannerwith a ready-to-display warning message.- If
genesis_datasets.jsonis already bound,dataset_strategycan auto-satisfy. - For
dashboard_readiness_v2, freshness is scoped to the data proof fingerprint rather than ordinaryapp.pyedits.attestation_status.code_changed_since_attestationstill 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 deckspresentation.jsandpresentation_styles.csswhen present), asset directories (templates,static,assets), and every authored.pymodule 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-startREVIEWresults tied to an older fingerprint.START/RESTARTalso treat changes topresentation.jsorpresentation_styles.cssas restart-relevant, just likeapp.pyandrequirements.txt. - The first
STARTorRESTARTis blocked until attestation is fresh andREVIEWpasses once.STARTandRESTARTnormally attempt thatREVIEWautomatically and surface any blocking findings so you can fix them and retry. A standalone passingREVIEWmay start and stop a temporary preview runtime; callSTARTnext to launch the persistent runtime.
Datasets (Recommended for Dashboards)
The Datasets fast layer pre-materializes query results into SQLite snapshots. This avoids hitting your data warehouse on every dashboard page load.- Define a dataset with
DATASETS_SETUPor thedataset_create_tool. - Bind it to the app via
genesis_datasets.json: - Restart the app so dataset bindings and dataset env vars are refreshed.
GET /api/datasets/<id>also returns top-level freshness helpers for app code:active_snapshot_id,last_refresh_at,snapshot_built_at,row_counts, andtable_name_mapping.- In your app code, fetch data from
/api/datasets/<id>/tables/<table>/rowsusingGENESIS_APP_TOKEN:POST /api/datasets/<id>/datasourcealso acceptstableorviewin 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.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:
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.
Access Control
GenesisApps support four privilege levels: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
viewaccess.
Embedding Apps in Chat
Embed a running GenesisApp directly in a chat message using a fenced code block:--working-copy flag when you want the user to
preview unpublished draft changes instead of production:
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)
TheREVIEW action combines verification, screenshot, and log analysis:
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 alongsideapps_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
ForWRITE_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
Restart After Code Changes
restart_after_write=true to combine write + restart.Read the Skill First
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.
