CCML is a human-friendly configuration language that maps cleanly to JSON.
Project principles:
- Convenient for humans
- Compatible with JSON
- Clear to parsers
JSON compatibility is strict: every CCML document must map to one valid JSON value, and features that cannot map cleanly to JSON are out of scope for 1.0.
Use this section if you want to try CCML first. The design background starts at Why CCML?.
Create a small CCML document:
# comments are allowed
name: "Ada"
enabled: true
limits: {
retries: 3
timeout_ms: 1000
}
tags: ["alpha", "beta"]
It transcodes to one JSON value:
{"enabled":true,"limits":{"retries":3,"timeout_ms":1000},"name":"Ada","tags":["alpha","beta"]}Install the published CLI from crates.io:
cargo install ccml-cli
'answer: 42' | ccml-cliFrom a source checkout:
Set-Location core\rust
'answer: 42' | cargo run --offline -p ccml-cliOutput:
{
"answer": 42
}Run the shared conformance vectors from source:
Set-Location core\rust
cargo run --offline -p ccml-cli -- conformance ..\..\tests\conformanceUse the published Rust crate from crates.io:
[dependencies]
ccml-core = "1.0.0"Inside this repository's Rust workspace:
[dependencies]
ccml-core = { path = "core/rust/crates/ccml-core" }Example:
use ccml_core::{to_json, ToJsonOptions};
fn main() -> Result<(), ccml_core::CcmlError> {
let input = "name: \"Ada\"\nenabled: true";
let json = to_json(input, &ToJsonOptions { pretty: false })?;
assert_eq!(json, "{\"enabled\":true,\"name\":\"Ada\"}");
Ok(())
}Install the published Python package from PyPI:
pip install ccml-py
python -c "from ccml_py import to_json; print(to_json('answer: 42'))"From a source checkout:
Set-Location core\rust
cargo build --offline -p ccml-ffi
Set-Location ..\..\bindings\python
$env:UV_CACHE_DIR = ".uv-cache"
uv run python -c "from ccml_py import to_json; print(to_json('answer: 42'))"ccml-py loads the bundled prebuilt ccml-ffi library when the installed wheel includes one for your platform. If you are using an unsupported platform or a custom native build, set CCML_FFI_LIB to the built library path.
Install the published Node package from npm:
npm install ccml-node
node --input-type=module -e "const { createCcmlFfi } = await import('ccml-node'); const ffi = await createCcmlFfi(); console.log(ffi.toJson('answer: 42'));"From a source checkout:
Set-Location core\rust
cargo build --offline -p ccml-ffi
Set-Location ..\..\bindings\node
npm install
node --input-type=module -e "const { createCcmlFfi } = await import('./src/index.js'); const ffi = await createCcmlFfi(); console.log(ffi.toJson('answer: 42'));"ccml-node loads the bundled prebuilt ccml-ffi library when the installed package includes one for your platform. If you are using an unsupported platform or a custom native build, set CCML_FFI_LIB to the built library path.
The C ABI is the stable boundary used by Python and Node bindings. See spec/interfaces/ffi-phase1-interface.md for function signatures, status codes, memory ownership, and error payload rules.
CCML exists for configuration files that should be easier to write than JSON without becoming a separate data model.
Its design is governed by 3C, also documented in CONTRIBUTING.md and PROJECT_CHARTER.md:
- Convenient for humans: less punctuation, comments, and readable key/value files.
- Compatible with JSON: every valid CCML document maps to one valid JSON value.
- Clear to parsers: syntax choices must stay deterministic and easy to diagnose.
The practical advantages are:
- You can write common config shapes with less visual noise than JSON.
- You can keep JSON as the interchange, storage, and tooling boundary.
- You can reject ambiguous convenience features before they become parser edge cases.
- You can use one semantic core across CLI, FFI, Python, Node, and WASM bindings.
See spec/decisions/0002-open-decisions-3c.md for examples of how syntax decisions are evaluated against 3C.
CCML keeps the JSON data model, but changes the authoring syntax for configuration use.
| Dimension | JSON | CCML |
|---|---|---|
| Primary role | Universal data interchange format | Human-authored configuration syntax that transcodes to JSON |
| Data model | Objects, arrays, strings, numbers, booleans, null | Same JSON data model only |
| Top-level object config | Requires {} |
Allows implicit top-level object for key/value documents |
| Comments | Not allowed | # line comments are allowed |
| Separators | Commas required | Whitespace is the default separator; commas remain available when the author wants explicit intent or visual grouping |
| Keys | Quoted strings required | Bare keys allowed when parser-safe; quoted keys remain available |
| Compatibility boundary | Already JSON | Must transcode to valid JSON |
| Parser goal | Standardized strict format | Convenient syntax with explicit diagnostics and JSON-compatible output |
The detailed syntax contract is in spec/ccml-1.0-draft.md, and shared expected behavior is captured in tests/conformance.
This comparison is about design goals, not a complete feature matrix.
| Language | Main orientation | Difference from CCML |
|---|---|---|
| HJSON | Human-friendly JSON-like documents | HJSON looks syntactically similar, but it is primarily a relaxed authoring format. CCML is stricter about the 3C boundary: convenience is allowed only when the result remains JSON-compatible and parser-clear. |
| YAML | Broad human-readable serialization | YAML is feature-rich and can encode many shapes and conventions beyond JSON-style config. CCML intentionally avoids a broad type system and keeps JSON as the semantic boundary. |
| TOML | Typed application configuration | TOML has its own table-oriented structure and type conventions. CCML keeps object/array structure close to JSON so transcoding remains direct. |
| JSON5 | JavaScript-friendly JSON extension | JSON5 relaxes JSON syntax using JavaScript-like affordances. CCML instead targets config files with parser clarity and a strict JSON transcode contract. |
| INI | Simple section/key configuration | INI is small but underspecified across implementations. CCML aims for machine-readable conformance and nested JSON-compatible data. |
The closest-looking alternative is HJSON. The important distinction is intent: CCML is not "JSON with every convenient relaxation." It is a 3C-constrained configuration language where each syntax feature must justify itself across human convenience, JSON compatibility, and parser clarity. The current release scope and exclusions are tracked in spec/ccml-1.0-draft.md and docs/release-go-no-go-week5.md.
This repository is on the v1.0.0 release track for the Rust-core rebuild.
Rust, Python, and Node packages have been published at 1.0.0. Tagging and GitHub Release publication remain as the final release-record steps.
CCML keeps the JSON data model while adding a smaller config-oriented syntax:
# comments are allowed
name: "example"
enabled: true
limits: {
retries: 3
timeout_ms: 1000
}
tags: ["alpha", "beta"]
Transcoded JSON:
{"enabled":true,"limits":{"retries":3,"timeout_ms":1000},"name":"example","tags":["alpha","beta"]}- Top-level object braces are optional for key/value documents.
- Comments start with
#and continue to end of line. - Whitespace is the default separator; commas are optional when the author wants explicit intent or visual grouping.
- Bare keys match
[A-Za-z0-9_.-]+, except punctuation-only keys such as.or--. - Quoted keys are required for spaces or reserved separators.
- Duplicate object keys use keep-last semantics and emit warning
CCML2001. - Parser diagnostics include
code,message,line, andcolumn.
See spec/ccml-1.0-draft.md for the draft specification.
core/rust/ Rust workspace
crates/ccml-core/ parser, AST, diagnostics, JSON transcode
crates/ccml-cli/ CLI and conformance runner
crates/ccml-ffi/ C ABI for bindings
crates/ccml-wasm/ WASM bridge
bindings/python/ Python thin adapter over ccml-ffi
bindings/node/ Node thin adapter over ccml-ffi
tests/conformance/ shared machine-readable conformance vectors
tests/bindings/ cross-binding parity fixtures
tests/wasm/ WASM runtime smoke
docs/ architecture, plans, release-readiness notes
spec/ CCML language spec, interface contracts, and decisions
Architecture overview: docs/architecture.md. FFI interface contract: spec/interfaces/ffi-phase1-interface.md.
Build the CLI:
Set-Location core\rust
cargo build --offline -p ccml-cliTranscode CCML from stdin:
'a: 1' | cargo run --offline -p ccml-cliRun conformance vectors:
Set-Location core\rust
cargo run --offline -p ccml-cli -- conformance ..\..\tests\conformanceWindows PowerShell baseline:
Set-Location core\rust
cargo test --offline -p ccml-core
cargo test --offline -p ccml-ffi
cargo run --offline -p ccml-cli -- conformance ..\..\tests\conformance
Set-Location ..\..
powershell -ExecutionPolicy Bypass -File tests\bindings\run-parity-smoke.ps1
node bindings\node\tests\day1-regression.mjs
powershell -ExecutionPolicy Bypass -File scripts\ci\check-version-consistency.ps1Linux/macOS bash baseline:
cd core/rust
cargo test --offline -p ccml-core
cargo test --offline -p ccml-ffi
cargo run --offline -p ccml-cli -- conformance ../../tests/conformance
cd ../..
bash scripts/ci/check-version-consistency.sh
bash scripts/wasm/build-and-run-smoke.shCross-platform details: docs/cross-platform-validation-playbook.md.
Python:
- Build
ccml-ffifirst when needed. - Run smoke from
bindings/pythonwith repo-local uv cache:
Set-Location bindings\python
$env:UV_CACHE_DIR = ".uv-cache"
uv run python tests\smoke.pyNode:
- Install dependencies in
bindings/nodewhen needed. - Run parity/regression smoke:
node bindings\node\tests\day2-smoke.mjs
node bindings\node\tests\day1-regression.mjsRelease documents:
- docs/pre-release-checklist-week5.md
- docs/release-go-no-go-week5.md
- docs/release-notes-v1.0.0-draft.md
- docs/release-runbook-v1.0.0.md
Current release state: Rust/Python/Node package publishing is complete for v1.0.0; tag and GitHub Release publication are still pending.
Contributions must preserve the project principles in CONTRIBUTING.md. JSON compatibility is non-negotiable.