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 `