Changelog¶
All notable changes to wealthbox-cli are documented here. The format follows
Keep a Changelog, and this project
adheres to Semantic Versioning.
[2.4.1] - 2026-06-12¶
Patch release fixing a startup crash in 2.4.0. The cli/_factory.py module
(introduced in the 2.4.0 refactor) imported click at module level to
annotate a TyperGroup subclass, but click is only referenced in type
annotations. On installs where typer (>=0.26) does not pull in click as a
transitive dependency, wbox crashed on launch with
ModuleNotFoundError: No module named 'click' — the same failure class fixed
for skill_ref_gen in 2.3.1. This was not caught by CI because the test
environment always has click present via the dev dependencies.
Fixed¶
wboxstartup crash (ModuleNotFoundError: click) on clean installs that lackclick. Theimport clickincli/_factory.pyis now guarded byTYPE_CHECKING(it is only used in annotations, which are not evaluated at runtime underfrom __future__ import annotations).
Internal¶
- CI gains a
smokejob that installs the built wheel in isolation without dev dependencies and runswbox --version, so a missing-runtime-dependency startup crash can no longer reach PyPI. Thepublishjob now depends on it.
[2.4.0] - 2026-06-12¶
The notable user-facing change in this release is differentiated CLI exit
codes — scripts that branch on a specific non-zero code should read the note
below. Beyond that, 2.4.0 is largely an internal hardening release: src/ is
now mypy --strict clean and gated in CI, the test matrix gained a Windows leg
and a coverage floor, and the CLI command layer was refactored onto a shared
resource-command factory. Command syntax, options, help text, and output are
unchanged.
Changed¶
- Differentiated CLI exit codes (behavior change). Previously every error
exited with code
1.wboxnow distinguishes failure classes: validation / user errors and non-auth4xxresponses (e.g.404,422) still exit1, authentication errors (401/403) now exit2, and server errors (5xx) now exit3. Scripts that branched on a specific non-zero code for auth or server failures must be updated. (Click usage errors — unknown flags, missing arguments — continue to exit2as before; that overlap is pre-existing.)
Added¶
WBOX_DEBUGenvironment variable: set it to any non-empty value (e.g.WBOX_DEBUG=1) to print the full Python traceback to stderr alongside the friendly one-line error message. The mapped exit code is unchanged, so it is safe to enable in scripts.- Documented the existing
WBOX_BRIEF/--briefoutput mode (strips*_htmlduplicate fields to cut response size) in the README and CLI reference.
Security¶
- Token config file (
config.json) and the rate-limit state file are now written with0600permissions on POSIX so other local users cannot read a stored token. - Malformed
Retry-Afterresponse header values are truncated to 100 characters before being logged, bounding a hostile/oversized header.
Internal¶
- Typing:
src/is nowmypy --strictclean (zero errors, zerotype: ignore). Client mixins share a typed request protocol andfetch_all_pagesreturns a typed pagination envelope. A newtypecheckCI job runsmypy src/and gates publishing. - CI: added a
windows-latesttest leg (Python 3.12), a coverage floor (--cov-fail-under=91on the Ubuntu leg), a publish-time check that the top CHANGELOG version matchespyproject.toml, a weekly Dependabot config, and a.pre-commit-config.yaml(ruff, mypy, skill-ref drift). - Refactor:
cli/_util.pywas split into_client,_format,_resolve, and_factorymodules (with_utilkept as a re-export shim). Thenotes,projects,tasks,events,opportunities, andworkflowscommand groups now generate their commands from a shared resource-command factory;contactsremains hand-written. No change to the CLI surface. - Tests: added coverage for delete commands, project/workflow updates,
contacts list filters, HTTP base-client edge cases (missing/malformed
Retry-After,5xx, missing collection key), exit codes, and an update-model contract meta-test (every*UpdateInputrejects an empty payload).
[2.3.1] - 2026-06-01¶
Patch release fixing a startup crash introduced in 2.3.0. wbox crashed on
launch in clean environments because skill_ref_gen.py imported click at
module level — and typer 0.26+ dropped click as a dependency, so it was
no longer guaranteed to be present. The fix defers the import inside the
hidden regen-skill-refs dev command so normal CLI invocations never touch
it. CI also gains skip_existing on the PyPI publish step to survive
re-pushed tags without a spurious 400 error.
Fixed¶
wboxstartup crash (ModuleNotFoundError: click) in environments whereclickis not installed. Theskill_ref_genimport is now deferred to the body of the hiddenregen-skill-refscommand, which is only ever invoked during development.- PyPI publish job now uses
skip_existing: trueso re-pushing a tag (e.g. to re-run a failed release workflow) does not fail with a 400 from PyPI when the wheel was already uploaded on the first push.
[2.3.0] - 2026-06-01¶
Feature release. Adds writable contact-role support (--advisor-role),
fixing a long-standing gap where advisor assignments could not be set through
the CLI at all — even the --more-fields / --json escape hatches rejected
the payload because ContactRoleAssignment modeled the wrong write shape.
Also improves the Windows bootstrap installer (idempotent re-runs,
-SkipSkills opt-out, token re-use) and clarifies install/upgrade
documentation for uv tool and pipx users.
Added¶
--advisor-role ROLE:USERflag oncontacts add person|household|org|trustandcontacts update. Resolves role names and user substrings against the workspace category list so human-readable values like"Associate Advisor:Jane Smith"are accepted (#94).install.ps1gains a-SkipSkillsswitch for CI and non-agent installs that don't need the bundled agent skill.
Fixed¶
ContactRoleAssignmentnow uses{id, value}(the Wealthbox write shape) instead of{id, type}, unblocking all contact-role write paths including--more-fields(#94).install.ps1re-runs are now idempotent: if the skill directory already exists the installer runswbox skills upgradeinstead of erroring.install.ps1no longer prompts for a token when one is already stored in%APPDATA%\wbox\config.jsonorWEALTHBOX_TOKEN.
Changed¶
- README and
docs/getting-started.mdnow include a per-install-method upgrading table and clarify thatwbox self upgradeis for bundle installs only;uv tool upgrade/pipx upgradeare the correct paths for managed installs.
[2.2.1] - 2026-05-13¶
Bug-fix release. wbox self upgrade was silently no-op'ing for users who
installed wbox via uv tool install or pipx: it computed the install root
from sys.executable (the venv's python.exe) and tried to swap the
console-script shim there, but ~/.local/bin/wbox.exe (or pipx's equivalent)
is a separate copy uv/pipx made — replacing the venv-side shim never changed
what PATH resolved.
Fixed¶
wbox self upgradenow detects the install kind (bundle/uv-tool/pipx/pip) up front. Non-bundle installs exit1with the correct follow-up command (uv tool upgrade wealthbox-cli,pipx upgrade wealthbox-cli, orpip install --upgrade wealthbox-cli) instead of scheduling a swap that would never take effect onPATH.
[2.2.0] - 2026-05-13¶
Small feature + correctness release. Disambiguates the two IDs returned by
wbox me, fixes a silent truncation in wbox users list on large firms, and
clears Node 20 deprecation warnings from CI ahead of GitHub's June 2026 cutoff.
Added¶
wbox me user-id— printscurrent_user.id(the workspace user ID accepted by--assigned-to) as a bare integer, for composing with command substitution:wbox tasks list --assigned-to "$(wbox me user-id)"(#90, #91).wbox me --format tablenow labels the two IDs aslogin_idanduser_id (--assigned-to)so they aren't confusable at a glance. The JSON shape is unchanged — no breaking change for existing scripts (#91).- Skill docs (
lookups.md,tasks.md,contacts.md) flag the two-ID trap inline near--assigned-to.
Fixed¶
wbox users listnow paginates across all pages. Previously, firms with more than 25 users silently saw a truncated list — the CLI exposes no--pageflag, so there was no manual workaround.- mkdocs docs deploy was failing on every main push because
docs/index.mdlinked to a missingchangelog.md.CHANGELOG.mdis now staged intodocs/at build time and listed in nav (#92).
Changed¶
- CI actions bumped to Node 24 runtimes ahead of GitHub's June 2 2026 cutoff:
actions/checkoutv4→v6,astral-sh/setup-uvv6→v8.1.0 (pinned exact — setup-uv v8+ no longer publishes rolling major tags as a supply-chain mitigation),actions/setup-pythonv5→v6,actions/deploy-pagesv4→v5,actions/upload-pages-artifactv3→v5 (#92, #93).
[2.1.0] - 2026-05-09¶
Repository simplification release. Drops a runtime dep, retires .env support,
and switches dev tooling to uv.
Breaking¶
- Removed
.envfile support. Token resolution is now a 3-tier chain:--tokenflag →WEALTHBOX_TOKENenv var → config file. Users relying on a working-directory.envshould migrate towbox config set-token(preferred) or exportWEALTHBOX_TOKENin their shell. Thepython-dotenvruntime dependency was dropped.
Changed¶
- Development tooling moved to uv.
uv sync --extra devreplaces the manualpython -m venv+ activate +pip install -edance, anduv run wbox …replaces direct.venv/bin/wboxinvocation. CI now usesastral-sh/setup-uv@v6anduv buildfor the publish job. Plainpip install -e ".[dev]"continues to work —pyproject.tomlis the source of truth for both tools. scripts/run-wbox.shandscripts/smoke_test.shinvoke viauv runand no longer source a.envfile.
Removed¶
.envand.env.examplefiles at the repo root..python-versionfile.requires-python = ">=3.11"inpyproject.tomlis the authoritative interpreter constraint; uv reads it directly.
[2.0.0] - 2026-05-09¶
v2 retires the Claude marketplace plugin distribution and ships wbox as a
standalone binary plus a PyPI package. Existing v1 users must reinstall via the
new bootstrap script or pip install wealthbox-cli — see Breaking below.
Breaking¶
- Retired the Claude marketplace plugin distribution.
wboxno longer ships through the Claude marketplace. Install viapip install wealthbox-clior the bootstrap script (curl -fsSL https://github.com/massive-value/wealthbox-cli/releases/latest/download/install.sh | sh). v1'sclaude plugin installflow is gone. - Rewrote
install.shandinstall.ps1to fetch a prebuilt binary from GitHub Releases instead of detecting and preferring the Claude marketplace plugin (#42, #43). The installers now verify a checksum manifest before swapping the binary into place. - Removed v1 distribution artifacts — the in-repo plugin manifest and marketplace metadata are deleted (#27).
- Dropped plugin-cache scanning from the skill platform helpers;
wbox doctorandwbox skills listno longer probe Claude's plugin cache (#28).
Added¶
wbox firm export— end-to-end export of the configured firm's CRM data to a portable JSON snapshot (#31).wbox firm importwith--mode overwrite|merge|abort-on-conflictand--from-urlfor fetching a snapshot directly from a URL (#36, #46, #45).wbox firm diff— diff a local snapshot against the live firm to preview what an import would change (#47).- Post-import provenance metadata and a 90-day freshness warning surfaced by
wbox doctor(#48). wbox doctorpromoted to a top-level command, with a warning when the local install is more than 30 days behind the latest GitHub release (#41).wbox self upgrade— happy-path binary self-update (#32), Windows deferred-swap support (#67), and a subprocess hand-off so a freshwboxupgrades bundled skills after the binary swap (#40).wbox prefs— user-preferences slot for per-user defaults (#29).- Per-platform PyInstaller build + release workflow that publishes Linux, macOS, and Windows binaries plus a checksum manifest to GitHub Releases (#33).
- Skill-reference auto-generation markers across the bundled skill (#30, #85) and a CI drift-detection job that fails when generated skill blocks fall out of sync (#86).
- Bootstrap Q&A skips the onboarding prompts when an imported firm snapshot
already carries an
onboarded_attimestamp (#49). wbox firm applyandwbox doctornow sweep stale.old.<ts>backup files left behind by interrupted upgrades (#39).
Changed¶
- Rewrote the README around the v2 install flow — bootstrap script first, PyPI second, no marketplace path (#83).
- Documented the three-layer config resolution (flag > env > config file) and
the new
prefscommands inside the bundled skill (#34).
Fixed¶
wbox self upgradenow reads the checksum manifest under its release-asset filename, fixing the post-#33 break (#82).- Pytest no longer clobbers the developer's real
~/.wbox_rate_limit.json; the rate-limit state file is isolated per test session (#56).
1.3.0 - 2026-05-03¶
Added¶
wbox doctor— comprehensive top-level health check at the CLI root. Reports the wbox CLI version + Python version + binary location; authentication source detection (flag / env var / config file /.env) plus a smoke test against/me; agent CLI presence (claude/codexon PATH); legacy skill installs; plugin installs (managed viaclaude plugin install/codex plugin install); firm data state with file count, generated-vs-hand-edited split, and oldest-generated-file timestamp; and a Summary section listing actionable issues.wbox skills doctorkeeps working as an alias of the new top-level command — both call the same function so output never drifts.wbox skills listandwbox skills doctornow detect plugin-installed copies ofwealthbox-crmunder~/.claude/plugins/cache/.../skills/wealthbox-crm/and~/.codex/plugins/cache/.../skills/wealthbox-crm/. Previously a user who installed via the marketplace plugin path saw "not installed" everywhere even though the plugin was actively serving the skill.- Bootstrap installer (
scripts/install.sh/scripts/install.ps1) now prefers the Claude Code plugin marketplace path whenclaudeis on PATH — runsclaude plugin marketplace add+claude plugin installdirectly, then offers a separate Codex install. Falls back to the legacywbox skills installpicker when noclaudeCLI is detected. - Bootstrap installer pre-flight checks Windows PowerShell
ExecutionPolicyand offers to setRemoteSignedfor the current user if needed (no admin required), instead of bombing partway through with Astral's terse error.
Fixed¶
- Bootstrap
install.shno longer hangs at startup. The previous version did `exec