Reference · som-skill-library

Skills

SOM carries context; Skills carry knowledge. A skill is a rule written once, by editorial, readable by every tool. It declares what is true — the tool that owns the executor is the only thing that acts.

The model

Skills declare. Executors act.

1

The skill declares

A skill file states a condition and what is true when it holds — a flag stands, a hold applies, an enrichment is warranted. It never runs anything, never writes story state, and never changes content.

2

The executor recalls

Executors live inside vendor tools. Each matches incoming messages against skill adverts — the machine-read recall block — and publishes what the skill declares as skill.warning.raised.

3

The tool acts

The MAM keeps a held asset uncommittable, playout refuses the take, the CMS holds one path. Each in its own way, and each deciding for itself. Nothing is sent a command.

Open shape, house policy. Skills follow the open agentskills.io ↗ format: a markdown file with YAML frontmatter. The shared library is generic; a newsroom loads its own values against it. Your policy stays yours, and a newsroom can implement SOM 1.0 completely without using the library at all.

Anatomy

One file: frontmatter for machines, prose for people

---
skill_id: smart-stories/hold-while-flagged
skill_version: 0.2.2
som_schema_version: ["1.0.0"]
skill_type: REFERENCE
category: compliance
lifecycle: draft

recall:                      # the advert
  target_system_type: [mam, playout, rundown,
                       cms, compliance_hub]
  conditions:
    - kind: field
      path: editorial_gates[].gate_type
      op: equals
      value: "{{ config.gate_type }}"
    - kind: field
      path: editorial_gates[].status
      op: equals
      value: PENDING
  recall_on: ["story.context", …]
  state_path: editorial_gates[].status

output_messages: ["skill.warning.raised"]
severity_range: [hold]
auto_change_content: false
fail_closed: true
migration_policy: GATED
disclosure_level: L2
depends: []
---
# hold-while-flagged
…what it is, config surface, runtime loop,
 output contract, worked configurations,
 eval set, open items, vendor build notes
Identity

skill_id as publisher/name, a semver skill_version, the SOM schema versions it resolves against, a category and a lifecycle.

The advert

recall names which tool types may pick the skill up, the conditions over story paths (field and field_change), and which messages cause a look. Paths are literal and checked against the published schema; values can be templated from the house’s configuration.

Configured instance

One generic file with one house’s values loaded, watching one condition. A house runs several off the same file — a court restriction at story scope, an unconfirmed figure at link scope — and registers one advert row per configured instance.

Severity

hold / flag / inform, lower-case permanently. A skill declares which of them it can produce in severity_range.

GuaranteeValueWhat it means
auto_change_contentfalseThe only permitted value. What is withheld is an action, never the content — an executor that edits to release has broken the model.
fail_closedtrueAn unreadable value is treated as the condition holding, at the loudest severity the skill has. Silence on an unreadable restriction is never allowed.
output_messages["skill.warning.raised"]A skill has one way to say anything. It never writes story state.
depends[]Chaining happens over the bus, not through declared dependencies. A hold advertises against flag state, whoever raised the flag.

som-skill-library 0.2.2

Ten reference skills, one proposed

All lifecycle: draft, origin: reference, resolving against SOM 1.0. Find your tool type in the lookup table, read the skills in that row, and configure them for your house.

SkillDeclaresCategorySeverityRecalled by
raise-flag-on-matchA named flag on a story when a configured field matches a configured value — at mint, even before any media exists.compliance · X=1flaginform
planning
rundown
mam
graphics
discovery
hold-while-flaggedA named action withheld while a flag of a configured type stands, released only by a clearance of equal or higher authority on the same scope.compliance · X=1hold
mam
playout
rundown
cms
compliance_hub
gate-by-scopeWhether one destination path’s gate permits one telling right now. Always link-scoped.compliance · X=1holdinform
cms
playout
rundown
mam
distribution
record-provenance-on-ingestThat a source’s provenance is recorded as it enters a story — including an absent C2PA chain, recorded as absent.compliance · X=1inform
mam
ingest
verification
discovery
archive
flag-on-mismatchA mismatch when a bound asset or rundown item carries a value the story no longer holds — naming both values.editorial · X=2flaginform
rundown
graphics
cms
playout
apply-clearanceWhich member of a prepared version set a clearance makes current, and which members it supersedes.workflow · X=3inform
playout
rundown
mam
cms
graphics
enrich-on-conditionThat a named enrichment is warranted for an asset while a configured condition holds. It never runs the enrichment.workflow · X=3inform
mam
verification
multimodal
transcription
ingest
match-and-proposeA candidate story for a loose clip, at or above a house-set confidence. Confirmation is a human act recorded elsewhere.workflow · X=3inform
multimodal
mam
discovery
ingest
rundown
select-provider-by-contextWhich provider the house’s policy resolves for a capability, given the story context. It never assigns or invokes.workflow · X=3inform
transcription
verification
surface-on-context-matchAn item from a monitored source that matches the running story, with its provenance. Additive, off the critical path.workflow · X=3inform
transcription
verification
discovery
markets_data
mam
planning
declare-context-on-commit
proposed
The story context that applies on a link when an asset is committed to a destination.workflow · X=3inform
playout
mam
graphics

Lookup table ↗ · Conventions ↗ · All skill files ↗

When skills meet

Holds combine by conjunction

Any one hold means held

Where several gates bind the same fact on the same telling, it is served only when every one permits. “Most restrictive wins” and “story owner takes precedence” were formally withdrawn on 29 July 2026.

Precedence between two skills that clash on the same action is a separate question, ordered by X (category: compliance 1, editorial 2, workflow 3), Y (origin — every library skill is 5) and Z, which only the publishing house sets.

Chaining over the bus

A skill that both declared a state and withheld something would sit in two positions at once. So “flag and hold” is two skills: flag-on-mismatch declares the flag, and hold-while-flagged advertises against flag state — whoever raised it, a skill or a lawyer.

That is why depends is empty everywhere: declaring a dependency would invert it and create a cycle at the first version change.

Fail closed. An unreadable configuration or story value is treated as the condition holding, at the loudest severity the skill has, and detail names what couldn’t be read. If a rule can’t be evaluated, the output it guards stays held and a person decides.

What doesn’t clear a hold: time passing, the flag simply missing from a later snapshot, a clearance at a different scope, a lower authority, an executor restart, or clearing a different flag. Releasing a hold is never an instruction to release the asset.

Validation

The library checks itself

Five scripts ship with the library, and each asks a different question — including whether the documents agree with the files they describe.

cd som/skills
python3 scripts/validate_som_skill.py skills/<name>.md   # one skill file is legal
python3 scripts/check_library.py skills/                  # the library holds together
python3 scripts/check_paths.py skills/                    # every path resolves against
                                                          #   ../schema/story-context.schema.json
python3 scripts/build_lookup_table.py . --check           # the table matches the adverts
python3 scripts/check_cover_claims.py .                   # the docs match the files

One gap is named rather than hidden: check_paths.py resolves literal paths only. A {{ config.* }} value is unknowable until a house configures it, so catching a bad configured path is registration-time work for the house.

Honestly open

What the library doesn’t claim to settle

  • How authority is compared. “Cleared by equal or higher authority on the same scope” is the library’s working position, with the ordering supplied by each house as authority_scale. No group has ratified it.
  • Who turns a raised warning into gate state. A raise skill only publishes a warning; a hold skill reads editorial_gates[]. What materialises one into the other is not yet defined.
  • Scheme-qualified tag matching. Skills match tags[].value regardless of scheme today; whether to match newsroom:sport rather than sport is open.
  • Demo configuration. The configured instances used in the IBC walkthrough name individual vendors and are not published in 1.0, pending each vendor’s sign-off.

Next: validate and publish your first message →