Observe

A universe describes what could be true.

observe is how reality reports back.

It scans a codebase for small markers, and for each one writes a receipt — a quiet record that something the universe names exists here, at this place, at this moment.

It never changes the universe. It only adds evidence.


Marking code

You point at a universe entity from an ordinary comment, using a @sprig tag.

/**
 * @sprig Garden.Plant
 *
 * The Plant concept is defined and rendered here.
 */
export function plant() { /* ... */ }

The same idea works anywhere comments do — for example, in YAML:

# @sprig Garden.Plant
#
# The seed data for plants lives here.
plants:
  - tomato
  - basil

Three things are captured:

  • the target — a concept, dimension, or relationship the universe names (Garden.Plant)
  • the note — the rest of the comment, kept as-is
  • the subject — the next line of code, so the receipt remembers what it was attached to

Nothing else is required. If a file has comments, it can speak.


Running observe

A prose repository holds only prose. Your code lives elsewhere, as a projection of that truth. So observe runs in the code repository and points at the universe it answers to.

sprig observe --universe ../garden/universe.prose

The universe is compiled on the fly — no prior sprig compile is needed.

You can also set the universe once, so you don’t have to repeat it. observe looks in this order:

  1. --universe <path> on the command line
  2. the SPRIG_UNIVERSE_FILE environment variable
  3. a .sprig/config file in the repository
  4. a local universe.prose, if one happens to be present

A .sprig/config mirrors the prose convention and keeps the setting with the repo:

SPRIG_UNIVERSE_FILE=../garden/universe.prose

File discovery honors the repository’s .gitignore, so build output and dependencies are left alone. node_modules, .git, and .sprig are always skipped.

For the full set of options:

sprig observe --help

Receipts

Every run writes a single file — .sprig/receipt.json — regenerated each time, shaped like the manifest.

{
  "schema": 1,
  "meta": {
    "observedAt": "2026-07-10T22:44:19.267Z",
    "manifestId": "git:b040b749…",
    "producer": "scan@doc",
    "universe": "../garden/universe.prose"
  },
  "counts": { "total": 1, "recognized": 1, "unrecognized": 0 },
  "receipts": [
    {
      "receipt": "rcpt_4fda98…",
      "target": "Garden.Plant",
      "targetKind": "concept",
      "resolution": "recognized",
      "details": { "note": "The Plant concept is defined and rendered here." },
      "source": {
        "file": "src/plant.js",
        "line": 2,
        "column": 4,
        "subject": "export function plant() {}",
        "subjectLine": 6,
        "contextHash": "sha256:…"
      }
    }
  ]
}

Run-level facts live once on meta. Each receipt stays lean: what was named, and where it was found.

It is one small artifact per repository — easy to read, easy to hand to something upstream.


Recognized and unrecognized

A receipt is recognized when its target exists in the universe, and unrecognized when it does not.

Unrecognized targets are not dropped. Reality is allowed to mention something the universe hasn’t named yet — that is a useful signal, not an error. The receipt is recorded and clearly labeled.

How loudly this surfaces is up to you:

sprig observe --on-unrecognized warn    # default
sprig observe --on-unrecognized error   # fail the run
sprig observe --on-unrecognized silent  # record quietly

The universe stays the single source of truth for what things are. Receipts simply report what was seen.


Liveness and identity

Two things sit side by side in a receipt, and they answer different questions.

  • meta.observedAt is liveness — when reality was last confirmed. It refreshes on every run.
  • receipt (the id) is identity — a content hash of what was observed. For a git-backed universe it stays stable across runs, so the same observation keeps the same id.

Running observe again over unchanged code refreshes the timestamp while the ids hold steady. A change in the code, or in the universe, produces a new id.


What comes next

Receipts record what is true. The directions below are still in development — none of them are built yet:

  • reconciliation — comparing receipts against the universe, to see what is present, missing, or drifting
  • runtime emission — letting systems speak while they run, not only from their source
  • collection — gathering receipts upstream, across repositories and over time

The universe stays the same. Different systems respond to it.


Continue

  • Read sprig to see how a universe is compiled and explored
  • Read prose to understand the language
  • Read docs to see the documentation home

Prose describes a world. Sprig shows how systems respond to it.