From 573f4a1ed43f724973f96be93e791bd9fe3a599c Mon Sep 17 00:00:00 2001 From: ciregenz Date: Mon, 11 May 2026 14:54:07 -0700 Subject: [PATCH] [eric] App Builder skill as editable built-in (Skills page, undeletable) + onboarding step 1 unsticks after Claude Max / ChatGPT Pro / Gemini / custom-provider connect (subscription state moved to Redux) --- backend/apps/agents/agent_manager.py | 10 +- ..._builder_skill.md => app_builder_skill.md} | 110 +++++++++--------- backend/apps/outputs/outputs.py | 10 +- .../apps/outputs/view_builder_templates.py | 34 +++++- backend/apps/skills/models.py | 6 + backend/apps/skills/skills.py | 101 ++++++++++++++-- .../Onboarding/steps/skipPredicates.ts | 30 ++++- frontend/src/app/pages/Settings/Settings.tsx | 54 ++++----- frontend/src/app/pages/Skills/Skills.tsx | 33 ++++-- frontend/src/shared/state/skillsSlice.ts | 4 + frontend/src/shared/state/store.ts | 2 + .../src/shared/state/subscriptionsSlice.ts | 104 +++++++++++++++++ 12 files changed, 385 insertions(+), 113 deletions(-) rename backend/apps/outputs/{view_builder_skill.md => app_builder_skill.md} (62%) create mode 100644 frontend/src/shared/state/subscriptionsSlice.ts diff --git a/backend/apps/agents/agent_manager.py b/backend/apps/agents/agent_manager.py index d0aa654b..2472c36c 100644 --- a/backend/apps/agents/agent_manager.py +++ b/backend/apps/agents/agent_manager.py @@ -1482,8 +1482,14 @@ class AgentManager: ) if session.mode == "view-builder": - from backend.apps.outputs.view_builder_templates import VIEW_BUILDER_SKILL - skill_block = f"\n{VIEW_BUILDER_SKILL}\n" + # Read the LIVE skill content rather than a frozen-at-import + # constant. The skill is registered as a built-in skill at + # ~/.claude/skills/app_builder_skill.md (see + # backend/apps/skills/skills.py); user edits in the Skills + # page land there and propagate to the agent's prompt on + # the next turn without a restart. + from backend.apps.outputs.view_builder_templates import load_app_builder_skill + skill_block = f"\n{load_app_builder_skill()}\n" composed_prompt = f"{composed_prompt}\n\n{skill_block}" if composed_prompt else skill_block # Per-turn estimate of framework overhead (subtracted from displayed diff --git a/backend/apps/outputs/view_builder_skill.md b/backend/apps/outputs/app_builder_skill.md similarity index 62% rename from backend/apps/outputs/view_builder_skill.md rename to backend/apps/outputs/app_builder_skill.md index 1e78377d..531819d7 100644 --- a/backend/apps/outputs/view_builder_skill.md +++ b/backend/apps/outputs/app_builder_skill.md @@ -1,8 +1,10 @@ # App Builder — Platform Reference -You are building an **App**: a self-contained web app served in an iframe. -The workspace you're working in is the source of truth — every file you write -here is served directly to the live preview. +You are building an **App**: a self-contained web app rendered inside an +Electron `` (so it behaves like a real browser tab — cross-origin +`fetch`, popups, mic/camera, etc. all work). The workspace you're working +in is the source of truth — every file you write here is served directly +to the live preview. --- @@ -10,10 +12,9 @@ here is served directly to the live preview. | File | Required | Purpose | |------|----------|---------| -| `index.html` | **Yes** | Entry point. Must be a complete HTML document. This is the ONLY file the preview iframe loads — never rename it. | +| `index.html` | **Yes** | Entry point. Must be a complete HTML document. This is the ONLY file the preview loads — never rename it. | | `meta.json` | **Yes** | `{"name":"…","description":"…"}` — displayed in the UI header. Always write this. | -| `schema.json` | Recommended | JSON Schema defining the input form (the "Test Input" tab). | -| `backend.py` | Optional | Server-side Python executed before rendering. | +| `backend.py` | Optional | Long-running HTTP server. See "Backend" below. | | Everything else | Optional | JS, CSS, images, subdirectories — referenced from `index.html` via relative paths. | ### ⚠️ Do NOT @@ -21,75 +22,72 @@ here is served directly to the live preview. - Name the main HTML file anything other than `index.html` — the platform will not find it and the preview will be blank. - Use `document.write()` — it breaks the injected data globals. -- Assume any external server or API is available unless the user provides one. +- Treat `backend.py` like a one-shot helper. It's a real HTTP server (see below). --- ## Injected globals -Before `index.html` loads, the platform injects two globals: +Before `index.html` loads, the platform injects: ```javascript -window.OUTPUT_INPUT // Object — structured input from the schema form -window.OUTPUT_BACKEND_RESULT // Object | null — result from backend.py execution +window.OUTPUT_INPUT // Object — optional structured input (may be {}) +window.OUTPUT_BACKEND_URL // string | null — base URL of the running backend.py, e.g. "http://127.0.0.1:54213" ``` -These are available immediately in any `