Sprinter Platform

@sprinterai/typespec

Markdown DSL for defining entity types with fields, connections, scoring, and extraction config. Parse, compile, and generate TypeSpec definitions.

Install

pnpm add @sprinterai/typespec

Overview

@sprinterai/typespec provides a Markdown-based DSL for defining entity types. Instead of writing JSON Schema and EntityTypeConfig objects by hand, you author a human-readable .md file and the package compiles it to the database-ready shape.

The package depends only on @sprinterai/core for type definitions.

Three Stages

The TypeSpec pipeline has three stages:

StageFunctionDirection
ParseparseTypeSpec(markdown)Markdown string to TypeSpec IR
CompilecompileTypeSpec(spec)TypeSpec IR to JSON Schema + EntityTypeConfig
GenerategenerateTypeSpec(record)DB record back to Markdown string
Markdown ──parse──▶ TypeSpec IR ──compile──▶ { slug, name, json_schema, config }

                         Markdown ◀──generate──────────────┘

DSL Syntax

A TypeSpec file is a Markdown document with YAML frontmatter and structured sections:

---
type: opportunity
icon: target
color: #3B82F6
cardFields: [name, stage, value]
---

# Opportunity

A deal in the investment pipeline.

---

## Fields

- name: text (required) — The name of the deal or target company
- stage: select [Sourced, Screening, Due Diligence, Closed] (required) — Current pipeline stage
- value: currency (min: 0) — Estimated deal value in USD
  sources: connected-entities, linked-documents
  dependsOn: name
- probability: number (min: 0, max: 100) — Likelihood of closing as a percentage
- website: url — Company website URL
- tags: array — Categorization tags

## Connections

- portfolio-company → company (many) — Companies in this deal
- lead-partner → person (one) — Partner leading the deal

## Scoring

- Revenue Impact: weight 0.30, scale 1-10
- Strategic Fit: weight 0.25, scale 1-10
- Risk Level: weight 0.25, scale 1-10
- Time to Close: weight 0.20, scale 1-5

Frontmatter

KeyRequiredDescription
typeYesEntity type slug (unique identifier)
iconNoIcon name for UI display
colorNoHex color for UI theming
cardFieldsNoArray of field names shown on entity cards
isParentNoWhether this type acts as a parent container
hideFromDataNavNoHide from data navigation sidebar

Fields

Each field is a list item with the format:

- field_name: type [options] (constraints) — Extraction instructions
    sources: source1, source2
    dependsOn: field1, field2

Supported field types:

TypeJSON Schema Output
text{ type: "string" }
long_text{ type: "string" }
number{ type: "number" }
currency{ type: "number" } with displayType: "currency"
select{ type: "string", enum: [...] }
multi_select{ type: "array", items: { type: "string", enum: [...] } }
boolean{ type: "boolean" }
date{ type: "string", format: "date" }
url{ type: "string" }
email{ type: "string" }
array{ type: "array", items: { type: "string" } }

Constraints: required, min: N, max: N, integer: true, label: Display Name.

Connections

Each connection follows the format:

- relationship_type → target_slug (one|many) — Label

Use * as the target slug for connections to any entity type.

Scoring

Each scoring criterion follows the format:

- Label Text: weight 0.30, scale 1-10

The name is derived automatically from the label (e.g., "Revenue Impact" becomes revenue_impact).

API

parseTypeSpec

Parses a Markdown string into the TypeSpec intermediate representation.

import { parseTypeSpec } from "@sprinterai/typespec";

const spec = parseTypeSpec(markdownString);
// spec.slug, spec.name, spec.fields, spec.connections, spec.scoring

compileTypeSpec

Compiles a TypeSpec IR into the shape expected by the entity_types table.

import { compileTypeSpec } from "@sprinterai/typespec";

const { slug, name, json_schema, config } = compileTypeSpec(spec);
// json_schema: EntityJsonSchema with properties, required
// config: EntityTypeConfig with ui, fields, relations, scoring

generateTypeSpec

Converts a database entity type record back into a Markdown string. Useful for exporting, diffing, or editing entity types as files.

import { generateTypeSpec } from "@sprinterai/typespec";

const markdown = generateTypeSpec({
  slug: "opportunity",
  name: "Opportunity",
  json_schema: { /* ... */ },
  config: { /* ... */ },
});

entityTypeToTypeSpec / typeSpecToMarkdown

Lower-level functions if you need to work with the intermediate representation directly:

import { entityTypeToTypeSpec, typeSpecToMarkdown } from "@sprinterai/typespec";

// DB record → TypeSpec IR
const spec = entityTypeToTypeSpec(record);

// TypeSpec IR → Markdown string
const markdown = typeSpecToMarkdown(spec);

Type Exports

TypeDescription
TypeSpecFull intermediate representation of an entity type
TypeSpecFieldA single field with name, type, options, constraints, extraction config
TypeSpecFieldTypeUnion of supported field types ("text", "number", "select", etc.)
TypeSpecConnectionA relationship to another entity type
TypeSpecScoringCriterionA scoring dimension with weight and scale
CompiledEntityTypeOutput of compileTypeSpec: { slug, name, json_schema, config }

Round-Trip Fidelity

The parse/compile/generate pipeline is designed for round-trip fidelity. You can parse a Markdown file, compile it to the database shape, store it, then generate the Markdown back out and get an equivalent document. This enables version-controlled entity type definitions alongside your code.

Testing

All three pipeline stages have co-located test suites. A shared makeSpec() factory in test-helpers.ts builds a minimal valid TypeSpec with safe defaults and accepts partial overrides.

import { makeSpec } from "./test-helpers";

// Minimal valid spec
const spec = makeSpec();

// Override specific fields
const specWithFields = makeSpec({
  fields: [{ name: "status", type: "select", options: ["active", "inactive"] }],
});
Test fileWhat is covered
compile.test.ts42 cases: all field type mappings to JSON Schema, required arrays, numeric constraints, field config (displayType, label, extraction), connections (cardinality, relation config), scoring criteria, UI config
generate.test.tsentityTypeToTypeSpec round-trip: field type inference, select/multi-select, connections, scoring, config passthrough, null/missing inputs
markdown.test.tstypeSpecToMarkdown and generateTypeSpec: frontmatter, prose, field serialization, connection serialization, scoring serialization, round-trip fidelity