silk.schema.json_schema.

Describe a Schema type as a JSON Schema, for validators, editors, and AI tools.

When to use#

Call JsonSchemas.write with the silk.schema.shape.Shapes of a type, from silk.schema.schema.Schemas.shape, to write its JSON Schema to the ambient Writer. Pick a JsonSchemaDialect for where the schema goes: Standard for validators and MCP tools, and the strict dialects for a model's structured output or tool parameters. Call JsonSchemas.writeVariant for the parameters of one tool, when a union lists the tools.

Details#

The output is JSON Schema draft 2020-12. Structs are objects with their fields' wire names, unit unions are an enum of names, and unions with fields are a oneOf of one object per variant, whose tag property holds the variant's name. A named type that the root uses is an entry in $defs, used through $ref, so recursive types work; the root itself is written in place. Doc comments become description. Spec rules become minimum, maxLength, pattern and the like, and a field's default becomes default.

A rule the dialect has no keyword for, a codec's check, or a rule about a value after a codec changed it, goes into description as text instead, and the schema is then approximate: it accepts at least what the decoder accepts, never less. JsonSchemas.write returns whether it is exact, and an approximate schema uses anyOf where an exact one uses oneOf.

The dialects follow the providers' documented subsets:

  • Standard: all of the above, with $schema. MCP tool schemas use it.

  • OpenAiStrict: the root is an object, every property is required and a field that may be absent is nullable instead, every object has additionalProperties: false, and const, oneOf, minLength, maxLength and default are not used.

  • AnthropicStrict: every object has additionalProperties: false, and there are no numeric, length or count keywords and no default. A recursive type is an error.

  • Gemini: no const, oneOf, pattern, length keywords or default.

Examples#

Write the JSON Schema of a config#

silk
import silk.core.effect { Effect }
import silk.io.writer { Writer, WriterError }
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.schema.json_schema { JsonSchemaDialect, JsonSchemaError, JsonSchemaOptions, JsonSchemas }
import silk.schema.schema { Schema, Schemas, Spec }

/// A server to start.
struct Server {
  /// The port to listen on.
  pub port: u16,
}

impl Schema for Server {
  static fn spec() -> Spec<Server> {
    return Spec<Server>.of() |> Spec<Server>.between("port", 1, 65535)
  }
}

struct Capture {
  length: usize,
}

impl Writer for Capture {
  effect fn writeAll(self: &mut Self, val: &[u8]) -> () ! WriterError ? &mut Writer {
    self.length = self.length + val.length
    return ()
  }
  effect fn flush(self: &mut Self) -> () ! WriterError ? &mut Writer { return () }
}

effect fn check() -> bool ! JsonSchemaError | WriterError | OutOfMemoryError ? &mut Allocator {
  let shapes = run Schemas.shape<Server>()
  let mut capture = Capture {length: 0}
  // {"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":
  //  {"port":{"type":"integer","minimum":1,"maximum":65535,"description":"The port to listen on."}},
  //  "required":["port"],"description":"A server to start."}
  let exact = run JsonSchemas.write(&shapes, JsonSchemaOptions.of(JsonSchemaDialect.Standard))
    |> Effect.provideMut<Writer>(&mut capture)
  return exact && capture.length > 0
}

pub effect fn main() -> i32 ! JsonSchemaError | WriterError | OutOfMemoryError {
  let mut allocator = Allocator.systemAllocatorProvider()
  let exact = run check() |> Effect.provideMut<Allocator>(&mut allocator)
  return if exact { 0 } else { 1 }
}

Import as JsonSchemas with import silk.schema.json_schema { JsonSchemas }.

Public declarations: 5.

JsonSchemaDialect#

silk
pub enum JsonSchemaDialect

Which subset of JSON Schema to write, for where the schema goes.

Standard#

silk
Standard

Draft 2020-12, for validators, editors, and MCP tools.

OpenAiStrict#

silk
OpenAiStrict

OpenAI structured outputs and strict function calling.

AnthropicStrict#

silk
AnthropicStrict

Anthropic strict tool use and structured outputs.

Gemini#

silk
Gemini

Gemini response and function parameter schemas.

JsonSchemaOptions#

silk
pub struct JsonSchemaOptions

How JsonSchemas.write writes a schema.

Field dialect#

silk
pub dialect: JsonSchemaDialect

The subset of JSON Schema to write.

Implementation Copy for JsonSchemaOptions#

silk
impl Copy for JsonSchemaOptions

Implementation JsonSchemaOptions#

silk
impl JsonSchemaOptions

Associated function of#

silk
pub fn of(dialect: JsonSchemaDialect) -> JsonSchemaOptions

Returns options for dialect.

JsonSchemaProblem#

silk
pub enum JsonSchemaProblem

Why a type has no schema in a dialect.

RootNotObject#

silk
RootNotObject

The dialect needs an object at the root, and the type is not a struct.

Recursive#

silk
Recursive

The dialect has no recursive references, and the type contains itself.

JsonSchemaError#

silk
pub struct JsonSchemaError

A type that has no schema in the dialect asked for.

Field problem#

silk
pub problem: JsonSchemaProblem

Why it has none.

Field name#

silk
pub name: string<'static>

The name of the type, or empty text for a type with no name.

Implementation Debug for JsonSchemaProblem#

silk
impl Debug for JsonSchemaProblem

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the name of the problem, such as Recursive.

Implementation Debug for JsonSchemaError#

silk
impl Debug for JsonSchemaError

Operation debug#

silk
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut Writer

Writes the fields, as JsonSchemaError { problem: ..., name: ... }.

JsonSchemas#

silk
pub struct JsonSchemas

Writes JSON Schemas from shapes.

Implementation JsonSchemas#

silk
impl JsonSchemas

Associated function write#

silk
pub effect fn write(shapes: &Shapes, options: JsonSchemaOptions) -> bool
    ! JsonSchemaError | WriterError | OutOfMemoryError ? &mut Writer | &mut Allocator

Writes the JSON Schema of the root of shapes to the ambient Writer, as compact JSON, and returns whether it is exact: whether every rule became a keyword.

Errors#

  • JsonSchemaError if the dialect cannot describe the type.

  • WriterError if the Writer fails.

  • OutOfMemoryError if the Allocator cannot supply the bookkeeping.

Associated function writeVariant#

silk
pub effect fn writeVariant(shapes: &Shapes, variant: &VariantShape, options: JsonSchemaOptions) -> bool
    ! JsonSchemaError | WriterError | OutOfMemoryError ? &mut Writer | &mut Allocator

Writes the JSON Schema of the object of variant's fields, without its tag, as the parameters of a tool. shapes holds the shapes variant refers to. Returns whether it is exact.

Errors#

  • JsonSchemaError if the dialect cannot describe a field's type.

  • WriterError if the Writer fails.

  • OutOfMemoryError if the Allocator cannot supply the bookkeeping.

Category: Data formats.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2, x86_64-pc-windows-msvc, wasm64-unknown-unknown.

View the source of this page