@sprig-and-prose/receipts
v0.1.7
Published
Doc-comment receipt scanner: turns @sprig markers in source files into receipts that link back to universe manifest IDs
Downloads
1,235
Readme
@sprig-and-prose/receipts
A doc-comment receipt scanner. It reads @sprig markers in your source files
and turns them into receipts — small records that acknowledge a named entity
from a compiled universe manifest at a real source location.
A receipt never defines anything. It is the reality side of sprig & prose: the universe (prose) names what exists; a receipt is evidence that the code actually references one of those names, and where.
Most people never call this package directly. You produce receipts with
sprig observeand read them back withsprig ui. This package is the pure engine underneath.
The @sprig marker
Write a marker in a comment, anywhere the file's language supports comments:
/**
* @sprig Garden.Plant
*
* The Plant concept is created and rendered here.
*/
export function plant() { /* ... */ }# @sprig Garden.Plant
# The primary plant entity lives here.
plant:
id: 1Rules:
- Target —
@sprigis followed by a dotted manifest id (e.g.Garden.Plant,Garden.grows). It must match an id in the universe manifest to be recognized; otherwise it is recorded as unrecognized (drift), never refused. - Note — any remaining prose in the comment block becomes the receipt's
details.note. - One marker per comment block — if a block has more than one
@sprig, only the first is recorded and a warning is emitted. - Subject — the "thing that lives here" is inferred automatically: the code before a trailing comment, otherwise the next non-blank, non-comment line.
Supported file types
.yaml, .yml, .js, .mjs, .cjs, .jsx, .ts, .tsx, .css, .scss,
.html, .htm, .md, .markdown, .toml, .sh, .bash, .py
Comments inside string literals are ignored, so a // inside a quoted string
won't be mistaken for a marker.
The receipt shape
Each receipt is lean — run-level facts live on the bundle envelope the CLI assembles, not on every receipt:
{
"receipt": "rcpt_<sha256>", // content-addressed id (stable across runs)
"target": "Garden.Plant", // the acknowledged manifest id
"targetKind": "concept", // concept | dimension | relationship | null
"resolution": "recognized", // recognized | unrecognized
"details": { "note": "…" },
"source": {
"file": "src/plant.js",
"line": 3,
"column": 4,
"subject": "export function plant() {",
"subjectLine": 6,
"contextHash": "sha256:…"
}
}The receipt id is a SHA256 over the target, location, surrounding context, note,
and the manifest snapshot id. Re-scanning an unchanged state of reality yields the
same id (idempotent); any real change produces a new one. Observation time is
not part of the id — it is a run-level fact the CLI stamps once on the bundle.
Library API
The engine is pure: text + manifest in, receipts + diagnostics out. All filesystem work (globbing sources, writing the bundle) lives in the CLI.
import { scanFiles, supportedExtensions, PRODUCER } from '@sprig-and-prose/receipts';
const { receipts, diagnostics } = scanFiles({
files: [{ file: 'src/plant.js', text: '…' }],
manifest, // a compiled universe manifest
onUnrecognized: 'warn', // 'error' | 'warn' | 'silent'
});scanFiles({ files, manifest, onUnrecognized })— scan many files.scanText({ file, text, manifestIndex, onUnrecognized, ext })— scan one.supportedExtensions()/grammarForExtension(ext)— the extension registry.PRODUCER—'scan@doc', identifying doc-comment scanning as the producer.
Not built yet
receipt()runtime producer — the package exports an inertreceipt()placeholder so code can already be written against the eventual call form. It is not implemented: it warns once and returns. Today the only producer is the doc-comment scanner (scan@doc); a future runtime producer would emit the same receipt shape with measured details.
See the CLI README for the observe -> ui workflow and the
receipt.json bundle, including where the receipt system is headed (shipping
receipts per environment to a central place for a live reading).
