@cs4alhaider/screenbook 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,208 +1,186 @@
1
1
  # ⧉ ScreenBook
2
2
 
3
- **A static, no-build prototype studio built for AI agents to author, humans to review.**
3
+ **Your local design studio for prototyping real products with AI agents offline, versioned, and owned by you.**
4
4
 
5
- Drop folders of plain HTML screens plus small JSON files into a project and get a navigable,
6
- device-framed design gallery: iPhone / Android / browser frames, mock-data scenarios, design-token
7
- themes, dark/light and LTR/RTL toggles, guided demo flows, pinned review comments, and a
8
- machine-verified self-test plus a CLI and an MCP server so agents can build screens
9
- **without ever holding the engine's implementation in context**.
5
+ ScreenBook turns a folder on your machine into a professional prototyping studio: every screen
6
+ of your product rendered inside real device frames iPhone, Android, browser with live mock
7
+ data, dark mode, right-to-left languages, guided demo walkthroughs, and a built-in design-review
8
+ workflow. AI agents build and revise the screens through a standard interface; you and your
9
+ stakeholders review, comment, and approve. When a screen is final, you hand that same file to
10
+ your agent and say: *now build the native version.*
10
11
 
11
- ![The ScreenBook studio — Qahwa demo project](docs/shots/hero-studio.png)
12
+ ![The ScreenBook studio](docs/shots/hero-studio.png)
12
13
 
13
- ## Why this exists
14
-
15
- Prototyping with AI agents has a failure mode: the prototype starts as "just an HTML file,"
16
- grows into a hand-rolled single-page app, and after a month you have a 20k-line runtime where
17
- **an agent can't touch one screen without reading the whole world** — and neither can you.
14
+ ```bash
15
+ npm install -g @cs4alhaider/screenbook
16
+ ```
18
17
 
19
- ScreenBook inverts every cause of that rot:
18
+ ## Why I built this
20
19
 
21
- | Instead of… | ScreenBook does… |
22
- |---|---|
23
- | One growing SPA runtime | **One file = one screen.** Full standalone HTML documents; each opens alone in a browser. |
24
- | Metadata trapped in code | **Metadata as data.** A JSON block inside each screen; indexes are derived, never hand-kept. |
25
- | App code and viewer code tangled | **A hard engine/app boundary.** Screens know one include (`bridge.js`) and a tiny API. |
26
- | Hard-coded demo data | **Seed + scenario overlays** with `{{today±N}}` date tokens — "mid-trip today" is literally today. |
27
- | CSS forks per restyle | **Design tokens as JSON themes**, flattened to CSS variables, dark mode as a delta. |
28
- | "Trust me, it works" | **A self-test gate**: every screen × theme × light/dark × LTR/RTL must render with zero console errors. |
20
+ I design and ship products with AI agents every day. The prototyping phase kept failing me in
21
+ the same way: designs lived inside chat windows. A concept would look great in a conversation,
22
+ and then reality arrived I needed *forty* screens, not one. I needed to see the empty state
23
+ and the busy state. I needed Arabic right-to-left and dark mode. I needed my co-founder to
24
+ point at a button and say "this one, move it." I needed all of it next week, again, revised.
29
25
 
30
- | | | |
31
- |---|---|---|
32
- | ![Web dashboard frame](docs/shots/web-dashboard.png) | ![Android frame, dark](docs/shots/android-dark.png) | ![Two-theme re-skin](docs/shots/theming-noir.png) |
33
- | Browser-chrome frame, scenario-driven data | Android frame, dark mode | Same screens, different theme JSON |
26
+ Chat canvases aren't built for that. Every iteration re-generates a wall of code inside a
27
+ conversation that will eventually scroll away. Nothing is versioned. Nothing runs offline.
28
+ Reviews happen in screenshots over WhatsApp. And when the design is finally "done," it's
29
+ trapped there's no clean way to hand it to the next stage of work.
34
30
 
35
- ## Setup
31
+ So I built the thing I needed: a studio where **screens are plain files on my disk**, agents
32
+ do the labor, humans do the taste, and the finished prototype becomes the specification for
33
+ the real app.
36
34
 
37
- Requirements: **Node 18**. For headless validation/screenshots: Google Chrome (or see below).
35
+ ## Why not just design in Claude?
38
36
 
39
- Full guides live in **[docs/](docs/README.md)** getting started & prerequisites, the
40
- studio tour, the authoring guide, CLI/MCP references, app mode, troubleshooting.
37
+ Keep using Claude that's the point. ScreenBook isn't a competitor to your AI; it's the
38
+ **workspace your AI works in**. The difference is where the output lives and what you can do
39
+ with it:
41
40
 
42
- ```bash
43
- # 1. Put the engine into your project (this repo IS the engine — folder name matters):
44
- git clone https://github.com/cs4alhaider/screenbook my-prototypes/engine
45
- # (npm: @cs4alhaider/screenbookafter first publish)
41
+ | Designing in a chat window | Designing in ScreenBook |
42
+ |---|---|
43
+ | One artifact per conversation; multi-screen products fall apart | A whole product: features → screens, organized like your app actually is |
44
+ | Output trapped in the thread; gone when context resets | Plain HTML + JSON files in **your git repo** diff, branch, revert, forever |
45
+ | Needs the vendor's website, account, and connection | Runs from a folder on your machine — **works fully offline** |
46
+ | Tied to one AI vendor's canvas | **Any agent** that speaks MCP (Claude Code today; the protocol is open) — or no agent at all, it's just files |
47
+ | One rendering, usually desktop-ish | Real device frames: iPhone, Android, browser — plus dark/light, LTR/RTL, and named data states you switch live |
48
+ | "Looks right" is the only test | A machine gate: every screen must render in every theme × mode × direction with **zero console errors** |
49
+ | Feedback = screenshots and paragraphs | **Pin comments on the screen itself**; your agent reads them, fixes, and marks them resolved |
50
+ | Regenerates everything each round | Agent edits one small file per screen — faster, cheaper, and nothing else breaks |
46
51
 
47
- # 2. Scaffold the project around it:
48
- cd my-prototypes
49
- node engine/cli/screenbook.js init .
52
+ ## What working in it feels like
50
53
 
51
- # 3. Run the studio:
52
- node engine/cli/screenbook.js serve .
53
- # → http://127.0.0.1:4600 · live reload · manifests auto-regenerate · no cache, ever
54
- ```
54
+ A concrete example a specialty-coffee ordering app (it ships in `examples/qahwa`, so you can
55
+ open exactly this):
55
56
 
56
- `init` creates `app.config.json`, a starter theme, a `welcome` feature with one screen — and
57
- drops **`CLAUDE.md`** (the authoring contract) plus a **packaged agent skill** into the project,
58
- so any AI agent that opens it immediately knows the rules.
57
+ **1. You brief your agent, it builds screens.**
59
58
 
60
- For headless `validate` / `screenshot`, install the one dev dependency once:
59
+ > *"Create an ordering feature: menu with our drinks from the seed data, a drink detail screen
60
+ > with a size/milk customization sheet, a cart, and a live order-status screen. iPhone frames,
61
+ > match our warm theme."*
61
62
 
62
- ```bash
63
- cd engine && npm i # playwright-core drives your installed Chrome
64
- # no Chrome? use: npm i -D playwright && npx playwright install chromium
65
- ```
63
+ The agent creates each screen as its own small HTML file. They appear in your studio's sidebar
64
+ as they land framed in an iPhone, styled by your design tokens, wired to your mock data.
66
65
 
67
- Try the shipped examples first:
66
+ **2. You review like it's a real app.** Click through the flow. Flip the 🎭 scenario dropdown
67
+ from *Regular morning* to *First visit* — the same screens now show the empty state honestly.
68
+ Toggle dark mode. Switch to Arabic and watch the layout mirror right-to-left. Nothing is
69
+ staged; the "order ready by 08:44" timestamp is computed from *today* every time you demo.
68
70
 
69
- ```bash
70
- node engine/cli/screenbook.js serve engine/examples/qahwa # ☕ coffee app: iOS + Android + web
71
- node engine/cli/screenbook.js serve engine/examples/tokens-lab # 🎨 two themes, live token lab
72
- ```
71
+ ![Scenario-driven data on a real dashboard frame](docs/shots/web-dashboard.png)
73
72
 
74
- ## How it helps a five-minute story
75
-
76
- **1. A screen is one honest file.** No framework, no build, one conventional include:
77
-
78
- ```html
79
- <!DOCTYPE html>
80
- <html lang="en">
81
- <head>
82
- <script type="application/json" id="screen-meta">
83
- { "title": "Cart", "description": "Lines, totals, checkout.",
84
- "order": 30, "device": "ios", "status": "wip" }
85
- </script>
86
- <script src="../../../engine/bridge.js"></script>
87
- </head>
88
- <body>
89
- <button data-go="040-checkout">Checkout</button>
90
- <script>
91
- Engine.ready(function (data) { /* seed ⊕ active scenario, dates resolved */ });
92
- </script>
93
- </body>
94
- </html>
95
- ```
73
+ **3. Your team comments on the pixels, not around them.** Turn on 📌 Review Mode and click
74
+ anywhere: each pin captures the screen, the data state, the theme, the mode, the direction,
75
+ and the exact element under the cursor. Then:
96
76
 
97
- Save it under `features/shop/screens/030-cart.html` it's already in the sidebar, framed as an
98
- iPhone, styled by your tokens (`var(--color-accent)`), live-reloading on every save.
77
+ > *"Read the open review comments, apply the fixes, and resolve them."*
99
78
 
100
- **2. Colors are a panel, not a hunt.** The 🎨 **Theme Lab** shows every token the active theme
101
- defines and edits them **live against the hosted screens** — color pickers for hex values,
102
- plain fields for fonts/radii/spacing, a theme switcher, Export, and one-click **Save** straight
103
- back to `themes/<id>.json` while `serve` runs:
79
+ Your agent does exactly that it has tools for reading pins and marking them resolved.
104
80
 
105
- ![Theme Lab live token editing](docs/shots/theme-lab.png)
81
+ **4. The finished screen becomes the spec for the real app.** This is the step that pays for
82
+ everything. When a screen survives review, it's a complete, self-contained HTML file: exact
83
+ layout and spacing, your design tokens, final copy in both languages, all interaction states.
84
+ Now point your agent at it:
106
85
 
107
- **3. States are data, not branches.** Add a scenario and the 🎭 dropdown demos your empty state:
86
+ > *"Take `features/order/screens/030-cart.html` and build it as a SwiftUI view. Use our design
87
+ > tokens for colors and spacing. Preserve the empty state exactly as the `first-visit` scenario
88
+ > shows it."*
108
89
 
109
- ```json
110
- { "id": "first-visit", "icon": "🆕", "title": "First visit",
111
- "remove": ["order"], "patch": { "user": { "isNew": true } } }
112
- ```
90
+ The prototype you approved *is* the design document — no Figma-to-code guesswork, no "it looked
91
+ different in the mockup." The same works for Jetpack Compose, React Native, Flutter, or web
92
+ components.
113
93
 
114
- **4. Demos tell themselves.** A `flows.json` walkthrough gives stakeholders a guided,
115
- captioned story — each step can pin its own scenario, and every state is a shareable URL:
116
- `…#shop/030-cart?scenario=first-visit&mode=dark&dir=rtl`.
94
+ ![One click from English light to Arabic dark](docs/shots/rtl-arabic.png)
117
95
 
118
- **5. Review closes the loop.** Reviewers pin comments directly on screens; each pin captures
119
- screen, scenario, theme, mode, direction and the exact element clicked, and syncs to
120
- `review/comments.json` — where agents read and resolve them.
96
+ ## Two commands to your own studio
121
97
 
122
- **6. The machine decides "done".**
98
+ Requirements: Node ≥ 18. Nothing else no cloning, no per-project installs. (The automated
99
+ screen checks use your installed Chrome, or download a headless browser once by themselves.)
123
100
 
124
101
  ```bash
125
- node engine/cli/screenbook.js validate .
126
- # ✓ static contract checks
127
- # ✓ 28/28 render checks green across 7 screens (× themes × dark/light × ltr/rtl, zero console errors)
102
+ npm install -g @cs4alhaider/screenbook # once, ever
103
+
104
+ cd any-project-you-are-working-on
105
+ screenbook init # creates .screenbook/ — that's the whole setup
106
+ screenbook serve # → http://127.0.0.1:4600 — live reload, no cache headaches
128
107
  ```
129
108
 
130
- ## The agent workflow (the actual point)
109
+ `init` creates a single **`.screenbook/`** folder in your project — the self-contained source
110
+ of truth for the prototype: your **`brief.md`** (requirements — agents read it first), screens,
111
+ mock data, scenarios, themes, review comments, and the agent authoring contract. Commit it or
112
+ gitignore it; that's your call. The studio itself always runs from the installed package —
113
+ your project never carries runtime code.
131
114
 
132
- Register the MCP server with your agent for Claude Code:
115
+ Connect your agent (Claude Code shown; any MCP client works):
133
116
 
134
117
  ```bash
135
118
  claude mcp add screenbook -- npx -y @cs4alhaider/screenbook mcp --root .
136
- # or from a checkout: claude mcp add screenbook -- node engine/cli/screenbook.js mcp --root .
137
119
  ```
138
120
 
139
- Then ask for work in plain language:
140
-
141
- > *"Add a checkout screen to the shop feature: summary card, payment method list from the seed,
142
- > a pay button that toasts. Match the existing screens. Validate and show me a screenshot."*
143
-
144
- The agent never opens `engine/` — it calls `list_screens` → `get_screen` (steals an existing
145
- screen's idioms) → `add_screen` (which **lints the contract, stamps the date, regenerates the
146
- manifest, writes atomically**) → `validate` (full headless render matrix) → `screenshot`
147
- (a PNG inside the real device frame). Human taste, machine discipline.
148
-
149
- 18 tools: `list_features · list_screens · get_screen · add_screen · update_screen ·
150
- remove_screen · add_feature · get_data · set_data · get_theme · set_theme · get_flows ·
151
- set_flows · get_review_comments · resolve_comment · validate · screenshot · add_app`.
152
-
153
- ## CLI
154
-
155
- | Command | Does |
156
- |---|---|
157
- | `init [dir] [--name X]` | Scaffold a project + authoring contract + agent skill |
158
- | `serve [dir] [--port]` | Studio server: live reload, auto-manifests, review sync, `/engine/*` mounted from this package, no-cache always |
159
- | `manifest [dir]` | Rescan screens → regenerate derived `manifest.json` per feature |
160
- | `validate [dir] [--static] [--json]` | Contract checks + headless render of every screen × theme × mode × direction |
161
- | `screenshot [dir] --screen f/s [--mode light,dark] [--dir ltr,rtl] [--scenario id] [--theme id]` | Device-framed PNGs (comma lists = matrix) |
162
-
163
- ## What's in this repo
164
-
165
- ```
166
- bridge.js the ONLY file screens include (dual-mode: shell-driven / standalone)
167
- index.html + shell/ the studio: frames, dropdowns, flows, review mode, selftest
168
- core/ shared project API (scan, manifests, atomic writes, validate, serve, browser)
169
- cli/ · mcp/ two thin faces over the same core
170
- CLAUDE.md the authoring contract agents follow (scaffolded into projects)
171
- skill/ packaged agent skill + reference docs (scaffolded into projects)
172
- examples/ qahwa (☕ 3-device demo app) · tokens-lab (🎨 multi-theme lab)
173
- test/ 42-test suite: unit + serve E2E + CLI E2E → npm test
174
- TESTING.md the full test map and gaps
175
- ```
176
-
177
- RTL and Arabic are first-class (`dir` flipping, per-screen language dictionaries):
178
-
179
- <img src="docs/shots/rtl-arabic.png" width="320" alt="RTL Arabic screen in dark mode">
180
-
181
- ## App mode — embed entire existing apps
182
-
183
- Already have a single-page prototype? Don't rewrite it — **embed it**:
121
+ Want to explore first? Complete demo projects ship inside the package:
184
122
 
185
123
  ```bash
186
- node engine/cli/screenbook.js app add legacy/index.html --device ios --chrome self
124
+ screenbook serve "$(npm root -g)/@cs4alhaider/screenbook/examples/qahwa" # iPhone + Android + web
125
+ screenbook serve "$(npm root -g)/@cs4alhaider/screenbook/examples/tokens-lab" # 🎨 two themes, edited live
187
126
  ```
188
127
 
189
- The app's views appear in the sidebar as screens, deep links work, dark/RTL/scenario toggles
190
- drive it live. Cooperative apps include `engine/app-bridge.js` and register themselves
191
- (`examples/spa-demo`); sealed apps get a small project-owned **driver** injected at runtime
192
- **zero changes to the app's own files**. `validate` boots each app and visits every screen it
193
- reports, still demanding zero console errors.
128
+ ## What's in the box
129
+
130
+ - **Device frames** iPhone (Dynamic Island, status bar), Android (punch-hole), browser
131
+ chrome, or bare; scaled to fit, screenshot-ready.
132
+ - **Data scenarios** named states over your mock data (*brand-new user*, *mid-trip*,
133
+ *after close*) with date tokens like `{{today+3}}`, so time-based demos are always true.
134
+ - **Theme Lab** — every design token visible and editable live against your screens; save
135
+ writes the JSON back to disk. Dark mode is a delta, not a fork.
136
+
137
+ ![Theme Lab](docs/shots/theme-lab.png)
138
+ - **Flows** — guided, captioned walkthroughs for stakeholder demos; every step is a shareable
139
+ URL that opens in the exact state (screen, data, theme, direction).
140
+ - **Review Mode** — pinned comments with full context, synced to a JSON file your agent reads
141
+ and resolves.
142
+ - **Multilingual by design** — per-feature strings files with side-by-side translations;
143
+ right-to-left is a first-class toggle, not an afterthought.
144
+ - **Embed existing prototypes** — already have a working single-page prototype? One command
145
+ mounts the *whole app* inside the studio without touching its files
146
+ (`screenbook app add legacy/index.html`) — see [App mode](docs/app-mode-guide.md).
147
+ - **A machine-verified quality gate** — `screenbook validate` renders every screen in every
148
+ theme × light/dark × LTR/RTL and fails on any console error. Green means done — for humans
149
+ and agents alike.
150
+ - **CLI + 18 agent tools** — everything above is scriptable and agent-operable:
151
+ create screens, update data, restyle themes, take device-framed screenshots, run the gate.
152
+
153
+ Full guides: **[docs/](docs/README.md)** — getting started, the studio tour, the authoring
154
+ contract, CLI and agent references, troubleshooting.
155
+
156
+ ## The shape of a project
194
157
 
195
- ![A sealed legacy app running inside the studio](docs/shots/app-mode.png)
196
-
197
- ## Status
158
+ ```
159
+ my-product/ ← your real project, any stack, untouched
160
+ └── .screenbook/ ← everything ScreenBook, in one folder
161
+ ├── brief.md your requirements — agents read this FIRST
162
+ ├── app.config.json product name · features · devices · themes · languages
163
+ ├── CLAUDE.md the authoring contract agents follow
164
+ ├── themes/default.json design tokens (light + dark)
165
+ ├── features/
166
+ │ └── order/
167
+ │ ├── feature.json title, icon, order
168
+ │ ├── flows.json demo walkthroughs
169
+ │ ├── i18n.json strings, side-by-side languages
170
+ │ ├── data/seed.json mock data
171
+ │ ├── data/scenarios.json named data states
172
+ │ └── screens/
173
+ │ ├── 010-menu.html ← one file = one screen
174
+ │ └── 020-drink.html
175
+ └── review/comments.json pinned feedback, read by your agent
176
+ ```
198
177
 
199
- **v1 complete and machine-verified** (studio, 4 frames, scenarios, flows, Theme Lab,
200
- review mode, selftest, CLI, MCP, agent onboarding, example projects, 44-test suite).
201
- **v2 in progress**: app mode shipped (above) · theme write-back (Theme Lab Save) ·
202
- i18n strings ✓ (`Engine.t` + key-first per-feature `i18n.json`, fallback chain, validate
203
- warnings on gaps) · npm packaging next.
178
+ Everything is a plain file an intern could read. That's the whole trick: it's why agents stay
179
+ fast and cheap (they touch one small file at a time), why git can review every change, why it
180
+ works on a plane, and why the approved prototype can walk straight into production.
204
181
 
205
- Born inside [Rahhal](https://github.com/cs4alhaider)'s product lab, where the predecessor
206
- prototypes grew to ~22k lines and taught every lesson this engine inverts.
182
+ ## Status & license
207
183
 
208
- License: MIT.
184
+ v0.2.0 — studio, frames, scenarios, themes, flows, review, i18n, app mode, self-test gate,
185
+ CLI, MCP server, docs, and a 64-test suite; built and verified end-to-end with AI agents,
186
+ reviewed by a human with taste. MIT © [Abdullah Alhaider](https://github.com/cs4alhaider).
package/bridge.js CHANGED
@@ -12,7 +12,7 @@
12
12
  (function () {
13
13
  'use strict';
14
14
 
15
- var VERSION = '0.1.0';
15
+ var VERSION = '0.2.0';
16
16
 
17
17
  /* ------------------------------------------------------------------ *
18
18
  * EngineKit — pure helpers shared by bridge (screens) and shell
package/cli/screenbook.js CHANGED
@@ -10,7 +10,7 @@ import { startServer } from '../core/serve.js';
10
10
  import * as T from './templates.js';
11
11
 
12
12
  const ENGINE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
13
- const VERSION = '0.1.0';
13
+ const VERSION = '0.2.0';
14
14
 
15
15
  /* ---------------- arg parsing ---------------- */
16
16
 
@@ -48,13 +48,17 @@ async function requireRoot() {
48
48
  /* ---------------- commands ---------------- */
49
49
 
50
50
  async function cmdInit() {
51
- const dir = path.resolve(positional[0] || '.');
51
+ /* Everything lands in <project>/.screenbook/ — the self-contained source of
52
+ truth for the prototype. The user decides to commit or gitignore it.
53
+ No cloning, no runtime copy: `serve` mounts the studio from this package. */
54
+ const projectDir = path.resolve(positional[0] || '.');
55
+ const dir = path.join(projectDir, '.screenbook');
52
56
  const configPath = path.join(dir, 'app.config.json');
53
57
  if (await exists(configPath) && !flags.force) {
54
- console.error(bad(`app.config.json already exists in ${dir} — refusing to overwrite (use --force).`));
58
+ console.error(bad(`.screenbook/ already exists in ${projectDir} — refusing to overwrite (use --force).`));
55
59
  process.exit(2);
56
60
  }
57
- const name = flags.name || path.basename(dir);
61
+ const name = flags.name || path.basename(projectDir);
58
62
  const day = today();
59
63
 
60
64
  await mkdirp(path.join(dir, 'features/welcome/screens'));
@@ -63,6 +67,7 @@ async function cmdInit() {
63
67
  await mkdirp(path.join(dir, 'review'));
64
68
 
65
69
  await writeJSON(configPath, T.APP_CONFIG(name));
70
+ await writeAtomic(path.join(dir, 'brief.md'), T.BRIEF(name));
66
71
  await writeJSON(path.join(dir, 'themes/default.json'), T.DEFAULT_THEME);
67
72
  await writeJSON(path.join(dir, 'review/comments.json'), { comments: [] });
68
73
  await writeJSON(path.join(dir, 'features/welcome/feature.json'), T.WELCOME_FEATURE);
@@ -71,39 +76,45 @@ async function cmdInit() {
71
76
  await writeJSON(path.join(dir, 'features/welcome/flows.json'), T.WELCOME_FLOWS);
72
77
  await writeAtomic(path.join(dir, 'features/welcome/screens/010-hello.html'), T.WELCOME_SCREEN(day));
73
78
 
74
- /* agent onboarding ships with the product (EN-32) */
75
- const claudeMd = path.join(dir, 'CLAUDE.md');
76
- if (!(await exists(claudeMd))) {
77
- const contract = await readTextSafe(path.join(ENGINE_DIR, 'CLAUDE.md'));
78
- if (contract) await writeAtomic(claudeMd, contract);
79
- }
79
+ /* Agent onboarding, multi-agent (Abdullah's panel picks):
80
+ - the full contract at .screenbook/AGENTS.md (the 2026 open standard —
81
+ Codex, Cursor, Gemini, Copilot AND Claude Code read it natively)
82
+ - .screenbook/CLAUDE.md as a 3-line pointer for older Claude versions
83
+ - the skill in BOTH standard locations: .agents/skills/ + .claude/skills/
84
+ - a marked, idempotent breadcrumb appended to the PROJECT's root AGENTS.md */
85
+ const contract = await readTextSafe(path.join(ENGINE_DIR, 'AGENTS.md'));
86
+ if (contract) await writeAtomic(path.join(dir, 'AGENTS.md'), contract);
87
+ await writeAtomic(path.join(dir, 'CLAUDE.md'), T.CLAUDE_POINTER);
80
88
  const skillSrc = path.join(ENGINE_DIR, 'skill');
81
89
  if (await exists(skillSrc)) {
82
- await copyDir(skillSrc, path.join(dir, '.claude/skills/screenbook'));
90
+ await copyDir(skillSrc, path.join(projectDir, '.claude/skills/screenbook'));
91
+ await copyDir(skillSrc, path.join(projectDir, '.agents/skills/screenbook'));
83
92
  }
93
+ await upsertRootPointer(projectDir);
84
94
 
85
95
  await regenAllManifests(dir);
86
96
 
87
- /* `init --app <path>`: register an existing SPA in this folder as an
88
- embedded app in the same breath (Abdullah's flow: point ScreenBook at
89
- any folder that already contains an app). */
97
+ /* `init --app <path>`: register an existing SPA from the USER'S project as
98
+ an embedded app recorded as project/<path>, served via the /project mount. */
90
99
  if (flags.app) {
91
- const rel = path.relative(dir, path.resolve(flags.app)) || flags.app;
100
+ const rel = path.relative(projectDir, path.resolve(flags.app));
101
+ if (rel.startsWith('..')) {
102
+ console.error(bad(`--app must point inside ${projectDir}`));
103
+ process.exit(2);
104
+ }
92
105
  const r = await addApp(dir, {
93
- src: rel.split(path.sep).join('/'),
106
+ src: `project/${rel.split(path.sep).join('/')}`,
94
107
  driver: !flags.cooperative
95
108
  });
96
109
  console.log(ok(`✓ app registered: ${r.feature.id}`) + dim(` → ${r.feature.src}`));
97
- if (r.driver) console.log(` fill in ${bold(r.driver)} to teach ScreenBook the app's internals`);
110
+ if (r.driver) console.log(` fill in ${bold('.screenbook/' + r.driver.replace(/^features\//, 'features/'))} to teach ScreenBook the app's internals`);
98
111
  }
99
112
 
100
- console.log(ok(`✓ ScreenBook project scaffolded in ${dir}`));
101
- console.log(` app.config.json · themes/default.json · features/welcome/ · review/`);
102
- console.log(` CLAUDE.md + .claude/skills/screenbook/ ${dim('(agent authoring contract)')}`);
103
- if (!(await exists(path.join(dir, 'engine')))) {
104
- console.log(dim(` note: no engine/ folder here${bold('screenbook serve')} mounts it automatically;`));
105
- console.log(dim(` copy the engine folder in when you want plain static servers to work too.`));
106
- }
113
+ console.log(ok(`✓ ScreenBook ready everything lives in ${bold('.screenbook/')}`));
114
+ console.log(` ${bold('brief.md')} ${dim('(write your requirements here agents read it first)')}`);
115
+ console.log(` app.config.json · themes/ · features/welcome/ · review/ · AGENTS.md ${dim('(+CLAUDE.md pointer)')}`);
116
+ console.log(` agent setup: root AGENTS.md section · .agents/skills/ + .claude/skills/ ${dim('(Claude, Codex, Cursor, Gemini, …)')}`);
117
+ console.log(dim(` commit .screenbook/ or add it to .gitignore your call; it is the source of truth.`));
107
118
  console.log(`\nNext: ${bold(`screenbook serve ${positional[0] || '.'}`)} → http://127.0.0.1:4600`);
108
119
  }
109
120
 
@@ -112,6 +123,25 @@ async function readTextSafe(p) {
112
123
  catch { return null; }
113
124
  }
114
125
 
126
+ /* Root AGENTS.md breadcrumb: create the file if missing; if it exists, replace
127
+ only the marked ScreenBook section (or append it) — user content is never touched. */
128
+ async function upsertRootPointer(projectDir) {
129
+ const file = path.join(projectDir, 'AGENTS.md');
130
+ const START = '<!-- screenbook:start -->';
131
+ const END = '<!-- screenbook:end -->';
132
+ const existing = await readTextSafe(file);
133
+ if (existing === null) {
134
+ await writeAtomic(file, T.ROOT_POINTER + '\n');
135
+ return;
136
+ }
137
+ const s = existing.indexOf(START);
138
+ const e = existing.indexOf(END);
139
+ const next = (s >= 0 && e > s)
140
+ ? existing.slice(0, s) + T.ROOT_POINTER + existing.slice(e + END.length)
141
+ : existing.replace(/\s*$/, '') + '\n\n' + T.ROOT_POINTER + '\n';
142
+ if (next !== existing) await writeAtomic(file, next);
143
+ }
144
+
115
145
  async function copyDir(src, dest) {
116
146
  const fs = await import('node:fs/promises');
117
147
  await fs.mkdir(dest, { recursive: true });
@@ -123,8 +153,8 @@ async function cmdServe() {
123
153
  const port = parseInt(flags.port || '4600', 10);
124
154
  const srv = await startServer({ root, engineDir: ENGINE_DIR, port });
125
155
  console.log(bold(`⧉ ScreenBook`) + ` serving ${dim(root)}`);
126
- console.log(` studio ${ok(srv.url + '/engine/index.html')}`);
127
- console.log(` selftest ${dim(srv.url + '/engine/index.html?selftest=1')}`);
156
+ console.log(` studio ${ok(srv.url + '/screenbook/')}`);
157
+ console.log(` selftest ${dim(srv.url + '/screenbook/?selftest=1')}`);
128
158
  console.log(` live reload + manifest refresh + review sync ${ok('on')} ${dim('(no-cache always)')}`);
129
159
  }
130
160
 
@@ -205,8 +235,17 @@ async function cmdApp() {
205
235
  }
206
236
  positional.splice(0, 2, positional[2]); // remaining positional = project dir
207
237
  const root = await requireRoot();
208
- const rel = path.isAbsolute(srcArg)
209
- ? path.relative(root, srcArg).split(path.sep).join('/')
238
+
239
+ /* Normalize src: apps usually live in the USER'S project. With a .screenbook
240
+ root, record them as project/<path> (served via the /project mount).
241
+ Relative paths are taken relative to the project directory. */
242
+ const isDotRoot = path.basename(root) === '.screenbook';
243
+ const projectDir = isDotRoot ? path.dirname(root) : root;
244
+ const absSrc = path.isAbsolute(srcArg) ? srcArg : path.resolve(projectDir, srcArg);
245
+ const fromRoot = path.relative(root, absSrc);
246
+ const fromProject = path.relative(projectDir, absSrc);
247
+ const rel = !fromRoot.startsWith('..') ? fromRoot.split(path.sep).join('/')
248
+ : isDotRoot && !fromProject.startsWith('..') ? `project/${fromProject.split(path.sep).join('/')}`
210
249
  : srcArg;
211
250
  const r = await addApp(root, {
212
251
  src: rel,
package/cli/templates.js CHANGED
@@ -87,7 +87,7 @@ export const WELCOME_SCREEN = (today) => `<!DOCTYPE html>
87
87
  "updated": "${today}"
88
88
  }
89
89
  </script>
90
- <script src="../../../engine/bridge.js"></script>
90
+ <script src="../../../screenbook/bridge.js"></script>
91
91
  <style>
92
92
  * { box-sizing: border-box; }
93
93
  body {
@@ -137,3 +137,56 @@ export const WELCOME_SCREEN = (today) => `<!DOCTYPE html>
137
137
  export const GITIGNORE = `node_modules/
138
138
  .DS_Store
139
139
  `;
140
+
141
+ /* Marked section appended to the PROJECT's root AGENTS.md so every agent
142
+ (Codex, Cursor, Gemini, Claude, …) discovers ScreenBook unprompted.
143
+ Idempotent: init replaces the content between the markers. */
144
+ export const ROOT_POINTER =
145
+ `<!-- screenbook:start -->
146
+ ## UI prototyping (ScreenBook)
147
+
148
+ This project's UI prototypes live in **.screenbook/** — a [ScreenBook](https://github.com/cs4alhaider/screenbook) studio.
149
+ Before designing or changing any screen: read **.screenbook/brief.md** (the requirements)
150
+ and **.screenbook/AGENTS.md** (the authoring contract).
151
+ Preview locally: \`screenbook serve\` → http://127.0.0.1:4600
152
+ Agent tools (MCP, 18 tools): \`npx -y @cs4alhaider/screenbook mcp --root .\`
153
+ <!-- screenbook:end -->`;
154
+
155
+ export const CLAUDE_POINTER = `# ScreenBook
156
+
157
+ The authoring contract for this prototype lives in **AGENTS.md** (same folder) — read
158
+ that, plus **brief.md** for the product requirements, before creating or changing any
159
+ screen.
160
+ `;
161
+
162
+ export const BRIEF = (name) => `# ${name} — product brief
163
+
164
+ > **AI agents: read this file first, before creating or changing any screen.**
165
+ > It is the source of truth for what we are building and why.
166
+
167
+ ## What we're building
168
+
169
+ _One paragraph: the product, who it's for, the core promise._
170
+
171
+ ## The screens we need
172
+
173
+ _List the features and screens you expect, roughly in user-journey order.
174
+ Agents: turn each line into screens under features/, and ask (via review
175
+ comments) when something here is ambiguous._
176
+
177
+ - …
178
+
179
+ ## Design direction
180
+
181
+ _Tone, references, the feeling. The design tokens in themes/ are the palette —
182
+ change them there, not per-screen._
183
+
184
+ ## States that must exist
185
+
186
+ _Empty / first-run · busy / real usage · edge cases. Agents: model these as
187
+ data scenarios so every screen can be reviewed in each state._
188
+
189
+ ## Out of scope (for now)
190
+
191
+ - …
192
+ `;