Vocabulary format
opentide vocabularies are TOML files (`.vocab.toml`) defining allowed enum values for object and configuration fields. Canonical copies live in `vocabularies/`; opentide bundles them at build time.
Requirements
- Every vocabulary file MUST validate against schemas/vocabulary.schema.json.
- Every vocabulary file MUST declare
nameandfieldat the top level. - Vocabulary files MUST NOT declare a top-level
versionproperty; versioning is per[[keys]]entry (see RFC 0003). - Entry keys MUST be declared in
[[keys]]tables unless usingstagesfor scoped vocabularies. - Clients MUST NOT override vocabulary files in
.opentide/configurations/; extensions useschema.toml[[vocabulary.*]]entries only. - The
fieldvalue MUST match the YAML/JSON field path the vocabulary constrains (e.g.tlp,att&ck,detection.methodology). - Sync direction MUST be specifications → opentide (canonical data originates here).
Definition
Top-level properties
| Property | Type | Required | Description |
|---|---|---|---|
name | string | yes | Human-readable vocabulary name |
field | string | yes | Field path this vocabulary applies to |
description | string | no | Vocabulary description |
icon | string | no | Display icon for UI/schema generation |
key | "name" | "id" | no | Whether entries are keyed by name or id (default: name-based) |
model | boolean | no | When true, vocabulary models a nested object type |
keys | array of KeyEntry | no | Enum entries |
stages | array | no | Scoped stage identifiers for multi-stage vocabularies |
source | string | no | Upstream a generated vocabulary is ingested from (e.g. mitre-attack) |
source_version | string | no | Upstream release the keys were last refreshed from (e.g. ATT&CK 20.0) |
source_fetched_at | string | no | UTC timestamp (ISO 8601) of the upstream fetch |
source, source_version and source_fetched_at are provenance only. They are not a contract revision and MUST NOT be read as one; contracts come from per-key version and removed.
Top-level version is not permitted. Vocabulary contract revisions (field::major.minor) are derived from per-key lifecycle metadata, not file stamps.
[[keys]] entry
| Property | Type | Required | Description |
|---|---|---|---|
id | string | no | Stable identifier (e.g. TLP:AMBER) |
name | string | yes* | Display/slug value used in YAML |
version | string | yes | Contract line when this key enters the vocabulary (major.minor, e.g. 1.0) |
removed | string | no | Contract line when this key leaves (major.minor); excludes key from contracts at or above this revision |
description | string | no | Entry description (markdown in schema) |
icon | string | no | Entry icon |
misp | string | no | MISP taxonomy mapping |
tide.vocab.stages | string | list | no | Stage scope for this entry |
* Required when key = "name" (default).
Per-key bump rules
| Change type | Key metadata | Contract effect |
|---|---|---|
| Add new key | set version to introducing minor line | new minor contract available (e.g. killchain::1.1) |
| Remove key | set removed at next major | major contract line |
| Rename key | removed on old key + new key at major | major |
| Description/icon-only edit | no change | none |
Contract resolution
A vocabulary contract field::M.m resolves to all keys where:
version <= M.m(cumulative minor semantics), andremovedis absent orremoved > M.m.
Object schema revisions pin explicit contracts via schemas/pins/ manifests (see RFC 0003).
Staged vocabularies
Entries MAY be scoped to lifecycle stages via tide.vocab.stages. Metaschema fields use tide.vocab.scoped and tide.vocab.stages keywords to filter allowed values at generation and validation time.
- A field bound to a staged vocabulary MUST declare
tide.vocab.scoped, and its authored values MUST be<stage>::<key>. The prefix is what tells two stages' identically-named keys apart, and omitting it makes those values unreachable (see RFC 0005). - Stage identifiers naming a human-facing category SHOULD be capitalised (
Host,Protocol). A stage naming an external framework keeps that framework's own spelling (misp,att&ck). - Key names MAY themselves contain
::as hierarchy within the key (AWS::Compute::EC2), and a key's first token MAY coincide with a stage identifier (Security::Kerberosis aProtocolkey). A consumer resolving an authored value MUST therefore try the whole value as a key name before reading its leading token as a stage identifier. - Scoping a field changes no key's lifecycle, so it MUST NOT trigger a vocabulary contract revision under RFC 0003.
Example file
name = "Traffic Light Protocol"
field = "tlp"
description = "TLP classification for information sharing."
key = "name"
[[keys]]
id = "TLP:CLEAR"
name = "clear"
version = "1.0"
description = "Recipients can spread this to the world."Relationships
- catalog.md — index of bundled vocabularies
- metaschema-keywords.md —
tide.vocabkeyword resolution - RFC 0003 — per-key versioning and schema pins
- configuration.md —
schema.tomlvocabulary extensions - validation.md — vocabulary conformance checks
Defaults & overrides
| Mechanism | Allowed? |
|---|---|
Edit vocabularies/*.vocab.toml here (via RFC) | Yes |
Client copy of .vocab.toml in configurations | No |
schema.toml [[vocabulary.*]] extension | Yes |
opentide sync interface
| Location | Role |
|---|---|
specifications/vocabularies/ | Canonical source (this repo) |
opentide/src/opentide/data/vocabulary/ | Runtime bundle (copied at build) |
schemas/vocabulary.schema.json | Validation schema for TOML files |
The sync script is an opentide build concern; this spec defines the data contract only.
Examples
- Canonical TLP vocabulary: vocabularies/tlp.vocab.toml
- JSON Schema: schemas/vocabulary.schema.json
History
| Version | Date | Notes |
|---|---|---|
| 1.1 | 2026-10-19 | removed excludes a key from contracts at or above its revision; the description said "at or below" while Contract resolution already required removed > M.m. Document the source, source_version and source_fetched_at provenance keys. |
| 1.1 | 2026-06-26 | Per-key version/removed; no top-level file version (RFC 0003) |
| 1.0 | 2026-06-25 | Initial spec from opentide vocabulary.schema.json |
Detection rule (MDR)
A detection rule (MDR — Managed Detection Rule) is the deployable unit of detection content: metadata, severity, ATT&CK techniques, platform-specific query configurations, optional response playbook, and lifecycle status. Schema identifier: `rule::1.0`.
Vocabulary catalog
Index of canonical vocabulary files bundled with opentide. Each file lives in `vocabularies/` and is referenced by field path in object specs and metaschema `tide.vocab` keywords.