Skip to content

Collections

A knowledge base holds prose — policies, guides, FAQs, the kind of thing an agent reads and paraphrases. A Collection holds structured records: rows with typed fields you filter, count, look up, and keep up to date. Where a knowledge entry answers “what is our returns policy?”, a Collection answers “which of our 400 assets are due for inspection this month?”

Collections are built and maintained by your agents. They live in your organisation’s own Sprigr index, alongside your knowledge bases, and they are the right home for any dataset your team will come back to over time.

A Collection is a typed set of records with three defining properties:

  • Typed — every field has a declared type (string, number, boolean, enum, or date). Incoming values are coerced and validated against the schema, so a “price” field always holds a number and a “status” field only holds one of its allowed values.
  • Deduplicated — each record has a deterministic identity (its key), derived from the fields you nominate. Re-ingesting the same source record maps to the same record and updates it in place, rather than creating a duplicate. Loading the same spreadsheet twice is safe.
  • Faceted — fields you flag as facets become filterable and countable. An agent can filter to status:available AND location:warehouse-2 and get value counts grouped by any facet, the same fast group-by-count that powers the rest of Sprigr search.

Typical Collections:

  • Asset registers — equipment, serial numbers, locations, inspection dates
  • Inventories — items on hand, quantities, shelves, reorder points
  • Contact lists and CRMs — people, companies, roles, last contact
  • Parts catalogues — part numbers, suppliers, sizes, prices
  • Compliance and obligations logs — requirements, owners, due dates, status

How Collections differ from knowledge entries

Section titled “How Collections differ from knowledge entries”
Knowledge entryCollection record
ShapeFreeform title + content + keywordsTyped fields you declare up front
IdentityEach entry is its own thingDeduplicated by a deterministic key
Read patternSearch returns a distilled answerQuery returns whole records, filtered and counted
Best forProse an agent reads and paraphrasesData the user filters, looks up, updates, or reconciles

Rule of thumb: if the answer is a paragraph, use Shared Knowledge. If the answer is a filtered list or a count over rows, use a Collection. And if the user only needs to see an extraction once and will never come back to it, neither — a one-off file is enough.

A Collection is declared before anything is ingested. Defining it sets its scope, its typed fields, which fields are facets, and the key that makes a record unique.

  • Scopeprivate (only the caller reads and writes it) or company (every agent in the organisation shares it).
  • Name suffix — a slug-safe suffix (lowercase letters, digits, dashes, up to 64 characters). The full Collection name is derived from the scope and suffix and returned to the agent, so names never collide between organisations.
  • Fields — each field has a name and a type. Flags on a field:
    • facet: true makes it filterable and counted (facets must be declared at define time).
    • searchable: true includes it in full-text search.
    • required: true rejects any record that lacks it.
    • values lists the allowed values for an enum field.
  • Key — how a record’s identity is derived, which is also what dedupes it:
    • natural — one field is the identity (an email, an ISBN, a serial number).
    • composite — several fields together are the identity (supplier plus part number).
    • surrogate — keyless data, where a caller-supplied id is honoured or a random one is minted.
    • Optional normalize operations (lower, upper, trim, collapse_ws, strip_nonalnum) are applied to key fields before matching, so John@Example.com and john@example.com resolve to the same record.

Defining is idempotent: calling define again with the same name updates the schema rather than erroring, so a Collection can evolve as your needs change. The schema is stored inside the index itself, so a Collection is self-describing.

  • History — turn on append-only change history (see History and versioning). Off by default; it adds a small read-before-write cost to each ingest.
  • Row-level access control — for the case where different end users must see different rows of the same Collection. Each record’s visibility is derived at ingest from identity fields you name (a user email field, a group field), and queries return only the rows a requester may see. A row whose identity fields are empty is visible to no one, so it fails closed. Use this only when per-user visibility is genuinely needed; ordinary Collections are readable by every agent in the organisation. Row-level access control is mutually exclusive with history.
  • Lifetime — when the Collection should be auto-swept. Omitting it makes the Collection permanent (the default). You can instead set ttl_days to delete it a fixed number of days after creation, or bind it to a conversation so it is deleted once that conversation is archived. This is for scratch, per-conversation data that should not pile up.

Once a Collection is defined, records go in through ingest. Each batch is validated and coerced against the schema, deduplicated by the key, and stamped with provenance (which source contributed each field). Up to 1000 records go in per batch, and any records that fail validation come back in a rejected list with the reason, so a bad row never silently disappears.

There are two ways in.

The most common path: you tell your agent what to track, and it builds the records from the conversation and loads them. This is how the fire-extinguisher example above works — you describe the fields and the items, and the agent ingests them.

When the source is a spreadsheet or CSV, the agent maps the columns to fields declaratively rather than hand-writing extraction code. It supplies the parsed rows, a mapping from source column name to Collection field, optional constant fields stamped on every record, and optional unit scaling (for example, converting an “in” column to millimetres). The mapped rows then run through the same validate-and-dedup pipeline as any other ingest.

When an incoming record has the same key as one already stored, a merge policy decides what happens:

  • Last write wins (the default) replaces the stored record with the incoming one. Every field you do not supply is wiped, so use this when you are sending the whole record.
  • Merge deep-merges only the fields you supply onto the stored record, leaving every other field (and its provenance) untouched. Use this for a partial update — setting one contact’s phone number without resending their name and email.
  • Conflict hold keeps the stored value when a different source disagrees on a field, and holds the incoming value aside in a conflicts shadow that is returned for review. This stops a re-import from one source quietly clobbering a value another source set. The agent reviews the held conflicts and resolves them by re-ingesting an explicit decision.

Querying reads whole records back out. A query can combine:

  • Full-text search over the searchable fields, or an empty query to browse filter-only.
  • Facet filters — an expression like status:available AND subject:CS. Filtered fields must be declared facets.
  • Facet counts — ask for value counts on any facet fields to get a group-by-count breakdown (how many records per status, per shelf, per location).
  • Sort — override the default sort, for example desc(updatedAt) or asc(name).
  • Pagination — results come back a page at a time (up to 100 per page).

Unlike a knowledge search, which returns a distilled answer, a Collection query returns the actual records, so the agent can list them, total them, or act on them.

Reconcile is a read-only cross-source diff. It matches another source against a Collection by a key and reports what has drifted:

  • Added — records in the other source with no match in the Collection
  • Removed (the gap) — records in the Collection with no match in the other source
  • Changed — records that match but differ on one or more compared fields, with the before and after for each field
  • Unchanged — records that match with no differences

The other source can be a fresh set of records (say, a newly received supplier list) or another Collection in your organisation. Because reconcile is read-only, nothing is written — the agent reviews the report with you, then commits the decision by ingesting it. This is the “here is what changed since last time, shall I apply it?” workflow.

When a Collection is defined with history turned on, every ingest records a field-level change log: one event per changed field, capturing the field name, the value before, the value after, the source, and the timestamp. The history is append-only and stored separately from the records themselves, so the Collection’s own counts and queries stay clean.

An agent can read the history for the whole Collection (recent changes across all records) or scope it to a single record and even a single field, newest first. This answers questions like “when did this asset’s status change to decommissioned, and who set it?”

History is off by default because it adds a small read-before-write cost to each ingest, and it is mutually exclusive with row-level access control. Turn it on at define time for Collections where an audit trail matters — compliance logs, asset registers, anything with regulatory weight.

Collections are an agent-maintained surface. You work with them in three ways.

The primary path. You describe what to track and your agent handles the define, ingest, query, reconcile, and history steps for you. You never write a schema by hand — you say what the records look like and what makes each one unique, and the agent translates that into a Collection. Everyday questions (“how many are overdue?”, “add these five”, “what changed since last week?”) are just chat.

External AI clients connected to Sprigr Teams over MCP get the same capabilities through a set of dedicated tools:

  • collection_define — declare the Collection (fields, facets, key).
  • collection_ingest — upsert a batch of records.
  • collection_ingest_from_table — map and ingest parsed spreadsheet or CSV rows.
  • collection_query — read records back with filters, facet counts, sort, and pagination.
  • collection_reconcile — diff another source against the Collection.
  • collection_describe — introspect the schema, record count, per-facet counts, and contributing sources.
  • collection_history — read the append-only change log.

See the MCP Overview for how to connect an external client.

Collections do not have their own management page in the portal today — they are created and maintained by agents (through chat or MCP), not hand-edited in the UI like knowledge entries. To see what a Collection holds or to change it, ask the agent that owns it: it can describe the schema and counts, query the records, and apply updates on your behalf.

  • Knowledge Bases Overview — The standard indexes and how agents search prose knowledge.
  • Custom Indexes — Create additional knowledge indexes with private, company, or public scope.
  • MCP Overview — Work with Collections and indexes from external AI clients.
  • Creating Agents — Build the agents that maintain your Collections.