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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@manifesto-ai/core

v0.3.0

Published

AI Native Semantic Layer for SaaS Business Logic

Readme

@manifesto-ai/core

AI Native Semantic Layer for SaaS Business Logic

The core package provides domain definition, runtime execution, expression evaluation, and effect system for Manifesto AI.

Installation

pnpm add @manifesto-ai/core
# or
npm install @manifesto-ai/core

Quick Start

import {
  defineDomain,
  createRuntime,
  defineDerived,
  defineAction,
  defineSource,
  sequence,
  setState,
  setValue,
  z
} from '@manifesto-ai/core';

// Define a domain
const todosDomain = defineDomain({
  id: 'todos',
  name: 'Todos',
  description: 'Todo list management domain',

  dataSchema: z.object({
    items: z.array(z.object({
      id: z.string(),
      title: z.string(),
      completed: z.boolean()
    }))
  }),

  stateSchema: z.object({
    filter: z.enum(['all', 'active', 'completed']),
    isLoading: z.boolean()
  }),

  initialState: {
    filter: 'all',
    isLoading: false
  },

  paths: {
    sources: {
      // Auto-prefixed: 'items' becomes 'data.items'
      items: defineSource({
        schema: z.array(z.object({
          id: z.string(),
          title: z.string(),
          completed: z.boolean()
        })),
        defaultValue: [],
        semantic: { type: 'list', description: 'Todo items' }
      })
    },
    derived: {
      // Auto-prefixed: 'activeCount' becomes 'derived.activeCount'
      activeCount: defineDerived({
        deps: ['data.items'],
        expr: ['length', ['filter', ['get', 'data.items'], ['!', '$.completed']]],
        semantic: { type: 'count', description: 'Number of active todos' }
      })
    }
  },

  actions: {
    // Set filter action
    setFilter: defineAction({
      deps: ['state.filter'],
      input: z.object({ filter: z.enum(['all', 'active', 'completed']) }),
      effect: setState('state.filter', ['get', 'input.filter'], 'Set filter'),
      semantic: { type: 'action', verb: 'set', description: 'Set todo filter' }
    }),

    // Clear completed todos
    clearCompleted: defineAction({
      deps: ['data.items'],
      effect: setValue('data.items',
        ['filter', ['get', 'data.items'], ['!', '$.completed']],
        'Clear completed todos'
      ),
      semantic: { type: 'action', verb: 'clear', description: 'Remove completed todos' }
    })
  }
});

// Create runtime
const runtime = createRuntime({ domain: todosDomain });

// Use the runtime
runtime.set('data.items', [
  { id: '1', title: 'Learn Manifesto', completed: false }
]);

console.log(runtime.get('derived.activeCount')); // 1

API Reference

Domain Definition

Note: Keys in sources, derived, and async are auto-prefixed (data., derived., async. respectively). Keys with existing prefixes are preserved for backward compatibility. Both activeCount and 'derived.activeCount' are valid.

defineDomain(options)

Creates a domain definition.

const domain = defineDomain({
  id: 'myDomain',
  name: 'My Domain',
  description: 'Domain description for AI understanding',
  dataSchema: z.object({ ... }),      // Required: Source data schema
  stateSchema: z.object({ ... }),     // Required: UI state schema
  initialState: { ... },               // Required: Initial state values
  paths: {
    sources: { ... },                  // Optional: Source definitions
    derived: { ... },                  // Optional: Computed values
    async: { ... },                    // Optional: Async data sources
  },
  actions: { ... },                    // Optional: Domain actions
  meta: { ... }                        // Optional: Domain metadata
});

defineSource(options)

Defines a source field with semantic metadata.

const sources = {
  // Auto-prefixed: 'user' becomes 'data.user'
  user: defineSource({
    schema: z.object({ name: z.string(), email: z.string() }),
    defaultValue: { name: '', email: '' },
    semantic: {
      type: 'entity',
      description: 'Current user information'
    }
  })
};

defineDerived(options)

Defines a computed value with explicit dependencies.

const derived = {
  // Auto-prefixed: 'fullName' becomes 'derived.fullName'
  fullName: defineDerived({
    deps: ['data.firstName', 'data.lastName'],
    expr: ['concat', ['get', 'data.firstName'], ' ', ['get', 'data.lastName']],
    semantic: {
      type: 'computed',
      description: 'User full name'
    }
  })
};

defineAsync(options)

Defines an async data source with result paths.

const async = {
  // Auto-prefixed: 'userData' becomes 'async.userData'
  userData: defineAsync({
    deps: ['data.userId'],
    condition: ['!=', ['get', 'data.userId'], null],
    debounce: 300,
    effect: {
      _tag: 'ApiCall',
      method: 'GET',
      endpoint: '/api/user',
      description: 'Fetch user data'
    },
    resultPath: 'state.userData',
    loadingPath: 'state.userLoading',
    errorPath: 'state.userError',
    semantic: {
      type: 'async',
      description: 'User data from API'
    }
  })
};

defineAction(options)

Defines a domain action with preconditions and effects.

const actions = {
  submit: defineAction({
    deps: ['derived.total', 'state.isSubmitting'],
    preconditions: [
      { path: 'derived.hasItems', expect: 'true', reason: 'Cart must have items' },
      { path: 'state.isSubmitting', expect: 'false', reason: 'Already submitting' }
    ],
    effect: sequence([
      setState('state.isSubmitting', true),
      apiCall({ method: 'POST', url: '/api/submit' }),
      setState('state.isSubmitting', false)
    ]),
    semantic: {
      type: 'action',
      verb: 'submit',
      description: 'Submit the order',
      risk: 'medium'
    }
  })
};

Runtime

createRuntime(options)

Creates a runtime instance for a domain.

const runtime = createRuntime({
  domain: myDomain,
  initialData: { count: 0 },
  initialState: { isLoading: false }
});

Runtime Methods

// Get a value by path
runtime.get('data.user.name');        // Returns the value
runtime.get('derived.fullName');      // Computes and returns

// Set a value
runtime.set('data.count', 10);
runtime.set('state.isLoading', true);

// Subscribe to changes
const unsubscribe = runtime.subscribe('data.count', (value) => {
  console.log('Count:', value);
});

// Subscribe to all changes
runtime.subscribeAll((snapshot) => {
  console.log('Snapshot changed:', snapshot);
});

// Get current snapshot
const snapshot = runtime.getSnapshot();

// Check action availability
const canSubmit = runtime.checkAction('submit');
// { available: true, reason: null }

// Execute an action
await runtime.executeAction('submit', { orderId: '123' });

// Explain why a value is what it is
const explanation = runtime.explain('derived.total');

Expression DSL

Manifesto uses a JSON-based DSL for declarative expressions. All expressions use array format: ['operator', ...args].

Path Reference

['get', 'data.user.name']     // Get value at path
['get', 'state.isLoading']    // Get state value
['get', 'derived.total']      // Get derived value

// In predicates (filter, map, etc.)
'$.price'                      // Current item's price field
'$.completed'                  // Current item's completed field
'$'                            // Current item itself

Comparison Operators

['==', a, b]      // a === b
['!=', a, b]      // a !== b
['>', a, b]       // a > b
['>=', a, b]      // a >= b
['<', a, b]       // a < b
['<=', a, b]      // a <= b

Logical Operators

['all', expr1, expr2, ...]    // All expressions must be true (AND)
['any', expr1, expr2, ...]    // Any expression is true (OR)
['!', expr]                    // Negation (NOT)

Arithmetic Operators

['+', a, b]       // a + b
['-', a, b]       // a - b
['*', a, b]       // a * b

String Functions

['concat', str1, str2, ...]     // Concatenate strings
['join', array, delimiter]       // Join array elements
['includes', str, search]        // Contains substring
['slice', str, start, end]       // Substring

Array Functions

['length', array]                // Array length
['at', array, index]             // Element at index (0 = first, -1 = last)
['filter', array, predicate]     // Filter elements
['map', array, transform]        // Transform elements
['some', array, predicate]       // Any element matches
['every', array, predicate]      // All elements match
['concat', array1, array2]       // Concatenate arrays
['includes', array, element]     // Array contains element
['sort', array, key]             // Sort by key
['slice', array, start, end]     // Slice array
['indexOf', array, element]      // Find index of element

Note: There is no find operator. Use ['at', ['filter', array, predicate], 0] instead.

Conditional

// Case expression (if-else chain) - each condition-value pair is a tuple
['case',
  [condition1, value1],
  [condition2, value2],
  defaultValue
]

// Example: return 'large', 'medium', or 'small' based on total
['case',
  [['>', ['get', 'derived.total'], 100], 'large'],
  [['>', ['get', 'derived.total'], 50], 'medium'],
  'small'
]

// Match expression (pattern matching)
['match', value,
  [pattern1, result1],
  [pattern2, result2],
  defaultResult
]

// Coalesce (first non-null value)
['coalesce', value1, value2, value3]

Object Operations

['pick', object, ['key1', 'key2']]   // Pick specific keys
['omit', object, ['key1', 'key2']]   // Omit specific keys

Examples

// Filter active todos
['filter', ['get', 'data.items'], ['!', '$.completed']]

// Count completed items
['length', ['filter', ['get', 'data.items'], '$.completed']]

// Find first item by id (no find operator, use filter + at)
['at', ['filter', ['get', 'data.items'], ['==', '$.id', ['get', 'input.id']]], 0]

// Concatenate first and last name
['concat', ['get', 'data.firstName'], ' ', ['get', 'data.lastName']]

// Conditional value (each condition-value pair is a tuple)
['case',
  [['>', ['get', 'derived.total'], 100], 'large'],
  [['>', ['get', 'derived.total'], 50], 'medium'],
  'small'
]

Known Limitations

  1. No object literal construction: You cannot create new objects with dynamic values directly in expressions.

    // ❌ This does NOT work
    ['concat', ['get', 'data.items'], [{ id: ['get', 'input.id'], name: 'New' }]]
    
    // ✅ Use pick/omit for existing objects, or handle in effect handlers
    ['pick', '$', ['id', 'name']]
  2. No empty object literal: {} is not a valid expression. Use ['coalesce'] or handle in application code.

  3. No find operator: Use ['at', ['filter', array, predicate], 0] instead.

Effect System

Effects describe side effects as data.

Effect Types

// Set a value
setValue('data.count', 10)
setValue('data.count', ['+', ['get', 'data.count'], 1])

// Set state
setState('state.isLoading', true)

// API call
apiCall({
  method: 'POST',
  url: '/api/orders',
  body: ['get', 'data.order'],
  headers: { 'Content-Type': 'application/json' }
})

// Navigation
navigate('/success')

// Delay
delay(1000)  // milliseconds

// Emit event
emitEvent('orderCreated', { orderId: '123' })

Effect Composition

// Sequential execution
sequence([
  setState('state.isLoading', true),
  apiCall({ method: 'GET', url: '/api/data' }),
  setState('state.isLoading', false)
])

// Parallel execution
parallel([
  apiCall({ method: 'GET', url: '/api/user' }),
  apiCall({ method: 'GET', url: '/api/settings' })
])

// Conditional execution
conditional(
  ['get', 'state.isPremium'],
  apiCall({ method: 'GET', url: '/api/premium' }),
  apiCall({ method: 'GET', url: '/api/basic' })
)

// Error handling
catchEffect(
  apiCall({ method: 'POST', url: '/api/submit' }),
  setState('state.error', ['get', 'error.message'])
)

Running Effects

import { runEffect } from '@manifesto-ai/core';

const result = await runEffect(effect, runtime, {
  apiHandler: async (config) => {
    const response = await fetch(config.url, {
      method: config.method,
      body: JSON.stringify(config.body)
    });
    return response.json();
  }
});

if (isOk(result)) {
  console.log('Success:', result.value);
} else {
  console.log('Error:', result.error);
}

Result Type

A functional error handling type.

import { ok, err, isOk, isErr, map, flatMap, unwrapOr } from '@manifesto-ai/core';

// Create results
const success = ok(42);
const failure = err({ code: 'NOT_FOUND', message: 'Item not found' });

// Check type
if (isOk(success)) {
  console.log(success.value);  // 42
}

// Transform
const doubled = map(success, (x) => x * 2);  // ok(84)

// Chain operations
const result = flatMap(success, (x) =>
  x > 0 ? ok(x) : err({ code: 'INVALID', message: 'Must be positive' })
);

// Get with default
const value = unwrapOr(failure, 0);  // 0

Schema Utilities

import {
  schemaToSource,
  validateValue,
  zodErrorToValidationResult,
  CommonSchemas
} from '@manifesto-ai/core';

// Common schemas
CommonSchemas.email    // z.string().email()
CommonSchemas.phone    // Phone number pattern
CommonSchemas.money    // Positive number with 2 decimals

// Validate values
const result = validateValue(userSchema, inputData);
if (!result.valid) {
  console.log(result.issues);
}

Related Packages

License

MIT