AbsoluteJS

Rules

@absolutejs/rulesv0.1.0alphaAI

Closed, typed trigger/action vocabulary for standing automations that an AI agent can author without hallucinating behavior.

Typed standing automations ("if X do Y") for AI-agent products, designed so the agent itself can safely author rules on a member’s behalf. You define your triggers and actions once as a closed vocabulary with typed, bounded parameters, and everything derives from that single definition: the validator, the LLM tool schemas, and a capped, cooldown-guarded firing engine. A stored rule can never carry behavior your engine does not implement.

#Installation

BASH
bun add @absolutejs/rules

#Capabilities

Overview

Typed standing automations ("if X do Y") for AI-agent products — safe for the agent itself to author.

Used by the hosted AbsoluteJS.ai platform and available as a standalone rules package.

The idea

Letting an LLM create automations on a member's behalf is only safe if the rule language is closed. This package makes the vocabulary the contract: you define your triggers and actions once, with typed, bounded parameters, and everything derives from that single definition —

The validator (validateRuleInput): unknown triggers/actions reject with

the available options spelled out (an error the LLM can relay verbatim), unknown params strip, numbers clamp to their bounds, closed-set strings narrow. A stored rule can never carry behavior your engine doesn't implement.

Show 5 more

The AI tool schemas (ruleToolSchemas): create/update tool inputs whose

trigger/action fields are enums of your vocabulary — the hallucination-proofing.

The firing engine (createRuleEngine): per-entity cooldown via a firing

ledger, daily firing + auto-execution caps, a kill switch, and your authoring policy re-checked at fire time (a rule authored under a looser policy can't outrun a tightened one).

The only free text a rule carries is guidance — a bounded style note your drafting pipeline applies to generated copy. It never selects behavior.

Quick start

Storage is pluggable via the small RuleStore interface (list enabled rules, ledger reads/writes). createMemoryRuleStore ships for tests; a drizzle/ Postgres store is a few lines against your own tables (see the onSpark reference integration).

Closed rule vocabulary

defineRuleVocabulary declares triggers and actions with typed, bounded parameters once; validator, tool schemas, and engine all derive from it.

Hallucination-proof validation

validateRuleInput rejects unknown triggers and actions with the available options spelled out (an error the LLM can relay verbatim), strips unknown params, clamps numbers to bounds, and narrows closed-set strings.

Derived LLM tool schemas

ruleToolSchemas emits create/update tool inputs whose trigger and action fields are enums of your vocabulary, so the agent cannot invent behavior.

Guarded firing engine

createRuleEngine fires occurrences with per-entity cooldowns via a firing ledger, daily firing and auto-execution caps, a kill switch, and your authoring policy re-checked at fire time.

Pluggable rule storage

Storage plugs in through the small RuleStore interface; createMemoryRuleStore ships for tests, and a Drizzle or Postgres store is a few lines against your own tables.

Outcomes

What you can build

Overview

Typed standing automations ("if X do Y") for AI-agent products — safe for the agent itself to author.

The idea

Letting an LLM create automations on a member's behalf is only safe if the rule language is closed. This package makes the vocabulary the contract: you define your triggers and actions once, with typed, bounded parameters, and everything derives from that single definition —

Quick start

Storage is pluggable via the small RuleStore interface (list enabled rules, ledger reads/writes). createMemoryRuleStore ships for tests; a drizzle/ Postgres store is a few lines against your own tables (see the onSpark reference integration).

Hardening checklist

Production guidance

Make every external boundary explicitPin the deployed @absolutejs/rules version, replace example or memory-backed dependencies with durable implementations, bound external calls, protect credentials, and emit enough evidence to retry or recover safely.

Follow in order

Troubleshooting path

1
Trace from the first failed boundary
Reproduce the smallest canonical @absolutejs/rules example, confirm the supported entry point and version in the API explorer, then inspect the first boundary that did not produce its documented result.

#Quick start

Partial snippet

Working example for Quick start.

TS
import {
	createMemoryRuleStore,
	createRuleEngine,
	defineRuleVocabulary,
	ruleToolSchemas,
	validateRuleInput
} from '@absolutejs/rules';

const vocabulary = defineRuleVocabulary({
	triggers: {
		no_reply: {
			label: 'My outreach gets no reply',
			paramsHelp: 'days (default 4)',
			params: {
				days: { type: 'number', min: 1, max: 30, defaultValue: 4 }
			}
		}
	},
	actions: {
		draft_followup: {
			label: 'Draft a follow-up for my approval',
			paramsHelp: 'none (guidance styles the copy)',
			capability: 'outbound'
		}
	}
});

// 1. Validate anything that wants to become a rule (AI tool, REST, forms):
const result = validateRuleInput(
	vocabulary,
	{
		trigger: 'no_reply',
		action: 'draft_followup',
		triggerParams: { days: 45 }
	},
	{
		canUseAction: (action) =>
			memberTier !== 'restricted' ||
			'Outbound rules need a higher score.',
		canAutoSend: () =>
			memberTier === 'trusted' || 'Auto-send needs the trusted tier.'
	}
);
// result.ok.triggerParams.days === 30 (clamped)

// 2. Give your agent the tools (schemas only — you own the handlers):
const { createInput, updateInput, help } = ruleToolSchemas(vocabulary);

// 3. Fire occurrences from your signal hooks / sweeps:
const engine = createRuleEngine({
	vocabulary,
	store, // your RuleStore (drizzle, memory,)
	executeAction: async (rule, event, { autoSend }) => {
		// queue a draft for approval, create a task, auto-execute…
		return autoSend ? 'executed' : 'drafted';
	}
});

await engine.fire(
	ownerId,
	{
		trigger: 'no_reply',
		entityId: `noreply:${matchId}`,
		context: 'no reply from Brendan in 5 days',
		signal: { days: 5 }
	},
	{
		killSwitch: false,
		cooldownDays: 3,
		maxFiringsPerDay: 10,
		maxAutoPerDay: 3,
		canUseAction: () => true,
		canAutoSend: () => true
	}
);

#Quick Start

Partial snippet

Define the vocabulary once; validation, agent tool schemas, and the guarded firing engine all derive from it.

TS
import {
	createRuleEngine,
	defineRuleVocabulary,
	ruleToolSchemas,
	validateRuleInput
} from '@absolutejs/rules';

const vocabulary = defineRuleVocabulary({
	triggers: {
		no_reply: {
			label: 'My outreach gets no reply',
			paramsHelp: 'days (default 4)',
			params: {
				days: { type: 'number', min: 1, max: 30, defaultValue: 4 }
			}
		}
	},
	actions: {
		draft_followup: {
			label: 'Draft a follow-up for my approval',
			paramsHelp: 'none (guidance styles the copy)',
			capability: 'outbound'
		}
	}
});

// 1. Validate anything that wants to become a rule (AI tool, REST, forms):
const result = validateRuleInput(
	vocabulary,
	{
		trigger: 'no_reply',
		action: 'draft_followup',
		triggerParams: { days: 45 }
	},
	{
		canUseAction: () => true,
		canAutoSend: () => 'Auto-send needs the trusted tier.'
	}
);
// result.ok.triggerParams.days === 30 (clamped)

// 2. Give your agent the tools (schemas only; you own the handlers):
const { createInput, updateInput, help } = ruleToolSchemas(vocabulary);

// 3. Fire occurrences from your signal hooks / sweeps:
const engine = createRuleEngine({
	vocabulary,
	store, // your RuleStore (drizzle, memory, ...)
	executeAction: async (rule, event, { autoSend }) =>
		autoSend ? 'executed' : 'drafted'
});

await engine.fire(
	ownerId,
	{
		trigger: 'no_reply',
		entityId: `noreply:${matchId}`,
		context: 'no reply from Brendan in 5 days',
		signal: { days: 5 }
	},
	{
		killSwitch: false,
		cooldownDays: 3,
		maxFiringsPerDay: 10,
		maxAutoPerDay: 3,
		canUseAction: () => true,
		canAutoSend: () => true
	}
);
Alpha API
This is an early release used by the hosted AbsoluteJS.ai Studio; pin an exact version while the vocabulary and engine APIs continue to mature.
Bounded free text
The only free text a rule carries is guidance, a bounded style note applied to generated copy. It never selects behavior.

#API reference

Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.

25 symbols
createRuleEngineexportPermalink
TS
createRuleEngine
Exported from @absolutejs/rules

Current package surface

What ships today

@absolutejs/rulesv0.1.0 · betaAInpmSource
3entry points26symbols

Import surface · click to copy