Expert assistant for the Okyline schema language. Okyline enables JSON data validation by example, where constraints are expressed inline on field names. Use when creating, editing, or converting JSON Schema, Avro, or other schema formats to Okyline, or when answering questions about Okyline syntax and features. This skill should be triggered whenever the user mentions Okyline, references .oky files, or asks about example-driven JSON schema validation.
Scanned 9/2/2026
Install to Claude Code
npx -y skills add majiayu000/claude-skill-registry --skill okyline-okyline-okyline-skill-3 --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Okyline Okyline Okyline Skill 3?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/majiayu000-okyline-okyline-okyline-skill-3)More formats (shields.io, HTML) on the badges page.
---
name: okyline
description: >
Expert assistant for the Okyline schema language. Okyline enables JSON data
validation by example, where constraints are expressed inline on field names.
Use when creating, editing, or converting JSON Schema, Avro, or other schema
formats to Okyline, or when answering questions about Okyline syntax and features.
This skill should be triggered whenever the user mentions Okyline, references
.oky files, or asks about example-driven JSON schema validation.
---
# Okyline Schema Language v1.3.0
Okyline is a declarative language for describing and validating JSON structures using inline constraints on field names. Schemas are valid JSON documents with real example values.
# Okyline skill version : 1.7.0
## ⚠️ Before any schema generation
**MANDATORY**: Read the reference files BEFORE producing an Okyline schema:
1. `references/syntax-reference.md` — complete syntax of constraints
2. `references/internal-references.md` — $defs and $ref
3. `references/conditional-directives.md` — if conditional logic
4. `references/expression-language.md` — if $compute is necessary
Never generate a schema based solely on this SKILL.md file.
The examples here are a summary, not an exhaustive reference.
## $ref: when to use
Use `$defs`/`$ref` when:
1. **Recursion** (mandatory — only way to express recursive structures)
2. **Repeated structures** identical across multiple usages (e.g. `Period`, `Address`)
3. **Template pattern** — base structure specialized per usage via `$override` (e.g. `Coding`)
4. **Explicit user request**
Default → inline in `$oky`. Don't over-abstract — factorize only when it reduces real duplication or expresses a meaningful shared type.
## Core Syntax
```
"fieldName | constraints | label": exampleValue
```
- **fieldName**: JSON field name
- **constraints**: Validation rules (space-separated)
- **label**: Optional human-readable description
- **exampleValue**: Determines the inferred type
If a label is present without constraints, use `| |`:
❌ `"acheteur|Client"` → "Client" parsed as constraint!
✅ `"acheteur| |Client"` → "Client" is the label
## Minimal Schema Structure
```json
{
"$oky": {
"name|@ {2,50}|User name": "Alice",
"email|@ ~$Email~": "alice@example.com",
"age|(18..120)": 30
}
}
```
## Essential Constraints
| Symbol | Meaning | Example |
|--------|---------|---------|
| `@` | Required field | `"name\|@": "Alice"` |
| `?` | Nullable (can be null) | `"middle\|?": "John"` |
| `{min,max}` | String length | `"code\|{5,10}": "ABC123"` |
| `(min..max)` | Numeric range | `"age\|(18..65)": 30` |
| `('a','b')` | Enum values | `"status\|('ACTIVE','INACTIVE')": "ACTIVE"` |
| `~pattern~` | Regex or format | `"email\|~$Email~": "a@b.com"` |
| `[min,max]` | Array size | `"tags\|[1,5]": ["eco"]` |
| `[*]` | Array (no size constraint) | `"items\|[*]": [1, 2]` |
| `->` | Element validation constraint | `"tags\|[*] -> {2,10}": ["eco"]` |
| `!` | Unique elements | `"codes\|[*]!": ["A","B"]` |
| `#` | Key field (for object uniqueness) | `"id\|#": 123` |
| `$ref` | Reference to definition (type indicator, not a validation constraint) | `"address\|$ref": "&Address"` |
### Contraintes numériques ouvertes
Quand une seule borne est nécessaire, utiliser les opérateurs de comparaison :
| Syntaxe | Signification | Exemple |
|---------|---------------|---------|
| `(>0)` | Strictement positif | `"quantity\|(>0)": 5` |
| `(>=0)` | Positif ou zéro | `"price\|(>=0)": 29.99` |
| `(<100)` | Strictement < 100 | `"percentage\|(<100)": 50` |
| `(<=100)` | ≤ 100 | `"score\|(<=100)": 85` |
❌ Ne jamais inventer de syntaxe avec borne manquante : `(0..)`, `(..100)`
✅ Utiliser les comparaisons : `(>=0)`, `(<=100)`
❌ Ne jamais inventer borne manquante : `(0..99999999)`, `(-99999999..100)`
✅ Utiliser les comparaisons : `(>=0)`, `(<=100)`
⚠️ **INVALID SYNTAX** — Okyline does NOT support open ranges:
- ❌ `(0..)`, `(..100)`, `(1..*)`, `(0..*)`
- These will cause validation errors
### Taille de collection illimitée
Utiliser `*` pour indiquer "pas de limite" :
| Syntaxe | Signification |
|---------|---------------|
| `[*]` | Tableau sans contrainte de taille |
| `[1,*]` | Au moins 1 élément, pas de maximum |
| `[~pattern~:*]` | Map avec clés validées, nombre d'entrées illimité |
❌ Ne jamais omettre une borne : `[1,]`, `[~pattern~:]`
✅ Utiliser `*` explicitement : `[1,*]`, `[~pattern~:*]`
## Built-in Formats
Use with `~$FormatName~`: `$Date`, `$DateTime`, `$Time`, `$Email`, `$Uri`, `$Uuid`, `$Ipv4`, `$Ipv6`, `$Hostname`
## Type Inference Rules
- Type is inferred from example value (no explicit declarations)
- `42` → Integer, `3.14` → Number, `"text"` → String, `true` → Boolean
- Arrays must have at least one element for type inference
- **`null` cannot be used as example** — no type can be inferred. Use `?` for nullable fields with a real example value:
❌ `"middleName|?": null`
✅ `"middleName|?{1,50}": "Marie"`
❌ `"discount|?(0..100)": null`
✅ `"discount|?(0..100)": 15`
### Decimal Values Ending in .00
JSON serializers drop trailing zeros: `78.00` becomes `78`.
To preserve decimal precision in examples, wrap in quotes:
❌ `"amount": 78.00` → Serialized as 78, type inferred as Integer
✅ `"amount": "78.00"` → Preserved, type inferred as Number
This only affects decimals with zero fractional parts (.00, .0).
Regular decimals (45.5) and integers (10) are unaffected.
## ⚠️ `?` vs Absence — Critical Distinction
`?` and "optional field" are NOT the same thing in Okyline:
| | Meaning | When to use |
|--|---------|-------------|
| No `@` | Field may be **absent** from the document | FHIR optional fields, nullable in most APIs |
| `?` | Field may be explicitly **`null`** | Only when `null` is a meaningful intentional value |
```json
// ❌ Wrong — using ? for optional fields (common LLM mistake)
"meta|?|Resource metadata": { ... }
"subType|?|Claim subtype": { ... }
// ✅ Correct — optional = no @, never ?
"meta||Resource metadata": { ... }
"subType||Claim subtype": { ... }
// ✅ ? only when null is intentional and meaningful
"active|?|Explicitly unknown status": true
```
> In FHIR R4 and most REST APIs, absent fields are simply omitted — they are never sent as `null`. Use `?` only when the standard explicitly allows `null` as a distinct semantic value (e.g. "unknown" vs "not provided").
## Legacy Null Tolerance
```json
{ "$nullAsAbsentIfUndeclared": true }
```
When `true`, a `null` value on a field not marked `?` is treated as absent instead of invalid. Use only for legacy systems that send `null` instead of omitting fields. Default: `false`.
## Polymorphism vs Structural Directives — Key Distinction
These look similar but serve different purposes:
| | Target | Meaning |
|--|--------|---------|
| `$exactlyOne` / `$mutuallyExclusive` | Fields of an object | Constrain **presence** of sibling fields |
| `$oneOf` / `$anyOf` | A single field | Constrain the **structure** of that field's value |
```json
// $exactlyOne — exactly one of these sibling fields must be present
"diagnosisCodeableConcept": { ... },
"diagnosisReference": { ... },
"$exactlyOne": ["diagnosisCodeableConcept", "diagnosisReference"]
// $oneOf — the payment field itself must match exactly one variant
"payment|@ $oneOf": [
{ "type|@ ('card')": "card", "cardNumber|@ {16}": "1234567812345678" },
{ "type|@ ('paypal')": "paypal", "email|@ ~$Email~": "user@example.com" }
]
```
## Reusable Definitions — `$defs` and `$ref`
Okyline supports **internal references** to promote reuse and consistency.
### `$defs` — Definition Repository
`$defs` is placed at root level (alongside `$oky`) and contains reusable schema fragments:
```json
{
"$oky": {
"person": {
"address | $ref": "&Address",
"contact | $ref @": "&Email"
}
},
"$defs": {
"Address": {
"street|@ {2,100}": "12 rue du Saule",
"city|@ {2,100}": "Lyon"
},
"Email|~$Email~ {5,100}": "user@example.com"
}
}
```
Definitions can be **objects** or **scalars** (with constraints in the key).
### Reference Syntax — `&Name`
References use `&` prefix: `&Address`, `&Email`, `&Person`
### Property-Level Reference — `field | $ref`
A field uses another schema as its type:
```json
"address | $ref @": "&Address" // Required address
"backup | $ref ?": "&Address" // Optional, nullable
"emails | $ref [1,5]": ["&Email"] // Array of 1-5 emails
```
**Structural constraints** (`@`, `?`, `[min,max]`, `!`) are defined locally at each usage.
**Value constraints** (`{min,max}`, `(min..max)`, `~pattern~`) are inherited from the definition.
### Important: `$ref` vs `->` for arrays
`$ref` and `->` serve different purposes:
- `$ref` = type indicator (what the elements ARE) — comes BEFORE `->`
- `->` = validation constraints (rules elements must satisfy) — comes AFTER `$ref`
For arrays of referenced types, `$ref` is placed with the array constraint, never after `->`:
```json
// Correct syntax
"items|[*] $ref": ["&Item"] // Array of Item references
"items|[1,10] $ref": ["&Item"] // Array of 1-10 Item references
"items|[*] $ref -> {2,50}": ["&Item"] // With additional element constraint
// Wrong syntax - $ref must never be after ->
❌ "items|[*] -> $ref": ["&Item"]
```
### Object-Level Reference — Inheritance
Include all fields from a base schema:
```json
{
"$oky": {
"Article": {
"$ref": "&Auditable",
"title|@ {1,200}": "Mon article"
}
},
"$defs": {
"Auditable": {
"createdAt|@ ~$DateTime~": "2025-01-01T00:00:00Z",
"updatedAt|@ ~$DateTime~": "2025-01-01T00:00:00Z"
}
}
}
```
Multiple inheritance: `"$ref": ["&Auditable", "&Deletable"]`
### Modifying Inherited Fields
| Directive | Usage | Description |
|-----------|-------|-------------|
| `$remove` | `"$remove": ["field1", "field2"]` | Exclude inherited fields |
| `$override` | `"field \| $override ...": value` | Replace inherited definition |
| `$keep` | `"$keep": ["&A.field"]` | Resolve collision in multiple inheritance |
## $compute Context Rules
Expressions in `$compute` must be **attached to a field** using `|(%ComputeName)` syntax. The expression is evaluated in the context of the **object that directly contains the annotated field** — all properties of that object are accessible, including sibling arrays.
See `references/expression-language.md` for full details and examples.
## Schema Design Workflow
1. Start with `{"$oky": { ... }}`
2. Write example JSON with realistic values
3. Add `@` to required fields
4. Add constraints progressively: length, range, format, enums
5. Add conditional logic if needed (`$appliedIf`, `$requiredIf`)
6. Add computed validations if needed (`$compute`)
7. Identify repeated structures → extract to `$defs` with `$ref`
## Reference Files
For detailed syntax and features, consult these references:
- **Constraint syntax & patterns**: See [references/syntax-reference.md](references/syntax-reference.md)
- **Conditional directives**: See [references/conditional-directives.md](references/conditional-directives.md)
- **Expression language ($compute)**: See [references/expression-language.md](references/expression-language.md)
- **Internal references ($defs, $ref)**: See [references/internal-references.md](references/internal-references.md)
## Quick Patterns
```json
// Required email
"email|@ ~$Email~": "user@example.com"
// Required string 2-50 chars
"name|@ {2,50}": "Alice"
// Optional number range
"discount|(0..100)": 15
// Enum from nomenclature
"status|@ ($STATUS)": "ACTIVE"
// Array of unique strings, 1-10 items, each 2-20 chars
"tags|@ [1,10] -> {2,20}!": ["eco", "bio"]
// Required but nullable
"middleName|@ ?{1,50}": "Marie"
// Map with pattern keys
"translations|[~^[a-z]{2}$~:10]": {"en": "Hello", "fr": "Bonjour"}
// Reference to definition (required)
"address | $ref @": "&Address"
// Array of referenced type ($ref before ->, never after)
"items | $ref @ [1,100]": ["&OrderItem"]
// Array of referenced type with element constraint
"codes | $ref [1,10] -> {2,20}": ["&Code"]
// Object inheritance
"$ref": "&Auditable"
// Template pattern — $ref + $override inline in array element
"coding|[*]": [{
"$ref": "&Coding",
"code|$override @ ($MARITAL_STATUS)|Code": "M"
}]
// Property-level $ref (field IS the type, no specialization)
"period|$ref||Validity period": "&Period"
// Multiple inheritance
"$ref": ["&Auditable", "&Deletable"]
```
## Document Metadata (Optional) - Must be generated in this order
```json
{
"$okylineVersion": "1.3.0",
"$version": "1.0.0",
"$id": "my-schema",
"$title": "My Schema",
"$description": "Schema description",
"$additionalProperties": false,
"$oky": {
...
},
"$defs": { ... },
"$format": { "Code": "^[A-Z]{3}-\\d{4}$" },
"$compute": { "Total": "price * quantity" },
"$nomenclature": { "STATUS": "ACTIVE,INACTIVE" }
}
**`$id` format**: Only letters, digits, underscores and dots allowed. Pattern: `^[a-zA-Z][a-zA-Z0-9_]*(\.[a-zA-Z][a-zA-Z0-9_]*)*$`
❌ `"personne-vehicules"` (hyphen not allowed)
✅ `"personne.vehicules"` or `"personne_vehicules"`
```
## Structural Group Directives
Constrain which fields from a group must be present. No condition required.
```json
"$atLeastOne": ["email", "phone"] // at least one present
"$mutuallyExclusive": ["deceasedBoolean", "deceasedDateTime"] // at most one
"$exactlyOne": ["diagnosisCode", "diagnosisRef"] // exactly one
"$allOrNone": ["street", "city", "zip"] // all or none
// Multiple independent groups → use suffix
"$mutuallyExclusive_deceased": ["deceasedBoolean", "deceasedDateTime"],
"$mutuallyExclusive_birth": ["multipleBirthBoolean", "multipleBirthInteger"]
```
See `references/conditional-directives.md` for full details.
## $compute — Cross-Collection Pattern
To validate a constraint across an array from root context, attach the compute to the array field itself:
```json
"insurance|@ [1,*] -> ! (%FocalInsurance)": [{
"focal|@": true, ...
}],
"$compute": {
"FocalInsurance": "countIf(insurance, focal) == 1"
}
```
- `countIf(collection, expr)` — counts elements where expr is truthy
- For boolean fields: `countIf(insurance, focal)` counts `true` values
- For other fields: `countIf(items, status == 'ACTIVE')`
- Always attach the compute to the most semantically relevant field
## Common Mistakes to Avoid
- Missing `$oky` wrapper
- Empty arrays (need at least one element)
- Confusing `[1,10]` (array size) with `-> {1,10}` (element constraint)
- Forgetting to escape backslashes in regex (`\d` → `\\d`)
- Defining `$compute` expressions without attaching them to fields with `|(%Name)`
- Using absolute paths in `$compute` instead of relative references to parent context
- Using `$ref` without the `&` prefix (correct: `"&Address"`, wrong: `"Address"`)
- Object-level `$ref` targeting a scalar definition (must target object schema)
- Redefining an inherited field without using `$override`
- Creating circular object-level references (A includes B includes A)
- Placing `$defs` inside `$oky` (must be at root level)
- Using empty brackets `[]` for arrays — use `[*]` or omit size constraint entirely
- Applying element constraints (enum, length, range) directly to array field instead of using `->`:
❌ `"permis|@ ('A','B','C')[]": ["B"]`
✅ `"permis|@ -> ('A','B','C')": ["B"]`
✅ `"permis|@ [1,5] -> ('A','B','C')": ["B"]`
- Using hyphens in `$id` — only letters, digits, underscores and dots are allowed
- Applying element constraints (enum, length, range) directly to array field instead of using `->`:
❌ `"permis|@ ('A','B','C')[]": ["B"]`
✅ `"permis|@ -> ('A','B','C')": ["B"]`
✅ `"permis|@ [1,5] -> ('A','B','C')": ["B"]`
- Placing `$ref` after `->` for arrays of references (`$ref` is a type indicator, not a validation constraint):
❌ `"children|[*] -> $ref": ["&Node"]`
✅ `"children|[*] $ref": ["&Node"]`
✅ `"children|[1,10] $ref -> {2,50}": ["&Node"]`
- Using open-ended range syntax `(0..)` or `(..100)` — these don't exist!
❌ `"price|(0..)": 29.99`
✅ `"price|(>=0)": 29.99`
- Using multiple value constraint blocks `(...)` on the same field:
❌ `"montantTTC|@ (>=0) (%LigneTTC)": 4320`
✅ `"montantTTC|@ (%LigneTTC)": 4320`
- Using null as an example value, even with ? Okyline needs a valid example to infer the type.:
❌ `"name|? ": null`
✅ `"name|? ": "Charles"`
- Using decimal number example terminant par .00 sans " ".
❌ `"amount|? ": 800.00`
✅ `"amount|? ": "800.00"`
When a field uses `$compute`, ALL value constraints must be inside the compute expression:
```json
"$compute": {
"LigneTTC": "montantTTC >= 0 && montantTTC == montantNetHT + montantTVA"
}
```
## ⚠️ Erreurs silencieuses (pas d'erreur syntaxe, mais problème à la validation)
- [ ] Décimales en `.00` → `"150.00"` (sinon inféré comme Integer)
- [ ] Exemple `null` → impossible d'inférer le type
- [ ] Tableau vide `[]` → impossible d'inférer le type des éléments
- [ ] `"champ|Label"` → "Label" interprété comme contrainte (utiliser `"champ| |Label"`)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!