OSS-first docs
These docs teach the open system first: contracts, generated surfaces, runtimes, governance, and incremental adoption. Studio shows up as the operating layer on top, not as the source of truth.
Spec-driven validation + typing
Define a single operation with SchemaModel, generate validation, and keep your existing handler logic.
What you'll build
- One command spec with explicit input/output models.
- Validation + typing without rewriting your service layer.
- Clear acceptance scenarios for regression safety.
1) Define the spec
Create src/contracts/contact-create.operation.ts:
import { defineCommand } from "@contractspec/lib.contracts-spec/operations";
import { SchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
const ContactInput = new SchemaModel({
name: "ContactInput",
fields: {
email: { type: ScalarTypeEnum.Email(), isOptional: false },
firstName: { type: ScalarTypeEnum.NonEmptyString(), isOptional: false },
lastName: { type: ScalarTypeEnum.NonEmptyString(), isOptional: false },
},
});
const ContactOutput = new SchemaModel({
name: "ContactOutput",
fields: {
id: { type: ScalarTypeEnum.String(), isOptional: false },
email: { type: ScalarTypeEnum.Email(), isOptional: false },
createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },
},
});
export const ContactCreateCommand = defineCommand({
meta: {
key: "contact.create",
version: "1.0.0",
description: "Create a CRM contact",
owners: ["@sales"],
tags: ["crm", "contacts"],
},
io: {
input: ContactInput,
output: ContactOutput,
},
policy: {
auth: "user",
},
acceptance: {
scenarios: [
{
key: "create-contact",
given: ["User is authenticated"],
when: ["ContactCreateCommand executes"],
then: ["Contact is persisted", "Email is validated"],
},
],
},
});2) Wire the handler
Keep your existing code. Just ensure the handler returns the output shape defined above.
import { ContactCreateCommand } from "@/contracts/contact-create.operation";
export async function handleContactCreate(
input: (typeof ContactCreateCommand)["io"]["input"],
ctx: { userId: string }
) {
// Your existing persistence logic
return {
id: "contact_123",
email: input.email,
createdAt: new Date().toISOString(),
};
}3) Validate
contractspec validate src/contracts/contact-create.operation.tsExpected output: Validation passed.
Example package
The CRM Pipeline example includes real specs, handlers, and presentations for contact + deal flows.
# Build + validate the CRM pipeline example
cd packages/examples/crm-pipeline
bun install
bun run build
bun run validateNeed validation tied to real outcomes?
Studio links checks to evidence, focus decisions, and post-release verification so specs evolve with product truth.
See what Studio addsImport an existing codebase
Stabilize a live codebase incrementally instead of rewriting it from scratch.
Generate docs, clients, and schemas
Export stable docs and client-facing artifacts from the same contract layer.
Why ContractSpec
Keep educational and comparison content reachable without letting it define the primary OSS learning path.