> ## Documentation Index
> Fetch the complete documentation index at: https://dench.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Dench CRM: objects, fields, and queries

> Model people, companies, tasks, and custom objects in the Dench CRM with typed fields, relations, statuses, batch writes, queries, and aggregates.

The Dench CRM is the shared database for agents and humans. Every list-shaped
thing lives here, not in ad-hoc files.

<CardGroup cols={3}>
  <Card title="Objects" icon="table">
    Tables like `people`, `company`, `task`, or any custom object.
  </Card>

  <Card title="Fields" icon="table-columns">
    Typed columns: text, enum, relation, user, date, and more.
  </Card>

  <Card title="Entries" icon="list">
    Rows, written one at a time or in batches up to 200.
  </Card>

  <Card title="Cells" icon="table-cells">
    Individual values, set, appended, or read per field.
  </Card>

  <Card title="Query" icon="magnifying-glass">
    Filter, sort, paginate, search, and aggregate.
  </Card>

  <Card title="Statuses" icon="signal">
    Kanban columns with colors for any object.
  </Card>
</CardGroup>

<Note>
  `people`, `company`, and `task` are protected and cannot be deleted. Tasks are
  CRM entries on the `task` object, there is no separate `dench tasks` command.
</Note>

## Create an object

<Steps>
  <Step title="Inspect what exists">
    ```bash theme={null}
    dench crm objects list --json
    ```
  </Step>

  <Step title="Create it with an icon">
    ```bash theme={null}
    dench crm objects create lead --description "Sales leads" --default-view kanban --icon target --json
    ```
  </Step>

  <Step title="Add fields">
    ```bash theme={null}
    dench crm fields create lead "Name" --type text --required
    dench crm fields create lead "Email" --type email --indexed
    dench crm fields create lead "Company" --type relation --related-object company --relationship many_to_one --indexed
    dench crm fields create lead "Status" --type enum --enum-values '["New","Working","Qualified","Lost"]'
    ```
  </Step>

  <Step title="Optional: kanban statuses">
    ```bash theme={null}
    dench crm statuses set lead --statuses '[{"name":"New","color":"#94a3b8"},{"name":"Qualified","color":"#22c55e"}]' --json
    ```
  </Step>
</Steps>

## Field types

<Tabs>
  <Tab title="Common">
    `text`, `email`, `phone`, `url`, `number`, `boolean`, `date`, `file`, `tags`.

    ```bash theme={null}
    dench crm fields create deal "Amount" --type number
    dench crm fields create deal "Close Date" --type date
    ```
  </Tab>

  <Tab title="Enum">
    Options with optional colors. Add `--enum-multiple` for multi-select.

    ```bash theme={null}
    dench crm fields create lead "Status" --type enum \
      --enum-values '["New","Working","Qualified","Lost"]'
    dench crm fields enum-set-color lead Status Qualified "#22c55e"
    ```
  </Tab>

  <Tab title="Relation">
    Link to another object instead of flattening foreign keys to text.

    ```bash theme={null}
    dench crm fields create people "Company" --type relation \
      --related-object company --relationship many_to_one --indexed
    ```
  </Tab>

  <Tab title="User">
    Stores one workspace member `userId` or an array of member IDs. The default
    `task` user field is `Assignee`, not `Owner`; confirm the schema first.
    Preserve every assignee from the source instead of choosing only one.

    ```bash theme={null}
    dench members list --json
    dench crm fields list task --json

    # One assignee: the positional value is a JSON string.
    dench crm cells set task <entryId> Assignee '"<userId>"' --json

    # Multiple assignees: pass every member ID in a JSON array.
    dench crm cells set task <entryId> Assignee \
      '["<userId1>","<userId2>"]' --json
    ```
  </Tab>
</Tabs>

<Warning>
  Field **type** is immutable. To change a field's type, create a new field and
  migrate. `dench crm fields update` changes name, options, indexing, and
  enrichment, but not the type.
</Warning>

## The protected `Notes` field

<Info>
  Every object ships a protected `Notes` (richtext) field for free-form prose,
  meeting notes, summaries, task details. It is hidden from list views and shown
  only when an entry is opened. Do not invent parallel `Description`/`Summary`
  columns, write Markdown to `Notes`.
</Info>

## Write data

<CodeGroup>
  ```bash One entry theme={null}
  dench crm entries create people --data '{"Name":"Ada Lovelace","Email":"ada@example.com"}' --json
  ```

  ```bash Many (≤200) theme={null}
  dench crm entries create-many people --data '[{"Name":"Jane"},{"Name":"Bob"}]' --json
  ```

  ```bash Set a cell theme={null}
  dench crm cells set task <entryId> Status '"In progress"' --json
  ```

  ```bash Batch ops theme={null}
  dench crm batch --file ops.jsonl --idempotency-key import-2026-06-01 --json
  ```
</CodeGroup>

## Read data

<CodeGroup>
  ```bash Query theme={null}
  dench crm query lead --where '{"Status":"Qualified"}' --sort '-Score' --limit 100 --json
  ```

  ```bash Search theme={null}
  dench crm search --object people "jane" --json
  ```

  ```bash Aggregate theme={null}
  dench crm aggregate deal --field Stage --json
  ```
</CodeGroup>

<Tip>
  Over the API, operator filters (`$gt`, `$in`, `$contains`, `$and`, `$or`) go in
  `dslJson` because the wire format rejects `$`-prefixed keys in nested objects.
  See the [API playground](/docs/api/overview).
</Tip>

## Relation-first modeling

<AccordionGroup>
  <Accordion title="When to use a relation" icon="link">
    If a field name matches or aliases an existing object (Company, Client,
    Deal, Owner), use a `relation` (or `user`) field, not text.
  </Accordion>

  <Accordion title="Auto-link defaults" icon="diagram-project">
    `people → company`, `deal → people/company`, `task → people/project`,
    `invoice → company/deal`. Create the target object if it should exist.
  </Accordion>

  <Accordion title="Batch everything" icon="layer-group">
    Use `entries create-many`, `entries update-many`, `cells set-many`, or
    `batch --file` for three or more writes.
  </Accordion>
</AccordionGroup>
