| name | twin-lifecycle |
| description | Use for day-2 operations on a digital twin — adding, modifying, or deprecating a domain with breaking-change discipline, monitoring twin health (binding/freshness, governance ownership, event-stream, drift), and adopting ontology into an existing codebase. Trigger whenever the user wants to evolve, change, deprecate, or remove a domain concept, asks if a change is breaking, wants to health-check/audit a twin, or wants to bring ontology into a brownfield project. |
Twin Lifecycle — Day-2 Operations
A twin that stays frozen after launch dies the same death as a Word document. The real value of
ontology-as-code is that every business change becomes a disciplined, validated change — with a
diff, a reviewer, and a CI gate. This skill covers three daily scenarios (add / modify / deprecate),
the developer loop, twin health monitoring, and brownfield adoption.
Principle
A twin has value when it evolves, not just at launch.
Every business change = one disciplined change on the model, validated before it merges.
The same rule you know from docs-as-code (all changes through PR) applies here — but the change is
validated: a schema error makes CI red immediately, not at production.
Add a Domain
Adding a concept (example: Collateral) touches all six atoms but keeps blast radius small because
each atom lives in its own file.
Steps:
- Create
ontology/objects/collateral.yaml — define the ObjectType (fields + link securing
pointing to Loan).
- Register it in the root schema — add
- objects/collateral to the root imports list.
- Optionally add supporting atoms in separate files:
ontology/actions/add-collateral.yaml — an ActionType that emits CollateralAttached.
ontology/policies/pol-002.yaml — a PolicyType enforcing the collateral requirement.
ontology/events/collateral-attached.yaml — an EventType for downstream subscribers.
- Validate locally before committing:
bash scripts/ontology-validate.sh ontology/objects/collateral.yaml
Why blast radius stays small: one new file + one imports line. Existing atoms are untouched,
so the diff is clean and review is fast. This is the direct payoff of the one-atom-one-file
structure from /ontology-as-code:model.
Modify: Non-Breaking vs Breaking
Distinguishing these two is the most important operational skill.
| Change type | Examples | Risk | Action |
|---|
| Non-breaking (additive) | Add optional attribute phone; add enum value platinum | Low — existing data still valid | Edit, validate, normal PR |
| Breaking (contractive) | Make a field required; remove a permissible_value in use; rename full_name → name | High — existing data / consumers break | Needs migration + MAJOR version bump + consumer notice |
Practical rules:
- Extend = safe. Contract = dangerous. Add optional field / add enum value → non-breaking.
Drop field / add constraint / rename → breaking.
- Breaking changes must leave a trace. Never rename silently. Mark the old field
deprecated
first (see the Deprecate section below), give consumers a cycle to migrate, then remove in a
later version.
- CI is the safety net. Keep a "golden" data file in
data/ that exercises existing valid
instances. If a change breaks it during ontology-validate.sh, CI catches it in the PR before
any consumer is hurt.
To automate detection, run the breaking-change-detector agent or pipe the diff through
ontology-evolve.sh:
bash scripts/ontology-evolve.sh --git HEAD ontology/objects/loan.yaml
Deprecate — Don't Delete Outright
Deleting a field or object that consumers still read is a silent breaking change — the exact
"pain in three places at once" that ontology-as-code is designed to prevent.
Pattern: deprecate first, remove later.
- Annotate
x_deprecated in the YAML instead of deleting:
attributes:
asset_type:
range: string
annotations:
x_deprecated: "2026-06-09, use asset_class instead"
The field still validates. The annotation is the as-code signal: "stop using this."
-
Audit downstream consumers. Grep the generated SDK imports; check which services subscribe
to the affected EventType. The twin gives you one place to look instead of guessing.
-
Wait one cycle. Give consumers time to migrate to the replacement field or object.
-
Remove in a later version — once no consumer reads it, delete the field and bump the
MAJOR version (this is a breaking change per the table above).
Deprecate-first turns removal into a controlled, visible process instead of a surprise.
Developer Loop
A twin is a source for running code, not an artifact to admire.
edit ontology/*.yaml ──► validate locally ──► gen SDK
▲ │
│ ▼
commit + PR ◄── code reads object / subscribes event ◄── import SDK
Steps in practice:
- Validate before committing — catch schema errors early, not in CI:
bash scripts/ontology-validate.sh ontology/
- Regenerate the SDK after any ontology change:
bash scripts/ontology-codegen.sh ontology/<root>.ontology.yaml --out sdk/
This corresponds to the /ontology-as-code:codegen skill entry-point.
-
Application code imports the generated models — typed objects with IDE autocomplete, no
hardcoded field names. Subscribe to EventType instances as topics in your event bus.
-
A business change = edit one YAML + open one PR. The change propagates through SDK regen rather
than scattered edits across multiple services.
Monitor Twin Health — 4 Signals
A live twin needs monitoring like any live system. Measure these four signals regularly:
| Signal | Question to answer | How to detect |
|---|
| Drift | Does the model still match reality? | Compare x_data_binding declarations against the actual source schema — any mismatch is drift |
| Binding freshness | Is the twin data still current? | Check x_sync_mode (batch/stream) + timestamp of last successful sync run |
| Event-stream health | Is telemetry still flowing? | Count EventType instances over time — unexpected silence = blockage or broken publisher |
| Governance ownership | Does every object have an owner? | Audit x_governance_owner annotations — ownerless objects are governance debt |
Run the full audit in one command:
bash scripts/ontology-audit.sh ontology/
This corresponds to the /ontology-as-code:audit skill entry-point and can also be delegated to
the twin-health-auditor agent for a structured report with remediation suggestions.
Maturity signal: re-score the twin on the maturity ladder periodically. A healthy twin is
climbing, not frozen at Level 1. A twin that passes all four health signals but never advances
maturity is stagnant — plan the next improvement cycle.
Brownfield Adoption
Adding ontology-as-code to an existing codebase does not require a rewrite. The approach is
scan → candidate atoms → model → validate.
Steps:
- Scan existing code and docs for implicit domain concepts — entity names in DB schemas,
API payloads, spreadsheet headers, legacy data dictionaries:
bash scripts/ontology-scan.sh .
-
Review candidates. The scan produces a list of candidate ObjectType and AttributeType
atoms. Discard noise; keep what the business actually talks about.
-
Model the highest-value candidates first. Use /ontology-as-code:model to author the
YAML atoms. Start with one object + its links; do not try to capture everything at once.
-
Validate and commit. Run ontology-validate.sh, open a PR, wire CI — same workflow as a
greenfield twin.
The ontology-adopter agent automates steps 1–2 and drafts initial YAML for step 3, reducing the
cold-start effort on large codebases. Reference the /ontology-as-code:adopt skill entry-point
for the full brownfield onboarding protocol.
Quick Reference
| Task | Command / skill |
|---|
| Validate local changes | bash scripts/ontology-validate.sh ontology/ |
| Detect breaking changes | bash scripts/ontology-evolve.sh --git HEAD <file> |
| Regen SDK after edit | bash scripts/ontology-codegen.sh ontology/<root>.ontology.yaml --out sdk/ |
| Full health audit | bash scripts/ontology-audit.sh ontology/ |
| Scan brownfield source | bash scripts/ontology-scan.sh <repo-dir> |
| Add / model new domain | /ontology-as-code:model |
| Regenerate SDK (skill) | /ontology-as-code:codegen |
| Full health audit (skill) | /ontology-as-code:audit |
| Brownfield onboarding | /ontology-as-code:adopt |