OwlLayer AI

OwlLayer AI

Make your web interface drivable by AI: turn buttons, links, and form fields into tools an agent can call.

OwlLayer AI is an open-source TypeScript Agentic UI SDK for building interfaces where actions are explicit, contextual, and always owned by your application: buttons, links, form fields, and components become tools the AI agent can call to operate the interface, and the agent lives inside your app, so your users simply talk to it.

Documentation · Get started · Contributing · Security · Français

CI Docs deploy Latest release npm Pre-release GitHub stars Repository views Last commit License: MIT TypeScript Node.js 22 pnpm 9

In a demo shop, the user says into the microphone that they want a navy T-shirt, size M, under 50 euros. The agent built into the app calls the tools the page declares: it searches the catalogue, filters it, opens the OwlLayer T-shirt, adds it to the cart when the user says yes, fills in the checkout, and the payment waits for the user's approval before the order is confirmed.

The user just says it. The agent built into the shop searches, filters, opens the product and checks out with the tools each screen declares.

--- ## Table of contents - [Table of contents](#table-of-contents) - [1. Why OwlLayer AI](#1-why-owllayer-ai) - [1.1 OwlLayer AI and MCP](#11-owllayer-ai-and-mcp) - [2. The OwlLayer AI model](#2-the-owllayer-ai-model) - [2.1 Neural-DOM Binding](#21-neural-dom-binding) - [2.2 Tools](#22-tools) - [3. Framework support](#3-framework-support) - [4. Models, realtime, and voice](#4-models-realtime-and-voice) - [5. Connect your app](#5-connect-your-app) - [6. Declare a capability where it belongs](#6-declare-a-capability-where-it-belongs) - [6.1 In script](#61-in-script) - [6.2 Declarative components](#62-declarative-components) - [6.3 HTML attributes](#63-html-attributes) - [7. Publish context without exposing the whole app](#7-publish-context-without-exposing-the-whole-app) - [7.1 In script (React)](#71-in-script-react) - [7.2 Browser SDK (imperative)](#72-browser-sdk-imperative) - [8. Interaction lifecycle and protocol](#8-interaction-lifecycle-and-protocol) - [9. Security by construction](#9-security-by-construction) - [10. Repository development and contributing](#10-repository-development-and-contributing) - [10.1 Repository layout](#101-repository-layout) - [10.2 Contributor workflow](#102-contributor-workflow) - [11. Project status](#11-project-status) - [12. License](#12-license) ## 1. Why OwlLayer AI Most AI integrations in web applications can describe a product, but they cannot safely operate it. OwlLayer AI gives an agent a **bounded, live view of what it is allowed to do** in the interface that the user is currently using. It is not a DOM scraper, a generated replacement UI, or a chatbot bolted onto an application. Your components, business rules, and existing workflows remain the source of truth. With OwlLayer AI, an agent can: - understand the allow-listed context you decide to share; - discover only the actions available on the active screen; - invoke application-owned handlers with validated input; - request human approval before sensitive work; - return results to the conversation without bypassing your domain logic. This makes OwlLayer AI useful for guided commerce, product operations, support flows, enterprise dashboards, and voice experiences where an AI must be helpful without becoming an unrestricted automation layer. ### 1.1 OwlLayer AI and MCP The **Model Context Protocol (MCP)** is a standard for exposing tools **on the server side**: an MCP server declares functions (`query_database`, `create_ticket`, …) that an AI agent such as Codex or Claude Code can call. OwlLayer AI works **on the interface side**: it turns the elements of your web app (buttons, links, form fields, components) into tools, and puts the agent **inside the app**. Your users chat with it directly in your product; they do not install or configure any agent tool. | | MCP | OwlLayer AI | | --- | --- | --- | | **Tools come from** | Functions declared in a backend MCP server | Buttons, forms, and components of your UI (plus server tools if you need them) | | **Who uses them** | An agent in the user's own AI client (Codex, Claude Code, …) | The agent embedded in your app, used by your end users in text or voice | | **What the agent knows** | What each tool returns | The current screen, through the context you choose to share | | **When a tool exists** | As long as the server exposes it | Only while its component is on screen | | **Human approval** | Depends on the client | Built in for `high` and `critical` actions | ## 2. The OwlLayer AI model The model is built around five concepts, deliberately independent of any UI framework or backend implementation. | Concept | What it means | Details | | --- | --- | --- | | **Neural-DOM Binding** | The principle: the page exposes its defined actions and what it can do, and the model reasons about those intentions without being given control of the DOM. | [2.1](#21-neural-dom-binding) | | **Tools** | The actions the agent can call. The interface registers them when they appear on screen, unregisters them when they disappear, and your code executes them. | [2.2](#22-tools), [6](#6-declare-a-capability-where-it-belongs) | | **Shadow Context** | A compact, allow-listed representation of relevant UI state. It gives the agent product awareness without exposing the DOM, internal stores, or arbitrary data. | [7](#7-publish-context-without-exposing-the-whole-app) | | **Policy-controlled execution** | Every tool has an explicit contract. Risky operations can pause for Human-in-the-Loop approval before any handler runs. | [9](#9-security-by-construction) | | **AITP** | The Agent-to-Interface Transfer Protocol synchronizes context, capabilities, messages, calls, approvals, and results across the runtime boundary. | [8](#8-interaction-lifecycle-and-protocol) | ### 2.1 Neural-DOM Binding **Neural-DOM Binding is the connection between a living page and an LLM brain.**

Neural-DOM Binding: the visible DOM declares tools and context to OwlLayerClient, which synchronizes them with the OwlLayerServer session over AITP; the model picks an allowed tool and the handler runs in the app

- **Neural** is the reasoning network: Gemini, GPT, Claude, or another language model that understands intent and decides what to do. - **DOM** is the living product interface: the current page, its visible state, its available actions, and its rules. - **Binding** is the governed link that lets the model understand and act on the page through explicit contracts. OwlLayer AI turns the page into a semantic surface, readable by an AI agent. Instead of making an agent hunt for a button, click it, and guess what changed, the application tells the model: *these are the intentions that exist on this page, this is the context, and these are the rules for executing them.* It is not browser automation, and it is not a framework virtual DOM. The agent receives a named, typed, policy-governed intention such as `add_to_cart`, `get_order`, or `approve_refund`. | Imperative UI automation | Neural-DOM Binding | | --- | --- | | Find a button, click it, wait for the screen, then infer whether it worked. | Request a declared intention with validated input; the application executes its own handler and returns a structured result. | | Fragile when layout, labels, or navigation change. | Stable across UI changes because the capability contract is explicit. | | May bypass product permissions and domain rules. | Keeps permissions, Human-in-the-Loop approval, transactions, and business logic in the application. | ### 2.2 Tools A tool is an action the agent can call: a name, a description the model reads, an input schema, a risk level, and a handler in your application code. The binding is declarative and lifecycle-aware, and three parts of the runtime manage it: - **Registration:** a component registers its tools when it appears on screen (`useAgentTool`, declarative components, `OwlLayer.registerTool()`, or `data-owllayer-tool` attributes). The client sends the updated list to the server. - **Unregistration:** when the component disappears, its tools are removed, so navigation changes what the agent can do. Tools declared with `global: true` stay available for the whole session. - **Execution:** when the agent calls a tool, the executor finds it, applies the risk policy, waits for the handler to finish, and returns a structured result. If the tool navigated to another page, it first waits for the tools of that page, so the agent continues with the tools of the new screen. On the server, the tool router runs server-side tools itself and forwards interface tools to the client.

Tool lifecycle: a tool is registered when its component mounts, synchronized with CONTEXT_UPDATE, called with TOOL_CALL, and unregistered when the component unmounts

The same model applies to every integration. [Section 6](#6-declare-a-capability-where-it-belongs) shows how to declare a tool. ## 3. Framework support Pick the integration style that matches your product. | Integration | Best for | Guide | | --- | --- | --- | | React
Next.js | React and Next.js share the same integration model: hooks, providers, and components; in Next.js, used from client components. | [React guide](https://borisbob91.github.io/owllayer/react-sdk.html) | | Vue
Nuxt.js | Vue and Nuxt.js share the same integration model: plugin, composables, and components; in Nuxt, used from client components. | [Vue guide](https://borisbob91.github.io/owllayer/vue-sdk.html) | | Svelte | Stores, actions, and Svelte-native components | [Svelte guide](https://borisbob91.github.io/owllayer/svelte-sdk.html) | | Angular | Providers, services, signals, directives, and widgets | [Angular guide](https://borisbob91.github.io/owllayer/angular-sdk.html) | | Browser | HTML, multi-page applications, server-rendered pages, and progressive adoption | [Browser guide](https://borisbob91.github.io/owllayer/vanilla-browser.html) | | Shopify | Voice shopping on an existing Shopify storefront (experimental) | [Shopify plugin](./packages/shopify/README.md) | | WooCommerce | Voice shopping on an existing WooCommerce store (experimental) | [WooCommerce plugin](./packages/woocommerce/README.md) | | Flutter | Cross-platform mobile runtime | [Flutter SDK](https://github.com/borisbob91/owllayer-flutter) | | Swift | Native iOS surface | [Swift SDK](https://github.com/borisbob91/owllayer-swift) | | Kotlin | Kotlin Multiplatform surface | [Kotlin SDK](https://github.com/borisbob91/owllayer-kotlin) | Each guide covers installation, runtime setup, components, and framework-specific API details. Start from the maintained entry points: - [Getting started](https://borisbob91.github.io/owllayer/quick-start.html) - [Widget and embedded UI](https://borisbob91.github.io/owllayer/chat-widget.html) - [Text and voice experiences](https://borisbob91.github.io/owllayer/livekit.html) - [Server orchestration](https://borisbob91.github.io/owllayer/server-setup.html) - [Plugin model](https://borisbob91.github.io/owllayer/plugins-system.html) On native mobile the equivalent is a compact, screen-scoped context: `ScreenContext`. The same rule applies: expose only the relevant UI state and the active tools, and keep execution inside the application owner. ## 4. Models, realtime, and voice OwlLayer AI separates agent reasoning, low-latency conversation, and speech services so each product can choose the right interaction model.

The OwlLayer widget inside a web app, used by voice with a listening indicator or by text with an input field

| Category | Current support | What it enables | | --- | --- | --- | | **LLM and tool calling** | OpenAI Google Gemini Anthropic Claude | Text conversations, structured tool calls, and provider-specific model selection. | | **Native realtime models** | OpenAI Realtime Gemini Live | Persistent bidirectional audio, live transcriptions, barge-in, and tools during a voice turn. | | **Speech-to-text** | OpenAI Whisper Google Cloud Speech-to-Text Deepgram Nova and Flux | Audio transcription for voice experiences that use a text-model pipeline. | | **Text-to-speech** | OpenAI TTS Google Cloud TTS ElevenLabs Deepgram Aura | Configurable speech synthesis and voice selection. | | **Voice runtime** | LiveKit | Rooms, tokens, agent-session bridging, Gemini realtime, and tool execution routed back through the OwlLayer AI Runtime. | | **Deepgram voice** | Deepgram | Three voice modes with one key: batch speech (Nova + Aura), streaming turn-aware speech with any text model (Flux + Aura), or the Deepgram Voice Agent as the realtime model. | The runtime keeps the same capability and approval model whether a turn is text-based, uses a STT/LLM/TTS pipeline, or runs on a native realtime audio model. See the [server documentation](https://borisbob91.github.io/owllayer/server-setup.html) and [voice guide](https://borisbob91.github.io/owllayer/livekit.html) for integration details. ## 5. Connect your app Every package is published on npm. Install the server and the SDK of your front end: ```bash npm install @owllayer/server @owllayer/adapter-google # server npm install @owllayer/react @owllayer/core zod # front end (or vue, svelte, angular, browser) ``` The server connects the model, the sessions, and the approval policy. Model keys stay on the server; the browser only holds the public `pk_…` key. ```ts import { OwlLayerServer } from '@owllayer/server'; import { GoogleAdapter } from '@owllayer/adapter-google'; const server = new OwlLayerServer({ llm: new GoogleAdapter({ model: 'gemini-2.0-flash', apiKey: process.env.GOOGLE_API_KEY! }), port: 3001, path: '/owllayer', }); server.addApiKey('pk_live_your_public_api_key'); server.listen(); ``` On the client, the runtime is established once, at the application root. It opens the live connection and makes agent context and tool registration available to every component below it. ```tsx import React from 'react'; import { OwlLayerProvider } from '@owllayer/react'; import MainLayout from './MainLayout'; export default function App() { return ( ); } ``` ## 6. Declare a capability where it belongs A capability, or **tool**, is an action the agent can call. It is declared next to the UI it belongs to, with a description the model reads, the input schema it accepts, and the risk level that governs it. The handler is your existing application code. (Information the agent should know without acting, such as what the page shows or what the user is trying to do, is **context**, covered in [section 7](#7-publish-context-without-exposing-the-whole-app).) There are two ways to declare it: in script, for dynamic or schema-driven tools, or with declarative components for standalone elements. The examples use React; the other SDKs follow the same model. ### 6.1 In script ```tsx import React from 'react'; import { useAgentTool } from '@owllayer/react'; import { z } from 'zod'; const addToCartSchema = z.object({ productId: z.string(), qty: z.number().min(1).default(1), }); export function ProductCatalog({ products }) { // One tool for the entire list: the LLM selects the right product via productId. // Listing all products in the description gives the model full awareness. // Creating one tool per product would flood the registry with near-identical entries. useAgentTool( { name: 'add_to_cart', description: `Add a product to the cart. Available: ${ products.map((p) => `${p.id} — ${p.name} $${p.price}`).join('; ') }`, schema: addToCartSchema, risk: 'low', }, async ({ productId, qty }) => { const product = products.find((p) => p.id === productId); await apiAddToCart(productId, qty); return { success: true, message: `${qty}× "${product?.name ?? productId}" added to cart.`, }; }, ); return ( ); } ``` Because the tool is registered on mount and released on unmount, the capability surface follows the screen the user is on. Navigating to checkout exposes a different surface: the agent never acts on a stale global command list. The handler must return (or `await`) all the asynchronous work its result depends on: the result is sent to the agent only when the handler has finished. See the [tools guide](https://borisbob91.github.io/owllayer/tools-guide.html) for good practices and anti-patterns. Without a framework, the same declaration is imperative: ```ts import { OwlLayer } from '@owllayer/browser'; await OwlLayer.init({ apiKey: 'pk_live_your_public_api_key', endpoint: 'wss://your-server.example.com/owllayer' }); OwlLayer.registerTool('track_order', { description: "Show the delivery status of one of the user's orders", parameters: { type: 'object', properties: { orderId: { type: 'string', description: 'Order number, e.g. A-1042' } }, required: ['orderId'], }, risk: 'none', handler: async ({ orderId }) => fetchOrderStatus(String(orderId)), }); ``` ### 6.2 Declarative components For standalone elements, each framework SDK exposes two co-location components. `` renders its own ` ``` `data-owllayer-action` accepts `click` (default), `setValue`, `focus`, `scrollIntoView`, `show`, `hide`, `addClass`, and `removeClass`. For elements created dynamically, use `OwlLayer.registerTool()` instead. ## 7. Publish context without exposing the whole app Context is passive information the agent reads to understand the current situation: what the page shows, what the user is trying to do, and instructions the developer wants the agent to follow on this screen. It is not a tool and triggers no action. Write it as a human-readable description: the LLM reads it as text, so explicit sentences are more useful than raw variable dumps. ### 7.1 In script (React) ```tsx import { useAgentContext } from '@owllayer/react'; function CartPage({ cart, user }) { useAgentContext({ page: 'Shopping cart', summary: `${user.name} has ${cart.items.length} item(s) in their cart for a total of $${cart.total}. ` + `The cart contains: ${cart.items.map((i) => `${i.qty}× ${i.name}`).join(', ')}.`, nextStep: 'User can confirm the order, remove items, or continue shopping.', }); return ; } ``` The hook re-publishes the context whenever its data changes. ### 7.2 Browser SDK (imperative) Outside a framework, context is pushed imperatively whenever the page state changes. An element marked as a tool can also carry context in HTML, as JSON in `data-owllayer-context`. ```ts import { OwlLayer } from '@owllayer/browser'; // Call after navigation or whenever the relevant state changes. OwlLayer.updateContext({ page: 'Product catalog', summary: 'User is browsing 24 headphones. Active filter: Bluetooth. Sort: Price ascending.', }); ``` ## 8. Interaction lifecycle and protocol A single turn follows the same path whether the user types or speaks.

One agent turn: the UI declares tools and context, the user asks, the agent picks a tool, approval is requested when needed, your code runs, the agent answers

Step 5 is the boundary that matters: the agent does not implement business operations. It requests a named capability, and your application performs the work. The messages travel over **AITP**, a typed JSON protocol over WebSocket. It defines 14 message types, and the server checks the protocol version strictly when the connection opens. For the complete model, read [Core concepts](https://borisbob91.github.io/owllayer/concepts.html), [Architecture](https://borisbob91.github.io/owllayer/architecture.html), and the [AITP protocol](https://borisbob91.github.io/owllayer/aitp-protocol.html). ## 9. Security by construction

Checkout screen: the agent asks to run confirm_checkout, a critical action of 49 euros, and waits for the user to approve or refuse; the side panel lists the tools available on this screen

OwlLayer AI treats AI execution as an explicit application capability, not as arbitrary automation.

Risk policy: none runs directly, low runs and notifies, high and critical wait for the user approval, and a tool blocked with server.blockTool never runs

- **No DOM scraping:** agents receive structured contracts and selected context, never implicit access to the rendered page. - **Schema validation:** every tool defines the input it accepts before execution. - **Risk-aware policy:** `none` runs directly, `low` runs with a notification, and `high` and `critical` always wait for the user's approval before running. - **Isolated approval dialog:** in the React and browser SDKs, the approval dialog is rendered in a closed Shadow DOM, so page scripts and styles cannot reach or hide it. - **Scoped context:** only data you publish becomes available to the agent. - **Authoritative handlers:** application code owns side effects, permissions, transactions, and domain rules. - **Server authority:** the runtime merges UI tools with the tools declared on the server before each agent turn; a server declaration wins if a name collides, so a transient UI component cannot weaken a protected operation, and `server.blockTool('name')` blocks a tool even if a client declares it. - **Runtime observability:** sessions, calls, approvals, and tool results remain traceable through the runtime surface. Read the [HITL security guide](https://borisbob91.github.io/owllayer/security-hitl.html) before exposing destructive or high-impact operations. Never place provider credentials in browser bundles. For vulnerabilities, follow [SECURITY.md](./SECURITY.md) instead of opening a public issue. ## 10. Repository development and contributing Requirements: Node.js 22 and pnpm 9. ```bash git clone https://github.com/borisbob91/owllayer.git cd owllayer pnpm install --frozen-lockfile pnpm lint:packages pnpm test:packages pnpm build:packages ``` While developing, target a single package: ```bash pnpm --filter @owllayer/core test pnpm --filter @owllayer/react build ``` Public npm artifacts are built only from `packages/`. Applications, plugins, documentation sites, and local planning material are not released. ### 10.1 Repository layout - `packages/`: the public framework surface, with runtime packages, shared primitives, adapters, and the main integrations meant to be consumed by other projects. This is what gets published to npm. - `apps/`: demo applications and validation environments used to exercise the framework in real scenarios. Excellent for testing behavior and UX, but not part of the published surface. - `packages/shopify/` and `packages/woocommerce/`: experimental integrations that bring voice shopping to existing storefronts. They evolve quickly and are not published to npm. - `packages/angular/`: Angular SDK with providers, injectable service, directives, and standalone components. - `packages/adapter-anthropic/`: Anthropic Claude adapter (text and tool calling). - `packages/adapter-livekit/`: optional LiveKit runtime for WebRTC rooms, Gemini Live, and agent-session bridging. - Audio and realtime packages are foundational and tightly coupled to the rest of the system. Changes there must be validated across every package that depends on them. ### 10.2 Contributor workflow 1. Read [CONTRIBUTING.md](./CONTRIBUTING.md) and the [Code of Conduct](./CODE_OF_CONDUCT.md). 2. Search existing issues, then open or reference one before starting non-trivial work. 3. Keep the change inside a single domain: one SDK, Core, Server/adapters, UI, or infrastructure. 4. Add a Changeset for any functional modification to a public `@owllayer/*` package. 5. Explain the affected packages and public APIs in the pull request, and keep CI green before requesting review. ## 11. Project status OwlLayer AI is under active development. The packages are published on npm and are pre-1.0: APIs may change between minor versions, so use exact versions for production evaluation and review the changelogs when upgrading. ## 12. License OwlLayer AI is available under the [MIT License](./LICENSE).