Skip to content

v0.14.0 - Colorful CLI Output and a Documentation Overhaul (2026-07-06)

What Changed?

This release replaces fnb's plain-text CLI output with rich-powered color and tables, closes out a batch of maintainability fixes found during a full codebase review, and finishes migrating the documentation site from MkDocs to Zensical with a reorganized set of guides for users, contributors, and maintainers.


What's New

Main Feature: Colored, Table-Based CLI Output

What it does: Every user-facing message in fetch, backup, sync, status, and init is now rendered through rich.Console instead of plain print()/typer.echo(). Errors are bold red, successes are bold green, warnings and dry-run notices are yellow, and progress messages are cyan — on top of the emoji fnb already used. fnb status now renders fetch and backup tasks as tables (Label, Source, Target, and a Directory column showing whether each local target exists) instead of indented bullet lines.

Behavior change worth knowing about: error messages (❌) now go to stderr instead of stdout, following Unix convention. If you pipe or capture only stdout from fnb in a script, error messages that used to appear there will now show up on stderr instead — fnb fetch logs 2>&1 captures both as before, but fnb fetch logs 2>/dev/null now correctly silences only the errors.

How to use it: No new flags — this applies automatically. Color is disabled automatically when output isn't a terminal (pipes, redirects, CI logs), so scripting behavior is unaffected beyond the stdout/stderr split above.

fnb status
# renders two tables instead of a bullet list

fnb fetch missing-label
# ❌ Label not found: missing-label   (now on stderr)

Installation

Quick Start

# Get the release
git checkout v0.14.0

# Setup
uv sync --all-groups

# Run CLI
uv run fnb --help

What's Different from the Last Version?

✅ Added

  • Colored, table-based CLI output — see above
  • Documentation reorganization: new Installation Guide (For Users / For Developers), Contributor Guide, and Maintainer Guide replacing the old single installation.md and development/contributing.md
  • Documentation site now builds with Zensical instead of MkDocs, on both ReadTheDocs and a new GitHub Pages workflow

🔧 Changed

  • verify_directory()'s remote-path detection no longer misidentifies Windows drive letters (e.g. C:\Users) as remote rsync specs; the same fix applies to fnb status's directory check
  • Local paths starting with ~ (e.g. ~/backup) are now expanded to the home directory in fnb.toml, matching how $HOME-style variables already worked. Remote paths keep their ~ untouched for the remote shell to expand
  • generator.run() no longer re-validates an already-validated ConfigKind, and reports failures by returning False instead of calling sys.exit() directly — fnb init error handling now goes entirely through Typer's exit mechanism
  • Test suite reduced from 153 to 121 tests, prioritizing tests that protect real behavior over raw coverage numbers: removed tests that only exercised test fixtures/mocks themselves, tests of dead code, and tests that were skipped since introduction and never ran
  • pyproject.toml's ruff line length is now 100 (previously 88), reformatted accordingly
  • CI dependency installs switched from optional-dependencies extras to dependency-groups, cutting what each job installs

🐛 Fixed

  • logger.get_logger() no longer calls logger.bind(name=...), which had no effect on the {name} shown in log output (loguru resolves that automatically from the call site) and only added noise
  • Several docstring examples that showed stale example output (e.g. fetcher.run()'s docstring claimed stdout included the full source/target path, when only the label is actually printed there)
  • env.py now documents the host-normalization collision where my-server.com and my.server.com resolve to the same environment variable name
  • .env.plain generated by fnb init env now correctly documents the FNB_PASSWORD_* prefix fnb actually reads (previous versions of the docs referenced an unrelated prefix)

Is It Safe to Upgrade?

Backward Compatible: Yes, with one behavior change worth checking.

  • Configuration file format (fnb.toml) and CLI arguments are unchanged
  • If your scripts or automation only capture fnb's stdout (e.g. fnb fetch logs > log.txt), note that error messages moved to stderr — check 2>&1 usage if you were relying on errors appearing in redirected stdout
  • If your fnb.toml has local paths starting with ~, they'll now expand to your home directory correctly instead of being treated as a literal ./~/... path — this is a fix, but double-check any config that depended on the old (broken) behavior

Tests Passed

  • ✅ 126 unit and integration tests passed
  • ✅ 89% code coverage
  • ✅ All pre-commit hooks pass (mypy, ruff, trailing whitespace, etc.)
  • ✅ Manual verification of colored output (FORCE_COLOR=1) and stderr-only error routing

Release Details

  • Date: 2026-07-06
  • Version: v0.14.0
  • Commits: 23 commits since v0.13.0, spanning documentation migration (Zensical), maintainability fixes (issue #52), a test suite quality pass, and the rich.Console CLI output work
  • 6c2c13b: feat: replace print/typer.echo with rich.Console, add status table
  • d791bfc: feat: add color to CLI output, not just emoji
  • ae291fd: refactor: address maintainability issues from issue #52
  • a85053c: test: remove tests that don't protect real behavior, fix weak assertions
  • f71f1e2 / 9ce9f3c / 3886045: docs(zensical): migrate site settings, ReadTheDocs, and GitHub Pages build from MkDocs
  • bd1cea0 / 510ff41 / 1adf1c6: docs: add Maintainer Guide, Contributor Guide, and the For Users/For Developers Installation Guide

Next Steps

  • Harden the pexpect-based SSH path further: list-based command execution instead of string concatenation, and handling for the SSH host-key confirmation prompt on first connection (#51)