This is a draft version of the blog post.
Hi, I'm Ryo Hirayama from Hihaheho Studio, 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.dev It supports syntax highlighting, to-JSON conversion, schema verification, and real-time diagnostics.
Landing page / Web playground: https://eure.dev GitHub: https://github.com/Hihaheho/eure
TL;DR for TOML users (click to expand)
- It's arbitrarily nestable
- For array tables,
@ project.member[]instead of[[project.member]]
Table of Contents
Filling the gap between TOML and YAML
I'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.
Suggested use cases
- Mid-sized or large configuration files
- Data-driven test suite for a spec (Eure does have a massive test suite written in Eure)
- Manifest files for Kubernetes, CI/CD pipelines, etc., which tend to be complex and hard to maintain
- Generate complex JSON from Eure (Eure itself does this for a tmLanguage file)
- 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)
- Write a JSON Schema in a more fluent and readable way by converting from Eure Schema
First glance at the syntax:
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 noticed, this is what a GitHub Action workflow could look like in Eure.
Path
push.branches and jobs.hello_world are paths. A path is a sequence of keys separated by .. 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
There 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.
Bindings can have composite paths like push.branches =.
Section
@ 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.
Code
As 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.
Things not in the first example.
Variant
@ pull_request {
$variant: union
$optional = true
$variant-repr = "untagged"
/// Config variant (tried first in definition order)
variants.config {
branches = [`text`]
branches.$optional = true
paths = [`text`]
paths.$optional = true
paths-ignore = [`text`]
paths-ignore.$optional = true
types = [`text`]
types.$optional = true
}
variants.null = `null`
}
This is from the Eure Schema of a GitHub Actions workflow. $variant: union tells the Eure Schema deserializer this value is about defining a union type (union variant of the type union), and not another type like record. This schema defines a union which has two variants, config and null, and a document can specify a variant like:
pull_request = null
pull_request.$variant: null
Though it's verbose since no other variants accept the null value.
Extension
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 = "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
This 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 built-in extension
$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 & interpretation (from the spec)
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
- When converting to JSON, tuples may become arrays and text language tags/extensions can be dropped
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 arrays
Spec reference (interpretation): https://github.com/Hihaheho/eure/blob/v0.1.4/docs/spec/alpha.md#8-document-interpretation
Differences from TOML (high level):
- Arbitrary nesting with sections and block sections (no top-level table/array-table limitations)
- Richer value types (tuples, holes, tagged text, extensions)
- Text binding with
:for raw plaintext on a line - Paths are first-class (e.g.,
a.b[0].c, tuple index#0)
What's next in the BETA release?
- (
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 (likecargo addmodifies Cargo.toml) - (
vscode): "Preview JSON" action in VS Code ext
Things I want to do but need someone to help me.
- Zed editor support.
- Vim/Neovim support.
- Publish Node.js package to npm with native builds.
- Publish Python package to PyPI with native builds.
Spec (alpha)
Alpha notes
- Current release at the time of writing: v0.1.4
- 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
Web playground: https://eure.dev
Install CLI:
cargo install eure-cli
Convert Eure to JSON:
echo 'greeting: Hello World!' | eure to-json -
Output:
{"greeting":"Hello World!"}
Editor extensions (optional):
- VS Code Marketplace: https://marketplace.visualstudio.com/items?itemName=hihaheho.eurels
- Open VSX: https://open-vsx.org/extension/hihaheho/eurels
Needs feedback
- The pronunciation of Eure sounds like "your" is fine?
- The symbol selection for grammar looks good or bad? Especially for the
@ - Overall syntax looks good or bad?
- The $variant seems nice or bad for union tag?
- What tooling is essential to use Eure for your use cases?
- Any questions
Places for feedback are:
- GitHub Discussion/ Issue on the repo
- any SNS I can query with #eurelang tag
- Hihaheho Studio Discord
I don't plan to do statistics for this, but I just want to know things I didn't know or consider in the design.