tulipfarm docs
Concepts

Resources

Schema-defined data types and the records that fill them.

A resource is a data type, like customer or ticket. A resource type is its shape; a record is one instance of that type. You create a type by describing it to the assistant — "track customers with a name and an email" — and from then on you get validated storage and a full interface for its records.

You never have to write the shape yourself. The rest of this page describes what the assistant builds on your behalf and how it behaves, so you know what is possible to ask for. To do it, see Define a resource type.

Two halves: schema and data

Under the hood a type is a JSON Schema the assistant writes into the soul at resources/{name}/schema.yml; the records live in the datastore. TulipFarm reads each schema and materializes a table for it — this is called reconciliation. A type the assistant creates is reconciled immediately, ready to hold records with no restart.

The schema it writes is plain JSON Schema in YAML — for the customer example, this:

resources/customer/schema.yml
type: object
properties:
  name:
    type: string
  email:
    type: string
    format: email
required:
  - name

Every write is validated against the schema before it is stored.

Identifiers

Each record has a system id that is a UUID — stable, internal, and used for linking. Human-friendly identifiers like TICK-123 are a separate field, produced by the x-id-strategy extension and never the primary id:

properties:
  ref:
    type: string
"x-id-strategy":
  field: ref
  prefix: "TICK-"
  sequence: true

A field can declare that it points at another resource using x-links. On write, TulipFarm verifies the target record exists; a link to a missing record is rejected. This catches the common case of an agent inventing a customerId that was never real.

Deletes are soft and do not cascade. If you delete a record that others link to, the referencing records remain — their link simply no longer resolves to a live record, and the UI surfaces it as unresolved rather than blocking the delete.

Computed and normalized fields

Beyond identifiers and links, schemas support declarative transforms applied before a write:

  • x-normalize — clean a value into canonical form. Supported strategies: trim, lowercase, uppercase, slugify, phone-e164, email-normalize.
  • x-computed — derive a field's value from others. Supported strategies: sha256, uuid, sequence.

These cover the common before-write cases without code. For arbitrary logic, a resource type can include a hooks.ts file executed in an isolated sandbox (isolated-vm). You ask for these in plain language too — "auto-number tickets as TICK-1", "lowercase the email" — and the assistant wires up the right extension.

You create resource types by asking the assistant — see Define a resource type. You can also edit schema.yml in the soul by hand if you prefer; that is the power-user path. Either way, Work with records covers managing data once a type exists.

On this page