npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

astral-site

v0.1.3

Published

Official site SDK for Astral, a protocol for browser–site cooperation that lets websites expose tools, UI regions, and metadata to AI browsers.

Readme

astral-site

Official SDK for implementing the Astral protocol on websites. Enable AI browsers to discover and safely invoke on-page actions.

npm version License: MIT

What is Astral?

Astral is a protocol for browser-site cooperation that lets websites expose on-page capabilities to AI browsers. Instead of AI browsers blindly manipulating the DOM, sites explicitly offer safe, typed actions that AI can invoke.

What Astral Provides

An Astral-enabled website exposes:

  1. Tools - Named, typed actions AI browsers can invoke (e.g., "add task", "reorder items", "filter results")
  2. UI Regions - Marked DOM areas that tools can safely read or mutate
  3. Events - Real-time notifications when state changes
  4. Metadata - Site context, intents, and examples to help AI understand your site's purpose

What This SDK Does

This SDK makes it trivial to add Astral support to any website:

  • Automatic manifest generation from your configuration
  • JSON-RPC 2.0 tool invocation handling
  • Region versioning with conflict detection
  • Framework-agnostic - works with vanilla JS, React, Vue, Svelte, or any framework

Scope: Client-side tools only (on-page UI actions). No server RPC or backend endpoints.

Framework-Agnostic Design

This SDK is built entirely on standard Web APIs and has zero framework dependencies. It works seamlessly with:

  • Vanilla JavaScript - Plain DOM manipulation
  • React - Integrate with hooks and state management
  • Vue - Use with Composition API or Options API
  • Svelte - Works with Svelte's reactive stores
  • Any other framework - Or no framework at all

The core implementation uses only standard browser APIs (Element, MessagePort, CustomEvent, window). Tool handlers are user-provided functions that can use any framework or library you prefer.

Installation

npm install astral-site

Or via CDN:

<script src="https://unpkg.com/astral-site/dist/index.umd.js"></script>

Quick Start

Three steps to add Astral support to your site:

  1. Configure - Define tools, regions, and metadata
  2. Mount - Activate the actuator
  3. Signal - Announce readiness to AI browsers

The SDK automatically generates the Astral manifest from your configuration.

Minimal Example (Vanilla JS)

import { createActuator } from 'astral-site';

// 1. Configure: Define tools and regions
// The manifest is automatically generated from this config
const actuator = createActuator({
  project: {
    name: 'My Todo App',
    version: '1.0.0',
  },

  tools: {
    addTask: {
      description: 'Add a new task to the list',
      scope: 'ui:mutate',
      input: {
        type: 'object',
        properties: {
          title: { type: 'string' },
        },
        required: ['title'],
      },
      output: {
        type: 'object',
        properties: {
          receipt: { type: 'string' },
        },
      },
      handler: ({ title }) => {
        // Your implementation
        const taskList = document.getElementById('tasks');
        const li = document.createElement('li');
        li.textContent = title;
        li.setAttribute('data-agent-item-id', `task-${Date.now()}`);
        taskList.appendChild(li);

        // Emit event
        actuator.emit('task.added', { title });

        return { receipt: `Added: ${title}` };
      },
      events: ['task.added'],
    },
  },

  regions: {
    'task-list': {
      selector: '#tasks',
      type: 'list',
      mutable: true,
    },
  },
});

// 2. Mount: Activate the actuator
actuator.mount();

// 3. Signal: Announce readiness to AI browsers
actuator.signalReady();

// The manifest is now available at actuator.getManifest()
// It's automatically used in the HELLO/WELCOME handshake

HTML Markup

Mark your regions with data-agent-region and items with data-agent-item-id:

<ul id="tasks" data-agent-region="task-list">
  <li data-agent-item-id="task-1">Buy milk</li>
  <li data-agent-item-id="task-2">Email Alice</li>
</ul>

Core Concepts

Tools

Tools are named actions that AI browsers can invoke. Each tool has:

  • Description: Human-readable explanation
  • Scope: ui:read (read-only) or ui:mutate (can modify DOM)
  • Input Schema: JSON Schema describing parameters
  • Output Schema: JSON Schema describing the result
  • Handler: Function that implements the behavior
  • Events: List of events this tool emits

Example with region versioning:

tools: {
  reorderTasks: {
    description: 'Reorder tasks by ID',
    scope: 'ui:mutate',
    input: {
      type: 'object',
      properties: {
        region: { type: 'string' },
        order: { type: 'array', items: { type: 'string' } },
      },
      required: ['region', 'order'],
    },
    output: {
      type: 'object',
      properties: {
        receipt: { type: 'string' },
        post: {
          type: 'object',
          properties: {
            region: { type: 'string' },
            version: { type: 'integer' },
          },
        },
      },
    },
    handler: ({ region, order }, meta) => {
      // Check precondition (version)
      const currentVersion = actuator.getRegionVersion(region);
      if (meta.pre?.version && meta.pre.version !== currentVersion) {
        throw { code: 'preconditionFailed', message: 'Version mismatch' };
      }

      // Perform reordering
      const container = actuator.getRegionElement(region);
      const itemsById = new Map(
        Array.from(container.children).map(el => [
          el.getAttribute('data-agent-item-id'),
          el
        ])
      );

      order.forEach(id => {
        const item = itemsById.get(id);
        if (item) container.appendChild(item);
      });

      // Increment version and emit event
      const newVersion = actuator.incrementRegionVersion(region);
      actuator.emit('region.changed', { region, version: newVersion });

      return {
        receipt: `Reordered ${order.length} items`,
        post: { region, version: newVersion },
      };
    },
    events: ['region.changed'],
  },
}

Regions

Regions are DOM containers that tools can interact with:

regions: {
  'sidebar': {
    selector: '#sidebar',  // CSS selector
    type: 'stack',         // 'grid', 'list', or 'stack'
    mutable: false,        // Can tools modify this region?
  },
  'main-content': {
    element: document.getElementById('main'),  // Or direct element reference
    type: 'grid',
    mutable: true,
  },
}

Regions are versioned - every mutation increments the version number, enabling:

  • Conflict detection
  • Optimistic locking
  • Event-driven updates

Events

Events notify AI browsers about state changes:

// In your tool handler
actuator.emit('task.completed', { taskId: 'task-123' });

Events declared in tools are automatically included in the manifest.

Advanced Features

Site Context

Help AI browsers understand your site's purpose:

project: {
  name: 'TaskMaster Pro',
  version: '2.0.0',
  siteContext: {
    summary: 'A powerful task management application',
    category: 'productivity',
    entities: ['task', 'project', 'user'],
    keywords: ['todo', 'organize', 'collaborate'],
  },
}

Intents

Map high-level user goals to specific tools:

project: {
  intents: [
    {
      name: 'capture_task',
      description: 'Quickly add a new task',
      uses_tools: ['addTask'],
    },
    {
      name: 'organize_tasks',
      description: 'Rearrange tasks by priority',
      uses_tools: ['reorderTasks', 'setTaskPriority'],
    },
  ],
}

Examples

Provide few-shot learning examples for better AI understanding:

project: {
  examples: [
    {
      prompt: 'Add a task: Buy groceries',
      intent: 'capture_task',
      tool: 'addTask',
      input: { title: 'Buy groceries' },
    },
    {
      prompt: 'Move task-5 to the top',
      intent: 'organize_tasks',
      tool: 'reorderTasks',
      input: {
        region: 'task-list',
        order: ['task-5', 'task-1', 'task-2'],
      },
    },
  ],
}

Error Handling

Throw structured errors in your tool handlers:

import { notFound, preconditionFailed, invalidParams } from 'astral-site';

handler: ({ taskId }) => {
  const task = findTask(taskId);
  if (!task) {
    throw notFound('Task', taskId);
  }

  // Or throw plain objects
  throw { code: 'permissionDenied', message: 'User not authorized' };
};

Standard error codes:

  • invalidParams - Input validation failed
  • notFound - Resource doesn't exist
  • preconditionFailed - Version mismatch
  • permissionDenied - Action requires confirmation
  • conflict - Concurrent modification
  • retryable - Temporary failure
  • internal - Unexpected error

Auto-mount and Auto-signal

Simplify initialization with automatic mounting and readiness signaling:

const actuator = createActuator({
  // ... config ...
  autoMount: true, // Automatically call mount()
  autoSignalReady: true, // Automatically call signalReady()
});

Custom Logger

Debug your integration:

const actuator = createActuator({
  // ... config ...
  logger: (message, data) => {
    console.log('[MyApp]', message, data);
  },
});

Framework Integration Examples

The following examples demonstrate how to integrate the actuator with popular frameworks. These are optional patterns - the SDK itself has no framework dependencies.

React

import { useEffect } from 'react';
import { createActuator } from 'astral-site';

function TodoApp() {
  const [tasks, setTasks] = useState([]);

  useEffect(() => {
    const actuator = createActuator({
      tools: {
        addTask: {
          description: 'Add a task',
          scope: 'ui:mutate',
          input: {
            /* ... */
          },
          output: {
            /* ... */
          },
          handler: ({ title }) => {
            // Update React state
            setTasks((prev) => [...prev, { id: Date.now(), title }]);
            actuator.emit('task.added', { title });
            return { receipt: `Added: ${title}` };
          },
        },
      },
      regions: {
        'task-list': {
          selector: '#task-list',
          type: 'list',
          mutable: true,
        },
      },
      autoMount: true,
    });

    // Signal ready after hydration
    actuator.signalReady();

    return () => actuator.destroy();
  }, []);

  return (
    <ul id="task-list" data-agent-region="task-list">
      {tasks.map((task) => (
        <li key={task.id} data-agent-item-id={task.id}>
          {task.title}
        </li>
      ))}
    </ul>
  );
}

Vue

<template>
  <ul id="tasks" data-agent-region="task-list">
    <li v-for="task in tasks" :key="task.id" :data-agent-item-id="task.id">
      {{ task.title }}
    </li>
  </ul>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { createActuator } from 'astral-site';

const tasks = ref([]);

onMounted(() => {
  const actuator = createActuator({
    tools: {
      addTask: {
        description: 'Add a task',
        scope: 'ui:mutate',
        input: {
          /* ... */
        },
        output: {
          /* ... */
        },
        handler: ({ title }) => {
          tasks.value.push({ id: Date.now(), title });
          actuator.emit('task.added', { title });
          return { receipt: `Added: ${title}` };
        },
      },
    },
    regions: {
      'task-list': {
        selector: '#tasks',
        type: 'list',
        mutable: true,
      },
    },
    autoMount: true,
  });

  actuator.signalReady();
});
</script>

Manifest Generation

Automatic Generation (Default)

The SDK automatically generates the Astral manifest when you call createActuator():

const actuator = createActuator({ /* config */ });

// Manifest is auto-generated and stored internally
const manifest = actuator.getManifest();

// Used automatically in HELLO/WELCOME handshake with AI browsers

The manifest includes:

  • Tool definitions with JSON schemas
  • Region declarations
  • Event catalog
  • Site metadata (context, intents, examples)
  • Protocol version and timestamps

Static File Generation (Optional)

For serving at /.well-known/agent-manifest.json (protocol discovery):

import { buildManifestJSON } from 'astral-site';
import fs from 'fs';

const config = {
  project: { name: 'My App', version: '1.0.0' },
  tools: { /* ... */ },
  regions: { /* ... */ },
};

// Generate static JSON file
const manifestJSON = buildManifestJSON(config);
fs.writeFileSync('.well-known/agent-manifest.json', manifestJSON);

Note: Static files are optional. The runtime manifest from createActuator() is sufficient for full protocol support.

API Reference

createActuator(options)

Creates and returns an AgentActuator instance.

Options:

  • project - Project metadata (name, version, siteContext, intents, examples)
  • tools - Tool definitions (keyed by tool name)
  • regions - Region definitions (keyed by region ID)
  • events - Additional events beyond those in tools
  • policy - Custom policy overrides
  • logger - Custom logging function
  • autoMount - Auto-call mount() on creation
  • autoSignalReady - Auto-call signalReady() after mounting

AgentActuator Interface

Lifecycle Methods:

  • mount() - Attach listeners and expose on window.AgentActuator
  • destroy() - Cleanup listeners and remove from window
  • signalReady() - Emit readiness signals (CustomEvent + postMessage)
  • isMounted() - Check if actuator is mounted
  • isConnected() - Check if connected to an AI browser

Manifest & Regions:

  • getManifest() - Get the auto-generated Astral manifest
  • markRegion(element, id) - Mark a DOM element as a region
  • getRegionVersion(id) - Get current version of a region
  • getRegionElement(id) - Get DOM element for a region
  • incrementRegionVersion(id) - Increment region version (for tool handlers)

Events:

  • emit(event, payload) - Emit an event to connected AI browser

Browser Compatibility

  • Modern browsers with ES2020 support
  • MessageChannel API (all modern browsers)
  • CustomEvent API (all modern browsers)

Protocol Compliance

This SDK implements the Astral Site Protocol with full compliance:

Core Protocol:

  • ✅ Automatic manifest generation with protocol version and metadata
  • ✅ JSON-RPC 2.0 tool invocation
  • ✅ HELLO/WELCOME handshake via MessagePort
  • ✅ Region versioning with monotonic counters (start at 1)
  • ✅ Precondition checking (meta.pre.version)
  • ✅ Post-condition reporting (result.post.version)
  • ✅ Event emission via MessagePort
  • ✅ Readiness signaling (CustomEvent agent-protocol-ready + postMessage ASTRAL_ANNOUNCE)

Data & Metadata:

  • ✅ JSON Schema validation (minimal subset: type, properties, required, items)
  • ✅ Site context metadata (site-context, intents, examples)
  • ✅ Error classification (transient/permanent) with standard codes
  • ✅ Idempotency via meta.idempotency cache

Implementation:

  • ✅ Framework-agnostic (zero dependencies, standard Web APIs only)
  • ✅ TypeScript with strict mode
  • ✅ Multi-format builds (CJS, ESM, UMD)

TypeScript Support

Full TypeScript definitions included:

import type {
  AgentActuator,
  AstralManifest,
  ToolHandler,
  CreateActuatorOptions,
} from 'astral-site';

Examples

A complete working example is included in example.html - a todo list built with vanilla JavaScript demonstrating all core features.

Contributing

Contributions welcome! Please read CONTRIBUTING.md first.

License

MIT © Astral Team

Resources