Installation

moonctl is one MoonBit package. Use it as a library and the whole generator is a function call; build the mctl command when you want the spec tools and the project scaffolds too.

Requirements #

A MoonBit toolchain — moon — and git. The library builds for all four targets; the command is a native binary, because it reads and writes files. Check what you have:

terminal
$ moon version
moon 0.1.20261023 (3778465 2026-10-23)

As a library #

Add the module to a MoonBit project:

terminal
$ moon add moonbitstack/moonctl

Import the package where you generate from:

moon.pkg
import {
  "moonbitstack/moonctl",
}

Parsing a spec gives a tree; generating reads that tree and returns a string:

main.mbt
let spec = @moonctl.parse(source)
let code = @moonctl.generate(spec)       // a moonapi scaffold, as text
let tree = @moonctl.generate_tree(spec)  // the layered project, file by file

There is no IO in the library, so it does not force a target on the project that imports it. A server, a build script, a browser page and a test can all call it.

The mctl command #

Build it from the repository:

terminal
$ git clone https://github.com/moonbitstack/moonctl
$ cd moonctl
$ moon build --target native --release

The binary lands in _build/native/release/build/cmd/mctl/ as mctl — mctl.exe on Windows. Put that directory on your PATH:

terminal
# bash, zsh
$ export PATH="$PWD/_build/native/release/build/cmd/mctl:$PATH"

# PowerShell
> $env:PATH = "$PWD\_build\native\release\build\cmd\mctl;$env:PATH"

Check it #

mctl env prints the configuration it would use, and where each value came from:

terminal
$ mctl env
  config                  ~/.mctl/config
  home                    (bundled template library)
  remote                  https://github.com/moonbitstack/templates
  branch                  main
  style                   gozero
  templates               (none pinned)
  working dir             /home/you/shop

Then ask it for the commands it knows:

terminal
$ mctl help
usage:
  mctl gen <api|rpc|model|crud|doc|gql|agent> <file> generate a project tree, models or a document from a spec
  mctl api <format|validate|doc|ts|dart|kt|java> <file.api> work on a .api spec itself: format it, check it, document it, or generate a client

Shell completion #

mctl completion writes a script for bash, zsh, fish or powershell. The command table it completes from is the same one that prints mctl help, so the two cannot disagree.

terminal
# bash
$ mctl completion bash > ~/.local/share/bash-completion/completions/mctl

# zsh, for the current shell
$ source <(mctl completion zsh)

# fish
$ mctl completion fish > ~/.config/fish/completions/mctl.fish

Configuration #

Settings live in one small file — ~/.mctl/config, or %USERPROFILE%\.mctl\config on Windows, or wherever $MOONCTL_CONFIG points. Read and write it with the command rather than an editor:

terminal
$ mctl config list
version = 2
home = 
remote = https://github.com/moonbitstack/templates
branch = main
style = gozero

$ mctl config set style go_zero
mctl: style = go_zero in ~/.mctl/config

$ mctl config get style
go_zero

The keys:

KeyWhat it setsDefault
homea template library on diskempty — the bundled catalogue
remotea git remote holding a template libraryhttps://github.com/moonbitstack/templates
branchthe branch of remotemain
stylehow generated names are spelledgozero
templatestemplates pinned to a versionnone
Not honoured yet

home, remote and branch are recorded, reported by mctl env, and passed through the configuration — but generation still reads the bundled template catalogue. Pinning a home directory today changes what mctl template list reports, not what it writes.

Next #

Write a spec and generate a project from it. The whole loop takes three commands.