Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Types

Markdown

Markdown Body; // a document-backed member — reads and writes markdown text

A member that holds a markdown document. You read and write it as ordinary text, but it is stored as a list of sections split on its headings, so a person and an agent can edit different parts of the same document without overwriting each other. A markdown member is never required, and one that has never been written reads back null.

stable3 examples compiled by CItypesentitycontentauthoring

Summary#

Markdown is the type for a member that holds a document rather than a line of text. You use it exactly like a string — assign markdown to it, read markdown back — but it is not stored as one blob. The platform splits the text on its headings and keeps one row per section.

That storage is what buys you the behaviour you actually want from a document:

  • Two writers can work at once. A person editing one section and an agent rewriting another do not collide, because they are writing different rows.
  • An edit costs what the edit is worth. Ticking a checkbox rewrites one section, not the whole document.
  • Search sees sections, not files. With [Searchable], each section is indexed on its own, so a search result points at the part that answered rather than at a ten-page document.

You do not have to think about any of that to use one. Assign a string, read a string.

Signature#

entity Article {
  Markdown Body;            // document-backed; reads null until something writes it
  Markdown? Notes;          // `?` is accepted but changes nothing — see below
  [Searchable] Markdown Manual;   // each SECTION is indexed separately
}

Description#

Reading and writing#

A markdown member reads and writes as text. Assigning replaces the whole document; reading returns the document reassembled in order.

entity Article {
  [MaxLength(200)] string Title;
  Markdown Body;
}

void PublishDraft(string title) {
  var a = new Article {
    Title = title,
    Body  = "# Overview\n\nWhat this is about.\n\n## Details\n\nThe specifics."
  };
}

string ReadBody(Article a) {
  return a.Body;
}

The document written above is stored as two sections — Overview and Details — because those are its two headings. ReadBody returns the text you wrote, reassembled from them.

A markdown member is never required#

Most value-shaped types with no natural zero — string, an enum, DateTime, Guid — are required: you must supply a value before a row can be saved (see Optional and required members). Markdown is not one of them.

A document that has never been written to genuinely is not there, and there is nothing you could "supply" at create time that would make it there. So a bare Markdown Body; is optional, and a row that never touches it saves fine:

entity Page {
  [MaxLength(200)] string Title;
  Markdown Body;
}

void CreateEmptyPage(string title) {
  var p = new Page { Title = title };   // Body is never set — this is fine
}

Reading p.Body afterwards returns null, not an empty string: nothing has been written, and the platform does not invent a document to hand you. Writing Markdown? Body; is accepted and means the same thing — the ? is redundant here rather than wrong.

Assigning null clears it#

a.Body = null; empties the document — it removes its sections. It does not delete the row that owns it.

It has no column of its own#

A markdown member is stored in its own section rows, keyed by the owning row and the member's name, so it adds no column to its entity's table. Two consequences worth knowing:

  • Do not filter on it in a query. There is no column to compare against, so Where(a => a.Body.Contains("x")) is not the way to find text. Use [Searchable] and search it — that is what section-level indexing is for.
  • Deleting the row deletes its document. You do not clean it up yourself.

Searching it#

[Searchable] on a markdown member indexes each section separately, which is almost always what you want from a long document — a hit points at the section that matched.

entity Manual {
  [Searchable] Markdown Body;     // sections indexed individually
}

See [Searchable] for how the results are queried.

Examples#

entity Kb {
  [MaxLength(200)] string Title;
  Markdown Body;
}

void Seed(string title) {
  var k = new Kb { Title = title, Body = "# Intro\n\nStart here." };
}

void Rewrite(Kb k, string body) {
  k.Body = body;
}

See also#

Related

Optional and required members

A member is required or optional by how you spell its type. A bare value type with a natural zero reads that zero; a…

[Searchable]

Mark a text field searchable. `[Searchable]` gives a String or Markdown property the best relevance search the app can…

entity

Declares a persisted type — a table of rows the app stores, queries and secures. Every entity gets an Id and audit…

Json

A member that holds a JSON document — an object, an array, or any value. It is stored as real jsonb, and written and…