Skip to content

Changelog

All notable changes to wealthbox-cli are documented here. The format follows Keep a Changelog, and this project adheres to Semantic Versioning.

[2.5.0] - 2026-09-20

Fills in the work-record commands an AI agent needs, and corrects two list defaults that were quietly returning a slice of the data.

Fixed

  • wbox tasks list --include-completed returned completed tasks only. Wealthbox's completed parameter is a two-way switch, not an "include": omitted or false means open only, true means completed only. The flag mapped to completed=true, so it did the opposite of its name. It is now a hidden alias for --status all and keeps working in existing prompts.
  • A bad --category, --advisor-role, or --custom-field value printed "Unexpected error". These resolvers raise BadParameter from inside the command body, after Click's own parsing is finished, so the generic handler caught them. handle_errors now renders them as the user errors they are. The exit code was already 1 and has not changed.

Added

  • wbox tasks list --status open|completed|all (default open). all issues both calls in sequence and merges by id, keeping the copy with the later updated_at. In a firm with 5,174 tasks, 4,994 of them complete, the default was showing 3% of the record set without saying so.
  • wbox workflows list --status all, alongside the existing active, completed, and scheduled. The default is now an explicit active, which is what the API did all along when given no status. all runs three sequential calls and merges by id.
  • wbox teams list and wbox users groups. Team IDs are what --assigned-to-team expects and there was no way to look one up; group IDs are what visible_to accepts. Both render id, name, and member_count, with the full member list under --verbose.
  • wbox comments list, filtered by --task, --event, --note, --opportunity, --project, or --workflow, or by an --updated-since/--updated-before window. An unfiltered call exits 1 with a one-line reason: GET /comments costs about 8.5 seconds per page of 100 unfiltered, against about 1.5 seconds inside a one-month window.
  • wbox workflows next now lists the active step's outcomes (id, name, action, go_to_step_id) in JSON and on stderr, so they stay readable in every --format. complete-step --outcome-id is the only way to branch such a step and the IDs appeared nowhere else in the CLI. complete-step's own advance hint lists them too.
  • --custom-field NAME=VALUE on tasks add|update and events add|update (repeatable, accepts a name or a numeric ID). Names are resolved against wbox categories custom-fields --document-type Task|Event and an unknown name is a hard error listing the valid ones. That check is load-bearing: Wealthbox accepts a custom-field payload keyed by name with a 200 and then silently discards it.

Changed

  • Help text on wbox opportunities list and --include-closed now says that closed opportunities are dropped by default (117 records in the firm, 73 returned). No behavior change.
  • New references/comments.md; the tasks, workflows, opportunities, events, and lookups references document the defaults, the new flags, and the teams/user-group lookups.

Not built

  • wbox comments add. The token-authenticated v1 REST API cannot write a comment: POST /v1/comments returns a response byte-identical to a nonexistent path, as does POST /v1/tasks/{id}/comments. The write route lives on Wealthbox's session-authenticated web surface (POST /comments without the /v1 prefix answers 302 to /users/login), which the official Wealthbox MCP reaches over OAuth via its CreateComment tool. Supporting it from wbox would mean driving a logged-in web session with CSRF tokens, a different auth model than the rest of the CLI. references/comments.md documents the MCP-writes / wbox-reads split; a comment created through the MCP is immediately readable by wbox comments list.
  • tasks add --parent. The API takes subtasks only as inline objects in a parent task's create payload, never as a parent reference on a child. The read side's parent {id, type} object has no write counterpart. Use --more-fields '{"subtasks": [...]}'.

[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

  • wbox startup crash (ModuleNotFoundError: click) on clean installs that lack click. The import click in cli/_factory.py is now guarded by TYPE_CHECKING (it is only used in annotations, which are not evaluated at runtime under from __future__ import annotations).

Internal

  • CI gains a smoke job that installs the built wheel in isolation without dev dependencies and runs wbox --version, so a missing-runtime-dependency startup crash can no longer reach PyPI. The publish job 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. wbox now distinguishes failure classes: validation / user errors and non-auth 4xx responses (e.g. 404, 422) still exit 1, authentication errors (401/403) now exit 2, and server errors (5xx) now exit 3. 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 exit 2 as before; that overlap is pre-existing.)

Added

  • WBOX_DEBUG environment 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 / --brief output mode (strips *_html duplicate 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 with 0600 permissions on POSIX so other local users cannot read a stored token.
  • Malformed Retry-After response header values are truncated to 100 characters before being logged, bounding a hostile/oversized header.

Internal

  • Typing: src/ is now mypy --strict clean (zero errors, zero type: ignore). Client mixins share a typed request protocol and fetch_all_pages returns a typed pagination envelope. A new typecheck CI job runs mypy src/ and gates publishing.
  • CI: added a windows-latest test leg (Python 3.12), a coverage floor (--cov-fail-under=91 on the Ubuntu leg), a publish-time check that the top CHANGELOG version matches pyproject.toml, a weekly Dependabot config, and a .pre-commit-config.yaml (ruff, mypy, skill-ref drift).
  • Refactor: cli/_util.py was split into _client, _format, _resolve, and _factory modules (with _util kept as a re-export shim). The notes, projects, tasks, events, opportunities, and workflows command groups now generate their commands from a shared resource-command factory; contacts remains 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 *UpdateInput rejects 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

  • wbox startup crash (ModuleNotFoundError: click) in environments where click is not installed. The skill_ref_gen import is now deferred to the body of the hidden regen-skill-refs command, which is only ever invoked during development.
  • PyPI publish job now uses skip_existing: true so 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:USER flag on contacts add person|household|org|trust and contacts 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.ps1 gains a -SkipSkills switch for CI and non-agent installs that don't need the bundled agent skill.

Fixed

  • ContactRoleAssignment now uses {id, value} (the Wealthbox write shape) instead of {id, type}, unblocking all contact-role write paths including --more-fields (#94).
  • install.ps1 re-runs are now idempotent: if the skill directory already exists the installer runs wbox skills upgrade instead of erroring.
  • install.ps1 no longer prompts for a token when one is already stored in %APPDATA%\wbox\config.json or WEALTHBOX_TOKEN.

Changed

  • README and docs/getting-started.md now include a per-install-method upgrading table and clarify that wbox self upgrade is for bundle installs only; uv tool upgrade / pipx upgrade are 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 upgrade now detects the install kind (bundle / uv-tool / pipx / pip) up front. Non-bundle installs exit 1 with the correct follow-up command (uv tool upgrade wealthbox-cli, pipx upgrade wealthbox-cli, or pip install --upgrade wealthbox-cli) instead of scheduling a swap that would never take effect on PATH.

[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 — prints current_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 table now labels the two IDs as login_id and user_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 list now paginates across all pages. Previously, firms with more than 25 users silently saw a truncated list — the CLI exposes no --page flag, so there was no manual workaround.
  • mkdocs docs deploy was failing on every main push because docs/index.md linked to a missing changelog.md. CHANGELOG.md is now staged into docs/ 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/checkout v4→v6, astral-sh/setup-uv v6→v8.1.0 (pinned exact — setup-uv v8+ no longer publishes rolling major tags as a supply-chain mitigation), actions/setup-python v5→v6, actions/deploy-pages v4→v5, actions/upload-pages-artifact v3→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 .env file support. Token resolution is now a 3-tier chain: --token flag → WEALTHBOX_TOKEN env var → config file. Users relying on a working-directory .env should migrate to wbox config set-token (preferred) or export WEALTHBOX_TOKEN in their shell. The python-dotenv runtime dependency was dropped.

Changed

  • Development tooling moved to uv. uv sync --extra dev replaces the manual python -m venv + activate + pip install -e dance, and uv run wbox … replaces direct .venv/bin/wbox invocation. CI now uses astral-sh/setup-uv@v6 and uv build for the publish job. Plain pip install -e ".[dev]" continues to work — pyproject.toml is the source of truth for both tools.
  • scripts/run-wbox.sh and scripts/smoke_test.sh invoke via uv run and no longer source a .env file.

Removed

  • .env and .env.example files at the repo root.
  • .python-version file. requires-python = ">=3.11" in pyproject.toml is 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. wbox no longer ships through the Claude marketplace. Install via pip install wealthbox-cli or the bootstrap script (curl -fsSL https://github.com/massive-value/wealthbox-cli/releases/latest/download/install.sh | sh). v1's claude plugin install flow is gone.
  • Rewrote install.sh and install.ps1 to 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 doctor and wbox skills list no 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 import with --mode overwrite|merge|abort-on-conflict and --from-url for 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 doctor promoted 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 fresh wbox upgrades 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_at timestamp (#49).
  • wbox firm apply and wbox doctor now 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 prefs commands inside the bundled skill (#34).

Fixed

  • wbox self upgrade now 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 / codex on PATH); legacy skill installs; plugin installs (managed via claude 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 doctor keeps working as an alias of the new top-level command — both call the same function so output never drifts.
  • wbox skills list and wbox skills doctor now detect plugin-installed copies of wealthbox-crm under ~/.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 when claude is on PATH — runs claude plugin marketplace add + claude plugin install directly, then offers a separate Codex install. Falls back to the legacy wbox skills install picker when no claude CLI is detected.
  • Bootstrap installer pre-flight checks Windows PowerShell ExecutionPolicy and offers to set RemoteSigned for the current user if needed (no admin required), instead of bombing partway through with Astral's terse error.

Fixed

  • Bootstrap install.sh no longer hangs at startup. The previous version did `exec