---
name: entity-schema
description: Field reference for canonical entity types — file layout, base fields, wikilinks. Enum values come from get_entity_schema.
loading: on-demand
---

# Entry Schema Reference

Use this reference when creating, validating, or mapping entries. All entries are Markdown files with YAML frontmatter stored in `{folder}/{entity_id}/main.md` (entity-folder layout).

Studiograph has 16 canonical entity types (15 user-facing + 1 system). The full per-type field list — including enum values, defaults, and descriptions — lives in `src/core/validation.ts` (`ENTITY_SCHEMAS`). **Do not memorize field shapes from this document.** Call `get_entity_schema(entityType)` to fetch the authoritative schema before writing. Workspaces may also define custom types via `schema_extensions` in their workspace config; those types are returned by `get_entity_schema` too.

## When to call `get_entity_schema`

- Before the first create/update of a given entity type in a conversation.
- After any error mentioning an unknown enum value, a missing field, or a type mismatch.
- Whenever you're about to write a field name that hints at an enum (`stage`, `status`, `category`, `priority`, `audience`, `source`, `type`) and you don't have the current list in this turn.

The response shape:

```json
{
  "success": true,
  "entityType": "deal",
  "fields": {
    "name": { "type": "string", "optional": false, "description": "Deal name is required" },
    "stage": {
      "type": "enum",
      "optional": true,
      "description": "Pipeline stage",
      "enum": ["qualification", "scoping", "proposal", "negotiation", "pending-signature", "won", "lost"],
      "default": "qualification"
    },
    "deal_value": { "type": "number", "optional": true, "description": "Estimated deal value" },
    "services": {
      "type": "string[]",
      "optional": true,
      "description": "Service entities this project includes (wikilinks)",
      "itemType": "string"
    }
  }
}
```

Use `enum` to know what's allowed, `default` to know what you'll get if you omit the field, and `description` to disambiguate similar field names.

## Base Fields (all entries)

Every entry inherits these fields. Most are auto-populated by the system on create/update — do not pass them yourself.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `entity_type` | string | Yes | The entry type identifier (passed as the `entityType` parameter, not in `data`) |
| `entity_id` | string (kebab-case) | Yes | Unique ID: lowercase letters, numbers, hyphens, underscores |
| `created_at` | datetime | Yes | ISO 8601 (auto) |
| `updated_at` | datetime | Yes | ISO 8601 (auto) |
| `created_by` | string | Yes | Username (auto) |
| `updated_by` | string | Yes | Username (auto) |
| `date` | string | No | Human-friendly date (event date, project start, etc.) |
| `tags` | string[] | No | Categorization tags (Title Case, except acronyms which stay uppercase: "AI", "UI Design", "B2B") |

Schemas use `.passthrough()` — custom fields beyond the schema are preserved on disk.

## Canonical Entity Types

The 16 canonical types are grouped into five categories. For each, call `get_entity_schema` to see required fields, enums, and defaults.

**CRM:** `person`, `organization`, `position`, `deal`
**PM:** `project`, `event`, `task`, `deliverable`
**KM (authored):** `document`, `deck`, `publication`, `case-study`, `service`, `skill`
**Capture:** `note`, `reference`
**System:** `comment` (virtual, SQLite-backed)

Quick notes on common types:

- **person** — `name` is required; `role` is free-text (distinct from the `position` entity type, which is a job spec).
- **organization** — clients/vendors/partners/prospects.
- **deal** — pre-project pipeline opportunity. `stage` defaults to the earliest pipeline value.
- **event** — any scheduled gathering (meeting, call, workshop, review, presentation, conference). Body holds Summary / Notes / Action Items.
- **task** — `assignee` (not `assigned_to`), free-text `phase`.
- **note** — freeform capture. Decisions land here as plain notes.
- **deck** — slide decks. Has a dedicated renderer; pattern-matches on `entity_type === 'deck'`.

For anything more specific (which enum values are valid, what's required, what defaults apply), call `get_entity_schema`.

## Wikilinks

Cross-entry references use `[[entity-id]]` wikilink syntax in string or string[] fields. Fields named `attendees`, `team`, `assignee`, `organization`, `client`, `services`, `depends_on`, `enables`, `project` typically hold wikilinks. The schema returns `string` / `string[]` for these — the wikilink convention is semantic, not enforced at the type level.

## File Layout

Entries use the **entity-folder** layout:

```
{folder}/
  {entity_id}/
    main.md          # Sentinel file (frontmatter + body)
    notes/           # Optional sub-content
    artifacts/       # Optional attachments
```

- `entity_id` must be kebab-case: `acme-website-redesign`
- The folder name IS the `entity_id`
- `main.md` is the sentinel — its presence defines the entity

## Example Frontmatter

```yaml
---
entity_type: project
entity_id: acme-website-redesign
name: Acme Website Redesign
client: "[[acme-corp]]"
start_date: "2026-01-15"
date: "2026-06-30"        # a project's `date` is its end date
status: in-progress
tags:
  - Website
  - Redesign
created_at: "2026-01-15T00:00:00Z"
updated_at: "2026-02-20T00:00:00Z"
created_by: alice-smith
updated_by: alice-smith
---

# Acme Website Redesign

Project content goes here. Use [[wikilinks]] to reference other entries.
```

The `status` value above is illustrative — call `get_entity_schema('project')` to see the current allowed values before writing.
