Build

Get started

Bring up a bus, publish a story, watch skills fire, approve one warning and reject another. Fifteen minutes, end to end.

Quick start

Two commands

The reference starter is a single .NET process hosting an executor, a dashboard and a story simulator, with a bundled broker alongside it.

cd som-hackathon-starter-dotnet

# 1. the bus (plus a broker UI on :8080)
docker compose up -d

# 2. executor + dashboard on :5050
dotnet run

Prerequisites: the .NET 10 SDK and Docker. Topics auto-create on first publish in local mode.

Then
  • Open http://localhost:5050 — the websocket pill, top right, should read connected.
  • Click a seed-story button in the header to publish a story.context event.
  • Watch the four lanes: stories → skill runs → pending approval → decisions.
  • Approve or reject each staged warning to push it to som.skills.events or som.skills.rejected.

Verify

Sixty seconds to know it works

1

Connect

The dashboard’s websocket pill says connected. If it says reconnecting, the app is down — the page will re-attach itself once it’s back.

2

Publish

Click the Informal seed. A story lands in Stories on Bus and two style warnings appear in Pending Approval within a second or two.

3

Decide

Approve one and reject the other. Both show up in Decisions, and the bus event log at the bottom shows the full message trail.

The six seed stories each exercise a different combination of fields — a full compliance and gates set, a story with the compliance key absent at URGENT priority, informal headline terms, a clean story that should fire nothing at all, an election story on EDITORIAL_HOLD, and a hurricane story whose live feed transitions CAPTURING → CAPTURED.

Shell

The whole loop without the UI

B=http://localhost:5050

# publish a story (a live feed, still CAPTURING, open-ended range)
curl -X POST $B/api/publish/hurricane

# see what's waiting on the gate
curl $B/api/pending

# decide
curl -X POST $B/api/decision/<warning_id> \
  -H 'Content-Type: application/json' \
  -d '{"decision":"approve","reviewer":"me"}'

Endpoint paths belong to the reference implementation, not to SOM itself — the standard defines messages, not an HTTP API. Check the starter’s README for the current list.

Media

Drive a TAMS arrival

The mock MAM plays the store; the media coordinator plays the consuming participant. Two arrivals show both halves of the contract.

# a rolling arrival — noted, no story change
curl -X POST $B/api/mam/emit/landfall-feed-01 \
  -H 'Content-Type: application/json' -d '{"timeRange":"[0:0_30:0)"}'

# the final one — the asset flips CAPTURING → CAPTURED,
# skills re-run, and an inform lands in Pending Approval
curl -X POST $B/api/mam/emit/landfall-feed-01 \
  -H 'Content-Type: application/json' -d '{"captureComplete":true}'

# the safe-state path — media no story references
curl -X POST $B/api/mam/emit/ugc-flood-77aa41b0   # → WITHHELD on som.system.audit

“I emitted the clip and nothing happened.” If it matched no story, that is the result — look for the WITHHELD record on the audit topic. By design, no story is created.

“The final emit didn’t flip the asset.” Either the story isn’t on the bus yet — publish the seed first, since the coordinator only re-checks for about a second — or the asset is already CAPTURED.