# Application records

TendBase memory remains the default for things the user asks you to remember. Application records are an optional, typed layer in the same account. Use them when the user wants a structured list they will query exactly, such as tasks, a project tracker, or an inventory. They are also the right choice when software needs stable keys, validation, conditional writes, or ordered pages.

TendBase does not create collections automatically and has no built-in business schemas. Create a collection only when the user asks for this kind of structure, or agrees when you propose it.

## Tools

- `tendbase_get_collection` and `tendbase_define_collection` read and define a collection.
- `tendbase_application_transaction` commits puts and deletes atomically.
- `tendbase_get_record` reads one record by key.
- `tendbase_list_records` reads ordered, optionally filtered pages.

Call `tendbase_help` first. Its session policy shows the application role: `none` blocks these tools.

## Schemas belong to the user

- Use the user's own words for collection and field names. The examples here are only illustrations.
- Before you define a collection, call `tendbase_get_collection`. If it already exists and fits, reuse it. If it lacks a field, add that field as optional with the current revision. If it conflicts, ask the user. Never delete records or collections to make a definition fit.
- Declare only the fields the user needs. Field types are `string`, `number`, `boolean`, `datetime`, and `json`. A field used for sorting or a unique constraint must be required and scalar.

An illustrative task collection:

```json
{
  "name": "tasks",
  "fields": {
    "title": { "type": "string", "required": true },
    "state": { "type": "string", "required": true },
    "dueAt": { "type": "datetime", "required": true },
    "timezone": { "type": "string" },
    "projectKey": { "type": "string" },
    "estimateHours": { "type": "number" }
  },
  "sortableFields": ["dueAt"]
}
```

## Keys, display names, and references

- A record key is a stable identifier, not a display name. Two records can share a title or name, so add a unique suffix, such as `task:renew-passport-k7q2`. Never build a key from a display name alone.
- When a lookup by name finds more than one record, or a match is uncertain, show the candidates and ask the user before updating or merging.
- A field that holds another record's key, such as `projectKey`, is a reference that TendBase stores as text. TendBase does not check that the target exists and does not cascade updates or deletes. Create or confirm the target first, and write its exact key.

## Writes

- Use one idempotency key per logical change, and reuse it for retries. A replay returns the original receipt with `replayed: true`.
- Create with `{ "kind": "create" }` so a retry or a duplicate key cannot overwrite an existing record.
- Put records that must change together in one transaction. If any command fails, none of them commit.
- A put replaces the whole value, so any field you leave out is removed. To update a record, read it, merge your change into the full value, and write it with `{ "kind": "revision", "revision": <revision you read> }`. On a conflict, read and merge again. Never force the write with `any`.
- Report a write only after TendBase returns a committed receipt.

## Filters and complete pages

`tendbase_list_records` accepts an optional `where` array with 1 to 20 filters. All of them must match (AND).

- `eq` works on string, number, boolean, and datetime fields.
- `lt`, `lte`, `gt`, and `gte` work on number and datetime fields.
- A record without the field does not match. An undeclared field, a `json` field, an unsupported operator, or a value of the wrong type returns an error. Fix the filter; do not drop it.
- Filters run before the page limit. When a page returns `nextPosition`, pass it as `after` and keep `collection`, `orderBy`, `direction`, and `where` unchanged. Read until no `nextPosition` is returned before you say a list is complete.

Open tasks due before the end of 2 October 2026 in Chicago:

```json
{
  "collection": "tasks",
  "orderBy": "dueAt",
  "where": [
    { "field": "state", "op": "eq", "value": "open" },
    { "field": "dueAt", "op": "lte", "value": "2026-10-02T23:59:59.999-05:00" }
  ]
}
```

## Time

- Store datetimes in UTC with three fractional digits, such as `2026-10-02T15:00:00.000Z`. Sorting compares the stored text, so a single format keeps sort order equal to time order.
- When local time matters, keep the user's IANA time zone in a field such as `timezone`, and convert times back to it when you display them.
- Datetime filters compare instants and may carry a UTC offset. Both sides are rounded to the nearest millisecond (a fraction of .9995 seconds or more is held at .999 of the same second), so values that differ by less than a millisecond can compare as equal.
- TendBase stores times but does not schedule or send reminders.

## Export and delete

- `tendbase_export` covers memory objects and relations only. To export application records, page through `tendbase_list_records` for each collection with `orderBy: "$key"` until no `nextPosition` is returned.
- An application delete is a direct, revision-guarded command that takes effect when its transaction commits, with no confirmation step. Memory deletion takes two confirmed steps. Delete either one only when the user explicitly asks, and confirm the exact records first. When the user wants to keep history, record the change in a field the user defined instead of deleting.

TendBase is free during beta. Built by JV, [@jvivas_official](https://x.com/jvivas_official). Please do not abuse it.