begeniux 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,119 +1,110 @@
1
1
  # begeniux
2
2
 
3
- **Behaviorally-adaptive UI through LLM agents and the AG-UI protocol.**
3
+ **Drop-in adaptive UI engine. Tracks user behavior, asks an agent for a CSS-level adaptation plan, mutates the live DOM in real time.**
4
4
 
5
- Most generative UI today reacts to *prompts*. **BeGeniux reacts to behavioral traces** clicks, scrolls, hovers, dwells and re-renders the UI to match observed user behavior, in real time, at session granularity.
5
+ Today's UX cycle is slow: research mock ship iterate. begeniux short-circuits it: install the library on an existing app, the agent observes how each user actually behaves, and the UI re-shapes itself live to match accent colors, density, emphasis, microcopy. No variants pre-baked. No design committee. Personalization happens *during the session*.
6
6
 
7
- You wrap a region of UI in `<BeGenSurface>`, pass in a set of variant components and a `classify` function. The library handles behavior tracking, summarization, and variant swapping. Bring your own LLM — Gemini, Claude, OpenAI, a heuristic, anything that satisfies `ClassifyFn`.
8
-
9
- ---
7
+ ```bash
8
+ npm install begeniux
9
+ ```
10
10
 
11
- ## Why this exists
11
+ ```tsx
12
+ <CopilotKitProvider runtimeUrl="/api/copilotkit">
13
+ <BeGenProvider designSystem={designSystem} pageContext={{ route: "/" }}>
14
+ <CopilotKitAdapter />
15
+ <App /> {/* unmodified existing app */}
16
+ </BeGenProvider>
17
+ </CopilotKitProvider>
18
+ ```
12
19
 
13
- Adaptive UI research is 30+ years old. SUPPLE (2004) showed UIs could regenerate per-user. Contextual bandits (2010) showed online learning could pick layouts. Implicit-feedback work (2005) showed clicks already encode preference. None of this shipped at scale. Why?
20
+ That's the whole integration. The library tracks behavior universally, hands a behavior summary + your design system + a DOM snapshot to your LangGraph (or any) agent, and applies the agent's `apply_adaptations` tool calls to the live DOM with full reversibility.
14
21
 
15
- - **Hand-coded rules** couldn't keep up with the combinatorics of real UIs.
16
- - **Shallow ML** needed huge population-level traffic to converge — too slow for a single session.
17
- - **A/B tests** optimize *populations*, not *individuals* — the wrong granularity.
22
+ ---
18
23
 
19
- In-context learning (GPT-3 onward) finally cracked it. An LLM can reason from a handful of behavioral signals to a sensible UI choice, **without training, without traffic, in one session**. That's the unlock.
24
+ ## Why this exists
20
25
 
21
26
  ```mermaid
22
27
  flowchart LR
23
28
  subgraph Trad["Today's generative UI"]
24
29
  direction LR
25
- P["💬 User<br/>prompt"] --> M1["LLM"] --> U1["Generated UI"]
30
+ P["💬 Prompt"] --> M1["LLM"] --> U1["Generated UI"]
26
31
  end
27
32
  subgraph Be["BeGeniux"]
28
33
  direction LR
29
- B["🖱️ Behavioral trace<br/>clicks · scrolls · hovers · dwells"] --> M2["LLM<br/>as policy"] --> U2["Adapted UI<br/>session-granular"]
34
+ B["🖱️ Behavioral trace<br/>clicks · dwell · scroll · hover<br/>focus · input · errors · rage clicks"] --> M2["Agent<br/>(your LangGraph)"] --> U2["Live DOM mutation<br/>session-granular"]
30
35
  end
31
36
  Trad ~~~ Be
32
37
  ```
33
38
 
34
- > Our contribution is the combination of three ideas that have not been combined before: **interaction traces as the input modality** (not text prompts), **LLM agents as the policy** (not hand-coded rules or shallow classifiers), and **session-granularity adaptation** (not population-level A/B tests) under developer-declared invariants that keep the policy honest. The first two are 2024+ technology that finally make 30 years of adaptive UI research tractable.
35
-
36
- ### The goal
39
+ > Most generative UI today reacts to *prompts*. begeniux reacts to *behavioral traces*. The contribution is the combination: **interaction traces as the input modality**, **LLM agents as the policy** (not hand-coded rules), **session-granularity adaptation** (not population A/B tests), and **mutation of the existing UI** (not replacement of pre-built variants) under developer-declared design-system invariants that keep the agent honest.
37
40
 
38
- Make any web region **behaviorally adaptive** with one component swap. The developer keeps full control of the variants the library only decides *which* one is rendered, *when*, and *why* (with the LLM's reasoning string attached).
41
+ The first three are 2024+ technology that finally make 30 years of adaptive UI research tractable. The fourth is what makes it *drop-in*.
39
42
 
40
43
  ---
41
44
 
42
45
  ## How it works
43
46
 
44
- Every `<BeGenSurface>` runs a tight loop, scoped to its own DOM region:
45
-
46
47
  ```mermaid
47
48
  sequenceDiagram
48
49
  autonumber
49
50
  participant U as User
50
- participant T as useBehaviorTracker
51
- participant S as BeGenSurface
52
- participant C as classify (your code)
53
- participant V as Active variant
54
-
55
- U->>T: clicks · scrolls · hovers · dwells
56
- Note over T: Ring buffer of last 50 events<br/>(scoped to this surface only)
57
- T->>T: Every 10 events OR 5s →<br/>compute BehaviorSummary
58
- T->>S: BehaviorSummary
59
- S->>S: rate-limit gate (≥4s since last call)
60
- S->>C: classify(summary)
61
- Note over C: Your LLM / AG-UI route /<br/>heuristic — anything matching ClassifyFn
62
- C-->>S: AgentDirective<br/>{variant, confidence, reasoning}
63
- S->>V: mount variants[directive.variant]<br/>with variantProps
64
- V->>U: new UI · 2s round-trip
51
+ participant T as Behavior tracker
52
+ participant P as BeGenProvider
53
+ participant A as Agent (your LangGraph)
54
+ participant E as AdaptationEngine
55
+ participant D as Live DOM
56
+
57
+ U->>T: clicks · scrolls · hovers · dwells · focuses · inputs · errors
58
+ Note over T: Ring buffer · 12 event kinds · plug-in extension API
59
+ T->>T: every N events / M ms → BehaviorSummary
60
+ T->>P: summary
61
+ P->>P: rate-limit gate (≥5s default) + change detection
62
+ P->>A: { summary, designSystem, dom: visibleSelectors }
63
+ Note over A: Agent reasons over signal,<br/>your design system tokens,<br/>and what's visible on the page
64
+ A-->>E: apply_adaptations(plan)
65
+ Note over E: Validates against scope.allow / deny.<br/>Reverts previous plan first.<br/>Tracks every mutation for clean rollback.
66
+ E->>D: set CSS var · add class · set style · set attribute
67
+ D->>U: UI shifts in real time
65
68
  ```
66
69
 
67
70
  Three things keep this honest:
68
71
 
69
- 1. **Listeners scoped to the container element**, not `window` two surfaces side-by-side never cross-pollute events.
70
- 2. **Rate limit on `classify`** (default 4s)caps cost and prevents thrash.
71
- 3. **Errors keep the current variant.** A classifier failure never crashes the UI; the user just stays on what they had.
72
+ 1. **Listeners scoped to the provider's container** (default `document.body`). Universal coverage, opt-in narrower scope via `containerRef`.
73
+ 2. **CSS-only mutations.** No `display`, no `position`, no structural reshuffles in v0.2 the engine refuses them. Layout cannot break.
74
+ 3. **Plan-level reversibility.** Every new plan reverts the previous one before applying. Mutations never accumulate. Provider unmount restores the page completely.
72
75
 
73
76
  ---
74
77
 
75
78
  ## Where it fits in your stack
76
79
 
77
- The library is one layer. You bring your variants and your policy:
78
-
79
80
  ```mermaid
80
81
  flowchart TB
81
- subgraph YourApp["Your application"]
82
- direction TB
83
- Page["Page / Route"]
84
- Variants["Your variant components<br/>DenseGrid · DeliberateGrid · NeutralGrid"]
85
- Classify["Your classify function"]
86
- Page --> Surface
87
- Surface -->|renders one of| Variants
88
- Surface -->|invokes| Classify
89
- end
90
-
91
- subgraph Lib["begeniux (this package)"]
92
- direction TB
93
- Surface["&lt;BeGenSurface&gt;"]
94
- Provider["&lt;BeGenProvider&gt;"]
95
- Tracker["useBehaviorTracker"]
96
- Ctx["BeGenContext"]
97
- Surface -.uses.-> Tracker
98
- Surface -.publishes to.-> Ctx
99
- Provider -.exposes.-> Ctx
82
+ subgraph YourApp["Your application (drop-in)"]
83
+ Page["Pages / Components"]
84
+ Provider["BeGenProvider"]
85
+ Adapter["CopilotKitAdapter<br/>(or HTTP adapter)"]
86
+ Page --> Provider
87
+ Provider -.contains.-> Tracker["useBehaviorTracker"]
88
+ Provider -.contains.-> Engine["AdaptationEngine"]
89
+ Provider -.contains.-> Snapshot["domSnapshot"]
90
+ Adapter --> Provider
100
91
  end
101
92
 
102
- subgraph Policy["Behind your classify fn (you choose)"]
93
+ subgraph Stack["Agent layer (your choice)"]
103
94
  direction TB
104
- Gemini["Gemini 2.0 Flash<br/>via createGeminiClassifier"]
105
- AGUI["AG-UI / CopilotKit route"]
106
- Anth["Claude / OpenAI / local model"]
107
- Heur["createHeuristicClassifier<br/>(zero-dep fallback)"]
95
+ CK["CopilotKit Runtime<br/>+ LangGraph"]
96
+ HTTP["Custom HTTP route<br/>(any framework)"]
97
+ Other["Anything that satisfies<br/>ClassifyFn"]
108
98
  end
109
99
 
110
- Classify -.-> Gemini
111
- Classify -.-> AGUI
112
- Classify -.-> Anth
113
- Classify -.-> Heur
100
+ Adapter -.canonical.-> CK
101
+ Adapter -.escape hatch.-> HTTP
102
+ Adapter -.also fine.-> Other
114
103
  ```
115
104
 
116
- **Nothing in this library imports CopilotKit, AG-UI SDK, Next.js, or any LLM SDK.** It runs anywhere React 18+ runs. The agent backend is a `ClassifyFn` injection that's the entire integration surface.
105
+ The library has **zero opinions** about your agent backend. CopilotKit + LangGraph + Gemini is the canonical hackathon stack and the easiest path; the HTTP adapter and the `useBehaviorTracker` / `AdaptationEngine` escape hatches let you wire anything else.
106
+
107
+ Peer-deps: `react`, `react-dom` (>=18). `@copilotkit/react-core` and `zod` are **optional** peers, only needed if you import the CopilotKit adapter.
117
108
 
118
109
  ---
119
110
 
@@ -121,190 +112,288 @@ flowchart TB
121
112
 
122
113
  Three types are the entire boundary between your code and the library:
123
114
 
124
- ```mermaid
125
- flowchart LR
126
- E["BehaviorEvent[]<br/><i>click · scroll · hover · dwell</i>"]
127
- S["BehaviorSummary<br/><i>clicks_per_min, avg_dwell_ms,<br/>scroll_depth, hover_count,<br/>events_seen, page_context</i>"]
128
- D["AgentDirective<br/><i>variant · confidence · reasoning</i>"]
129
- V["Rendered variant"]
130
-
131
- E -->|tracker aggregates| S
132
- S -->|ClassifyFn = your policy| D
133
- D -->|surface selects| V
134
- ```
135
-
136
- In code:
137
-
138
115
  ```ts
139
- type ClassifyFn = (summary: BehaviorSummary) => Promise<AgentDirective>;
140
-
141
- type BehaviorSummary = {
142
- clicks_per_min: number;
143
- avg_dwell_ms: number;
144
- scroll_depth: number; // 0–1
145
- hover_count: number;
146
- events_seen: number; // saturates at 50
147
- page_context: { route: string; visible_product_ids: string[] };
116
+ type ClassifyFn<TContext = { route: string }> =
117
+ (input: AdaptInput<TContext>) => Promise<AdaptationPlan>;
118
+
119
+ type AdaptInput<TContext> = {
120
+ summary: BehaviorSummary<TContext>; // 12 event kinds, aggregated
121
+ designSystem: DesignSystem; // your vocabulary (CSS vars + classes)
122
+ dom: { visibleSelectors: string[]; route: string }; // what's on screen
148
123
  };
149
124
 
150
- type AgentDirective = {
151
- variant: "decisive" | "deliberate" | "neutral";
152
- confidence: number; // 01
153
- reasoning: string; // one-sentence English
125
+ type AdaptationPlan = {
126
+ adaptations: Adaptation[];
127
+ confidence: number; // 0..1; engine skips below threshold
128
+ reasoning: string;
154
129
  };
130
+
131
+ type Adaptation =
132
+ | { kind: "set-css-var"; selector: string; name: string; value: string }
133
+ | { kind: "add-class"; selector: string; className: string }
134
+ | { kind: "remove-class"; selector: string; className: string }
135
+ | { kind: "set-style"; selector: string; property: string; value: string }
136
+ | { kind: "set-attribute"; selector: string; name: string; value: string }
137
+ | { kind: "set-aria-label"; selector: string; value: string };
155
138
  ```
156
139
 
157
- Whatever you put behind `ClassifyFn` Gemini, Claude, OpenAI, a CopilotKit/AG-UI route, a hand-tuned regex it's the policy that decides which variant the user sees. Freeze these types and the library and your agent backend evolve independently. See [`src/types.ts`](./src/types.ts) for the canonical definitions.
140
+ The full type contractincluding `BehaviorSummary`, `DesignSystem`, `BeGenProviderProps`lives in [`src/types.ts`](./src/types.ts).
158
141
 
159
142
  ---
160
143
 
161
- ## Install
144
+ ## Quick start (CopilotKit + LangGraph)
162
145
 
163
- ```bash
164
- npm install begeniux
146
+ The canonical wiring. See [`examples/with-copilotkit/`](./examples/with-copilotkit/README.md) for the full snippet, including the LangGraph node side.
147
+
148
+ ```tsx
149
+ import { CopilotKitProvider } from "@copilotkit/react-core/v2";
150
+ import { BeGenProvider, type DesignSystem } from "begeniux";
151
+ import { CopilotKitAdapter } from "begeniux/copilotkit";
152
+
153
+ const designSystem: DesignSystem = {
154
+ cssVariables: {
155
+ "--accent": { description: "Action color", type: "color", defaultValue: "#7c3aed" },
156
+ "--density": { description: "Layout density", type: "length", defaultValue: "16px" },
157
+ },
158
+ classes: {
159
+ "is-engaged": "High-engagement treatment",
160
+ "is-skimming": "Low-engagement treatment",
161
+ },
162
+ };
163
+
164
+ export default function App() {
165
+ return (
166
+ <CopilotKitProvider runtimeUrl="/api/copilotkit">
167
+ <BeGenProvider designSystem={designSystem} pageContext={{ route: "/" }}>
168
+ <CopilotKitAdapter />
169
+ <YourApp />
170
+ </BeGenProvider>
171
+ </CopilotKitProvider>
172
+ );
173
+ }
165
174
  ```
166
175
 
167
- Peer dependencies: `react@>=18`, `react-dom@>=18`. The library has zero runtime dependencies and works without CopilotKit, AG-UI, or any specific LLM SDK.
176
+ The agent gets a frontend tool called `apply_adaptations`. Whenever it decides the UI should change, it calls the tool — begeniux applies the plan, the DOM shifts, the user sees a different UI without a reload.
177
+
178
+ ---
168
179
 
169
- ## Quick start
180
+ ## Quick start (HTTP — any backend)
181
+
182
+ Don't use CopilotKit? Wire any HTTP endpoint:
170
183
 
171
184
  ```tsx
172
- import {
173
- BeGenProvider,
174
- BeGenSurface,
175
- createGeminiClassifier,
176
- } from "begeniux";
177
-
178
- const classify = createGeminiClassifier({
179
- apiKey: process.env.NEXT_PUBLIC_GEMINI_KEY!,
185
+ import { BeGenProvider, createHttpAdapter } from "begeniux";
186
+
187
+ const classify = createHttpAdapter({
188
+ url: "/api/begen/adapt", // your endpoint
189
+ // POST { summary, designSystem, dom } { adaptations, confidence, reasoning }
180
190
  });
181
191
 
182
- export default function App({ products }) {
192
+ <BeGenProvider designSystem={designSystem} pageContext={{ route: "/" }} classify={classify}>
193
+ <YourApp />
194
+ </BeGenProvider>
195
+ ```
196
+
197
+ Your endpoint can call Gemini, Claude, OpenAI, a Python service, anything. You shape the response into `AdaptationPlan` and the library handles the rest.
198
+
199
+ ---
200
+
201
+ ## Quick start (no agent — heuristic / offline / demo)
202
+
203
+ Pass a function inline. No network, no LLM. Useful for demos, tests, offline dev:
204
+
205
+ ```tsx
206
+ const classify: ClassifyFn = async ({ summary }) => {
207
+ const engaged = summary.clicks_per_min > 6;
208
+ return {
209
+ adaptations: [
210
+ {
211
+ kind: "set-css-var",
212
+ selector: ":root",
213
+ name: "--accent",
214
+ value: engaged ? "#dc2626" : "#2563eb",
215
+ },
216
+ ],
217
+ confidence: 0.8,
218
+ reasoning: engaged ? "Fast pace" : "Calm pace",
219
+ };
220
+ };
221
+ ```
222
+
223
+ See [`examples/basic/`](./examples/basic/) for a complete runnable demo using this pattern.
224
+
225
+ ---
226
+
227
+ ## Reading state from children
228
+
229
+ ```tsx
230
+ import { useBeGenContext } from "begeniux";
231
+
232
+ function Telemetry() {
233
+ const { summary, lastPlan, appliedAdaptations } = useBeGenContext();
183
234
  return (
184
- <BeGenProvider>
185
- <BeGenSurface
186
- variants={{
187
- decisive: DenseGrid,
188
- deliberate: DeliberateGrid,
189
- neutral: NeutralGrid,
190
- }}
191
- variantProps={{ products }}
192
- classify={classify}
193
- pageContext={{
194
- route: "/products",
195
- visible_product_ids: products.map((p) => p.id),
196
- }}
197
- />
198
- </BeGenProvider>
235
+ <pre>
236
+ events: {summary?.events_seen} ·
237
+ clicks/min: {summary?.clicks_per_min} ·
238
+ reasoning: {lastPlan?.reasoning} ·
239
+ mutations: {appliedAdaptations.length}
240
+ </pre>
199
241
  );
200
242
  }
201
243
  ```
202
244
 
203
- That's the whole integration. The surface tracks behavior in its DOM region, calls `classify` on a debounce, and swaps the rendered variant component when the directive changes.
245
+ Use it for debug overlays, telemetry strips, analytics pipelines, or to make components react to the agent's reasoning.
204
246
 
205
- ## API
247
+ ---
248
+
249
+ ## API surface
206
250
 
207
251
  | Export | What it does |
208
252
  |---|---|
209
- | `<BeGenProvider>` | Context provider for surface state. Required if you want to call `useBeGenContext()` from a child. |
210
- | `<BeGenSurface>` | The main component. Tracks behavior, calls `classify`, renders the active variant. |
211
- | `useBehaviorTracker(opts)` | Low-level hook for custom integrations same engine the surface uses. |
212
- | `useBeGenContext()` | Reads the current `variant`, `directive`, and `summary` from context. |
213
- | `createGeminiClassifier(opts)` | Returns a `ClassifyFn` that calls Google's Gemini API directly. |
214
- | `createHeuristicClassifier()` | Zero-dependency heuristic fallback. Useful for offline dev and demos. |
215
- | `PERSONAS` | Pre-canned behavior traces (`decisive`, `deliberate`) for deterministic demos via `seedPersona`. |
253
+ | Export | Where | What it does |
254
+ |---|---|---|
255
+ | `<BeGenProvider>` | `begeniux` | The provider. Tracks behavior, holds the engine, gates triggers, runs `classify`, exposes context. Drop-in. |
256
+ | `useBeGenContext()` | `begeniux` | Read the latest summary, last plan, applied adaptations, plus an `applyPlan(plan)` escape hatch. |
257
+ | `createHttpAdapter(opts)` | `begeniux` | Returns a `ClassifyFn` that posts the `AdaptInput` to your URL. Generic transport. |
258
+ | `useBehaviorTracker(opts)` | `begeniux` | Low-level hook used by the provider. Reach for it if you need a tracker outside a provider context. |
259
+ | `AdaptationEngine` | `begeniux` | Low-level class. Apply, revert, query mutations directly if you don't want a provider at all. |
260
+ | `snapshotVisibleSelectors(root, opts)` | `begeniux` | Returns a list of stable CSS selectors visible in the viewport. Useful when building your own classify fn. |
261
+ | `<CopilotKitAdapter />` | `begeniux/copilotkit` | Mount inside `<BeGenProvider>` to register `apply_adaptations` as a CopilotKit frontend tool. |
262
+ | `useCopilotKitAdapter(opts)` | `begeniux/copilotkit` | Hook variant of `<CopilotKitAdapter />`. |
263
+
264
+ The `/copilotkit` subpath is split out so consumers who don't use CopilotKit don't pull `@copilotkit/react-core` (and its transitive deps like KaTeX) into their bundle.
216
265
 
217
- Full type signatures live in [`src/types.ts`](./src/types.ts) — that file is the contract between the library and the consumer (also visualized [above](#the-contract)).
266
+ All exports are documented in [`src/index.ts`](./src/index.ts).
218
267
 
219
- ## Wiring AG-UI / CopilotKit
268
+ ---
220
269
 
221
- The library is intentionally agnostic to the agent backend. To route through CopilotKit/AG-UI, write a thin `ClassifyFn`:
270
+ ## What goes in the design system
222
271
 
223
- ```tsx
224
- const classify: ClassifyFn = async (summary) => {
225
- const res = await fetch("/api/copilotkit", {
226
- method: "POST",
227
- headers: { "content-type": "application/json" },
228
- body: JSON.stringify({ tool: "classify_behavior", summary }),
229
- });
230
- return res.json();
272
+ The design system is the **vocabulary the agent is allowed to speak**. Two tiers:
273
+
274
+ ```ts
275
+ const designSystem: DesignSystem = {
276
+ cssVariables: {
277
+ "--accent": { description: "Action color", type: "color", defaultValue: "#7c3aed" },
278
+ "--density": { description: "Layout density", type: "length", defaultValue: "16px" },
279
+ "--font-scale": {
280
+ description: "Font multiplier",
281
+ type: "number",
282
+ range: [0.8, 1.4],
283
+ defaultValue: "1",
284
+ },
285
+ "--surface-emphasis": {
286
+ description: "Which surface gets visual emphasis",
287
+ type: "enum",
288
+ values: ["price", "reviews", "imagery", "specs"],
289
+ defaultValue: "price",
290
+ },
291
+ },
292
+ classes: {
293
+ "is-engaged": "Visual treatment for engaged users",
294
+ "is-skimming": "Visual treatment for low-engagement",
295
+ "is-cta-prominent": "Boost CTA emphasis",
296
+ },
297
+ examples: [
298
+ {
299
+ adaptations: [
300
+ { kind: "set-css-var", selector: ":root", name: "--density", value: "10px" },
301
+ ],
302
+ confidence: 0.85,
303
+ reasoning: "Compact dense view for engaged user.",
304
+ },
305
+ ],
231
306
  };
232
307
  ```
233
308
 
234
- Your route is responsible for invoking the agent and returning a JSON body that matches `AgentDirective`. The library never imports CopilotKit directly keeping the package install-anywhere.
309
+ The agent receives this manifest as part of every `AdaptInput`, so it knows exactly which knobs are turnable and what each means. **Anything not declared here is invisible to the agent.** That's your safety net.
310
+
311
+ ---
235
312
 
236
- ## Determinism for demos
313
+ ## Safety + scope
237
314
 
238
- Pass `seedPersona="decisive"` or `seedPersona="deliberate"` to `<BeGenSurface>` and the surface will pre-seed its tracker with a canned trace. Within a couple of seconds of mount you'll get a stable directive — useful for split-screen demos, screenshots, and judges.
315
+ By default the provider tracks behavior on `document.body` and the agent can target any selector under it. You can narrow:
239
316
 
240
317
  ```tsx
241
- <BeGenSurface
242
- variants={variants}
243
- classify={classify}
244
- pageContext={pageContext}
245
- seedPersona="decisive"
246
- />
318
+ <BeGenProvider
319
+ designSystem={designSystem}
320
+ pageContext={{ route: "/" }}
321
+ scope={{
322
+ allow: ["[data-begen-adapt]", ".product-card", ":root"],
323
+ deny: ["[data-checkout]", ".payment-form"],
324
+ }}
325
+ >
247
326
  ```
248
327
 
249
- The traces live in [`src/personas.ts`](./src/personas.ts)feel free to tune them.
328
+ `scope.deny` is a hard vetothe engine refuses any adaptation whose selector matches a deny pattern. Use it to protect critical paths.
250
329
 
251
- ## Reading state from children
330
+ CSS-only invariants in v0.2:
252
331
 
253
- Wrap with `<BeGenProvider>` (or place provider above the surface) and call `useBeGenContext()`:
332
+ - The engine refuses `set-style` for `display`, `position`, `visibility`, `float`, `clear`, `z-index`, `overflow*`, `transform-origin`. Use CSS variables and classes instead.
333
+ - The engine reverts every previous plan before applying a new one — mutations never accumulate.
334
+ - On unmount, every applied mutation is reverted. The page is restored.
335
+ - Identical consecutive plans are skipped (cheap deterministic hash).
336
+ - Empty plans are no-ops.
254
337
 
255
- ```tsx
256
- function TelemetryStrip() {
257
- const { variant, directive, summary } = useBeGenContext();
258
- return (
259
- <div>
260
- Mode: {variant}
261
- {directive && ` · ${directive.reasoning}`}
262
- {summary && ` · ${summary.events_seen} events`}
263
- </div>
264
- );
265
- }
266
- ```
267
-
268
- Nice for debugging, demo overlays, or analytics.
338
+ ---
269
339
 
270
340
  ## Local development
271
341
 
272
342
  ```bash
273
- git clone <this repo>
274
- cd packages/begeniux
343
+ git clone https://github.com/WagnerAgent/BeGeniux
344
+ cd BeGeniux
275
345
  npm install
276
- npm run build # one-shot build to dist/
277
- npm run dev # tsup --watch
346
+ npm run build # one-shot build dist/
347
+ npm run dev # tsup --watch
278
348
 
349
+ # Smoke test
279
350
  cd examples/basic
280
351
  npm install
281
- npm run dev # http://localhost:5180
352
+ npm run dev # http://localhost:5180
282
353
  ```
283
354
 
284
- The example imports from `../../src/index.ts` via a Vite alias, so source changes hot-reload. Two seeded surfaces render side-by-side using the heuristic classifier no API keys required.
355
+ The example imports from `../../src/index.ts` via a Vite alias, so source changes hot-reload. No CopilotKit / LangGraph / API keys needed — the example uses an inline mock classifier.
356
+
357
+ ---
358
+
359
+ ## Migrating from v0.1
360
+
361
+ v0.1 was a variant-picker — you handed the library `{decisive, deliberate, neutral}` components and an LLM picked one. v0.2 deletes that model entirely:
362
+
363
+ - `BeGenSurface` → removed. `BeGenProvider` is now the entire library entrypoint.
364
+ - `Variant` / `AgentDirective` → removed. `AdaptationPlan` is what the agent returns.
365
+ - `createGeminiClassifier` → removed. Browser-side LLM calls were the wrong shape; use the CopilotKit adapter or a server-side HTTP endpoint.
366
+ - `createHeuristicClassifier` → removed. It's a 5-line `ClassifyFn` if you still want one.
367
+ - `PERSONAS` → removed. `seedTrace` on the provider takes any `BehaviorEvent[]`; bring your own.
368
+
369
+ If you've already integrated v0.1, stay on v0.1.x — it's still on npm. Upgrade to v0.2 when you're ready to switch from variant-picking to live adaptation.
370
+
371
+ ---
285
372
 
286
373
  ## Research lineages
287
374
 
288
- This library combines four threads of prior work that have rarely been combined in production UI:
375
+ - **Adaptive UIs** Gajos & Weld, *SUPPLE: Automatically Generating User Interfaces* (IUI 2004)
376
+ - **Contextual bandits** — Li et al., *A Contextual-Bandit Approach to Personalized News Article Recommendation* (WWW 2010)
377
+ - **Implicit feedback** — Joachims et al., *Accurately Interpreting Clickthrough Data as Implicit Feedback* (SIGIR 2005)
378
+ - **In-context learning as policy** — Brown et al., *Language Models are Few-Shot Learners* (NeurIPS 2020)
289
379
 
290
- - **Adaptive User Interfaces** Gajos & Weld, *SUPPLE: Automatically Generating User Interfaces* (IUI 2004).
291
- - **Contextual bandits** — Li et al., *A Contextual-Bandit Approach to Personalized News Article Recommendation* (WWW 2010).
292
- - **Implicit feedback / behavior modeling** — Joachims et al., *Accurately Interpreting Clickthrough Data as Implicit Feedback* (SIGIR 2005).
293
- - **In-context learning as policy** — Brown et al., *Language Models are Few-Shot Learners* (NeurIPS 2020).
380
+ The novel contribution is the combination: behavioral traces as input, LLM agents as policy, session-granularity adaptation, **live DOM mutation** as output, with developer-declared design-system invariants.
294
381
 
295
- The novel contribution is the combination: behavioral traces as input, LLM agents as policy, session-granularity adaptation, with developer-declared invariants.
382
+ ---
296
383
 
297
384
  ## Roadmap
298
385
 
299
- - Multi-armed bandit policies (Thompson sampling) for variant selection.
300
- - **Invariant DSL** — declare UI properties that must hold across variants (e.g., "cancel button always reachable", "checkout step never re-ordered").
301
- - Behavior embeddings for open-ended UI generation beyond a fixed variant set.
302
- - Eval harness with replay traces and counterfactual scoring.
303
- - First-class adapters for CopilotKit, LangGraph, Mastra, and the Anthropic SDK.
386
+ - **v0.3** — Tool-calling agent loop (agent inspects DOM iteratively); structural mutations (insert, reorder, hide/show under invariant constraints); streaming AdaptationPlan events.
387
+ - **v0.4** — Component replacement primitive; an invariant DSL ("checkout always reachable in ≤2 clicks"); replay traces + counterfactual scoring.
388
+ - **v0.5** — Cross-session memory (with explicit consent); behavioral embeddings; multi-armed bandit policies as a non-LLM fallback.
389
+
390
+ ---
304
391
 
305
392
  ## Contributing
306
393
 
307
- PRs welcome. Keep the public surface small — anything not exported from `src/index.ts` is private. Don't bundle React; don't add heavy dependencies; don't assume Next.js. The library should drop into Vite, CRA, Remix, Next, or anywhere React 18+ runs.
394
+ PRs welcome. Keep the public API minimal — anything not exported from `src/index.ts` is internal. Don't bundle React or CopilotKit. Don't assume Next.js. The library should drop into Vite, CRA, Remix, Next, or anywhere React 18+ runs.
395
+
396
+ If you're working in this repo with Claude Code (or another agent), the [`.claude/skills/`](./.claude/) directory has prebaked domain knowledge about CopilotKit, AG-UI, MCP, and LangGraph integrations — read the relevant `SKILL.md` before touching adapter code.
308
397
 
309
398
  ## License
310
399