@happyvertical/smrt-approvals
A decision gate: revision-bound, single-use approvals with quorum, expiry, tenant policy, and an append-only event ledger.
What it gives you
A decision gate: revision-bound, single-use approvals with quorum, expiry, tenant policy, and an append-only event ledger.
- 01A package defines an approval kind; a requester opens a request bound to one revision of one subject
- 02Only human principals of the same tenant holding the kind’s permission decide, once each; agents and services may request and consume
- 03Not a workflow engine: no stages, no executor, no compensation
Request, decide, consume
ApprovalRequest is one gate on one subject revision. ApprovalEvent is the append-only ledger and the source of truth. ApprovalPolicy lets a tenant tighten a kind with a higher quorum, a shorter expiry, or one more permission; it can never loosen the defaults. An approved request is consumed exactly once against the revision the consumer is about to act on.
Concurrency has one winner
Every transition is one guarded conditional UPDATE plus one event insert in the same transaction. Concurrent double approval or double consumption has exactly one winner; the loser is refused and writes nothing. Each transition returns transitioned, already_applied for an idempotent requestKey replay, or refused with a typed reason.
Only the service writes
A request or event built directly is refused at the model layer. Events cannot be updated or deleted. Optional self-approval needs an explicit selfApprovalPermission on the kind and is recorded on the event.
Package UI
No UI layer to carry
This package stays focused on models, runtime behavior, or tooling. Build its interface with smrt-ui, or use a related domain package that exposes a /svelte entry point.
Intentionally headless
Package previews
No playground module yet
This package does not currently export a ./playground module. Its component names and import path remain available in the Components tab.
Intentionally not registered
Generated interface
REST
The exact route set comes from each model's @smrt({ api }) policy
and the application manifest—not from a second controller definition.
The generated REST and MCP surface is list and get only, and there is no generated CLI. Writes go through ApprovalService.
Generated interface
MCP
AI tools are generated from the methods you explicitly include. Their inputs are validated against the same model metadata used by REST and CLI.
The generated REST and MCP surface is list and get only, and there is no generated CLI. Writes go through ApprovalService.
Browser-native agent interface
WebMCP
The generated web definitions carry the same tool names, descriptions, and JSON Schema
inputs as MCP. smrt-web registers them with document.modelContext.
The generated REST and MCP surface is list and get only, and there is no generated CLI. Writes go through ApprovalService.
Generated interface
CLI
The app CLI turns manifest resources into predictable operator commands while keeping package-specific actions close to their models.
The generated REST and MCP surface is list and get only, and there is no generated CLI. Writes go through ApprovalService.