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 .jsonic 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.
The TypeScript package (npm):
npm install @voxgig/model pinopino 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/goBoth implementations live in this repository — ts/ (TypeScript, canonical)
and go/ (Go, kept in parity). See go/README.md for Go usage
and AGENTS.md for working on the repo.
# 1. a model
mkdir -p model && cat > model/model.jsonic <<'EOF'
service: name: 'orders'
service: port: *8080 | integer
EOF
# 2. build it -> writes model/model.json
npx voxgig-model model/model.jsonic
# 3. or watch and rebuild on change
npx voxgig-model --watch model/model.jsonicmodel/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.jsonic', base: 'model' })
const result = await model.run()
if (!result.ok) throw new Error(result.errs.join('; '))- Unifies
.jsonicsource — 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 anyfsimplementation.
| 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 (including with an AI coding agent)? See AGENTS.md.
A model that generates an environment file from its services:
my-project/
├─ model/
│ ├─ model.jsonic
│ └─ .model-config/model-config.jsonic
└─ build/envFile.js
# model/model.jsonic
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.jsonic
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.jsonic # writes model/model.json and services.envSee the tutorial for the same example built up from scratch.
MIT © Voxgig Ltd. See LICENSE.