* Add stable trigger selectors to runtime and CLI * Update Grimoire skill docs for trigger selectors * Add trigger discovery CLI command * Fix --no-state CLI flag parsing
9.2 KiB
Compiler and Runtime API Reference
This page documents the programmatic API exported by @grimoirelabs/core.
Compiler API
Source: packages/core/src/compiler/index.ts
compile(source: string): CompilationResult
Compiles Grimoire source text.
Stages:
- parse AST
- transform to SpellSource
- generate IR
- type-check IR
- validate IR
Returns:
successirwhen successfulerrorswarnings
compileFile(filePath: string): Promise<CompilationResult>
Reads a .spell file and compiles it.
parseSpell(content: string): ParseResult
Parses source into SpellSource (without full compile/validate pipeline).
parseSpellFile(filePath: string): Promise<ParseResult>
File path variant for parse-only workflow.
Expression helpers
parseExpressiontryParseExpression
Runtime API
Source: packages/core/src/runtime/interpreter.ts
Runtime semantics are consistent across CLI and library entry points.
preview(options: PreviewOptions): Promise<PreviewResult>
Runs full spell in simulation mode and emits a receipt.
Key responsibilities:
- guard checks
- step execution loop (actions as planned actions)
- advisory output capture
- value-flow evaluation and constraints
- receipt generation
Accepts an optional queryProvider for blockchain data queries (see Query Provider API below).
Selected-trigger execution:
PreviewOptions.selectedTriggeraccepts exactly one of{ id, index, label }idis the canonical stable selector exported by compilationindexis the 0-based compile order for the handlerlabelis a legacy alias and may be ambiguous for duplicate handlersPreviewResult.selectedTriggerechoes the resolved handler selector
commit(options: CommitOptions): Promise<CommitResult>
Commits planned actions from a ready preview receipt.
Validation and safety gates:
- receipt status/identity checks
- in-process preview receipt provenance checks
- drift checks and optional max-age policy
buildTransactions(options: BuildTransactionsOptions): Promise<BuildTransactionsResult>
Builds unsigned transaction calldata from a ready preview receipt, without committing it.
Designed for client-side signing flows where a server previews and the client signs:
preview() → persist receipt → buildTransactions() → sign (client) → broadcast
Validation and safety gates:
- receipt status, phase, and ID format checks
- same-process tamper detection via issued-receipt registry
- cross-process integrity verification via HMAC (see
signReceipt()below) - already-committed receipt rejection
- provider chain must match receipt chain
- drift checks (same logic as
commit())
Behavior differences from commit():
- does not require a
Wallet— only needswalletAddressfor calldata construction - does not mark the receipt as committed (calling
commit()afterwards still works) - rejects offchain-only adapters (they produce no signable calldata; use
commit()instead) - defers provider creation until an EVM action needs gas estimation
- forwards
receipt.chainContext.vaultto adapter context for correct recipient routing
Key options:
receipt: the preview receipt to build fromwalletAddress: signing address for calldata constructionprovider?: EVM provider (must match receipt chain if provided)adapters?: venue adapters for action buildingreceiptSecret?+receiptIntegrity?: required for cross-process receipts (see below)driftPolicy?,driftValues?,resolveDriftValue?: drift check configuration
signReceipt(receipt: Receipt, secret: string): string
Computes an HMAC-SHA256 integrity hash over a receipt's tamper-critical fields.
Call at preview time, persist the returned hex string alongside the receipt, and pass it as receiptIntegrity to buildTransactions() when the receipt crosses process boundaries.
Fields covered by the hash: id, spellId, chainContext, timestamp, status, plannedActions (including each action's type, venue, amounts, and constraints).
Cross-process flow:
// Server A: preview and sign
const result = await preview({ spell, vault, chain, adapters });
const integrity = signReceipt(result.receipt, process.env.RECEIPT_SECRET);
// persist receipt + integrity, respond to client
// Server B (or later request): build transactions
const buildResult = await buildTransactions({
receipt: persistedReceipt,
walletAddress: signerAddress,
adapters,
receiptSecret: process.env.RECEIPT_SECRET,
receiptIntegrity: persistedIntegrity,
});
execute(options: ExecuteOptions): Promise<ExecutionResult>
Backward-compatible wrapper that also accepts an optional queryProvider:
- always runs
preview() - commits only if runtime mode requires commit and wallet is present
Execution-mode behavior:
simulate-> preview onlydry-run-> preview onlyexecute+ wallet + planned actions -> preview + commit
ExecuteOptions.selectedTrigger uses the same selector contract as preview().
Session API
Source: packages/core/src/runtime/session.ts
runSessionrunOneShotSessionrunManagedSession
These normalize trigger metadata for one-shot and managed runs while reusing execute() semantics.
State Store API
Source: packages/core/src/runtime/state-store.ts
StateStore contract:
load(spellId)save(spellId, state)addRun(spellId, run)getRuns(spellId, limit?)saveLedger(spellId, runId, entries)loadLedger(spellId, runId)listSpells()
Helper:
createRunRecord(result, provenance?)
SQLite implementation:
SqliteStateStoreinruntime/sqlite-state-store.ts- Bun path:
bun:sqlite - Node fallback:
better-sqlite3
Key Runtime Types
SpellIR
Defines compiled spell metadata, config, steps, guards, triggers, source map, and trigger handler selectors.
Relevant trigger fields:
triggers: legacy trigger graph representationtriggerStepMap: legacy mapping from multi-trigger handler index to top-level step idstriggerHandlers: stable per-handler metadata:selector.idselector.indexselector.labelselector.sourcetriggerstepIds
ExecutionResult
Includes:
- run IDs and duration
- success/error info
- metrics
- final state
- ledger events
- selected trigger metadata (
selectedTrigger) when a handler was selected - preview receipt
- commit result (when applicable)
Receipt
Preview artifact includes:
- guard and advisory results
- planned actions
- value deltas and accounting
- constraint results
- drift keys
- approval requirement signal
- final state and metrics
Query Provider API
Source: packages/core/src/types/query-provider.ts
QueryProvider is a pluggable interface that supplies blockchain data (balances, prices, APY, etc.) to spell expressions at runtime.
QueryProvider
interface QueryProvider {
meta: QueryProviderMeta;
queryBalance?: (asset: string, address?: string) => Promise<bigint>;
queryPrice?: (base: string, quote: string, source?: string) => Promise<number>;
queryMetric?: (request: MetricRequest) => Promise<number>;
queryHealthFactor?: (venue: string) => Promise<number>;
queryPosition?: (venue: string, asset: string) => Promise<unknown>;
queryDebt?: (venue: string, asset: string) => Promise<bigint>;
}
All query methods are optional. The provider declares which queries it supports via meta.supportedQueries.
QueryProviderMeta
interface QueryProviderMeta {
name: string;
supportedQueries: Array<"balance" | "price" | "metric" | "health_factor" | "position" | "debt">;
supportedMetrics?: string[];
description?: string;
}
Data flow
- Caller passes
queryProvideronPreviewOptionsorExecuteOptions. createContext()copies it ontoExecutionContext.queryProvider.createEvalContext()binds each provider method onto theEvalContext.- Expression evaluator maps spell functions (
balance(),price(),apy(),metric(),health_factor(),position(),debt()) to the correspondingquery*method onEvalContext.
If a spell calls a query function and no provider (or no matching method) is available, the evaluator throws at runtime.
Wallet and Provider API
Source: packages/core/src/wallet/*
Exports include:
- key loading and keystore helpers
- wallet creation
- provider creation
- transaction builder
- executor
Execution modes:
simulatedry-runexecute
Executor delegates venue-specific action building/execution to adapter registry when available.
Builder API
@grimoirelabs/core exports fluent builders from packages/core/src/builders for programmatic spell construction.
Examples of exported builder helpers:
spellactioncomputeconditionalrepeatforLoopparallelpipelineadvisoryemit
Minimal Example
import { compile, execute } from "@grimoirelabs/core";
import { adapters } from "@grimoirelabs/venues";
const compiled = compile(sourceText);
if (!compiled.success || !compiled.ir) throw new Error("compile failed");
const result = await execute({
spell: compiled.ir,
vault: "0x0000000000000000000000000000000000000000",
chain: 1,
params: {},
simulate: true,
adapters,
});
console.log(result.success, result.receipt?.status);