contextzip
Package exactly the right parts of your codebase and paste it into any AI tool — in one command.
pip install contextzip
Why contextzip
Every AI session starts the same way: hunt down the relevant files, manually skip node_modules, build artifacts, and lock files, zip them, find the zip, upload it. Then do it all again next session.
contextzip eliminates that entirely. Run it from your project root — it detects your stack, applies smart exclusions, produces a lean ZIP, and opens your file manager with the archive already selected. One Ctrl+C and you're done.
Features
- Smart framework detection — automatically identifies Node.js, Next.js, Python, Django, FastAPI, Rust, Go, and Ruby, applying the right exclusion rules for each. Detection isn't limited to the project root: a shallow, bounded scan of subdirectories means a monorepo (
frontend/+backend/, etc.) gets every ecosystem it contains detected and excluded correctly, not just whatever sits at the top level - Respects
.gitignore— your existing ignore patterns are honoured automatically - Git-aware packaging — use
--git-changesto package only modified, staged, and untracked files; perfect for incremental debugging and PR review sessions - AI-powered file selection — describe your task in plain English with
--promptand Gemini selects the minimum relevant files automatically, no manual hunting required - Terminal error watcher — wrap any dev server with
contextzip watchto auto-detect errors and package a ready-to-upload debug context in one keypress - Configurable workspace location —
.contextzip/lives at the git root by default, but you can pin it elsewhere per-machine (contextzip config --set-workspace) or for the whole team via a committed.contextzip/config.json - Visual config UI —
contextzip config --uiopens a local browser tab to set include/exclude by clicking through your actual file tree, with live counts and one-click suggestions for PDFs, media, and other non-code files — nothing leaves your machine - Persistent workspace — all generated ZIPs land in
.contextzip/output/, discoverable, reusable, and git-ignored automatically - Warns before it's a problem — flags large (≥ 1 MB) and binary files that AI tools can't read, before you waste an upload
- Handles edge cases — dangling symlinks, unreadable files, and paths outside the project tree are caught and reported, never silently dropped
- Full CLI control —
--include,--exclude,--dry-run,--output, all composable
Installation
Requires Python 3.9+
pip install contextzip
With pipx (recommended for CLI tools — keeps it isolated):
pipx install contextzip
Verify:
contextzip --version
Quick start
Navigate to any project and run:
cd ~/projects/my-app
contextzip
contextzip will:
- Detect your framework (e.g.
Next.js + Node.js) - Apply the appropriate exclusion rules
- Create a compressed ZIP in
.contextzip/output/at your project root - Open your file manager with the ZIP selected and ready to copy
Usage
contextzip [OPTIONS]
czis a shorthand alias forcontextzip— both commands are identical and support every option and subcommand shown below (e.g.cz --git-changes,cz exclude node_modules).
| Option | Description |
|---|---|
-p, --prompt TEXT |
Describe your task in plain English — Gemini selects only the relevant files |
-i, --include PATH |
Only include files under this path (repeatable) |
-e, --exclude PATTERN |
Add exclusion patterns in gitignore syntax (repeatable) |
--git-changes |
Only include files reported by git as modified, staged, or untracked |
-n, --dry-run |
Preview what would be included without creating a ZIP |
-o, --output FILE |
Write ZIP to a custom path |
-v, --verbose |
Show every included and excluded file with sizes |
--no-clipboard |
Skip the clipboard / folder-open step |
--no-gitignore |
Ignore the project's .gitignore |
Subcommands: exclude, include, watch, config — run contextzip --help for full details.
Examples
# Preview what would be packaged
contextzip --dry-run --verbose
# Package only specific directories
contextzip --include src --include app
# Exclude additional patterns
contextzip --exclude "*.log" --exclude "tests/"
# Package only git-modified files
contextzip --git-changes
# Let AI pick only the files relevant to your task
contextzip --prompt "Change toast color on failed login"
# Preview AI file selection without creating a ZIP
contextzip --prompt "Refactor auth middleware" --dry-run
# Save to a custom path
contextzip --output ~/Desktop/project-context.zip
Python API
contextzip is also usable as a library. All CLI capabilities are available as plain Python functions — no Click, no Rich output, no SystemExit.
from contextzip import get_git_changes, get_files, create_zip
# Get changed files and use them directly
collection = get_git_changes()
for f in collection.files: # plain pathlib.Path objects
upload(f) # no zip required
# Or zip them and upload the archive
pkg = create_zip(collection, output="/tmp/changes.zip")
with open(pkg.zip_path, "rb") as f:
upload_to_s3(f)
# Full project scan with filters
collection = get_files(include=["src/"], exclude=["tests/"])
pkg = create_zip(collection, output="/tmp/upload.zip")
print(f"{pkg.file_count} files, {pkg.compressed_bytes} bytes")
| Function | Description |
|---|---|
get_git_changes(path?) |
Modified, added, and untracked files from git |
get_files(path?, include?, exclude?) |
All project files after exclusion rules |
create_zip(collection, output?) |
Write a FileCollection to a ZIP archive |
detect_ecosystem(path?) |
Detect framework and confidence level |
All functions default path to Path.cwd(). Errors raise typed exceptions (NotARepositoryError, GitNotFoundError, NoFilesError, etc.) rather than exiting.
AI-powered file selection
The --prompt flag lets you describe a task in plain English. contextzip scans your project, builds a lightweight file map, and asks Gemini to return the minimum set of files needed for that task — typically 2–5, never more than 10. The result is a tightly scoped ZIP with only what you'd actually open to make the change.
contextzip --prompt "Change toast color on failed login"
# → components/ui/toast.tsx, app/login/page.tsx, lib/auth.ts
The ZIP also includes a prompt.txt describing the task, so when you drop it into Claude, ChatGPT, or any other AI tool, it immediately understands what you're trying to do.
First-time setup: --prompt requires a free Gemini API key from Google AI Studio — no credit card needed. On first use, contextzip guides you through obtaining and saving one. You can also skip the setup entirely with an environment variable:
export GEMINI_API_KEY=AIza...
Manage your key at any time:
contextzip config # show current key status
contextzip config --reset-key # clear and re-run setup
Terminal error watcher
The watch command wraps your dev server, buffers its output, and packages a debug-ready ZIP the moment you spot an error — no manual file hunting, no copy-pasting stack traces.
contextzip watch -- npm run dev
contextzip watch -- python manage.py runserver
contextzip starts your process normally. You see output exactly as you would without it. In the background, it watches the stream for errors. When one is detected, a prompt appears directly beneath the error output:
╭─ contextzip · error detected ─────────────────────╮
│ Press [D] to package debug context [S] to skip │
╰───────────────────────────────────────────────────╯
Press D and contextzip immediately writes .contextzip/output/debug-context.zip. Your server keeps running — no restart, no interruption.
What's in the ZIP:
| File | Contents |
|---|---|
prompt.txt |
Auto-generated: detected framework, error type, and task description — ready to paste into any AI tool |
terminal-error.txt |
The cleaned, noise-stripped error block and stack trace |
source-files.zip |
Source files referenced in the stack trace, paths preserved |
On Ctrl+C: If no errors were packaged during the session, contextzip offers one final prompt to capture the full session output — useful when something looked wrong but didn't match a known error pattern.
Supported frameworks: Python, Django, FastAPI, Node.js, Next.js, React. Each has its own error detection patterns and noise filters so the output stays clean across stacks.
Note:
watchworks best with dev servers that don't read stdin interactively (npm run dev,manage.py runserver, etc.). PTY emulation is not used — on Windows, color passthrough may be limited.
What gets excluded
contextzip stacks exclusion rules based on your detected stack, on top of your .gitignore.
Always excluded: .git/, .env files, logs, caches, editor config (.vscode/, .idea/), OS files (.DS_Store, Thumbs.db), common binary formats, and contextzip's own .contextzip/ working folder.
By framework:
| Stack | Additional exclusions |
|---|---|
| Node.js / Next.js | node_modules/, .next/, dist/, build/, lock files, *.min.js, *.d.ts |
| Python / Django / FastAPI | __pycache__/, .venv/, *.pyc, migrations/, .pytest_cache/, lock files |
| Rust | target/, Cargo.lock, *.rlib |
| Go | vendor/, go.sum, bin/ |
Detection is additive — a monorepo with both package.json and pyproject.toml gets both rule sets applied. Marker files don't have to sit at the project root: contextzip also does a shallow, bounded scan of subdirectories (2 levels deep, skipping node_modules/, .venv/, .git/, and other dependency/build dirs it would never want to look inside anyway), so a layout like
root/
frontend/package.json
backend/requirements.txt
detects both Node.js and Python from root/, without either marker existing at the top level. Run with default output (not --dry-run --verbose) and you'll see which subdirectory each ecosystem came from, e.g. Next.js (frontend/) + FastAPI (backend/).
Workspace location
By default, .contextzip/ is created at your git root — that's _find_git_root() walking up from the current directory until it finds a .git folder; outside a repo, it falls back to the current directory. This can be overridden two ways, in order of priority:
CONTEXTZIP_WORKSPACE_LOCATIONenvironment variable — for a one-off override on a single run- A committed
.contextzip/config.jsonat the project root — team-shared, applies to everyone who clones the repo:{ "workspace_location": "git-root" }
- Your personal config — a per-machine default that doesn't get committed:
contextzip config --set-workspace cwd # always use ./.contextzip wherever you run it contextzip config --set-workspace git-root # back to the default contextzip config --set-workspace ~/zips # a fixed custom location, anywhere contextzip config --reset-workspace # clear your personal override
Accepted values are "git-root", "cwd", or any path (absolute, or relative to the git root). Run contextzip config with no flags to see which value is currently active and where it came from.
This matters most for monorepos where you sometimes run contextzip from a subdirectory (cd frontend && contextzip) — with the default git-root setting, the workspace still lands at the repo root no matter where you ran it from, so you don't end up with scattered .contextzip/ folders across frontend/, backend/, etc. Set workspace_location: "cwd" in a project's .contextzip/config.json instead if you'd rather each subproject keep its own.
Project configuration
Every project gets a .contextzip/ workspace at the project root:
.contextzip/
├── config.json # project preferences — commit this
├── .gitignore # keeps output/ untracked, config.json trackable
└── output/ # generated ZIPs — never committed
├── codebase.zip
├── changes.zip (--git-changes)
└── debug-context.zip (contextzip watch)
.contextzip/ is not committed to Git by default — .contextzip/.gitignore is written automatically the first time you run contextzip in a repo, and it ignores everything in the folder except config.json and itself. That's deliberate: output/ is per-machine, disposable scratch space, while config.json holds team-shared preferences you'll usually want everyone on the same page about.
config.json currently supports:
{
"workspace_location": "git-root",
"scan_depth": null,
"always_include": [],
"always_exclude": [],
"ai": {
"enabled": true,
"provider": "gemini",
"max_files": 10
}
}
All keys are optional — start with just the ones you need.
| Key | What it does |
|---|---|
workspace_location |
Same as contextzip config --set-workspace, but team-shared. See Workspace location. |
scan_depth |
Reserved for a future bounded-depth scan mode. |
always_include |
A standing "force include" list (gitwildmatch patterns). Files matching it are packaged even if an auto-rule or .gitignore would otherwise exclude them — e.g. ["docs/architecture.md"] to always pull in a doc that lives in an otherwise-excluded folder. |
always_exclude |
A standing exclusion list, applied on every run without retyping -e/--exclude. |
ai.enabled |
Set to false to disable --prompt entirely for this project; contextzip will refuse with a clear message instead of silently ignoring it. |
ai.provider |
Reserved for future AI providers. Only "gemini" is currently supported. |
ai.max_files |
Caps how many files --prompt mode may return, for both the Gemini and keyword-heuristic paths. |
always_include/always_exclude are additive on top of --include/--exclude for that run — an explicit contextzip include PATH still has the final say over what's actually packaged. Persistent preferences belong in config.json rather than an ever-growing list of CLI flags; CLI flags stay for one-off, explicit actions (--dry-run, --prompt "…", --output FILE, etc.).
You don't have to hand-write config.json — see Visual config UI below for a point-and-click way to produce it.
Deprecation: .contextzip.json
Earlier versions of contextzip read a .contextzip.json file at the project root for workspace_location/scan_depth. That file is now deprecated in favor of .contextzip/config.json — contextzip still reads it automatically if .contextzip/config.json doesn't exist yet (so nothing breaks), and prints a one-time reminder to migrate. To migrate, just move its contents into the "workspace_location"/"scan_depth" keys of a new .contextzip/config.json and delete the old file.
~/.config/contextzip/config.json (your personal, per-machine config — API key, personal workspace override) is unrelated and unaffected by any of this.
Visual config UI
contextzip config --ui
Opens a local browser tab for setting always_include/always_exclude by clicking through your actual file tree instead of hand-writing patterns — live file counts and packed size update as you go, and one-click chips suggest excluding things like PDFs, office docs, fonts, media, or anything over 1MB that isn't already covered by contextzip's default rules.
It's also offered automatically the first time you run contextzip in a project that has no config at all:
$ contextzip
╭─────────────────────────╮
│ contextzip v0.3.5 │
╰─────────────────────────╯
...
╭─ First run ─────────────────────────────────────╮
│ No project config found yet. │
│ contextzip can open a local browser tab... │
╰───────────────────────────────────────────────────╯
Set up include/exclude visually now? [Y/n]:
Decline once and it won't ask again (run contextzip config --ui any time you want it). It's also skipped automatically for non-interactive runs, when CI is set, or when --prompt/--output are passed — it only ever offers on a plain, interactive, first-ever run.
Nothing about your project leaves your machine. The server binds to 127.0.0.1 only (never 0.0.0.0), every request needs a random per-session token embedded in the URL (the same approach Jupyter Notebook uses), and the page itself makes no calls anywhere except back to that local server — no CDN scripts, no web fonts, no analytics. Saving writes straight to .contextzip/config.json on disk and the server shuts itself down; if you close the tab without saving, it also shuts down after a short idle period so a forgotten session doesn't linger as an open port.
If you accept the first-run offer, the same contextzip invocation picks up whatever you saved and finishes packaging immediately — no need to run it again.
Contributing
Contributions are welcome — especially new framework rule sets, edge case fixes, and platform-specific clipboard improvements.
See CONTRIBUTING.md for local setup, how to add a new framework, and PR guidelines. Please open an issue before starting a large PR so we can align on the approach first.
License
MIT — see LICENSE for details.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file contextzip-0.3.7.tar.gz.
File metadata
- Download URL: contextzip-0.3.7.tar.gz
- Upload date:
- Size: 94.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f6adb7f04eb798826362a46256b8454b2d199110be0b17f729152f9a2c4a3dce
|
|
| MD5 |
3f76429b8df4cf085a131a52574f2b5b
|
|
| BLAKE2b-256 |
c7fabd876706f98e4386770a539ee3e98bd3e588c2f90ad50b0298f311d354f7
|
Provenance
The following attestation bundles were made for contextzip-0.3.7.tar.gz:
Publisher:
python-publish.yml on akadeepesh/contextzip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
contextzip-0.3.7.tar.gz -
Subject digest:
f6adb7f04eb798826362a46256b8454b2d199110be0b17f729152f9a2c4a3dce - Sigstore transparency entry: 2576258465
- Sigstore integration time:
-
Permalink:
akadeepesh/contextzip@a840e7fbc0280db2cc919a3a2839126a9bc80b23 -
Branch / Tag:
refs/tags/v0.3.7 - Owner: https://github.com/akadeepesh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@a840e7fbc0280db2cc919a3a2839126a9bc80b23 -
Trigger Event:
release
-
Statement type:
File details
Details for the file contextzip-0.3.7-py3-none-any.whl.
File metadata
- Download URL: contextzip-0.3.7-py3-none-any.whl
- Upload date:
- Size: 101.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5e859d7cf5a9d5eef41799858864a7c879f964b737b3f1e3b4004807a3c916d
|
|
| MD5 |
6d9e03afaabf13b51c72e645ef8a5c8e
|
|
| BLAKE2b-256 |
6a3c65914699a30710bacc8cd6826306463208c9cef3dbf29fa1169ce8914e4b
|
Provenance
The following attestation bundles were made for contextzip-0.3.7-py3-none-any.whl:
Publisher:
python-publish.yml on akadeepesh/contextzip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
contextzip-0.3.7-py3-none-any.whl -
Subject digest:
a5e859d7cf5a9d5eef41799858864a7c879f964b737b3f1e3b4004807a3c916d - Sigstore transparency entry: 2576258559
- Sigstore integration time:
-
Permalink:
akadeepesh/contextzip@a840e7fbc0280db2cc919a3a2839126a9bc80b23 -
Branch / Tag:
refs/tags/v0.3.7 - Owner: https://github.com/akadeepesh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@a840e7fbc0280db2cc919a3a2839126a9bc80b23 -
Trigger Event:
release
-
Statement type: