<!--
  Full-page Markdown export (rendered HTML → GFM).
  Source: https://neotoma.io/ur/agent-instructions/store-recipes
  Generated: 2026-04-28T13:34:36.528Z
-->
# Agent instructions: Store recipes and entity types

[← Agent instructions](/agent-instructions)

## Store recipes

Use only the recipes below. MUST NOT list, glob, or read MCP tool descriptor or schema files for chat, attachment, or entity-extraction flows. Tool parameters: `store_structured(entities, idempotency_key, relationships, file_path|file_content+mime_type, file_idempotency_key?)` and `create_relationship(relationship_type, source_entity_id, target_entity_id)`. Response IDs come back as `structured.entities[].entity_id` and `unstructured.asset_entity_id`.

-   **Relationship batching.** When related entities are created in the same call, define ALL their links via the `relationships` array using `{ relationship_type, source_index, target_index }` entries. Do not issue one `create_relationship` call per link when batching is possible.
-   **Turn identity.** Use host conversation and turn ids when available. If absent, build a synthetic `conversation_id` (never a generic prefix like `cursor` alone) plus a turn index/timestamp; set `turn_key = "{conversation_id}:{turn_id}"` and a unique `idempotency_key`. Unscoped turn keys cause cross-conversation entity collisions.
-   **Fallback IDs.** When the host gives no ids at all, use `idempotency_key "conversation-chat-<turn>-<timestamp_ms>"` and `turn_key "chat:<turn>"`.
-   **observation\_source.** Optional flag describing the kind of write, `sensor` (deterministic tool/telemetry), `workflow_state` (state-machine transitions), `llm_summary` (the default; omit it for ordinary chat), `human` (direct edit/acceptance), or `import` (batch/ETL). Used as a tie-break after `source_priority`; one value applies to every observation produced by the request.

### User-phase (one call per user message)

-   **Shape.** entities = \[`{ entity_type: "conversation", title? }`, `{ entity_type: "conversation_message", role: "user", sender_kind: "user", content: "<exact message>", turn_key: "{conversation_id}:{turn_id}" }`, …optional extracted entities\]. Indices: 0 = conversation, 1 = message, 2+ = extracted. The legacy `agent_message` type is accepted as an alias and resolved to `conversation_message` for pre-v0.6 clients.
-   **Relationships.** Always `PART_OF` from message (1) to conversation (0). For every entity created OR updated this turn, add `REFERS_TO` from the message to that entity. Skip when the edge already exists.
-   **Naming.** Keep names human-readable. For `conversation_message`, set `canonical_name` to a concise summary; never use turn keys, raw ids, timestamps, or tool names as the primary label. For `conversation`, keep `title` topical and update only when the central topic materially changes.
-   **Canonical-name scope.** `canonical_name` is a short label, not a container for every detail. Put message body in `content` and extra semantics in fields like `title`, `subject`, `summary`, `description`, `turn_key`, `role`, `status`, etc.
-   **Extraction.** If the message implies an entity (purchase, task, event, person, place, etc.), append it with a descriptive `entity_type` and the properties the message implies, no fixed schema. Do not call `list_entity_types` before storing.
-   **idempotency\_key.** `conversation-{conversation_id}-{turn_id}-{suffix}` or, on fallback, `conversation-chat-<turn>-{suffix}`.

### Attachments (one call: file + entities together)

1.  **Parse.** PDFs go through `parse_file`; text/CSV/JSON/Markdown read directly; images use vision. If parsing yields no usable text, store the raw file only.
2.  **Extract.** One snake\_case field per fact, no invention. Use a descriptive `entity_type` matching the document (receipt, invoice, note, contract, person, contact, company, task, event, transaction, etc.).
3.  **Store.** One `store_structured` with \[conversation, user message, …extracted entities\], idempotency key, `relationships` with `PART_OF` (message→conversation) and any `REFERS_TO` edges, plus `file_path` (resolve to absolute) or `file_content + mime_type`. Optional `file_idempotency_key: "file-<short-slug>"`.
4.  **EMBEDS.** `create_relationship(EMBEDS, user_message_id, asset_entity_id)` using the ids returned by step 3.

### Screenshots and images

Use the attachment recipe. Extract every distinct entity visible in the image (people, messages, dates, criteria, tasks, events, offers, transactions) before responding. Add `PART_OF` (message→conversation), `REFERS_TO` (message→each extracted entity), and `EMBEDS` (message→file entity).

### Chat fallbacks

-   Overwriting between branches is acceptable; users can audit history via `list_observations`. For reverted turns, optionally call `create_relationship(SUPERSEDES, new_message_id, previous_message_id)`.
-   When a client does not support inline relationships: call `store_structured` first, then `create_relationship(PART_OF, message_id, conversation_id)` and one `REFERS_TO` per extracted entity.

◆

## Entity types and schema

-   **Schema-agnostic for chat.** Use a descriptive `entity_type` and whatever properties the message implies; the server accepts arbitrary fields. Do not call `list_entity_types` before storing.
-   **Type reuse.** Before introducing a new type, check for semantic equivalents (singular vs plural, person/contact, social\_post/social\_media\_post). Prefer the type with more existing entities; consult `list_entity_types` with a keyword search if the cached list is stale. FORBIDDEN: creating a new type when an equivalent exists.
-   **Schema evolution.** Use `update_schema_incremental` to add fields (minor bump) or remove fields via `fields_to_remove` (major bump). Removed fields are excluded from snapshots but observation data is preserved; re-adding restores them. At least one field must remain.
-   **Existing-entity correction.** When fixing inaccurate values or normalizing ad hoc fields into an established schema, use `correct` on the existing entity rather than creating a duplicate. Prefer canonical schema fields over ad hoc additions.
-   **Type consistency in a workflow.** Within one import or workflow, pick one canonical type and keep it consistent. For generic financial rows, default to `transaction` and store source-specific details as fields (provider, account\_suffix, value\_date, concept).
-   **conversation\_message sender semantics.** Always set `sender_kind` (one of `user`, `assistant`, `agent`, `system`, `tool`) alongside the legacy `role` field. For agent-to-agent traffic, set `sender_kind: "agent"` with `sender_agent_id` and optional `recipient_agent_id`. For the parent `conversation`, set `thread_kind` to `human_agent`, `agent_agent`, or `multi_party`.