❯ rotini --documentation█

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 effects on commands and flags, give flags roles agents read (dry-run, confirm, machine-output, sort and more), and keep commands from agents with agent: false. rotini generate can 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 with rotini-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 with deprecated_since and removed_in show 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, UnsetConfigValue and ConfigFilePath edit a user’s YAML, JSON, JSONC, dotenv or TOML file in place, checked against the spec, so config set is 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 jsonl and bytes formats. inputfile and outputfile inputs come with rotini.OpenInput and rotini.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, like git -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 with rtx.Usage(). Completion hides flags already set, lists required flags first, keeps your order, and gains host, group and command kinds, a Nushell script and a Carapace export. See what completion offers.
  • Testing. The rotinitest package 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 import builds 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 __complete protocol ends with :32 where it sent :0.
  • Usage lines put flags before arguments: app sub [flags] <name>.
  • Stricter input checks. existingfile and existingdir values from the environment or a config file are now checked, list bounds count real elements, and type: url needs a scheme. Run rotini validate after upgrading.
  • A broken config file no longer breaks --help or --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:

  1. In main.go, replace cmd.Program with cmd.NewProgram(). rotini generate points at an old main.go that still uses it. To swap or wrap one command’s handler, pass your own handler set to cmd.NewProgramWith(handlers).
  2. WithOutputChecks() becomes WithOutputChecks(true).
  3. Tests that read infos or successes from stdout need to read stderr, and tests pinned to the __complete output need the new directives.
  4. A help template you seeded with template: true needs {{.Label}} on each flag row for the new alignment. Help now adds “(repeatable)” itself, so drop it from your summaries.
  5. Run rotini validate: a few specs and inputs v1.3 accepted are now errors, and it says which.

See upgrading for the general steps.