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.
How it fits
Section titled “How it fits”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-contract—LocationKindDefinition,Source,SourceInput,SourcePatch,PathMutationInput,RetrievalMetadata, the fourSource*Eventpayloads, 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.
Key pieces
Section titled “Key pieces”LocationKindDefinition— the contract a plugin implements per kind.name(e.g."gdrive.file","gmail.message"), a deterministicnormalize(pathId)that throwsInvalidPathIdErrorfor un-canonical input, and optionalformat/parseconvenience helpers.SourceRegistry—registerLocationKind,findSourceByAddress,createSource,updateSource,mutatePath, plus the listing read paths. Writes are core-internal; plugins do not call them directly today.Source*Event—source.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.
When to use this vs alternatives
Section titled “When to use this vs alternatives”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.
See also
Section titled “See also”- 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
ingestpackage will stitch alongside every Source write. arch/source/design.md— why Source is decoupled from Connection and whatpathIdis for.arch/source/spec.md— types, behavior, errors, acceptance criteria.