Built by the Nano Collective, a community collective building AI tooling not for profit, but for the community.
This release is the smallest in a while and the one most people will feel. Up to 1.5.x, every Nanotune command crashed when stdin was not a TTY. That included commands that never needed a keypress, like status. A 40-line React reconciler stack trace, exit code 1, no output. v1.6.0 fixes the underlying assumption and makes every command usable from CI, pipes, Docker (without -t), and shell scripts.
Pipe, redirect, and CI without a terminal
Ink enables raw mode as soon as a component calls useInput. Nanotune was calling useInput for keyboard hints across the whole TUI, which meant raw mode was turned on for every command, including ones that did not need it. Piping nanotune status into tee run.log, or running it inside a CI step, has always produced something like:
ERROR Raw mode is not supported on the target process.
The fix is in src/lib/tty.ts. Every command now detects whether a keyboard is available and behaves accordingly.
Render-and-exit commands
status, data validate, train, export, benchmark, and judge test render their output and exit on their own when there is no TTY, instead of parking on a "press any key" frame forever.
Two important consequences:
- Non-zero exit codes on failure. A failed run now sets exit code 1, so
nanotune train && nanotune exportchains correctly and CI can gate onnanotune data validate. - Keyboard hints are suppressed. Captured output is clean.
A pipeline like this now works end to end:
nanotune data validate && nanotune train && nanotune export
Interactive-only commands
init, data add, data list, chat, and judge configure genuinely need a keyboard. They now print a single clear sentence and exit 1, instead of crashing:
`nanotune chat` needs an interactive terminal.
stdin is not a TTY, so it cannot read keypresses. Run it directly in a
terminal rather than through a pipe, a CI job, or with stdin redirected.
Pairing the diagnostic with a non-zero exit code means CI jobs catch the misuse rather than carrying on.
nanotune data import --yes
New -y, --yes flag skips the confirmation prompt, making data import usable from scripts and CI:
nanotune data import examples.jsonl --yes
Without a TTY and without --yes, the command explains that the flag is required rather than failing obscurely.
Fixes
- Platform check now fires up front. The Apple Silicon assertion only ran inside
installLlamaCpp, so users on Linux or Intel Macs hit a confusingpip install mlx-lmresolver error duringtraininstead of the clear message that already existed.trainandexportnow assert supported hardware before doing any work. Extracted tosrc/lib/platform.ts. judge.jsonis written with0600permissions. The file can hold a literal API key for users who do not use the${ENV_VAR}form. Existing configs written by earlier versions are tightened on next save.
Documentation
nanotune chatis documented. The 1.5.0 headline feature shipped with no docs page. Addeddocs/commands/chat.mdcovering slash commands, all flags, per-turn stats, and chat-template handling, and listed it in the commands index.- Quick start covers
chatas step 5, between export and benchmark. data import --yesdocumented in the data command reference.- Fixed the benchmark preset table, where the max-tokens column read 50/100/150/200 instead of the actual 128/256/512/1024.
Internals
- Coverage now reports an honest number. The
c8excludepointed atsource/app/App.tsx, a path that has never existed, and spec files were counted as covered source, trivially 100%. Excluding them moves the reported figure from 88.62% to 78.97% with no change in actual test coverage. The point of the bump is honesty, not aesthetics. - New
src/lib/tty.ts(raw-mode detection) andsrc/lib/platform.ts(hardware assertion), both pure and unit-tested. - New
useKeyInput,useAutoExit, andExitHintinsrc/components/.useKeyInputis now the only sanctioned way to read keys. Calling Ink'suseInputdirectly reintroduces the crash. - 239 tests total (+16) covering raw-mode detection, platform assertions, and judge config file permissions.
Toolchain
- Dependency updates via Dependabot:
ai7.0.15,@ai-sdk/anthropic4.0.8,@ai-sdk/google4.0.8,ink7.1.0,ava8.0.1,c811.0.0,knip6.24.0,tsx4.23.0,typescript6.0.3,@types/node26.x,@biomejs/biome2.5.1. - Repaired a broken
pnpm-lock.yamland several latent toolchain breaks in CI. - Resolved Biome config deprecations and Semgrep findings.
Install
npm install -g @nanocollective/nanotune
Full source, issues, and the changelog are on the project repo at github.com/Nano-Collective/nanotune. If something breaks, open an issue with the command, the output, and your OS, and we will sort it out.