26 KiB
Changelog
All notable changes to contextzip are documented here.
The format follows Keep a Changelog. This project uses Semantic Versioning.
[0.1.1] — 2026-05-15
Fixed
- LICENSE link in README now points to GitHub instead of a relative path that broke on PyPI
- License metadata updated to SPDX string format (
"MIT") to comply with setuptools ≥ 77
[0.1.2] — 2026-05-15
Added
- Smart framework and language detection (Next.js, Node.js, Python, Django, FastAPI, Rust, Go, Ruby)
- Automatic exclusion rules per detected ecosystem
.gitignorepatterns respected automatically (--no-gitignoreto bypass)--includeflag for scoping to specific directories (exact path-boundary matching)--excludeflag for additional gitignore-style exclusion patterns--dry-runflag to preview without creating any files--verboseflag showing every file with its size--outputflag for custom ZIP destination--no-clipboardflag to skip clipboard/folder-open step- Tiered clipboard strategy: file-on-clipboard (macOS/Linux), Explorer with file selected (Windows), path fallback
- Warnings for large files (≥ 1 MB), binary files, and skipped files (dangling symlinks, permission errors)
- Rich terminal output with panels, progress bars, and colour-coded detection results
- Compression stats (ratio, size before/after) shown after ZIP creation
[0.2.0] — 2026-05-15
Added
--git-changesmode for packaging only files reported as changed by git- Automatic detection of:
- staged files
- unstaged modifications
- untracked files
- Dedicated git-aware packaging pipeline optimised for AI/code review workflows
- Rich git change summary panel with staged/unstaged/untracked breakdown
- Verbose git mode output showing categorized changed files
- Graceful handling for:
- repositories with no changes
- deleted files
- submodules
- repositories outside the selected project tree
- missing git installations
- non-git directories
- Support for monorepo-aware repository root resolution
- Binary and large-file checks now also apply in git-changes mode
Improved
- File resolution architecture refactored to support multiple packaging strategies cleanly
- Internal file scanning pipeline separated from git-based file selection logic
- CLI output consistency improved between standard scan mode and git-changes mode
Developer Notes
- Introduced new
contextzip.gitmodule for git integration and porcelain parsing - Added
resolve_files_from_git()pipeline for pre-selected file resolution - Added structured
GitChangesandGitErrormodels for cleaner error handling and extensibility
[0.2.1] — 2026-05-16
Fixed
--exclude/-epatterns containing Windows-style paths (e.g..\CHANGELOG.md) were silently ignored due to backslash and leading.\— patterns are now normalized to forward-slash posix paths before matching- Files passed to
-ewere not being excluded from the ZIP despite appearing in the exclusion list
Improved
-enow accepts multiple space-separated patterns in a single flag invocation:-e file1 file2 folder/in addition to the existing repeatable form-e file1 -e file2- Folder exclusion via
-e folder/*is now supported and normalized tofolder/automatically
[0.2.2] - 2026-05-16
Added
contextzip exclude PATTERN…subcommand — exclude multiple files and folders in a single invocation without repeating-e(e.g.contextzip exclude CHANGELOG.md LICENSE .github/)contextzip include PATH…subcommand — symmetric counterpart toexclude; packages only the specified paths (e.g.contextzip include src/ app/)- All modifier flags (
--dry-run,--verbose,--output,--no-clipboard,--git-changes,--no-gitignore) work on both subcommands
Changed
-e/--excludeflag on the main command restored and kept for full backwards compatibility alongside the new subcommand- Warning messages for large files now mention both
-e PATTERNandcontextzip exclude PATTERNas remediation options _normalize_patternpromoted to a named module-level function (testable, documented); behaviour is unchanged
Fixed
- Removed the previous positional-argument approach to exclusions on the main command, which was ambiguous and undiscoverable
[0.2.3] — 2026-05-19
Added
- Dedicated Ruby ecosystem exclusion rules via new
contextzip.rules.rubymodule - Automatic exclusion of common Ruby / Rails artifacts:
- Bundler directories and lockfiles
- Rails logs, temp files, assets, storage, and Spring cache
- Built gems and compiled Ruby extensions
- Coverage and generated documentation directories
- Additional package discovery keywords for AI tooling and code packaging:
claudechatgptcode-packaging
Changed
- Ruby project detection now uses the dedicated Ruby rule module instead of the generic base rules
- Git-based packaging now enforces base exclusion safety rules even for tracked files
- Repository governance and metadata files are now excluded by default:
CHANGELOG*LICENSE*CONTRIBUTING*SECURITY.md.githubissue / PR templates
.gitignoreis no longer excluded automatically from packaged context archives
Fixed
- Prevented git-tracked sensitive files (e.g.
.env, secrets, binaries) from being included in--git-changesmode - Improved ZIP packaging resilience when file stat operations fail during archive creation
- Fixed progress tracking during ZIP generation to avoid repeated filesystem stat calls
- Fixed Ruby framework detection routing so Ruby projects receive ecosystem-specific exclusion behaviour
[0.2.4] — 2026-05-20
Added
-
Persistent
.contextzip/workspace directory for generated context packages -
Automatic output naming based on packaging mode:
codebase.zipfor standard packagingchanges.zipfor--git-changes
-
Automatic
.contextzip/exclusion from packaged archives and file scanning -
Automatic
.gitignoreintegration:.contextzip/is appended when a git repository is detected- missing entries are added only once
-
Repository-root-aware workspace placement:
.contextzip/is created at the git repository root when.git/is detected- falls back to the current working directory outside git repositories
Changed
- ZIP outputs are now written to the persistent
.contextzip/workspace by default instead of temporary system directories - Generated archives now overwrite previous outputs with the same logical name instead of creating temporary randomized filenames
--outputnow bypasses all.contextzip/workspace logic and writes directly to the user-specified destination
Improved
-
Generated context packages are now easier to rediscover, reuse, and inspect across AI-assisted development workflows
-
Workspace output structure now provides a foundation for future features such as:
- timestamped package history
- metadata indexing
- incremental packaging
- AI debug sessions
- package caching
Fixed
- Prevented
.contextzip/contents from recursively packaging previous generated archives - Improved fallback behaviour when workspace creation fails due to filesystem permissions or read-only directories
[0.3.0] — 2026-05-24
Added
--prompt/-pflag for AI-powered file selection — describe your task in plain English and contextzip automatically selects the minimum relevant files (e.g.contextzip --prompt "Change toast color on failed login")- Gemini 2.5 Flash Lite integration via a thin
httpxclient — no Google SDK required; a single lightweight POST call to the Gemini API - First-run onboarding flow for users without an API key:
- Displays a guided panel with a link to Google AI Studio (free, no credit card)
- Optionally opens the browser automatically
- Saves the key persistently on confirmation
- Persistent API key storage in the platform-appropriate config directory:
~/.config/contextzip/config.jsonon Linux / macOS%APPDATA%\contextzip\config.jsonon WindowsGEMINI_API_KEYenvironment variable always takes precedence
contextzip configsubcommand for key management:contextzip config— show current key status and sourcecontextzip config --reset-key— clear stored key and re-run onboardingcontextzip config --show-key-path— print config file location
prompt.txtis written as the first entry in every AI-generated ZIP, containing the task description, detected framework, and selected file list — so any AI tool receiving the archive immediately knows the context- Keyword-based heuristic file scorer as a rate-limit fallback:
- Activates only on confirmed HTTP 429 from Gemini
- Scores files by token overlap with the prompt, directory semantics, and extension type
- User is warned clearly that heuristic was used and Gemini results are preferred
--prompt --dry-runcombination — preview AI-selected files without creating a ZIP- API key validation on load — keys not starting with
AIzaare treated as unconfigured and trigger onboarding rather than a cryptic API error diagnose_api_key()surfaces a human-readable explanation when a key exists but fails validation, before any API call is attempted
Changed
create_zip()inpackager.pynow accepts an optionalprompt_txtparameter; when provided,prompt.txtis written as the first ZIP entry- xdg-open on Linux now runs with stdout and stderr suppressed to prevent KDE / DBus / MIME warnings from appearing over the API key prompt
Developer Notes
- Introduced
contextzip.configmodule for cross-platform config path resolution and key read / write / delete operations - Introduced
contextzip.aipackage with three modules:gemini.py— Gemini API client with typed exception hierarchy (GeminiError,GeminiRateLimitError,GeminiUnavailable)heuristic.py— keyword + directory scoring fallback scorerselector.py— project map builder, AI orchestration,prompt.txtgeneration; returns(paths, prompt_txt, method)so callers know which selection path was taken
- Added
httpxas a required runtime dependency
[0.3.1] — 2026-05-25
Added
contextzip watch -- <command>subcommand — wraps any dev server or build process, buffers its output, detects errors automatically, and packages a debug-ready ZIP in a single keypress- Supports
npm run dev,python manage.py runserver, and any process that writes errors to stdout/stderr - On error detection, renders an inline prompt beneath the error output:
[D] package debug context [S] skip - Pressing
Dwrites.contextzip/debug-context.zipimmediately; the wrapped process continues running uninterrupted - On
Ctrl+C, if no errors were packaged during the session, a final prompt offers to capture the full session output as a fallback
- Supports
debug-context.zip— flat ZIP structure produced bywatch:prompt.txt— auto-generated from detected framework, error type, and referenced files; no--promptflag required from the userterminal-error.txt— cleaned, noise-stripped error block and stack tracesource-files.zip— inner ZIP containing source files extracted from stack frames, with relative paths preserved
contextzip/error_parser.py— full terminal output processing pipeline:strip_ansi()— removes all CSI, OSC, and Fe escape sequences and bare carriage returns from raw process outputdetect_error_block()— backward scan through the rolling buffer to find the most recent error; walks back from terminal exception lines to capture the full block including theTracebackheaderextract_paths()— runs per-framework path regexes on the error block, resolves relative and bare filenames, and filters out stdlib, venv, andnode_modulespathsstrip_noise()— removes known noise lines (request logs, startup banners, HMR chatter) and collapses blank line runsbuild_prompt_txt()— generates structured, AI-readyprompt.txtcontentprocess_buffer()— convenience function running the full pipeline in a single call
contextzip/watcher.py— process management and packaging:- Spawns child via
subprocess.Popenwith piped stdout/stderr; two daemon threads drain pipes concurrently into adeque(maxlen=2000)rolling buffer - Detection thread polls the buffer every 300ms using
detect_error_block() - Error deduplication: MD5 of the first three non-blank lines of an error block; same signature within a session suppresses repeat prompts
- Single-keypress D/S prompt via
termios/ttyraw mode on Unix andmsvcrton Windows, with aninput()fallback for unusual environments - Child terminated cleanly on
Ctrl+C: SIGTERM → 3-second grace period → SIGKILL
- Spawns child via
contextzip/rules/errors/python.py— error detection pattern sets for Python, Django, and FastAPI:- 18 error start patterns covering tracebacks, syntax errors, Django/DRF exceptions, uvicorn/gunicorn ERROR logs, and pytest failures
- 4 stack frame path patterns
- 21 noise patterns for Django startup, request logs, pytest collection output, and pip install chatter
contextzip/rules/errors/node.py— error detection pattern sets for Node.js, Next.js, and React:- 33 error start patterns covering JS runtime errors, Next.js error symbols
(
✗,×,⨯), webpack/bundler errors, npm errors, and unhandled promise rejections - 7 stack frame and import path patterns
- 32 noise patterns for Next.js/Vite/CRA startup, HMR chatter, and request logs
- 33 error start patterns covering JS runtime errors, Next.js error symbols
(
Changed
cli.pyrefactored from a single 1,100-line file into four focused modules with no behaviour changes:cli.py— Click group, four subcommands, and_run(); routing onlycli_display.py— all Rich rendering helpers (print_detection,print_scan_summary,print_file_warnings,print_package_result, etc.)cli_ai.py— AI selection orchestration andnormalize_patterncli_onboard.py— Gemini API key onboarding flow and browser launch
pyproject.tomlupdated to includecontextzip.rules.errorsin package discovery
Developer Notes
contextzip/rules/errors/follows the same pattern ascontextzip/rules/: one file per ecosystem, each exportingERROR_START_PATTERNS,PATH_PATTERNS, andNOISE_PATTERNSas lists of compiledre.Patternobjects — adding support for a new framework means adding one file_load_patterns()inerror_parser.pymaps ecosystem names fromDetectionResult.ecosystemsto rule modules; unrecognised ecosystems fall back to loading both Python and Node patterns as a best-effort defaultcli_display.pyfunctions accept an optionalcon: Consoleparameter (defaulting to the module-level console) making every display function independently testable without monkey-patching- No new runtime dependencies introduced —
watchuses only stdlib (subprocess,threading,queue,termios/msvcrt,zipfile)
[0.3.2] — 2026-05-25
Added
-
Python API — contextzip is now usable as a library, not just a CLI tool:
get_git_changes(path?)— returns aFileCollectionof git-modified, added, and untracked files; applies base safety rules (no secrets, no binaries) automaticallyget_files(path?, include?, exclude?, use_gitignore?)— returns aFileCollectionof all project files after applying ecosystem rules,.gitignore, and any extra exclusion patternscreate_zip(collection, output?)— writes aFileCollectionto a ZIP archive and returns aPackageResult; output path is caller-controlleddetect_ecosystem(path?)— returns aDetectionResultwith ecosystem names, display string, and confidence levelFileCollection— unified return type forget_git_changesandget_files; supports iteration,len(), andbool()directly;.filesis always a plainlist[pathlib.Path]usable without zippingPackageResultre-exported from the top-level package- Exception hierarchy:
ContextzipError(base),NotARepositoryError,GitNotFoundError,GitCommandError,NoFilesError - All API functions default
pathtoPath.cwd(), matching CLI behaviour
-
contextzip/api.py— new module implementing the public API; no Click, no Rich output, noSystemExit; raises typed exceptions on failure -
contextzip/packager.py— addedcreate_zip_silent()and_workspace_output_path_silent(): same ZIP logic as the CLI path but without aConsoledependency, used internally by the API
Changed
contextzip/__init__.py— now exports the full public API (get_git_changes,get_files,create_zip,detect_ecosystem,FileCollection,PackageResult, and all exception types) sofrom contextzip import ...works without knowing internal module paths
Fixed
filters.py— symlink guard innertryblock repeated the identicalrelative_tocall that already failed in the outer block; the fallback now correctly uses the pre-resolve (original_path) to compute the relative path for symlinks that point outside the project treewatcher.py—_drain_output_queuesilently consumed sentinel values (raw=None) withcontinue, making them invisible to_check_reader_done; sentinels are now put back into the queue so done flags are set correctlywatcher.py—_read_key_windowshad no timeout and would spin forever in non-interactive terminals; now uses a 60-secondmonotonicdeadline matching the existing Unixselecttimeoutpackager.py— removed unused_safe_namehelperai/gemini.py— corrected stale docstring (gemini-2.0-flash-lite→gemini-2.5-flash-lite) to match the actualDEFAULT_MODELconstant
[0.3.3] — 2026-05-29
Fixed
contextzip.aiand all subpackages were missing from the published wheel due to an incompleteincludeallowlist inpyproject.toml— replaced with auto-discovery so all current and future subpackages are captured automatically
[0.3.4] — 2026-06-21
Added
-
contextzip eod— builds a paste-ready end-of-day prompt from today's Claude/ChatGPT conversation plus whatever code changed, copied straight to the clipboard. Does no summarizing itself — that's left to whichever AI tool the prompt gets pasted into -
contextzip handoff— same pipeline, aimed at continuing a project in a fresh chat after hitting a usage limit, rather than at an end-of-day report -
Per-branch commit checkpoints (
.contextzip/markers/eod.json,.contextzip/markers/handoff.json) so every run only reports what's new since that command last ran on that branch — no manual bookkeeping, no date-based guessing -
Three-case code-change resolution per file, checked in priority order:
- Not pushed — diff against the upstream branch (covers committed- but-unpushed commits and uncommitted edits in one comparison) + the complete current file
- Diverged from Claude — diff against the version Claude last produced, matched by filename against a local artifacts folder + the complete current codebase file
- Since last run — diff against the stored marker commit, or the branch's merge-base with the default branch on a branch never tracked before + the complete current file
Brand-new untracked files skip the diff (no baseline exists) and are included as full content only
-
Best-effort fetching of Claude's artifact files for case 2, using the user's own Claude.ai session key (
contextzip config --set-session-key). Explicitly degrades gracefully — a missing key, an expired cookie, or the endpoint changing shape just skips case 2 with a warning, never fails the wholeeod/handoffrun -
contextzip config --set-session-key/--reset-session-key— manage the Claude session key alongside the existing Gemini key; defaultcontextzip confignow shows both keys' status -
Text-clipboard support (
clipboard.handle_text()) —eod/handoffproduce a prompt to paste, not a file to upload, so the existing file-clipboard tiers gained a text-mode sibling (pbcopy/xclip+xsel/clip.exe) -
exports/added to the base exclusion ruleset (next to.contextzip/) — conversation exports and fetched Claude artifacts are contextzip's own working files, never code to package or report on
Changed
packager._ensure_gitignore()generalised to accept an arbitrary entry instead of being hardcoded to.contextzip/, soexports/can register itself in.gitignorethe same way on first use
Developer Notes
- New modules:
markers.py(per-branch checkpoint storage),code_changes.py(the three-case decision tree),claude_export.py(locating the latest export, inline-vs-attach sizing),claude_artifacts.py(best-effort artifact fetching, rewritten onhttpxfor consistency withai/gemini.pyrather than introducing a second HTTP stack),brief.py(orchestrateseod/handoffend to end) git.pygained branch-aware primitives:get_current_branch(),get_default_branch()(origin/HEAD detection with fallback chain),get_merge_base(),is_ancestor(),get_upstream_branch(),diff_against()(working-tree-aware — captures committed-since-baseline and uncommitted changes in one diff),changed_files_against()- A stored marker that's no longer an ancestor of
HEAD(e.g. after a rebase) is detected viais_ancestor()and silently recomputed from the branch's merge-base, with a warning surfaced to the user rather than producing a nonsense diff claude_artifacts.pymatches Claude's flat artifact filenames against the codebase by basename only, since artifacts carry no knowledge of the repo's directory structure; ambiguous matches (same filename in multiple directories) pick the most recently modified candidate and surface a warning rather than guessing silently
[0.3.5] — 2026-08-09
Added
- Monorepo-aware framework detection. Detection now scans project_dir plus a
shallow, bounded subdirectory tree (2 levels deep), instead of only checking
the project root. A layout like
root/frontend/package.json+root/backend/requirements.txtnow correctly detects both Node.js and Python and stacks both exclusion rule sets — previously this fell through to only the universal base rules, leavingnode_modules/,.venv/, and similar unexcluded except by whatever.gitignorehappened to catch. The scan skips dependency/build directories (node_modules/,.venv/,.git/, etc.) so it never walks into a large dependency tree. Detection output now shows which subdirectory each ecosystem was found in, e.g.Next.js (frontend/) + FastAPI (backend/). - Configurable
.contextzip/workspace location, resolved in priority order:CONTEXTZIP_WORKSPACE_LOCATIONenv var → project config (.contextzip.json, committed, team-shared) → personal config (per-machine, viacontextzip config --set-workspace) → default (git-root, unchanged behavior). Accepts"git-root","cwd", or an explicit path. contextzip config --set-workspace <location>/--reset-workspace— set or clear your personal workspace location default.contextzip config(no flags) now shows the resolved workspace location and which config tier it came from.- New
.contextzip.jsonproject config file (optional, git-committed) for pinningworkspace_locationfor every contributor.
Fixed
.gitignoreregistration for the.contextzip/entry now correctly derives the git root independently, rather than assuming it's always the workspace directory's parent — a latent bug this release's configurable workspace location would otherwise have triggered (it only skips writing when the workspace is genuinely outside the repo, e.g. an absolute custom path).
Removed
eodandhandoffcommands, along with the Claude.ai session-key config option they depended on. Both relied on an undocumented Claude.ai endpoint to fetch previously-produced artifacts, which was never a stable foundation for a shipped feature.- Removed modules:
brief.py,claude_export.py,claude_artifacts.py,code_changes.py,markers.py - Removed CLI options:
contextzip config --set-session-key/--reset-session-key - Removed config keys:
claude_session_key - Also removed now-unused branch-diffing internals from
git.py(get_current_branch,get_upstream_branch,diff_against, and related helpers) that existed solely to supporteod/handoff - If you relied on
eod/handoff, there's no replacement in this release — conversation exports and per-file diff prompts will need to be built by hand, or via your own script againstcontextzip --git-changes.
- Removed modules:
[0.3.6] — 2026-08-23
Added
czCLI alias.czcan now be used as a shorthand forcontextzip, with identical commands and behavior..contextzip/project workspace. Contextzip now uses a dedicated workspace containingconfig.jsonand anoutput/directory for generated context archives.- Project configuration via
.contextzip/config.json. Added persistent project-level preferences foralways_include,always_exclude, and AI-assisted context selection. - AI configuration. Added configurable AI preferences including whether AI selection is enabled, the provider to use, and the maximum number of files AI can select.
- Configured file selection.
always_includeandalways_excludepreferences are now applied during context generation. - Configurable AI file limits. The configured
ai.max_filesvalue is now respected by the AI selection pipeline. - Legacy
.contextzip.jsondeprecation. Project configuration is moving from.contextzip.jsonto.contextzip/config.json.
Changed
- Generated context archives are now organized under
.contextzip/output/. - Contextzip configuration is now resolved through the new project configuration system while preserving the existing personal configuration for machine-specific settings and credentials.