All notable changes to base-cli will be documented in this file.
The format follows Keep a Changelog,
and versions are tracked in the repo-root VERSION file.
- Continue compatibility hardening and adoption work for the next release.
-
Add a maintained, copyable five-minute starter template with explicit safe customization points and installed-consumer validation (#244).
-
Include
uv.lockfreshness in the authoritative local validation aggregate (#424). -
Document maintainer, independent review, release continuity, and reviewer onboarding responsibilities for the 1.0 release gate (#252).
-
State the explicit 0.3.x security-support row and make the v1.0 schedule evidence-driven rather than asserting an untracked ship date.
-
Add CodeQL analysis, Dependabot update policy, and repository security-control documentation for the 1.0 release gate (#280).
-
Configure Dependabot for the repository's checked-in uv lockfile instead of the pip ecosystem so automated updates preserve the lockfile validation gate.
-
Clarify that extension capabilities are informational metadata, and require fully qualified or distribution-prefixed extension allowlist entries (#397).
-
Match distribution-prefixed extension allowlists against the exact installed metadata spelling and precompute the approved distribution set.
-
Classify the compatibility facade in a reviewed API manifest and add the smaller
base_cli.corestarting surface for new applications (#242).
0.5.1 - 2026-10-10
- Align the release-facing README and reference-consumer documentation with the
published
base-cli0.5.x andbase-cli-demo0.2.0 lines. - Add release preflight, package-description, and PyPI metadata readback gates so published documentation stays bound to the reviewed tag.
0.5.0 - 2026-10-03
- Publish versioned, comparative CLI benchmark reports with lifecycle and feature scenarios, platform-specific regression gates, and retained CI evidence.
-
Derive default configuration directories from collision-resistant application identity namespaces so distinct names cannot share a path (#425).
-
Bound convenience-profile discovery and validate implicit project configuration trust; cap YAML input size (#385).
-
Skip contended retention passes instead of blocking CLI invocations on housekeeping locks (#386).
-
Reuse secure log lock descriptors and cache source paths per invocation; logging I/O failures stay inside logging (#381).
-
Align the Typer support floor with the tested matrix and cover representative minimum/maximum Typer and Click version pairings.
-
Prefix formula-leading CSV/TSV cells with an apostrophe by default to protect spreadsheet consumers; pass
formula_guard=Falseonly for an audited raw value contract. -
Stream CSV/TSV rows with bounded memory and document that earlier rows remain available when a later row cannot be encoded.
-
Add the namespaced
BASE_CLI_LOG_UTCenvironment variable and deprecateLOG_UTCwith a migration warning; the legacy alias is scheduled for removal no earlier than 0.7.
-
Capture inherited subprocess and descriptor-1 output inside the single JSON envelope, with bounded native-output handling (#379).
-
Enforce native Windows run-bundle retention with pinned directory handles; unsupported platforms fail closed once per pass (#378).
-
Preserve consumer-owned logging handlers, explicit levels, and parent routing across CLI invocations (#387).
-
Validate nested configuration mappings before merge/provenance traversal, reject recursive or excessively deep values with source-aware errors, and continue to accept shared YAML aliases.
-
Reject recursive and concurrent in-process
run_app()calls before they can replace another invocation's stdout or logging handlers. -
Rotate bounded byte-retention size walks across invocations with a persisted advisory cursor so bundles beyond the first scan budget are eventually seen.
-
Resolve lifecycle values through the active Typer/Click context for attached commands, including renamed options, defaults, and environment variables.
-
Reject non-finite numbers in JSON and NDJSON output so emitted records remain standards-compliant and failed NDJSON writes do not leave partial records.
-
Honor all five validated framework
log_levelvalues on native and attached user-facing streams while preserving DEBUG-level persistent diagnostics. -
Let explicitly supplied lifecycle values, including negative boolean flags, environment variables, and Click
default_mapentries, override validated file configuration while keeping config ahead of Click defaults. -
Surface expected output-format and optional-dependency failures as actionable usage errors at the process boundary, including a stable JSON error code.
-
Bind an allowlisted Python extension to its discovered entry-point source and fail closed if its distribution identity changes before loading.
-
Preserve run bundles while their lease is held through terminal metadata writing and cleanup; recheck lease state before deletion.
-
Detect JSON capture without running Click callbacks, callable defaults, type converters, or close hooks a second time; respect option-value arity so a payload equal to
--jsonremains human output. -
Preserve explicit application identities losslessly while using collision-resistant, path-safe runtime namespace components.
-
Give
BatteriesIncludedConfigLoader.cli_namea documented identity role by using it to derive an isolated default configuration directory when no explicit directory is supplied. -
Keep plain consumer configuration mappings opaque so only validated
ConfigSnapshot.frameworkvalues control lifecycle behavior. -
Preserve
KeyboardInterrupt,SystemExit, andGeneratorExitacross optional Rich, telemetry, and extension integrations while still shielding teardown cleanup from process-control exceptions. -
Preserve streaming human output unless JSON was explicitly requested, including pre-parse option, environment, and default-map detection.
-
Require output records to match the declared list-of-mappings contract and apply identical bounded width handling to Rich and plain renderers.
-
Make managed metadata and index replacements atomic, with bounded retries for transient Windows file-sharing locks.
-
Protect live run bundles with cross-platform process leases and fail closed when liveness is missing or cannot be established during retention recovery.
-
Bound foreground run-cache recovery work, avoid unnecessary recursive size walks, and report remaining retention policy debt for incremental passes.
-
Select platform-aware cache roots (
XDG_CACHE_HOME, macOS Caches, and WindowsLOCALAPPDATA) and normalize home-relative paths across separators. -
Add README health and support badges for CI, downstream consumers, PyPI, and supported Python versions.
-
Enforce the portable
0through255process exit-code contract for command return values, rejecting booleans and out-of-range integers consistently. -
Add Click 8.5 compatibility coverage across the dependency matrix and supported OS test lanes; the core dependency window now permits
<8.6.
0.4.3 - 2026-08-29
This is a compatible pre-1.0 patch release. It contains lifecycle hardening, security fixes, versioned machine-readable contracts, and adoption tooling after 0.4.2; it does not introduce a new API or JSON-contract compatibility boundary. Existing Click and Typer command trees remain supported.
- Add branch-aware coverage reporting with documented floors for lifecycle, filesystem, compatibility, history, and contract modules.
- Decompose the application implementation behind a compatibility facade into focused core, lifecycle-installation, attachment, and invocation-runner modules without changing the public import surface.
- Bound the core Click and PyYAML dependency windows, publish the tested compatibility matrix, and document the dependency update policy.
- Validate Click 8.1 through 8.4 on the supported Python floor and ceiling, and reject unvalidated Click 8.5+ versions through package metadata.
- Move PyYAML behind the optional
base-cli[yaml]extra and provide an actionable installation hint when YAML configuration or output is selected. - Add an explicit
App.async_command()adapter andrun_async()helper for deterministic async callbacks without changing the synchronous core. - Add versioned NDJSON output and typed writer protocols for bounded, flush-per-record machine output.
- Formalize typed extension callback protocols, entry-point capability metadata, and pre-load API-version negotiation.
- Redact recognized secret keys embedded in query strings, comma-separated
values, and header-style
key: valuearguments before they reach logs or persisted history.
- Keep the Typer adapter compatible with Typer 0.27.2's vendored exit exception layout and validate that release in the compatibility matrix.
- Apply the documented count-only 20-bundle retention default to implicit JSON
mode while preserving explicit retention policies, human-mode safe defaults,
and the
max_log_filescompatibility path. - Honor combined positive/negative JSON option declarations and explicit
--no-jsonvalues when deciding whether pre-parse errors use JSON output. - Isolate malformed third-party entry-point metadata so one invalid extension cannot prevent healthy extensions from being discovered.
-
Automate GitHub Releases from matching version tags with reviewed distributions, checksums, SBOM metadata, and generated comparison notes.
-
Publish a generated dependency and platform compatibility dashboard linked from the README and documentation site.
-
Add framework-specific migration guides for Click, Typer, Cement, and
argparse, with rollout and rollback checklists. -
Add golden success, error, inspection, log, NDJSON, and command-protocol fixtures with Python and Node.js validators for cross-language consumers.
-
Publish versioned JSON Schema artifacts for output, error, inspection, log, NDJSON, and decoded command-protocol contracts in the package and docs site.
-
Add a framework choice guide, five-minute evaluation path, and clearer production-lifecycle positioning for Click and Typer adopters.
-
Add deterministic SPDX SBOMs, artifact checksums, and OIDC-backed GitHub attestations to protected release workflows.
-
Add a generated public API reference and a strict CI drift check so every stable facade export remains searchable and documented.
-
Add a permissioned-adopter evidence policy and dated compatibility-run artifacts without presenting maintained fixtures as customer adoption.
-
Align the README, documentation landing page, package metadata, and search keywords around the production lifecycle layer positioning for Click and Typer CLIs.
0.4.2 - 2026-08-08
This is a compatible pre-1.0 patch release. It contains correctness fixes, security hardening, documentation improvements, and adoption polish after 0.4.1; it does not introduce a new API or JSON-contract compatibility boundary.
- Apply the profile-resolved display command to ambient production invocation metadata so logs and history match the documented wrapper-label contract.
- Compact the launcher path in retained invocation logs so diagnostic bundles do not disclose the local user's home directory or username.
- Fix the published documentation link to the reference applications.
- Classify a command that returns exit code
130asnonzero_return; theinterruptedoutcome remains reserved for actual interrupt exceptions.
- Document the exported history, command-protocol, and context APIs and enforce public-symbol docstrings in the API tests.
0.4.1 - 2026-08-07
This is a compatible pre-1.0 patch release. It contains adoption polish, security hardening, correctness fixes, and CI improvements after 0.4.0; it does not introduce a new API or JSON-contract compatibility boundary.
- Add the MkDocs documentation site configuration, strict documentation checks, and GitHub Pages deployment workflow.
- Add the importable, intentionally empty
base_cli.experimentalnamespace for future preview APIs without expanding the stable API surface.
-
Reclassify the project as Beta in package metadata to reflect its documented API stability policy, compatibility suite, and production-adoption guidance.
-
Add a version, license, install, and release-notes strip to the README and validate it against the repository version contract.
-
Extend the optional Typer adapter through Typer 0.27.x by selecting the command tree's matching public or vendored Click dialect, with a Python 3.10 through 3.14 compatibility matrix covering Typer 0.25.1, 0.26.0, and 0.27.1.
-
Document the intentional opaque
Context.user_configboundary and the compatibility requirements for any future fourth context type parameter. -
Expand CI quality gates with package-level strict mypy coverage, the full Ruff format surface, and the updated benchmark percentile calculation.
-
Improve the public documentation for inspection envelopes, delegated display labels, environment configuration, typed user configuration, Typer access, release guidance, and contributor setup.
- Compact home-relative paths in diagnostic
run.jsonandidentity.jsonmetadata so retained support bundles disclose less local path information.
- Capture command output consistently when JSON mode is supplied through Click's
default_mapor combined short flags, preserving the single-envelope stdout contract. - Preserve every first-seen document column when rendering heterogeneous records instead of silently dropping fields found only in later rows.
- Compute a real interpolated p95 in the runtime benchmark instead of reporting the maximum under two names.
- Reject Unicode digit-like input that is not a decimal integer while retaining the friendly positive-integer error message.
- Reuse one history display-command resolver across contexts, profiles, and history records.
- Correct release-facing examples, changelog structure, API documentation, contribution guidance, and package-level formatting coverage.
0.4.0 - 2026-08-05
This is a pre-1.0 minor release and therefore a compatibility boundary. See
the API stability policy and migration guide before upgrading from 0.3.x.
- Consumer profiles should raise
base_cli.ConfigurationErrorfor expected, user-correctable configuration failures instead of plainValueError. - Consumers should import
RuntimeLayoutfrombase_cli.runtime; the private_runtimemodule is not a compatibility surface. base_cli.testing.invoke()now exercises the productionrun_app()boundary, so tests should assert the same exit status users receive.- Click-native
--option=valuesyntax is accepted and redacted like the space-separated form.
- Add the security policy, runtime threat model, and threat-to-control release checklist covering secret handling, filesystem ownership, plugins, inherited runs, concurrency, and telemetry boundaries.
- Add the public API stability and deprecation policy, migration guide, and
base_cli.deprecated()warning helper with contract-test guardrails. - Add immutable
LifecycleOptionsandLifecycleOptionpolicies for enabling, disabling, renaming, and configuring each standard option independently, with normalizedLifecycleValuesstored in namespaced Click metadata without replacing application-ownedContext.objstate. - Add
App.attach()andbase_cli.attach()for applying one lifecycle to existing nested, aliased, chained, and lazy Click command trees while preserving their native callbacks, contexts, and result values. - Add public
sensitive_parametersattachment policy for existing and lazy Click parameters with domain-specific secret names. - Add
ConfigurationErrorso consumer profiles can explicitly mark user-correctable configuration messages as safe usage errors. - Add public typed runtime/profile/context contracts, generic attachment factories, isolated command-schema registries/codecs, and a strict consumer typing example.
- Add opt-in
CliProfile.batteries_included()layered configuration with platform-aware user paths, project and environment files, provenance, and validated framework settings. - Add the optional
base-cli[typer]integration withattach_typer(),TyperAdapter, andget_typer_command()so Typer command trees can adopt the same lifecycle without making Typer a core dependency. - Add opt-in versioned JSON success/error envelopes, redacted bounded JSON logs, and public contract helpers for machine-facing integrations.
- Normalize command returns, Click errors, aborts, interrupts,
SystemExit, and unexpected exceptions through one core outcome model and cleanrun_app()process boundary. - Treat plain profile-callback exceptions as private internal failures. Profiles
that used
ValueErrorfor expected configuration problems should raiseConfigurationErrorinstead. - Route
base_cli.testing.invoke()through the productionrun_app()boundary and add a keyword-onlyreraise_unexpectedopt-in for tests that need the original exception. - Reject native async callbacks explicitly and preserve Click command subtypes
through typed
attach()decorators and adapters.
- Reject missing, unreadable, and non-regular explicit
--configpaths before profile or runtime startup while preserving optional profile-owned files. - Make
App.nameauthoritative for single-command identity, reject duplicate or post-materialization registrations deterministically, stabilize inferred names across Click releases, and make module-level@command()functions retrievable and directly runnable throughrun_app(). - Redact sensitive option values across every declared alias and Click value form, redact sensitive positional arguments, and protect conventional secret parameter names automatically before argv reaches logs or history writers.
- Claim invocation temp leaves exclusively and refuse recursive cleanup unless ownership, strict run-root containment, the run-ID marker, and a symlink-free path can all be proven; content erasure uses a retained directory handle and intentionally leaves the empty directory skeleton instead of reopening a pathname-removal race.
- Finalize core-owned run metadata for successful, failed, aborted, interrupted, and unexpected command outcomes without letting secondary persistence failures replace the command result.
- Roll back partially constructed command contexts without leaking handlers, temporary directories, or incomplete run bundles.
- Preserve exception tracebacks in persistent logs and show them on stderr only when debug output is enabled.
- Make history persistence best-effort so secondary failures cannot mask the command outcome or skip cleanup, context reset, and logger shutdown.
- Allow finished history records to omit
log_pathwhen file logging is disabled. - Restore Click-native
--option=valueparsing, including redaction of sensitive equals-form values.
0.3.0 - 2026-08-01
- Keep private runtime files and directories owner-only on POSIX, use inherited user-profile ACLs on Windows, and make history appends binary-safe across locking backends.
- Make terminal detection tolerate closed streams and record
COMSPECwhen Windows has noSHELLenvironment variable. - Add Linux distribution and WSL2 validation guidance for the generic package.
- Document the Linux, WSL2, macOS, and native Windows support tiers and add matching operating-system package classifiers.
0.2.0 - 2026-08-01
- Make
base_cli.App()use the consumer-neutral profile by default. - Move manifest discovery, implicit configuration, owner-aware runtime layout,
and history persistence out of the generic package. Consumers now provide
those policies through an explicit
CliProfile. - Make
Context.user_configan opaque consumer-owned value and remove the Base-shapedUserConfigtypes from the public package facade. - Make command-filter normalization consumer-neutral by default. Consumers can provide a normalizer callback for legacy prefixes or aliases.
- Remove the Base-branded logger formatter and IDE schema parser from the standalone package; those consumer-specific concerns now belong to adapters.
- Make command protocol schemas consumer-owned. The generic protocol now ships
only framing and validation, with
COMMAND_PROTOCOL_V1as its default header; consumers can register schemas and preserve a legacy header through the protocol helper'sprotocol_headerargument.
- The removed implicit Base profile and Base path/config/history helpers are no
longer available from
base_cli. Existing Base integrations should use the adapter modules in the Base repository and passbase_cli_profile()tobase_cli.App. base_cli.history.write_history_record()andbase_cli.history.write_primary_record()now require a consumer-selected history path; they never choose an application cache location themselves.- Consumers that need a workspace root should provide the optional
CliProfile.resolve_workspace_rootprojection; the generic lifecycle no longer reads fields from a prescribed user-configuration schema.
- Initialized the repository with the Base-managed repo baseline.
- Added the guarded package build, artifact validation, and protected TestPyPI/PyPI publication workflow.
- Exposed
base_cli.__version__from the repository and installed package version contract. - Pinned the build backend to metadata compatible with the bundled publication action and made license-file validation portable across setuptools versions.