Skip to content

Source

A Source is one durable row per indexed thing — a Gmail message, a Google Drive file, a local file on disk. Each row is addressed by a plugin-owned LocationKind and a canonical pathId, and is decoupled from any specific Connection that might reach it. A plugin contributes a LocationKindDefinition per kind it wants inseam to index; core registers it, persists the rows, and emits source.* events on every mutation. Plugins compile against @inseam/source-contract alone.

Source is the address leg of the Connection / Source / Access split. A row carries first-class retrieval metadata (contentType, contentSize, contentHash, displayName, upstream timestamps) plus a plugin-namespaced metadata blob. The pathId is the plugin’s stable identifier within its kind; normalize is called before every write so non-canonical forms cannot reach storage.

Path mutations swap the address atomically and emit source.path_changed; the row’s id never changes. Path history is the stream of those events, not a sibling table.

Two surfaces, split by package:

  • @inseam/source-contractLocationKindDefinition, Source, SourceInput, SourcePatch, PathMutationInput, RetrievalMetadata, the four Source*Event payloads, the typed error hierarchy. Zero runtime deps.
  • @inseam/core (Source contribution) — openSourceRegistry, SourceRegistry. Owns the in-memory Location Kind table, persistence, the (location_kind, path_id) uniqueness rule, and single-batch coupling between each row mutation and its outbox event.
  • LocationKindDefinition — the contract a plugin implements per kind. name (e.g. "gdrive.file", "gmail.message"), a deterministic normalize(pathId) that throws InvalidPathIdError for un-canonical input, and optional format / parse convenience helpers.
  • SourceRegistryregisterLocationKind, findSourceByAddress, createSource, updateSource, mutatePath, plus the listing read paths. Writes are core-internal; plugins do not call them directly today.
  • Source*Eventsource.created, source.updated, source.path_changed, source.deleted. Every row mutation lands an event in the same Store batch as the row write.

Exact signatures: @inseam/source-contract API · arch/source/spec.md.

Reach for a LocationKind when there is a thing you want inseam to remember addressably — a file, a message, a record. Don’t use Source for ephemeral state (logs, counters, cursors) — those belong in plugin KV via the plugin runtime context, or in plugin-owned tables behind a materializer if you need durability.

A row’s identity is the (locationKind, pathId) tuple, not the URI. Two plugins that both observe the “same” thing under different LocationKinds get two rows, on purpose.

  • LLM summary — dense reference for agents.
  • Connection — how an endpoint is reached; Connection declares resolves: LocationKind[] against the vocabulary defined here, with no FK between the two.
  • Events — the outbox source.* events ride.
  • Access — Envelope coupling that the future ingest package will stitch alongside every Source write.
  • arch/source/design.md — why Source is decoupled from Connection and what pathId is for.
  • arch/source/spec.md — types, behavior, errors, acceptance criteria.