Source: Eure: filling the gap between TOML and YAML with arbitrary nesting and tagged unions

$frontmatter {  title: Eure: filling the gap between TOML and YAML with arbitrary nesting and tagged unions  description: Announcing the alpha release of Eure, a minimalist data notation language designed to cover the gap between TOML and YAML with support for arbitrary nesting and tagged unions.  date = `2026-01-28`}'#': Eure: filling the gap between TOML and YAML with arbitrary nesting and tagged unionsintro-message = ```markdownHi, I'm Ryo Hirayama from [Hihaheho Studio](https://hihaheho.com), an indie game studio. I'm excited to announce the first alpha release of a newly designed data notation language called Eure (pronounced "your"). It encourages users to write their data expressively.You can try it right now in the web playground: https://eure.devIt supports syntax highlighting, to-JSON conversion, schema verification, and real-time diagnostics.```eure-definition = ```markdownEure is a minimalist, schema- and editor-friendly data language for algebraic data types and deeply nested data.**Highlights:**- Minimalist / human-friendly- Algebraic data model + JSON compatibility- JSON Schema interoperability- Rich editor experience- Programmatically editable- Dedicated templating extension```tldr-links = ```markdownLanding page / Web playground: https://eure.devGitHub: https://github.com/Hihaheho/eure```tldr-for-toml-user = ```html<details>  <summary><strong>TL;DR for TOML users</strong> (click to expand)</summary>  <ul>    <li>It's arbitrarily nestable</li>    <li>For array tables, <code>@ project.member[]</code> instead of <code>[[project.member]]</code></li>  </ul></details>```tldr-for-toml-user.$mark.dangerously-inner-html = truetoc-here.$toc = true@ why-toml-yaml {  '##': Filling the gap between TOML and YAML  body = ```markdownI'm a fan of both TOML and YAML. I like TOML for its minimalism and flexibility, and YAML for its versatility and arbitrary nesting.Personally, I don't choose YAML for small configuration files because it makes the file too verbose, and TOML is more suitable for that. But for manifest files for Kubernetes, CI/CD pipelines, etc., which tend to be complex and hard to maintain, YAML is more suitable.Eure is designed to cover the gap between TOML and YAML. It's designed to have the minimalism and flexibility of TOML, but also the versatility and arbitrary nesting syntax of YAML. Thus, Eure is a good choice for both small configuration files and complex manifest files.Also, it's designed to cover modern data types like tuples and tagged unions. It'll cover various use cases not by adding a rich feature set into the language, but through built-in extensibility.```}@ usecases {  '##': Suggested use cases  body = ```markdown- Mid-sized or large configuration files- Data-driven test suite for a spec (see [Eure's own test suite](https://github.com/Hihaheho/eure/tree/main/test-suite/cases))- Manifest files for Kubernetes, CI/CD pipelines, etc., which tend to be complex and hard to maintain (see [GitHub Actions example](https://eure.dev/?example=github-action&tab=json))- Generate complex JSON from Eure (e.g., [TextMate grammar files](https://eure.dev/?example=textmate-grammar&tab=json))- Write a blog post or document in a CMS or static site generator with Eure instead of markdown (this blog post is also [written in Eure](/source/000-alpha-release.html))- Write a JSON Schema in a more fluent and readable way by converting from Eure Schema (see [GitHub Actions schema example](https://eure.dev/?example=github-action&tab=schema))```}@ syntax {  '##': First glance at the syntax:  github-action = ````eure  name: CI  @ on  pull_request = null  push.branches = ["main"]  @ jobs.hello_world {    runs-on: ubuntu-latest    @ steps[]    run: echo "Hello, World!"  }  @ jobs.build {    runs-on: ubuntu-latest    @ steps[].uses: actions/checkout@v6    @ steps[]    uses: actions/cache@v4    with {      key: ${{ runner.os }}-stable-${{ hashFiles('**/Cargo.toml') }}      path = ```        ~/.cargo/bin/        ~/.cargo/registry/index/        ~/.cargo/registry/cache/        ~/.cargo/git/db/        target/        ```    }    @ steps[]    uses: dtolnay/rust-toolchain@stable    with {      components: rustfmt, clippy    }    @ steps[]    name: Run all    run = ```bash      cargo fmt --check      cargo clippy      cargo test      ```  }  ````  as-you-notice = ```markdownThis is what a GitHub Action workflow could look like in Eure.```  reading-guide = ```markdownThe following sections explain: **paths** for addressing nodes, **bindings** for assigning values, **sections** for scoping, **nesting** for structuring complex documents, and **code** for language-tagged text.```  @ path  '###': Path  md = ```markdown`push.branches` and `jobs.hello_world` are paths. A path is a sequence of keys separated by `.`, similar to jq's path expressions. Path syntax is used in bindings, map keys, and section headers.**Key forms:**- Identifier: `jobs.hello_world`- Quoted string (with escapes/whitespace): `"title:\t aaa".value`- Integer key: `x.1 = 1`- Tuple key: `coords.(0, 1) = true`- Extension (metadata channel): `$local.note`**Path markers:**- Array append: `items[] = "new"`- Array index: `items[0] = "first"`- Tuple index: `point.#1 = 42`Eure's object keys are strings, integers, or tuples (only string keys are JSON-compatible). Extensions are a separate metadata channel (e.g. `$local.note`) and don't affect the data model unless your tools interpret them.```  @ binding  '###': Binding  binding-types = ```markdownThere are two types of binding: `=` (value binding) and `:` (text binding). The left-hand side is always a path. On the right-hand side of `=`, you can write any literals like `42` (integer), `3.24` (float), `"escaped\nstring"`, `'literal string'`, `(1.0, "tuple")`, code blocks (delimited with 3-6 backticks), `` `let a = 1` `` (inline code), `[1, 2, 3]`, and `{ x => 1, y => 2 }` (inline map).`:` is called "Text Binding". It interprets the right-hand side until newline or EOF as plaintext, always without escaping or implicit typing, unlike YAML. So `text: true` is always `text = "true"`. Use `=` when you want to bind a boolean or any other non-plaintext type. This avoids YAML's implicit typing pitfalls where `port: 8080` becomes an integer or `country: NO` becomes a boolean. Note: leading Unicode whitespace is trimmed, and `: ` followed by only whitespace until newline is equivalent to `= ""`.Example:```  text-binding-example = ```eure  // This is a text binding example  run: echo "Hello, World!"  // This is equivalent to the text binding example above  run = "echo \"Hello, World!\""  ```  composite-path = ```markdownBindings can have composite paths like `push.branches =`.```  @ section  '###': Section  section-body = ```markdown`@` is the beginning of a section and is like table syntax in TOML. Eure's `@ a.b[]` corresponds to TOML's `[[a.b]]`. Sections can have two types of body: bindings and nested documents. A binding body can contain any number of bindings; a nested body can contain a nested Eure document in `{}`. In the above example, `@ jobs.hello_world` and `@ jobs.build` have nested documents.```  @ nesting {    '###': Nesting    body = ```markdownEure allows arbitrary nesting with sections and block sections, so you can structure complex documents without TOML's table/array-table limitations.```    example = ```eure    @ jobs.hello_world {      runs-on: ubuntu-latest      @ steps[]      run: echo "Hello, World!"    }    ```    flattened = ```eure    // equivalent to (flattened paths)    jobs.hello_world.runs-on: ubuntu-latest    jobs.hello_world.steps[].run: echo "Hello, World!"    ```    array-nesting = ```markdownNested sections often read more naturally than TOML's array-table syntax. Here's a TOML example, followed by a more concise Eure equivalent.This is an example TOML from <https://toml.io/en/v1.1.0#array-of-tables>:```    example-toml = ```toml    [[fruits]]    name = "apple"    [fruits.physical]  # subtable    color = "red"    shape = "round"    [[fruits.varieties]]  # nested array of tables    name = "red delicious"    [[fruits.varieties]]    name = "granny smith"    [[fruits]]    name = "banana"    [[fruits.varieties]]    name = "plantain"    ```    eure-equivalent = markdown`In Eure:`    example-eure = ```eure    @ fruits[] {      name: apple      @ physical      color: red      shape: round      @ varieties[]      name: red delicious      @ varieties[]      name: granny smith    }    @ fruits[] {      name: banana      @ varieties[]      name: plantain    }    ```    or-more-concisely = markdown`Or more concisely:`    example-eure-concise = ```eure    @ fruits[] {      name: apple      physical.color: red      physical.shape: round      varieties[].name: red delicious      varieties[].name: granny smith    }    @ fruits[] {      name: banana      varieties[].name: plantain    }    ```  }  @ code  '###': Code  text-types = ```markdownAs I said "plaintext" before, there are other text types in Eure. One is inline code and another is a code block. Both can have a language tag like `` json`{"a": 1}` `` for inline code. One interesting point is that `` plaintext`hello` `` is equivalent to `"hello"` in the data model.The language tag can be used for non-programming languages, too. If you write `` uuid`b5607686-fcb9-4f80-9040-3f0ba14f6b97` `` or `` datetime`2026-01-18T23:56:00Z` ``, your editor can validate the string content against the format without adding those in Eure's spec and data model.```}@ other-features {  '##': Things not in the first example.  @ tagged-unions  '###': Tagged unions  body = ```markdownEure natively supports tagged unions in both the data model and the schema. This keeps documents flat and intuitive to write.```  simple-example = ```eure  @ action  $variant: set-text  text: Hello, world!  ```  simple-note = ```markdown`$variant` selects a branch of a union.```  yaml-label = markdown`In YAML:`  think-yaml = ```yaml  # This is a pseudo visual novel script in YAML  actions:    - !set-text      text: Hello, world!    - !set-selections      title: "Choose one of the following:"      selections:        - text: Option 1        - text: Option 2    - !spawn-script script0    - !wait-seconds 1.0  ```  eure-label = markdown`In Eure:`  eure-equivalent = ```eure  // This is a pseudo visual novel script in Eure  @ actions[]  $variant: set-text  text: Hello, world!  @ actions[]  $variant: set-selections  title: "Choose one of the following:"  selections[].text: Option 1  selections[].text: Option 2  @ actions[]: script0  $variant: spawn-script  @ actions[]: 1.0  $variant: wait-seconds  seconds: 1.0  ```  @ extension  '###': Extension  extension-definition = ```markdown  In Eure, an ident prefixed with `$` is called an extension or extension namespace and can be bound to any valid Eure value without affecting the data model level.  For example:  ```  schema-reference = ```eure  $schema = "eure-schema.schema.eure"  /// TextMate Language Grammar Schema  $variant: record  /// Grammar display name  name = `text`  /// Unique scope name (e.g., "source.eure")  scopeName = `text`  /// Schema URL reference  "$schema" = `text`  "$schema".$optional = true  ```  textmate-grammar-schema = ```markdownThis snippet is from Eure Schema of TextMate grammar: <https://github.com/Hihaheho/eure/blob/dd9a7aa9292201d6ce24d6fbb191d9a705377257/assets/schemas/textmate-grammar.schema.eure>`$schema: /path/to/a/schema/file` is used to tell a language processor about the schema of this file. And in a Eure schema file, an optional record field is specified by `$optional = true`. In both cases, those are unambiguous from string keys prefixed with "$". If you need to assign a value to a string key "$schema", you must write it like `"$schema" = "https://json-schema.org/draft/2020-12/schema"`.```  planned-language-builtin-extension {    '####': Planned language built-in extension    body = ```markdown- `$precision`: bulk specify the precision of floats in the scope to let the serializer/deserializer suggest how to serialize/deserialize the float value.- `$license`: specify the license of the document or the scope like `$license: MIT OR Apache-2.0`.- `$local`: a well-known extension namespace for document-local metadata for users.```  }}@ data-model-and-interpretation {  '##': Data model & interpretation (from the spec)  body = ```markdown**Data model (JSON-compatible, but richer):**- Same core types as JSON: null, bool, number, string, array, map- Extra types: arbitrary-precision integers, tuples, language-tagged text, and extensions (metadata channel)- Holes: optionally labeled placeholders for incomplete documents without emitting schema errors (e.g., `!todo`, `!`)- When converting to JSON, tuples may become arrays and text language tags/extensions can be dropped, and holes make the conversion fail.**Interpretation (how a document is applied):**- A document is interpreted as a series of actions that navigate a tree and bind values- Evaluation is deterministic and top-to-bottom with a well-defined, intuitive set of actions- Each binding asserts the target is unbound, then binds a value- Sections are just scoped path prefixes; `@ items[]` appends to arraysSpec reference (interpretation): https://github.com/Hihaheho/eure/blob/v0.1.5/docs/spec/alpha.md#8-document-interpretation```}@ eure-schema {  '##': Eure Schema  body = ```markdownEure Schema is a schema format for Eure documents. It is itself a valid Eure document, just like JSON Schema is valid JSON. You can validate Eure Schema files with a meta-schema the same way you validate normal documents.Compared to JSON Schema, Eure Schema has native support for tagged unions, tuples, and other Eure-specific types. Eure Schema can be converted to/from JSON Schema (implementation exists but not yet integrated into CLI).For interop with Rust and other languages built around algebraic data types, Eure Schema tends to be more direct and intuitive. I'm also working on bidirectional conversion between Eure Schema and Rust type definitions.```  example-label = markdown`Example: schema corresponding to the visual-novel actions in the [tagged unions](#tagged-unions) section`  example = ```eure  /// Actions list  actions = [`$types.action`]  /// Action types that can be performed  $types.action {    $variant: union    variants.set-text.text = `text`    variants.set-selections {      title = `text`      selections = [`$types.selection`]    }    variants.spawn-script.script = `text`    variants.use-script.script = `text`    variants.wait-seconds.seconds = `float`  }  /// Selection type  $types.selection {    text = `text`  }  ```}@ whats-next {  '##': What's next in the BETA release?  body = ```markdown- [ ] (`serde-eure`) Serde support with encoding extensions into configured special string keys.- [ ] (`bevy-eure-assets`) An ecosystem crate for Bevy to load Eure assets. That's one I'm keen to have for my game project.- [ ] (`eure-ls`): "Format" action to format a Eure document from the editor.- [ ] (`eure-ls`): Editor hover support- [ ] (`eure-ls`): Editor completion support- [ ] (`eure-ls`): Programmatic document edits (like `cargo add` modifies Cargo.toml)- [ ] (`vscode`): "Preview JSON" action in VS Code ext```}@ want-to-do {  '##': Things I'd like to implement (help welcome)  body = ```markdown- [ ] Zed editor support.- [ ] Vim/Neovim support.- [ ] Publish Node.js package to npm with native builds.- [ ] Publish Python package to PyPI with native builds.```}@ spec-reference {  '##': Spec (alpha)  body = ```markdownReference: https://github.com/Hihaheho/eure/blob/v0.1.5/docs/spec/alpha.md```}@ alpha-notes {  '##': Alpha notes  body = ```markdown- Current release at the time of writing: v0.1.5- Stability: alpha quality; syntax and features may change without notice- Compatibility: breaking changes may occur between alpha versions- Known limitations / not yet implemented: some features are unimplemented (e.g. formatting)```}@ try-it {  '##': Try it  body1 = ```markdownTry it in the web playground:<https://eure.dev>Or install the CLI:```  bash-install = ```bash  # Install the CLI  cargo install eure-cli  ```  bash-convert = ```bash  # Convert Eure to JSON  echo 'greeting: Hello World!' | eure to-json -  ```  bash-from-formats = ```bash  # Convert from existing formats  eure from-json config.json > config.eure  eure from-toml config.toml > config.eure  # (coming soon: from-yaml, to-toml, to-yaml)  ```  body2 = markdown`Output:`  json-output = ```json  {"greeting":"Hello World!"}  ```  body3 = ```markdownEditor extensions (optional):- VS Code Marketplace: https://marketplace.visualstudio.com/items?itemName=hihaheho.eurels- Open VSX: https://open-vsx.org/extension/hihaheho/eurels```}@ needs-feedback {  '##': Needs feedback  c = ```markdown- Is the pronunciation of Eure (like "your") okay?- How does the symbol selection look? Especially `@`- How does the overall syntax look?- Does `$variant` work well as a union tag?- What tooling is essential to use Eure for your use cases?- Any other questions?Places for feedback are:- GitHub Discussion/ Issue on the repo- any SNS I can query with #eurelang tag- Hihaheho Studio DiscordI don't plan to do statistics for this, but I just want to know things I didn't know or consider in the design.```}