Skip to content

Repository files navigation

@voxgig/model

A framework for universal application modeling: describe a system once as a single declarative model, then generate every downstream artifact — code, configuration, documentation, infrastructure — from that one source of truth.

The core tool unifies .aontu source (using CUE-style unification, via aontu) into one canonical JSON model, then hands that model to your generators ("actions"). It can build once or watch and rebuild on change.

Status: prototype. The concepts are stable; specific APIs and conventions may still change. Inspired by CUE.

Install

The TypeScript package (npm):

npm install @voxgig/model pino

pino is a peer dependency (logging). Requires Node.js — CI runs Node 24; Node 20.19+ generally works.

The Go module:

go get github.com/voxgig/model/go

Both implementations live in this repository — ts/ (TypeScript, canonical) and go/ (Go, kept in parity). See go/README.md for Go usage. TypeScript is canonical: change it first, with a test, then mirror the change in Go. Behaviour that a source compiles to (aontu in, model.json bytes out) is a row in the shared test/spec/*.tsv fixtures, which both suites run; an error case, or a value only a producer can introduce, is a mirrored per-language test instead.

Quick start

# 1. a model
mkdir -p model && cat > model/model.aontu <<'EOF'
service: name: 'orders'
service: port: *8080 | integer
EOF

# 2. build it -> writes model/model.json
npx voxgig-model model/model.aontu

# 3. or watch and rebuild on change
npx voxgig-model --watch model/model.aontu

model/model.json:

{ "service": { "name": "orders", "port": 8080 } }

Use it from code instead of the CLI:

const { Model } = require('@voxgig/model')

const model = new Model({ path: 'model/model.aontu', base: 'model' })
const result = await model.run()
if (!result.ok) throw new Error(result.errs.join('; '))

What it does

  • Unifies .aontu source — with types, defaults, references, wildcards, and imports — into a single validated JSON model.
  • Generates artifacts from that model through actions: small JS modules you declare in config and that receive the unified model.
  • Watches source and config files and rebuilds incrementally, tracking imports as dependencies.
  • Previews safely with --dryrun (writes redirected to an in-memory filesystem), and can build against any fs implementation.

Documentation

If you want to… Read
Learn by building a model step by step Tutorial
Accomplish a specific task How-to guides
Look up a flag, type, config key, or language construct Reference
Understand how and why it works Explanation

Working on this repository? From the root, make build and make test drive both languages. The TypeScript build output in ts/dist/ is committed, so rebuild it with any source change, and the documentation follows the style guide.

A fuller example

A model that generates an environment file from its services:

my-project/
├─ model/
│  ├─ model.aontu
│  └─ .model-config/model-config.aontu
└─ build/envFile.js
# model/model.aontu
shape: service: { name?: string, port: *8080 | integer }
service: orders: $.shape.service & { name: 'orders' }
service: web:    $.shape.service & { name: 'web', port: 443 }
# model/.model-config/model-config.aontu
sys: model: action: { envFile: load: 'build/envFile' }
// build/envFile.js
const Path = require('node:path')
module.exports = async function envFile(model, build) {
  const root = Path.resolve(build.path, '..', '..')
  const lines = Object.entries(model.service)
    .map(([n, s]) => `PORT_${n.toUpperCase()}=${s.port}`)
  build.fs.writeFileSync(Path.resolve(root, 'services.env'), lines.join('\n') + '\n')
  return { ok: true }
}
npx voxgig-model model/model.aontu   # writes model/model.json and services.env

See the tutorial for the same example built up from scratch.

License

MIT © Voxgig Ltd. See LICENSE.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages