원클릭으로
build-light-app
Build and launch a self-contained light app in a Wails child window, isolated from the workspace
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Build and launch a self-contained light app in a Wails child window, isolated from the workspace
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Extract text or structured fields from workspace files (image, PDF, doc, txt). Single file → content_extract; ≥3 files / Excel batch → delegate_task (do not OCR on the main agent).
Review recent experiences and synthesise recurring patterns into reusable skills. Set up a weekly cron to keep the loop running automatically.
Use UI window tools to see open/focused files and open workspace files for the user
| slug | build-light-app |
| name | Build Light App |
| description | Build and launch a self-contained light app in a Wails child window, isolated from the workspace |
Build a small, standalone app and open it in its own window alongside the workspace. Apps live under data/light-apps/ and are fully isolated — they cannot read workspace files.
| Tool | Purpose |
|---|---|
clarify | Confirm plan, storage, and acceptance spec before creating. Required for new apps. |
browser | Development: self-test launch URL against SPEC.md (navigate / content / click / type / eval / screenshot). |
light_app_list | List registered apps (id, name, runtime, status). Start here when editing an existing app. |
light_app_create | Register a new app and create its directory. Returns id. |
light_app_write | Write a file: path = "<app_id>/<file>" (e.g. "abc/index.html"). |
light_app_read | Read a file: path = "<app_id>/<file>". |
light_app_ls | List files inside one app: path = "<app_id>" or "<app_id>/subdir". |
light_app_launch | Start/restart the process → { url, port, name }. Needed for both self-test and later use. |
light_app_open | Usage only: open the child window for the user after self-test has passed. |
Light apps are outside the workspace sandbox. Never use:
fs_list / fs_read / fs_write / fs_deleteexec (find, ls, cat, sed, …) on data/light-apps/Wrong path args like "data/light-apps 内容" will fail. Correct flow for edits:
light_app_list → find id by name
light_app_read({ path: "<id>/index.html" })
light_app_write({ path: "<id>/index.html", content: "..." })
light_app_launch({ id }) → light_app_open({ url, title })
Do not call light_app_create until the user confirms a short plan + acceptance spec. Static HTML alone has no server DB — if you skip storage confirmation, apps silently fall back to localStorage / in-memory and users are surprised. If you skip acceptance criteria, “done” is undefined and you cannot self-test.
Use clarify (one or more rounds). Cover at least:
static vs python| Option | Runtime | When to use | How |
|---|---|---|---|
| None / ephemeral | static or python | Demo, calculator, one-shot UI | In-memory only; refresh loses data |
Browser localStorage | static | Small personal prefs / drafts, single device | localStorage.setItem — not shared, easy to clear |
| JSON/files in app dir | python | Structured app data without a DB | Read/write files under the app directory (e.g. data.json) via Flask/FastAPI |
| External database | python | Real persistence, multi-session, relational | User provides DSN/URL via Light Apps env (e.g. DATABASE_URL); never hard-code credentials |
| Export/import only | static | User owns the file | Download/upload JSON — no automatic persistence |
Default guidance:
localStorage is OK if the user explicitly accepts it.Example clarify options for storage:
- 不持久化(刷新即丢)
- 浏览器 localStorage(仅本机)
- Python + 应用目录 JSON 文件
- Python + 外部数据库(我会提供 DATABASE_URL)
During the same confirmation phase, propose a concrete checklist and get the user to confirm or edit it. Each item must be observable in the browser (UI text, map center, search results visible, button works, etc.).
Write the confirmed list into the app as SPEC.md via light_app_write right after create (path "<id>/SPEC.md"). Later self-test only against this file — not against vague memory.
Example SPEC.md:
# Spec: 旅行地图
## Storage
- runtime: static
- data: localStorage (places list)
- env: TIANDITU_TOKEN
## Acceptance
1. 打开后地图中心在中国(约 lat 35–40, lng 100–120),不是澳大利亚
2. 搜索框输入城市名后,结果列表有条目可点击
3. 点击地图可添加地点,侧栏列表出现该地点
4. 刷新页面后地点仍在(localStorage)
5. 页面无 JS 报错(控制台 / eval 检查)
Only after the user confirms plan and acceptance items → proceed to create.
Self-test is part of development, not handoff. Loop until SPEC passes before opening the app for the user.
light_app_write → light_app_launch → browser (test SPEC) → fail? fix & repeat
Do not call light_app_open in this loop.
After light_app_launch, use the browser tool on the launch url (http://127.0.0.1:<port>):
navigate → launch URLcontent and/or screenshot — page loads, no blank/error splasheval — key invariants (map center, no missing-env throw, etc.)click / type — primary flows from SPEC.mdRules:
light_app_write → light_app_launch → re-test. Stay in the development loop.browser, not by eyeballing the Wails window.browser is disabled: say so, paste SPEC, ask the user to verify — do not claim “已符合预期”.Only after self-test has passed, call light_app_open so the user gets the child window. This is usage / handoff, not part of debugging.
# development (above) finished with all SPEC items green
light_app_open({ url, title: name })
If the app is already running and SPEC was already verified, light_app_open alone is enough when the user just wants to use it again.
Do not only paste the URL unless light_app_open fails (CLI / no UI client).
Users configure secrets in Light Apps → Environment Variables (e.g. TIANDITU_TOKEN, DATABASE_URL). Injected at every launch.
window.swiflow.env(key)Auto-injected into HTML at launch (inline <script> at the start of <head>). Required keys must use .env() — missing or empty values throw, so users and tests notice immediately. Do not hard-code secrets or silently fall back.
const TOKEN = window.swiflow.env('TIANDITU_TOKEN');
If this throws, tell the user to add the key under Light Apps → Environment Variables, then re-launch.
os.environ["KEY"]token = os.environ["TIANDITU_TOKEN"] # KeyError if missing — preferred for required secrets
dsn = os.environ["DATABASE_URL"] # when storage = external DB
Avoid os.environ.get("KEY", "") for required secrets (silent empty string hides misconfiguration).
Rules:
light_app_launch restarts the process).staticPlain HTML + CSS + JS. No server. Fine for UI-only or localStorage / export-import. Cannot write server-side files or talk to a DB unless the user only uses remote HTTP APIs from the browser (CORS permitting).
Entry point: index.html
pythonFlask or FastAPI. Use when you need server-side logic, file persistence in the app directory, or an external database.
Entry point: app.py — must bind to 0.0.0.0 on the port provided via the PORT environment variable:
import os
port = int(os.environ.get("PORT", 8000))
app.run(host="0.0.0.0", port=port)
List pip dependencies in requirements.txt (one package per line, no version pins unless the user specifies).
localStorage / export-import (static, only if confirmed)static apps must use CDN scripts or inline code onlyPORT env varlight_app_launch stops the previous instance then starts freshfs_* / exec for light-app files — only light_app_*clarifylight_app_open until browser self-test against SPEC.md has passed (unless browser disabled)Plan
clarify — purpose, runtime, data storage, secrets, acceptance spec. Stop until answered.swiflow.env / os.environ).Develop
4. light_app_create → save id.
5. light_app_write "<id>/SPEC.md".
6. light_app_write sources.
7. light_app_launch → browser self-test each SPEC item → fix / re-launch until all pass.
Do not light_app_open yet.
Use (handoff)
8. light_app_open → report SPEC pass results to the user.
Develop
light_app_list → id.SPEC.md (or entry file); update SPEC via clarify if behavior/storage changes.light_app_write the fix.light_app_launch → browser self-test until SPEC passes.Use
5. light_app_open.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>App</title>
<style>
body { font-family: system-ui, sans-serif; margin: 2rem; }
</style>
</head>
<body>
<h1>Hello</h1>
<script>
// Required secrets — throws if unset:
// const token = window.swiflow.env('TIANDITU_TOKEN');
</script>
</body>
</html>
import json, os
from pathlib import Path
from flask import Flask, jsonify, request
app = Flask(__name__)
DATA = Path(__file__).with_name("data.json")
def load():
if DATA.exists():
return json.loads(DATA.read_text(encoding="utf-8"))
return {"items": []}
def save(obj):
DATA.write_text(json.dumps(obj, ensure_ascii=False, indent=2), encoding="utf-8")
@app.route("/")
def index():
return app.send_static_file("index.html")
@app.route("/api/items", methods=["GET", "POST"])
def items():
data = load()
if request.method == "POST":
data["items"].append(request.get_json(force=True))
save(data)
return jsonify(data)
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8000))
app.run(host="0.0.0.0", port=port)
requirements.txt:
flask
light_app_launch fails with a missing-dependency error, check requirements.txt and re-launch.light_app_launch again — a new port will be assigned.light_app_open is unavailable (CLI mode), report the url to the user so they can open it manually.swiflow.env('KEY') / os.environ["KEY"] throws, tell the user to set KEY in Light Apps env and re-launch — do not hard-code the value.light_app_list — do not fs_list / exec under data/light-apps.clarify before rewriting.SPEC.md is missing on an old app, draft one with clarify before claiming the edit is complete.