leglas 0.1.1 → 0.3.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,84 +1,273 @@
1
- # Leglas
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/FredAmartey/leglas/main/.github/assets/logo-duo.svg" width="640" alt="The Leglas mark, in light and dark" />
3
+ </p>
4
+
5
+ <p align="center">
6
+ <img src="https://raw.githubusercontent.com/FredAmartey/leglas/main/.github/assets/wordmark.svg" width="190" alt="Leglas" />
7
+ </p>
8
+
9
+ <p align="center">Your app is the canvas.</p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/leglas"><img src="https://img.shields.io/npm/v/leglas" alt="npm"></a>
13
+ <a href="https://github.com/FredAmartey/leglas/actions/workflows/ci.yml"><img src="https://github.com/FredAmartey/leglas/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
14
+ <a href="LICENSE"><img src="https://img.shields.io/npm/l/leglas" alt="license"></a>
15
+ </p>
16
+
17
+ Code is becoming the source of truth. Features go from prompt to
18
+ working code in minutes, and mockups/design files eventually lag behind the product and drift out of sync. The
19
+ fastest teams already design in the medium they ship. Leglas is built
20
+ for working that way: it lets you explore many design directions at
21
+ once, live, in your own app.
22
+
23
+ The goal is to help devs and designers try many variations of a component, feature, page or user-flow quickly and make coming up with ideas extremely easy.
24
+
25
+ Ask your agent for a handful of directions for the landing page,
26
+ or the checkout component, or the empty states, or your onboarding flow. Leglas runs them all as your
27
+ actual app, side by side in one place, and holds your notes on each. Explore far and wide without losing focus: you see more ideas
28
+ without losing your opinion of any of them.
29
+
30
+ And because every variation is the real product, your judgment is real
31
+ too. Everything behaves the way it will in production, motion and data
32
+ included. Choosing between two directions is choosing between two
33
+ things that already exist, and the winner never has to be rebuilt from
34
+ a picture or design file.
35
+
36
+ Your app doesn't change to make any of this work. Leglas proxies the same
37
+ dev server in your project: one config file to delete when you're done
38
+ and sessions that clean up after themselves.
39
+
40
+ ## What you can do with Leglas
41
+
42
+ - Pick any two variations for side-by-side comparison when it gets hard to choose.
43
+ - Name each direction, drag to reorder and organise your variants, set aside the ones that
44
+ don't feel right. Your actions on every idea survive a long exploration.
45
+ - Send a teammate the link to a direction. They open the live version instead of a screenshot and a paragraph of explanation.
46
+ - Compare things no design tool can hold: 3 git branches, a local
47
+ build against production, yesterday's direction against today's, or even 7 different worktrees.
48
+ - `leglas init` teaches any coding agent the workflow, and
49
+ `leglas explore` briefs an exploration. Five directions can be five
50
+ separate ideas, or five variants of the one you already like: you choose
51
+ the spread, your agent supplies the taste.
52
+ - Ask for changes without leaving the comparison: describe what you
53
+ want on the direction you're looking at, and Leglas turns it into a
54
+ precise request for your agent, file path included. Leave
55
+ `npx leglas watch --run "claude -p {prompt}"` running in another terminal
56
+ and your agent picks each request up as you send it. In Claude Code,
57
+ the Leglas MCP server can also push each request straight into your
58
+ open session as a channel event (channels are a research preview:
59
+ start Claude Code with `--dangerously-load-development-channels
60
+ server:<your leglas server name>`).
61
+ - Keep the winner with one command. Leglas moves it into your source
62
+ tree and clears the exploration away.
63
+ - No app yet or want plain HTML comparisons? Some people want exactly that, and it works fine. Same comparison, no dev server.
64
+
65
+ ## Quick start
66
+
67
+ Start your dev server, then run Leglas from the project directory:
2
68
 
3
- Compare design directions inside your own running app.
69
+ ```sh
70
+ npx leglas
71
+ ```
72
+
73
+ Leglas starts on port 4100, proxies your app, and opens
74
+ `http://localhost:4100/leglas`. With no configuration you get a single
75
+ preview of your app root. Add a config file to compare more than one thing.
4
76
 
5
- Leglas is a local development tool. You point it at a dev server you are
6
- already running, list the URLs you want to compare, and flip between them in
7
- one interface. Every preview is your real application: real data, real
8
- authentication, real behaviour. Nothing is mocked, nothing is cloned, and
9
- your project needs no changes to work with it.
77
+ It works with whatever you're building in. Leglas never imports or
78
+ executes your framework, so the target can be Next, Vite, Remix,
79
+ SvelteKit, Astro, or a folder of static files.
10
80
 
11
- ## Requirements
81
+ ## Install
12
82
 
13
- - Node.js 24 or newer, developed and tested against Node 26
14
- - A dev server you can run locally
83
+ There is nothing you have to install: `npx leglas` fetches the CLI on
84
+ first use and starts from npm's cache after that, and every instruction
85
+ Leglas writes for agents uses the same form, so a fresh clone works
86
+ with no setup at all. Requires Node 24 or newer.
15
87
 
16
- TypeScript config files rely on Node stripping types natively, which is
17
- available without a flag from Node 23.6. On an older runtime, use
18
- `leglas.config.mjs` or `leglas.config.json` instead.
88
+ Two optional upgrades:
19
89
 
20
- Leglas never imports or executes your framework, so the target can be Next,
21
- Vite, Remix, Create React App, SvelteKit, Astro, or static output.
90
+ - `npm install -D leglas` pins the version in a project. Teammates and
91
+ CI get the same Leglas from their normal install, and `npx` resolves
92
+ the local copy from then on.
93
+ - `npm install -g leglas` is for typing `leglas` without the prefix.
22
94
 
23
- ## Getting started
95
+ ## Working with coding agents
24
96
 
25
- Start your dev server as usual, then run Leglas from your project directory:
97
+ The fastest way in is the agent skill:
26
98
 
27
99
  ```sh
28
- npx leglas
100
+ npx skills add FredAmartey/leglas
29
101
  ```
30
102
 
31
- Leglas starts on port 4100, proxies your app, and opens the interface at
32
- `http://localhost:4100/leglas`. With no configuration it shows a single
33
- preview of your app root, which is enough to confirm the connection.
103
+ One install, and your agent recognises "give me a few directions for the
104
+ pricing page" as a Leglas exploration in any project, including ones
105
+ that have never seen Leglas. It sets the project up itself and gets to
106
+ work.
107
+
108
+ In a project, run `npx leglas init` once. It writes a section into your
109
+ project's `AGENTS.md`, creates a starter config, and gitignores Leglas's
110
+ working directory. That section travels with the repo, so Claude Code,
111
+ Cursor, Codex, or whatever you switch to next opens the project already
112
+ knowing how to add design directions to it. Every command accepts
113
+ `--json` and prints a single machine-readable envelope, so agents drive
114
+ the same CLI you do.
115
+
116
+ The instructions center on one rule: add beside what exists, never
117
+ rewrite it. Two directions that rewrite the same file cannot render from
118
+ one server, and asking an agent to "make the hero calmer" tempts it to
119
+ edit the hero. The supporting commands:
120
+
121
+ - `npx leglas explore hero --count 6` briefs the exploration: what the set
122
+ is for, why it only works if the six genuinely disagree, and how each
123
+ direction registers. Unbriefed, six requests come back as six variants
124
+ of one idea. With `--based-on "Aurora"` the goal flips: six deliberate
125
+ variants of a direction you already like, and drifting into a new
126
+ direction is the failure. The designs themselves are the agent's;
127
+ Leglas prescribes none.
128
+ - `npx leglas new hero --from src/Hero.tsx` scaffolds a switcher under
129
+ `.leglas/variants/hero/`. With `--from`, the baseline re-exports your
130
+ real component, so you never compare against a stale copy. Leglas
131
+ prints the one line to add in your component and does not edit it,
132
+ because rewriting a file it does not understand is how a tool breaks a
133
+ codebase. Scaffolded branch points return the fallback in production
134
+ builds, so a committed one cannot expose an unreleased direction.
135
+ - `npx leglas classify --change package.json --rewrite src/theme.css` answers
136
+ where a direction should live before it is written. Changing
137
+ dependencies, build configuration, or an existing file's behaviour
138
+ cannot be additive, so those directions build on their own git branch
139
+ and register with `leglas add --branch`. Everything else stays in-app,
140
+ where switching is instant.
141
+ - `npx leglas show "Aurora" --json` answers for one direction: its entry, the
142
+ source file behind it, the variants based on it, what it is being compared
143
+ against, and anything still pending on it. Copying a direction from the
144
+ rail hands over a block that ends in this command, so an agent given the
145
+ block can go and get the rest.
146
+ - `npx leglas keep "Aurora" --to src/components/hero.tsx` moves the winner
147
+ into real source and ends the exploration.
148
+
149
+ Asking for a change works from the interface too. Type what you want
150
+ changed into the field under the rail (or press `R`) and Leglas composes a
151
+ prompt naming the direction and the file behind it, copies it to your
152
+ clipboard, and queues it. The direction it means is the one highlighted
153
+ directly above the field. Your agent drains the queue with `npx leglas requests --json` and clears
154
+ it with `--clear`. Leglas runs no model of its own; your agent already
155
+ knows your conventions and your taste.
156
+
157
+ ### MCP server
158
+
159
+ For agent hosts that cannot run shell commands, `leglas-mcp` exposes the
160
+ same operations as MCP tools over stdio: `start`, `add`, `list`, `show`,
161
+ `classify`, `explore`, `scaffold`, `keep`, `requests`, and `init`. Each
162
+ tool calls exactly what the CLI calls and returns the same envelope.
163
+ `watch` is the one command with no tool behind it: it is a loop that
164
+ holds a terminal open, and on a host that speaks channels the server
165
+ already pushes each request into the session as it arrives.
34
166
 
35
- To compare more than one thing, add a config file.
167
+ ```sh
168
+ claude mcp add leglas -- npx -y leglas-mcp
169
+ ```
170
+
171
+ Or in `.mcp.json`:
172
+
173
+ ```json
174
+ { "mcpServers": { "leglas": { "command": "npx", "args": ["-y", "leglas-mcp"] } } }
175
+ ```
176
+
177
+ The host's working directory names the project, the same contract as the
178
+ CLI. A host that starts the server somewhere else is asked where the
179
+ project is, over MCP roots. The `start` tool boots the viewer and returns
180
+ its URL, and anything it started stops when the session ends.
181
+
182
+ ### As an Agent Plugin
183
+
184
+ The repository is also an [Agent Plugin](https://agent-plugins.org), the
185
+ open standard for shipping Agent Skills and MCP server configuration in
186
+ one format. Clients that implement it install the skill and the server
187
+ together, instead of the two steps above. It is a layout rather than a
188
+ build: `plugin.json` and `mcp.json` at the root, the skill in
189
+ `skills/leglas/`, nothing generated.
190
+
191
+ An Agent Plugins client starts a plugin's server in the plugin's own
192
+ install directory rather than the project, so on that path the working
193
+ directory names a copy of Leglas and nothing else. The server therefore
194
+ takes the project from the workspace the host declares over MCP roots,
195
+ and the working directory only when it sits inside one. If a host offers
196
+ neither, `LEGLAS_PROJECT_DIR` names the project outright; without it the
197
+ tools report that there is no project rather than writing into a plugin
198
+ cache. `mcp.json` passes `${PLUGIN_ROOT}` for exactly that check, and
199
+ nothing else.
200
+
201
+ The plugin's version covers the skill and the configuration, not the
202
+ server it launches: `npx` fetches the current `leglas-mcp` the same way
203
+ every `npx leglas` in these instructions fetches the current CLI, which
204
+ keeps both faces of Leglas on one version in a project they share.
36
205
 
37
206
  ## Configuration
38
207
 
39
- Create `leglas.config.ts` at the root of the project you want to preview.
40
- `.js`, `.mjs` and `.json` also work. Config resolution walks upward from the
41
- working directory, so in a monorepo the nearest file wins.
208
+ Create `leglas.config.ts` at the project root. `.js`, `.mjs`, and `.json`
209
+ work too. Resolution walks upward from the working directory, so in a
210
+ monorepo the nearest file wins. Node reads the TypeScript config natively;
211
+ there is no compiler or extra dependency involved.
42
212
 
43
213
  ```ts
44
214
  export default {
45
215
  devServer: "http://localhost:3000",
46
216
  previews: [
47
217
  { title: "Current", url: "/" },
48
- {
49
- title: "Wave",
50
- url: "/?v-hero=wave",
51
- note: "Client artwork, bottom anchored.",
52
- tags: ["Hero"],
53
- },
218
+ { title: "Wave", url: "/?v-hero=wave", note: "Full-bleed, anchored low.", tags: ["Hero"] },
54
219
  {
55
220
  title: "Dot grid",
56
221
  url: "/?v-hero=dotgrid",
57
- note: "Purple lattice that wakes near the pointer.",
222
+ note: "Lattice that wakes near the pointer.",
58
223
  tags: ["Hero"],
59
224
  },
60
225
  ],
61
226
  };
62
227
  ```
63
228
 
64
- | Field | Required | Purpose |
65
- | --- | --- | --- |
66
- | `title` | yes | Label in the rail, and the key for your saved layout |
67
- | `url` | unless `file` | Root relative (`/pricing`) or absolute (`https://staging.example.com`) |
68
- | `note` | no | Second line under the title |
69
- | `tags` | no | The first tag renders as a pill |
70
- | `branch` | no | Preview a git branch instead of the running dev server |
71
- | `file` | no | A project-relative HTML file served by Leglas itself, instead of `url` |
72
- | `devServer` | no | Defaults to `http://localhost:3000` |
73
- | `devCommand` | with `branch` | How to start the app; must contain `{port}`. Also lets Leglas start your own app when nothing is listening |
74
- | `installCommand` | no | Defaults to `npm install` |
75
-
76
- Titles must be unique. A configuration error does not stop the server: it
77
- starts anyway and the interface reports what is wrong, so you can fix the
78
- file without hunting through a stack trace.
79
-
80
- TypeScript config files are read natively by Node, so there is no compiler,
81
- bundler or extra dependency involved.
229
+ | Field | Required | Purpose |
230
+ | ---------------- | ------------- | ----------------------------------------------------------------------- |
231
+ | `title` | yes | Label in the rail, and the key for your saved layout. Must be unique. |
232
+ | `url` | unless `file` | Root relative (`/pricing`) or absolute (`https://staging.example.com`) |
233
+ | `note` | no | Second line under the title |
234
+ | `tags` | no | The first tag renders as a pill |
235
+ | `branch` | no | Preview a git branch instead of the running dev server |
236
+ | `file` | no | An HTML file served by Leglas itself, instead of `url` |
237
+ | `basedOn` | no | Title of the direction this is a variant of; the rail groups the family |
238
+ | `devServer` | no | Defaults to `http://localhost:3000` |
239
+ | `devCommand` | with `branch` | How to start the app. Must contain `{port}`. |
240
+ | `installCommand` | no | Defaults to `npm install` |
241
+
242
+ A broken config never stops the server. Leglas starts anyway and the
243
+ interface reports what to fix, so you are not hunting through a stack
244
+ trace.
245
+
246
+ ## The interface
247
+
248
+ Directions live in a rail on the left. The stage shows the active one in
249
+ a framed viewport at Full, 1440, 834, or 390 wide. Rename, reorder, hide,
250
+ and tag directions from the rail; layout is saved per project and
251
+ survives restarts and port changes.
252
+
253
+ Flipping shows a difference over time. A split shows it at once, which is
254
+ what you want for the last two directions in contention: press `C`, or
255
+ hover a direction and press its compare button, and it becomes the right
256
+ pane while the active direction holds the left.
257
+
258
+ Arrows move between directions, `1` to `9` jump straight to one, `R` asks
259
+ for a change to the one you are on, `Cmd K` (`Ctrl K` elsewhere) searches
260
+ and `B` collapses the rail. Press `?` for the whole keymap.
261
+
262
+ A small tools widget floats over the stage and can be dragged to any
263
+ corner, because a floating control has a habit of sitting exactly where
264
+ you need to look. Its popover holds the viewport presets and a few
265
+ preferences.
266
+
267
+ Frameworks paint a dev badge over the corner of the running app. It
268
+ belongs to your app, so Leglas leaves it alone; when it lands on the part
269
+ you are judging, the popover hides it, and does that by styling inside
270
+ the preview frame, never by altering what the proxy forwards.
82
271
 
83
272
  ## Command line
84
273
 
@@ -86,10 +275,11 @@ bundler or extra dependency involved.
86
275
  leglas init Prepare a project and teach its agents
87
276
  leglas [options] Start the server and open the interface
88
277
  leglas new <surface> Scaffold a branch point for a surface
89
- leglas explore <surface> Print distinct angles for an agent to build
278
+ leglas explore <surface> Brief an agent's exploration of a surface
90
279
  leglas classify Decide where a direction should live
91
280
  leglas add --title T --url U Register a preview on this machine
92
281
  leglas list Show every preview, shared and local
282
+ leglas show <title> Everything Leglas knows about one direction
93
283
  leglas requests Collect change requests made from the interface
94
284
  leglas keep <title> Keep a winner and end the exploration
95
285
 
@@ -97,224 +287,53 @@ leglas keep <title> Keep a winner and end the exploration
97
287
  --port <port> Port for Leglas (default 4100, next free if taken)
98
288
  --config <path> Use this config file instead of searching upward
99
289
  --no-open Do not open the browser
100
- --json Print one machine readable envelope
101
- -h, --help
102
- -v, --version
290
+ --json Print one machine-readable envelope
103
291
 
104
292
  --print (new) Print the scaffold instead of writing it
105
- --count <n> (explore) How many angles, default 3
106
- --to <path> (keep) Where the winner should live
293
+ --from <path> (new) Use an existing component as the baseline
294
+ --count <n> (explore) How many directions, default 3
295
+ --based-on <title> (explore) Variants of an existing direction instead of new ones
296
+ --based-on <title> (add) The direction this preview is a variant of; groups the family
297
+ --change <path> (classify) A file the direction creates or wires up
298
+ --rewrite <path> (classify) An existing file whose behaviour must change
107
299
  --note <text> (add) Second line under the title
108
300
  --tag <text> (add) Repeatable
109
301
  --branch <name> (add) Back the preview with a checkout of this branch
110
- --change <path> (classify) A file the direction creates or wires up
111
- --rewrite <path> (classify) An existing file whose behaviour it must change
112
- ```
113
-
114
- ### Shared and local previews
115
-
116
- `leglas.config.ts` is the shared description of a project: commit it, and a
117
- teammate gets the same directions on clone.
118
-
119
- `leglas add` registers a preview on your machine only, in
120
- `.leglas/previews.json`. Exploration is short-lived and its code lives in a
121
- gitignored directory, so a teammate must never receive a config entry
122
- pointing at something they do not have. `leglas list` shows both, marking
123
- which are local. Any command that writes into `.leglas/` also makes sure the
124
- directory is gitignored.
125
-
126
- ### Working with coding agents
127
-
128
- `leglas init` writes a section into your project's `AGENTS.md`, creates a
129
- starter config, and ignores the working directory. The section is read by
130
- Cursor, Claude Code and most other agents, and needs no per-user setup: it
131
- travels with the clone, so anyone who opens the repository gets an agent that
132
- already knows how to add design directions to it.
133
-
134
- The instruction that matters most in that section is to add directions beside
135
- what exists rather than rewriting it. Asked to make a hero calmer, an agent's
136
- instinct is to edit the hero, and two directions that both rewrite the same
137
- file cannot render from one server. Nothing in Leglas can prevent that,
138
- because it never sees your source, so the contract has to say it.
139
-
140
- Every command accepts `--json` and prints a single envelope with a stable exit
141
- code, so an agent can drive the tool without parsing prose.
142
-
143
- ### Agent hosts that cannot run a shell
144
-
145
- `leglas-mcp` is a stdio MCP server exposing the same operations as tools:
146
- `start`, `add`, `list`, `classify`, `explore`, `scaffold`, `keep`,
147
- `requests`, and `init`. It holds no logic of its own; each tool calls
148
- exactly what the CLI calls and returns the same JSON envelope.
149
-
150
- Register it in your agent host from the project directory, for example in
151
- Claude Code:
152
-
153
- ```sh
154
- claude mcp add leglas -- npx -y leglas-mcp
155
- ```
156
-
157
- or in a `.mcp.json`:
158
-
159
- ```json
160
- { "mcpServers": { "leglas": { "command": "npx", "args": ["-y", "leglas-mcp"] } } }
161
- ```
162
-
163
- The host's working directory names the project, the same contract as the
164
- CLI. The `start` tool boots the viewer and returns the interface URL, and
165
- the server it started stops when the session ends, so a dead host never
166
- leaves a dev server running on a forgotten port.
167
-
168
- ### When a direction cannot be additive
169
-
170
- Most directions are additive: new files beside what exists, rendering from
171
- the dev server you already run. Some genuinely are not. A direction that
172
- changes dependencies, changes build configuration, or only works by
173
- rewriting what an existing file renders cannot share the running server
174
- with its siblings.
175
-
176
- `leglas classify` decides which kind you have, before the code is written.
177
- Declare what the direction will touch and it answers with the route and the
178
- reason:
179
-
180
- ```sh
181
- leglas classify --change package.json --rewrite src/theme.css --json
302
+ --file <path> (add) An HTML file served by Leglas itself
303
+ --to <path> (keep) Where the winner should live
182
304
  ```
183
305
 
184
- `--change` marks a file the direction creates or wires up; `--rewrite`
185
- marks an existing file whose behaviour it must alter. The answer is either
186
- `in-app`, the ordinary path under `.leglas/variants/`, or `checkout`: build
187
- the direction on its own git branch and register it with
188
- `leglas add --title "Calm" --url "/" --branch <branch>`. Branch-backed
189
- previews need `devCommand` in the config so Leglas can start the checkout,
190
- and they appear in the same rail as everything else.
191
-
192
- The escalation is the exception, and it is never silent: isolation costs an
193
- install and a boot, so a direction goes to a checkout only when it names a
194
- reason it cannot sit in the running app.
195
-
196
- ### Exploring several directions at once
197
-
198
- `leglas explore hero --count 6` prints six distinct angles to build, each with
199
- a line naming the obvious approach that would collapse the difference. Left to
200
- itself an agent iterates narrowly around its first idea, so six requests come
201
- back as six shades of one design. The angles vary composition, medium, density,
202
- motion, texture and palette rather than colour alone, and they are ordered for
203
- spread so asking for three still explores widely.
204
-
205
- The `AGENTS.md` section tells agents to run this first, so "give me a few
206
- options" reaches for the angles instead of inventing variations of what is
207
- already there.
208
-
209
- ### Asking for a change without leaving
210
-
211
- The tools popover has a field for the direction you are looking at. Type what
212
- you want changed and press Enter: Leglas composes a prompt naming that
213
- direction and the file behind it, copies it to your clipboard, and queues it.
214
-
215
- Leglas runs no model of its own. Your agent already knows your conventions,
216
- your design system and your taste, which is context no external worker has, so
217
- it does the work. `leglas requests --json` hands over anything pending and
218
- `leglas requests --clear` empties the queue once it is done. If you would
219
- rather not wire that up, the clipboard copy is the whole feature: paste and
220
- go.
221
-
222
- ### Scaffolding a surface
223
-
224
- `leglas new hero --from src/Hero.tsx` creates a switcher and a first direction
225
- under `.leglas/variants/hero/`, and adds `.leglas/` to your `.gitignore`.
226
-
227
- `--from` points at whatever renders that surface today. The baseline then
228
- re-exports that component rather than copying it, so editing the real
229
- component changes the baseline too and you are never comparing against a stale
230
- duplicate of your own code. Without `--from` you get a placeholder to fill in
231
- yourself. The
232
- generated code is ordinary application code: it imports nothing from Leglas,
233
- so removing the tool leaves it working. It also renders the fallback in
234
- production regardless of the URL, so a branch point that reaches a deployed
235
- build cannot expose an unreleased direction.
236
-
237
- One step is left to you. Leglas prints the import and the element to use, but
238
- does not edit the component itself, because rewriting a file it does not
239
- understand is how a tool breaks a codebase. Use `--print` to see the scaffold
240
- without writing anything.
241
-
242
- `--json` exists so coding agents can drive the tool. It prints a single
243
- object with the interface URL, the resolved port, whether the dev server
244
- answered, and any configuration errors.
245
-
246
- ## Keyboard
247
-
248
- | Key | Action |
249
- | --- | --- |
250
- | Up, Down | Move between directions |
251
- | `\` | Split the stage against the direction you were last on |
252
- | `/` | Focus search |
253
- | `[` | Collapse or open the rail |
254
- | Escape | Clear search, or close the tools popover |
255
-
256
- Directions can be renamed, removed, restored and dragged into any order.
257
- Layout is saved per project, so it survives restarts and a change of port.
258
-
259
- ### Comparing two at once
260
-
261
- Flipping shows a difference over time. A split shows it at once, which is what
262
- you want for the last two directions still in contention.
263
-
264
- Hover any direction in the rail and press its compare button. It becomes the
265
- right pane, the active direction stays on the left, and the row is marked so
266
- you can see what you are comparing against without hovering. Press it again to
267
- close the split. `\` splits against whichever direction you were looking at
268
- before this one.
269
-
270
- The tools widget can be dragged to any corner, since a floating control has a
271
- habit of sitting exactly where you need to look. Its corner is remembered.
272
-
273
- Frameworks paint their own dev badge over the running app, which lands on the
274
- same corner and is tooling rather than design. Leglas hides those by default,
275
- and the popover turns them back on. This is done by styling inside the
276
- preview frame, never by altering what the proxy forwards, so what your dev
277
- server sent is what your app receives.
278
-
279
- ## How it works
280
-
281
- Leglas runs a local server that does two things. It serves the interface at
282
- `/leglas`, and it forwards every other request to your dev server. Because
283
- previews load through that proxy, they are same origin with the interface,
284
- which means no CORS configuration and no special cases for cookies.
285
-
286
- The proxy is designed to be invisible. Hot module replacement survives the
287
- hop, so editing a file still updates every preview. Redirects that point at
288
- your dev server are rewritten to keep you inside the interface, and
289
- redirects to anywhere else are left alone. Responses stream rather than
290
- buffer. If an app behaves differently through Leglas than it does on its own
291
- port, that is a bug.
306
+ `leglas.config.ts` is the shared description of a project: commit it and a
307
+ teammate gets the same directions on clone. `leglas add` registers a
308
+ preview on your machine only, in `.leglas/previews.json`, because
309
+ exploration is short-lived and its code lives in a gitignored directory.
310
+ `leglas list` shows both and marks which are local.
292
311
 
293
- ## Comparing more than design variants
312
+ Renaming a direction in the rail is local in the same way, recorded in
313
+ `.leglas/renames.json`. Leglas will not edit your config to rename
314
+ something you only renamed for yourself, so the config title stays the
315
+ one a teammate sees, and `leglas show` and `leglas keep` take either
316
+ name.
294
317
 
295
- A preview is a URL, so the same interface compares anything your server can
296
- serve:
318
+ ## Comparing branches
297
319
 
298
- - Two implementations of a surface, selected by a query parameter
299
- - Two routes, such as `/pricing` against `/pricing-v2`
300
- - A local server against a deployed one
320
+ A preview with a `branch` field is served from its own checkout: Leglas
321
+ creates a worktree, installs, starts the app with your `devCommand` on a
322
+ free port, and tears it all down when you quit. In the interface it looks
323
+ like any other direction, so a branch against your working tree, or three
324
+ branches against each other, compares the same way two query parameters
325
+ do.
301
326
 
302
- Absolute URLs load directly rather than through the proxy, so they are
303
- subject to the target's frame policy. A site that refuses to be framed will
304
- not preview, and the interface says so rather than showing an empty pane.
305
-
306
- ## Starting before you have an app
327
+ ## Without a dev server
307
328
 
308
329
  Leglas does not require a running app.
309
330
 
310
- **If the project exists but nothing is listening**, set `devCommand` in the
311
- config (with `{port}`) and Leglas starts your app itself on a free port,
312
- proxies it, and stops it when you quit, exactly as it does for branch
313
- checkouts. This is reported as status, never asked as a question. When
331
+ If the project exists but nothing is listening, set `devCommand` and
332
+ Leglas starts your app itself, proxies it, and stops it on exit. When
314
333
  `--user-port` names a server explicitly, Leglas never starts a different
315
334
  one behind that flag.
316
335
 
317
- **If there is no app at all**, a direction can be a plain HTML file:
336
+ If there is no app at all, a direction can be a plain HTML file:
318
337
 
319
338
  ```ts
320
339
  export default {
@@ -325,44 +344,48 @@ export default {
325
344
  };
326
345
  ```
327
346
 
328
- Leglas serves each file itself, from its own origin, so the full rail,
329
- stage, viewports, and split comparison work with no dev server anywhere.
330
- The file's directory is mounted rather than the lone file, so stylesheets
331
- and images beside it resolve normally. `leglas add --title "Aurora" --file
332
- .leglas/pages/aurora.html` registers one from the command line, and the
333
- AGENTS.md section teaches agents the same loop, so "show me three landing
334
- page directions" works in an empty repository. When the real app arrives,
335
- directions graduate to app code and nothing about the interface changes.
336
-
337
- ## When two directions render the same page
347
+ Leglas serves each file from its own origin, so the full interface works
348
+ with no dev server anywhere. The file's directory is mounted rather than
349
+ the lone file, so stylesheets and images beside it resolve. When the real
350
+ app arrives, directions graduate to app code and nothing about the
351
+ interface changes.
338
352
 
339
- Leglas compares what each preview actually draws and warns when two of them are
340
- identical. This catches the failure that is otherwise invisible: a typo like
341
- `?v-hero=wavee` that your app ignores, serving its default page while the rail
342
- implies you are comparing something.
343
-
344
- The comparison reads the rendered page rather than the server's response, so it
345
- works whether your app renders on the server or in the browser. A single-page
346
- app returns the same HTML for every URL, which makes any server-side comparison
347
- useless there.
353
+ ## How it works
348
354
 
349
- Previews are compared once they have been opened, and a preview served from
350
- another origin is never compared, because the browser will not let one page read
351
- another origin's content. Nothing here blocks the interface, and it stays quiet
352
- rather than guessing.
355
+ Leglas runs one local server that serves the interface at `/leglas` and
356
+ forwards every other request to your dev server. Previews load through
357
+ that proxy, so they are same origin with the interface: no CORS
358
+ configuration, no cookie special cases.
359
+
360
+ The proxy is designed to be invisible. Hot module replacement survives
361
+ the hop, redirects that point at your dev server are rewritten to keep
362
+ you inside the interface, and responses stream rather than buffer. If an
363
+ app behaves differently through Leglas than on its own port, that is a
364
+ bug.
365
+
366
+ Because a preview is a URL, the same interface compares two routes, two
367
+ implementations behind a query parameter, or a local server against a
368
+ deployed one. Absolute URLs load directly rather than through the proxy,
369
+ so a site that refuses to be framed will not preview; the interface says
370
+ so instead of showing an empty pane.
371
+
372
+ Leglas also compares what each preview actually draws and warns when two
373
+ are identical. This catches a typo like `?v-hero=wavee` that your app
374
+ silently ignores while the rail implies a comparison. The check reads the
375
+ rendered page, runs only on previews you have opened, and skips
376
+ cross-origin previews, which the browser will not let it read.
353
377
 
354
378
  ## Limitations
355
379
 
356
- Leglas shows design directions. It does not create them. Comparing routes
357
- that already exist costs nothing, but a new direction is still code you or
358
- your agent writes in the app.
359
-
360
- Only the rendered markup is compared for duplicates, and only when the server
361
- renders one. Two previews that differ solely in a script are reported as the
362
- same, and in a client-rendered app the check says nothing at all.
363
-
364
- The interface is built for desktop widths. It is a development tool and is
365
- not intended to ship in a production runtime.
380
+ - Leglas shows directions; it does not create them. Comparing existing
381
+ routes costs nothing, but a new direction is still code you or your
382
+ agent writes.
383
+ - The duplicate check compares rendered markup only, and only when the
384
+ server renders some. Two previews that differ solely in a script are
385
+ reported as identical, and in a fully client-rendered app the check
386
+ says nothing.
387
+ - The interface is built for desktop widths.
388
+ - Leglas is a development tool. Nothing in it ships to production.
366
389
 
367
390
  ## Development
368
391
 
@@ -375,17 +398,22 @@ pnpm test # run the test suite
375
398
  pnpm typecheck # type check every package
376
399
  ```
377
400
 
378
- | Package | Contents |
379
- | --- | --- |
380
- | `packages/server` | Config loading, the proxy, and the local server |
381
- | `packages/shell` | The interface, a React application built with Vite |
382
- | `packages/cli` | The `leglas` binary |
383
- | `packages/mcp` | The `leglas-mcp` stdio server for agent hosts |
401
+ | Package | Contents |
402
+ | ----------------- | -------------------------------------------------- |
403
+ | `packages/server` | Config loading, the proxy, and the local server |
404
+ | `packages/shell` | The interface, a React application built with Vite |
405
+ | `packages/cli` | The `leglas` binary |
406
+ | `packages/mcp` | The `leglas-mcp` stdio server for agent hosts |
384
407
 
385
408
  To work on the interface with live reload, run a Leglas server in one
386
- terminal and `pnpm --filter @leglas/shell dev` in another. The dev server
387
- proxies the API through to port 4100.
409
+ terminal and `pnpm --filter @leglas/shell dev` in another.
410
+
411
+ Two packages are published, both unscoped: `leglas`, which bundles the
412
+ server and the built interface, and `leglas-mcp`. Releases are
413
+ tag-driven: bump both versions, push a `v<version>` tag, and CI runs the
414
+ suite and publishes through npm trusted publishing. No npm token exists
415
+ anywhere in the project.
388
416
 
389
417
  ## License
390
418
 
391
- MIT
419
+ [MIT](LICENSE)