# JOE Schema Summary — Rules and Prompts

Purpose: Provide a consistent, agent‑friendly summary for each schema (including instance‑specific ones) so tools and UIs can reason without parsing full runtime schema files.

These summaries are served by MCP hydrate and by GET `/API/schema/:name?summaryOnly=true`.

## What to include in every summary

- description: One‑sentence explanation of what the schema represents
- purpose: When/why to use it; context among related schemas
- wip: true if the schema is under active development
- source: 'core' | 'instance' (filled automatically; you can override)
- labelField: Primary human label (prefer name → title → label)
- defaultSort: { field, dir } sensible default (prefer joeUpdated desc; pages often path asc; posts often post_date desc)
- searchableFields: Array of string field names that are good for text queries
- allowedSorts: Whitelist of sortable fields agents should use
- relationships:
  - outbound: Array of { field, targetSchema, cardinality } where cardinality is 'one' | 'many'
  - inbound: { graphRef: 'server/relationships.graph.json' } (do not hand‑maintain inbound; it’s computed from the graph later)
- joeManagedFields: ["created","joeUpdated"] (always include)
- fields: Array of normalized field descriptors:
  - Required: name, type
  - Optional: isArray, isReference, targetSchema, enumValues, display, comment, tooltip, format

Notes
- display/comment/tooltip are enriched automatically at runtime from the schema’s field definitions; include them in the summary when they clarify usage.
- For select fields, add enumValues when known (e.g., role, priority, content_type).

## Cardinality guidance

- A single reference (select/goto a single item) → 'one'
- Arrays, objectList, or multi‑select references → 'many'

## Heuristics (when unsure)

- labelField: name → title → label
- defaultSort: joeUpdated desc; pages: path asc; posts: post_date desc
- searchableFields: name, info, description, plus any user‑visible identifiers (code, slug, email)
- allowedSorts: include dates (joeUpdated, created, due_date), labelField, and common categoricals

## Authoring prompt (for new instance‑specific schemas)

Use this prompt to draft a `summary` block to paste into the schema file.

```
You are defining a curated summary for a JOE schema named <SCHEMA_NAME>.
Return strictly a JSON object with these keys:
{
  "description": "…",
  "purpose": "…",
  "labelField": "…",
  "defaultSort": { "field": "…", "dir": "asc|desc" },
  "searchableFields": ["…"],
  "allowedSorts": ["…"],
  "relationships": {
    "outbound": [
      { "field": "<field>", "targetSchema": "<schema>", "cardinality": "one|many" }
    ],
    "inbound": { "graphRef": "server/relationships.graph.json" }
  },
  "joeManagedFields": ["created","joeUpdated"],
  "fields": [
    {
      "name": "…",
      "type": "string|number|boolean|date-time|object|objectList|select|…",
      "isArray": false,
      "isReference": false,
      "targetSchema": null,
      "enumValues": [ ],
      "display": "…",
      "comment": "…",
      "tooltip": "…",
      "format": "date|date-time|…"
    }
  ]
}
Rules:
- Only include fields that materially help an agent construct/validate objects or reason about references.
- Prefer concise, high‑signal text for description and purpose.
- Do NOT populate inbound manually; leave graphRef as is.
- Include enumValues for selects where known; omit when unknown.
```

## Example (task)

```
summary: {
  description: "Scheduled unit of work tracked for users and projects.",
  purpose: "Use to plan and execute work; references status, project, members, tags.",
  labelField: "name",
  defaultSort: { field: "joeUpdated", dir: "desc" },
  searchableFields: ["name","info","description","_id"],
  allowedSorts: ["joeUpdated","created","due_date","priority","name"],
  relationships: {
    outbound: [
      { field: "status", targetSchema: "status", cardinality: "one" },
      { field: "project", targetSchema: "project", cardinality: "one" },
      { field: "members", targetSchema: "user", cardinality: "many" },
      { field: "tags", targetSchema: "tag", cardinality: "many" }
    ],
    inbound: { graphRef: "server/relationships.graph.json" }
  },
  joeManagedFields: ["created","joeUpdated"],
  fields: [
    { name: "_id", type: "string" },
    { name: "itemtype", type: "string" },
    { name: "name", type: "string" },
    { name: "status", type: "string", isReference: true, targetSchema: "status" },
    { name: "project", type: "string", isReference: true, targetSchema: "project" },
    { name: "members", type: "string", isArray: true, isReference: true, targetSchema: "user" },
    { name: "tags", type: "string", isArray: true, isReference: true, targetSchema: "tag" },
    { name: "priority", type: "number", enumValues: [1,2,3,1000] },
    { name: "joeUpdated", type: "date-time" },
    { name: "created", type: "date-time" }
  ]
}
```

## How to validate quickly

- Open: `/API/schema/<name>?summaryOnly=true`
- Check: description/purpose read well; labelField exists in fields; allowedSorts are valid; outbound list references real schemas; no inbound entries besides graphRef; joeManagedFields present.

## Notes for maintainers

- Runtime will enrich fields with display/comment/tooltip from the schema when available.
- Inbound relationships are not hand‑maintained; a graph builder will populate the shared graph later.
- For core vs instance: `source` is inferred automatically but can be overridden inside `summary` if needed.
