22 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