Rotini v1.4.1 has been released.
This version does contain more breaking API changes and a good bit of usage churn due to refining how rotini goes about some of its init/alloc/execution processes. I tried to keep many of the changes invisible, but there are changes that impact how users interact with rotini through its spec/conf files, the api surface used in a “main.go” entrypoint for building an executable binary, and rotini command handler files. When I saw the imported packages, symbol table, allocs, dispatch timing, and base rotini-powered binary size from the last release, I decided to re-focus on performance optimizations and again eat the cost of breaking the existing contract.
New
- Smaller binaries, faster start-up. Generated code now links only the runtime features its
spec declares. A CLI with no config files, stdin or plugins no longer carries the config codecs,
the JSON Schema compiler or
os/exec: a 13-command CLI went from 6.4 to 3.3 MB stripped on linux, and starts about 0.25 ms faster. Regenerate to get it. See what a program links. - Agent-ready CLIs. Declare
effectson commands and flags, give flags roles agents read (dry-run,confirm,machine-output,sortand more), and keep commands from agents withagent: false.rotini generatecan write tool definitions for MCP, OpenAI and Gemini, an Agent Skills page,llms.txt, and permission rules for agent harnesses. The new go-rotini/mcp module serves a Rotini CLI’s tools over MCP, from its own binary or withrotini-mcp serve. See agent-ready CLIs. - Checking for breaking changes.
rotini diff <old> [new]compares two contracts and reports what changed for your users, rule by rule. The old one can be a file, a git ref or a module version, so a CI step can fail a pull request that breaks a flag. Removals you planned withdeprecated_sinceandremoved_inshow as expected. See checking for breaking changes. - Config profiles and write-back.
profiles:selects a block of config from--profile, an environment variable or a default.rotini.SetConfigValue,UnsetConfigValueandConfigFilePathedit a user’s YAML, JSON, JSONC, dotenv or TOML file in place, checked against the spec, soconfig setis a few lines. Rotini can also write a JSON Schema for your users' config file, so their editor completes it. See profiles and writing config values. - Files and streams. Stdin can be streamed instead of read whole, with the
jsonlandbytesformats.inputfileandoutputfileinputs come withrotini.OpenInputandrotini.CreateOutput, and a failed write to stdout now fails the run. See files and streams. - Parsing. Reusable flag sets, flags that depend on another flag’s value, a directory flag
(
role: chdir, likegit -C), response files, partial passthrough, env and config fallbacks for arguments, several time layouts per input, and relative times. See sharing flags between commands and a directory flag. - Help and completion. Enum values with descriptions, aliases and deprecations; help topics;
stability: experimental|beta;--explain-inputs; the usage line as data withrtx.Usage(). Completion hides flags already set, lists required flags first, keeps your order, and gainshost,groupandcommandkinds, a Nushell script and a Carapace export. See what completion offers. - Testing. The
rotinitestpackage runs a command from a test with a typed inputs value, in its own environment and directory so tests can run in parallel, and decodes its structured output. See testing with typed inputs. - Bring a CLI over.
rotini importbuilds a spec, conf and handler stubs from a live Cobra, Kong or urfave/cli program, without touching its files, and reports what it couldn’t carry over. See rotini import.
Changed
- The default reporter writes infos and successes to stderr, so stdout carries only your program’s output.
- Completion keeps a completer’s order and an enum’s declared order. The
__completeprotocol ends with:32where it sent:0. - Usage lines put flags before arguments:
app sub [flags] <name>. - Stricter input checks.
existingfileandexistingdirvalues from the environment or a config file are now checked, list bounds count real elements, andtype: urlneeds a scheme. Runrotini validateafter upgrading. - A broken config file no longer breaks
--helpor--version.
Upgrading from v1.3
Bump github.com/go-rotini/rotini and the rotini tool to v1.4.1, raise version: in your spec
and conf to 1.4.0, and run rotini generate. Then:
- In
main.go, replacecmd.Programwithcmd.NewProgram().rotini generatepoints at an oldmain.gothat still uses it. To swap or wrap one command’s handler, pass your own handler set tocmd.NewProgramWith(handlers). WithOutputChecks()becomesWithOutputChecks(true).- Tests that read infos or successes from stdout need to read stderr, and tests pinned to the
__completeoutput need the new directives. - A help template you seeded with
template: trueneeds{{.Label}}on each flag row for the new alignment. Help now adds “(repeatable)” itself, so drop it from your summaries. - Run
rotini validate: a few specs and inputs v1.3 accepted are now errors, and it says which.
See upgrading for the general steps.