Construir
Primeiros passos
Leia os documentos curtos, rode o corpus de conformidade, valide sua própria mensagem com a validação de formatos ligada e publique. Depois escolha um nível e converse com o grupo de trabalho.
Passo 1
Leia quatro coisas, nesta ordem
Introdução ↗
Por que o SOM existe, os três substantivos e os seis princípios.
02 · para implementadoresConformidade ↗
O que significa estar conforme com o SOM 1.0 — mais curto do que você imagina.
03 · o retrato mais claroO exemplo do furacão ↗
Uma história contada ao longo de sete snapshots.
04 · sua primeira famíliaSchema story-context ↗
A família que você quase certamente vai implementar primeiro.
Passo 2
Rode o corpus de conformidade
O repositório da especificação traz exemplos completos que precisam validar, vinte casos negativos que precisam ser rejeitados e ferramentas em Python puro que verificam ambos.
git clone https://github.com/storyobjectmodel/som.git
cd som
pip install jsonschema rfc3339-validator
python3 tools/validate.py # every example is legal
python3 tools/validate_negative.py # every negative case is rejected
python3 tools/som_lint.py schema # schemas agree with their own claims
python3 tools/validate_sequence.py examples/hurricane-run
# a story over time holds together- Esta mensagem é válida? —
validate.py - Os schemas de fato restringem? —
validate_negative.py. Dezenove casos falham nos schemas; o vigésimo,som_version: "0.3.2", falha na regra de versão do fio, que a sua implementação precisa aplicar por conta própria. - O schema corresponde ao que diz sobre si mesmo? —
som_lint.py - Uma sequência de snapshots se sustenta? —
validate_sequence.py, onde moram os bugs caros.
Instale o rfc3339-validator. Sem ele, o jsonschema do Python aceita em silêncio um timestamp malformado. O corpus negativo inclui esse caso justamente para que a verificação falhe ruidosamente quando o pacote estiver faltando.
Passo 3
Valide na sua própria stack — com os formatos validados
Duas implementações que discordam sobre se message_id precisa ser um UUID não são interoperáveis. Em Node, isso significa o build 2020-12 do Ajv mais ajv-formats.
// npm i ajv ajv-formats
import Ajv2020 from 'ajv/dist/2020';
import addFormats from 'ajv-formats';
const BASE = 'https://storyobjectmodel.com/schema/1.0';
const FAMILY_SCHEMA: Record<string, string> = {
'story.context': 'story-context',
'skill.warning.raised': 'skill-warning',
'delivery.media_available': 'delivery-media-available',
'link.committed': 'link-event', 'link.gate_changed': 'link-event', 'link.withdrawn': 'link-event',
'telling.started': 'telling-event', 'telling.ended': 'telling-event', 'telling.exposed': 'telling-event',
'system.audit': 'system-audit',
};
const ajv = new Ajv2020({ strict: false, allErrors: true });
addFormats(ajv); // conformance §4: uuid and date-time MUST be asserted
const load = async (name: string) => (await fetch(`${BASE}/${name}.schema.json`)).json();
export async function validateMessage(msg: { som_version?: string; message_type?: string; payload?: unknown }) {
const envelope = ajv.compile(await load('envelope'));
if (!envelope(msg)) return { ok: false, errors: envelope.errors };
// §3: 0.3.2 is not SOM 1.0 — and never branch on the version otherwise.
if (msg.som_version?.startsWith('0.')) return { ok: false, errors: ['pre-1.0 som_version'] };
// §2 and §5: dispatch on message_type only; ignore families you don't handle.
const family = FAMILY_SCHEMA[msg.message_type ?? ''];
if (!family) return { ok: true, ignored: true };
const payload = ajv.compile(await load(family));
return payload(msg.payload) ? { ok: true } : { ok: false, errors: payload.errors };
}Ilustrativo, não uma implementação de referência — guarde em cache os validadores compilados em vez de buscá-los a cada mensagem. Os schemas são servidos na URL do seu próprio $id, então resolver pelo identificador também funciona.
Passo 4
Publique um snapshot de história conforme
{
"som_version": "1.0.0",
"message_id": "0199a1c4-7a2e-7b31-8c55-4d2f9e6a1b07",
"correlation_id": "0199a1c4-0000-7000-8000-000000000911",
"message_type": "story.context",
"timestamp": "2026-09-11T16:41:00.000000Z",
"originating_system": {
"system_id": "ncs-nyc-01", "system_type": "ncs"
},
"topic": "som.story.context.hurricane-2026-0911",
"payload": {
"story_id": "hurricane-2026-0911",
"slug": "HURRICANE-LANDFALL",
"headline": "Hurricane makes Cat 4 landfall",
"story_type": "ACTIVE",
"lifecycle": { "phase": "BREAKING",
"phase_entered_at": "2026-09-11T14:00:00Z" },
"sequence_number": 7,
"updated_at": "2026-09-11T16:41:00Z"
}
}- Um
message_idUUID novo (v7 recomendado); o mesmocorrelation_idao longo do ciclo de vida da história. - O mesmo
story_id, umsequence_numbermaior, umupdated_atposterior. - Todos os campos, inclusive os que outros sistemas contribuíram. Omitir significa ausente.
lifecyclepresente se, e somente se,story_typeforACTIVE.- O seu próprio
originating_system, carimbado de novo a cada publicação. - Tudo o que o padrão não carrega vai em
extensions["com.{vendor}.…"].
Veja numa pipeline ao vivo. O emulador ↗ do projeto é um painel sobre uma pipeline em funcionamento que você mesmo pode usar, e as demos da IBC ↗ mostram dois cenários completos de ponta a ponta. Uma implementação de referência em .NET virá num repositório separado; o starter do hackathon pré-1.0 emite 0.3.2 e não é tráfego 1.0.
Adesão
Nada do seu produto precisa sair
Um sistema basta para começar. As integrações são descritas em três níveis.
Assinar e publicar
Leia a história e coloque a sua própria família na pipeline. O projeto estima isso em dias, não em meses.
Contexto bidirecional
Sua ferramenta consome e também contribui com contexto estruturado — assertions, proveniência, links, tellings.
Decidir com base na história
Sua ferramenta age de forma autônoma sobre o que lê, por meio de um executor que aplica as skills da casa.
Participe
O grupo de trabalho está aberto
Registre seu interesse ↗
Desenvolva sobre o padrão, escreva skills, conduza uma sessão de Story Archaeology, entre no grupo de trabalho ou apenas acompanhe o trabalho — o formulário oficial pergunta quem você é e o que quer fazer.
formulário de storyobjectmodel.com →Proponha uma mudança ↗
Toda mudança chega como pull request, e qualquer pessoa pode abrir um. Mudanças nos schemas estão sujeitas à política de compatibilidade; as questões em aberto ficam no registro público.
GOVERNANCE · CONTRIBUTING →Converse sobre uma integração
Para qualquer coisa que o README do repositório não responda, escreva para o projeto.
hello@storyobjectmodel.com →Os schemas prevalecem. Quando qualquer texto — este site incluído — discordar de um schema publicado, o schema é que está certo. Veja as sete famílias →