@qmilab/lodestar-action-kernel
v0.5.0
Published
Tool registry, two-phase action execution, and sandbox profiles for the Lodestar epistemic chain. Part of Lodestar, the trust layer for AI agents.
Maintainers
Readme
@qmilab/lodestar-action-kernel
Tool registry, two-phase action execution, and sandbox profiles for the Lodestar epistemic chain. Part of Lodestar — the trust layer for AI agents.
The Action Kernel is the runtime gate every tool call passes through. It separates describing an intended action from executing it, so a policy gate or precondition checker can refuse the action before it touches the world.
Install
npm install @qmilab/lodestar-action-kernel
# or
bun add @qmilab/lodestar-action-kernelWhat it does
- Tool registry —
registerTool()declares a tool's name, inputs schema, output schema key, declared effects, reversibility, permissions, required trust level, sandbox profile, optional preconditions, and anexecute()function. Lookups go throughlookupTool(); nothing bypasses the registry. - Two-phase execution —
kernel.propose()builds a proposedActionfrom inputs +ActionContract.kernel.arbitrate()calls the policy gate to approve or reject.kernel.execute()re-checks preconditions (TOCTOU defense), invokes the tool, validates the output against the registered schema, and emits an Observation. - Sandbox profiles — four levels:
"read","write-isolated","write-local","controlled-shell". Declared per tool; no silent defaults. - Observations via the schema registry — every executed tool
emits an Observation validated against the output schema registered
in
@qmilab/lodestar-core.
Usage
import {
ActionKernel,
registerTool,
type PolicyGate,
type PreconditionChecker,
} from "@qmilab/lodestar-action-kernel"
import type { Action, Observation } from "@qmilab/lodestar-core"
registerTool({
name: "my.tool",
inputs: MyInputSchema, // Zod schema
output_schema_key: "my.tool@1", // registered in @qmilab/lodestar-core
effects: [], // read-only tool
reversibility: "reversible",
permissions: ["fs.read"],
required_trust_level: 0,
sandbox: "read",
execute: async (inputs, ctx) => { /* ... */ },
})
const policyGate: PolicyGate = async (action) => ({
approved: action.contract.effects.length === 0,
reason: "read-only actions are approved by default",
approver_id: "demo-policy",
})
const preconditionChecker: PreconditionChecker = async (_check) => ({
holds: true,
observed: null,
})
const observationSink = async (obs: Observation) => {
// route obs into the cognitive core / event log
}
const kernel = new ActionKernel(policyGate, preconditionChecker, observationSink)
const action = kernel.propose({
intent: "inspect repository state",
tool: "my.tool",
inputs: { /* ... */ },
contract: {
required_level: 0,
blast_radius: "self",
reversibility: "reversible",
scope: { level: "project", identifier: "my-project" },
data_sensitivity: "private", // action sensitivity is public | private | secret
preconditions: [],
},
proposed_by: "agent-1",
})
const arbitrated = await kernel.arbitrate(action)
if (arbitrated.phase === "approved") {
const executed = await kernel.execute(arbitrated)
// executed.phase === "completed" or "failed" or "rejected"
}Invariants
- No tool runs without a contract.
propose()is mandatory and validates inputs against the tool's Zod schema exactly once. - Two-phase execution is enforced by phase.
arbitrate()only runs fromproposed;execute()only runs fromapproved. - Tool-declared preconditions cannot be dropped. The kernel merges tool preconditions with the caller's contract; the caller can only add, not remove.
- Preconditions are re-validated at execution time. Any
precondition with
must_revalidate_at_execution: trueis re-checked immediately beforetool.executeruns — TOCTOU defense. - Outputs are validated against the registered schema. A tool
returning a value that doesn't match its
output_schema_keyraises a structural error rather than entering cognition.
