Packages / @de_canter/apogee-rules

@de_canter/apogee-rules

v0.2.0Live demo →

Natural-language business rules: host-declared dimensions, parse into assertions, validate, detect conflicts, evaluate in two layers, audit.

$ pnpm add @de_canter/apogee-rules

@de_canter/apogee-rules

Natural-language business rules for an AI assistant: the host declares what a rule can condition on, an administrator describes a rule in plain language, the model proposes it as a kernel Assertion, the administrator confirms it, and from then on the rule is injected into the assistant's prompt and evaluated in two layers. Spec: docs/design/ai-abstractions.md §3.6.

Surface

Concept Import One-liner
Dimensions defineDimensions({ event: z.enum([...]), ... }) The host's condition vocabulary; yields conditions and facts schemas and a prompt description
Rule Rule<S>, defineRule, ruleSchema, findMatchingRules, matchesConditions Conditions typed by the dimensions, instruction, actions, structured checks, priority, kernel Provenance
Checks evaluateChecks, resolvePath, CheckResult Deterministic checks (exists, not_empty, eq, gt, matches, min_count, ...) against a subject object
Evaluate evaluateGate(rules, engine, { facts, subject }), evaluateRule Layer 1 conditions and checks; layer 2 one model call over the instructions; decidedBy says which layer decided
Compile compileRules, formatRule, rulesContributor Matching rules as a prompt section; a @de_canter/apogee-prompts contributor for a rules slot
Parse parseRule(text, engine) → ParsedRule, confirmRule, rejectRule Natural language to a proposed Assertion with confidence and ambiguities; confirmation records who and when
Validate validateRule, validateRules, structuralDiagnostics, crossRuleDiagnostics S0xx structural, C0xx cross-rule, optional A0xx model checks
Conflicts detectConflicts, deterministicConflicts, resolutionsFor Identical or nested conditions, priority ties, and (with ai) contradictory instructions, each with resolutions
Suggest suggestRules(auditEntries, rules, engine), aggregateAudit Off-script actions and low-engagement rules become proposed rules
Simulate simulate(rules, scenarios, { dims }) Which rules match a scenario, their checks, the compiled section; no model
Store RuleStore, createInMemoryRuleStore, createRuleLoader Persistence port; DB-first loader with a TTL cache and a fallback
Audit RuleAuditSink, createInMemoryRuleAudit Every rule firing and every admin decision, queryable
Tools ruleTools({ engine, store, audit, actorFromCtx }) Admin tool set for @de_canter/apogee-agent: propose, confirm, reject, list, toggle, delete, simulate, check conflicts
Prompts rulesPromptRegistry(), RULE_PARSER_PROMPT, ... The five registered prompts this package sends

Guarantees

Example

const dims = defineDimensions({
  event: z.enum(['rental.created', 'rental.returned']),
  rentalTier: z.enum(['standard', 'high-value']).describe('high-value when the total is $2,000 or more'),
});
const engine = { dims, client, domain: 'an equipment rental company', categories: ['desk', 'gate'] };
const store = createInMemoryRuleStore<typeof dims.shape>();
const loader = createRuleLoader({ store, fallback: () => seedRules });

// Admin assistant: an agent session with the rule tools and memory.
const { tools } = ruleTools({ engine, store, audit, actorFromCtx: (c) => ref('User', c.manager), onChange: () => loader.invalidate() });
const admin = createAgentSession({ sessionId, client, prompt: adminPrompt, tools: [...tools, memoryTool(...)], ctx });

// Desk assistant: the same rules, injected into its prompt.
const desk = createAgentSession({
  sessionId, client, prompt: deskPrompt, tools: deskTools, ctx,
  contributors: { rules: rulesContributor({ rules: () => loader.rules(), factsFromCtx: (c) => ({ rentalTier: tierOf(c) }) }) },
});

// Gate: structured checks, then the instructions.
const gate = await evaluateGate(await loader.rules(), engine, { facts: { event: 'rental.created', rentalTier: 'high-value' }, subject: rental });
if (!gate.passed) console.log(gate.errors, gate.ai?.findings);