Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: test

on:
push:
pull_request:

jobs:
unit-tests:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Run unit tests
run: python -m unittest discover -s tests -v
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.contextzip/
__pycache__/
*.py[cod]
.pytest_cache/
.mypy_cache/
.ruff_cache/
.DS_Store
158 changes: 158 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,159 @@
# ContextZIP

Prepare a local project for ChatGPT web without rewriting its files.

ContextZIP is a lightweight Codex skill that copies the project files you choose into a flat, drag-and-drop upload folder. The copied file contents stay byte-for-byte identical to the originals. ContextZIP does not summarize, concatenate, compress, or send files to an API.

## Why

Local coding agents are convenient for editing a repository, while ChatGPT web can be convenient for longer design discussions, debugging, research, and review. Moving the relevant project context between those environments is usually manual and error-prone.

ContextZIP turns this:

```text
my-project/
├── README.md
├── src/
│ └── retrieval/
│ └── router.py
├── tests/
│ └── test_router.py
└── papers/
└── bright.pdf
```

into this:

```text
my-project/.contextzip/upload/
├── README.md
├── src__retrieval__router.py
├── tests__test_router.py
└── papers__bright.pdf
```

The files can then be selected together and dragged into a ChatGPT conversation or project.

Directory separators become `__`. Extensionless files such as `Dockerfile` receive a `.txt` suffix for web upload compatibility. Only the output filename changes; the file bytes do not.

## Core principles

- **Original contents only** - copied files are verified byte-for-byte.
- **No wrapper tokens** - no XML, Markdown fences, generated summaries, or concatenation.
- **Local only** - no API key, hosted service, or automatic upload.
- **Deterministic** - selection uses paths, Git metadata, ignore rules, and explicit options rather than an LLM reading every file.
- **Safe by default** - common secrets, generated folders, symlinks, and oversized files are blocked or skipped.

ContextZIP reduces packaging overhead. It does not compress the original text tokens inside a file.

## Install as a Codex skill

Clone the repository into your Codex skills directory:

```bash
git clone https://github.com/junjunjunbong/ContextZIP.git ~/.codex/skills/contextzip
```

Restart Codex if the skill is not discovered immediately.

## Use

In Codex:

```text
$contextzip
```

Useful variations:

```text
$contextzip Prepare all eligible files in this project for ChatGPT web.
$contextzip Prepare only my current Git changes and the root context files.
$contextzip Dry-run first and do not open Finder.
```

The skill creates:

```text
<project>/.contextzip/
├── upload/ # drag these files into ChatGPT
└── manifest.json # local mapping and integrity record; not uploaded by default
```

## Direct script use

The script uses only the Python standard library and requires Python 3.10 or later.

Preview all eligible files:

```bash
python3 scripts/pack.py --root /path/to/project --mode all --dry-run
```

Create a pack:

```bash
python3 scripts/pack.py \
--root /path/to/project \
--mode all \
--max-files 40 \
--open
```

Create a smaller pack from current Git changes plus root context files:

```bash
python3 scripts/pack.py \
--root /path/to/project \
--mode current \
--max-files 40 \
--open
```

Use `--help` for all options.

## Selection behavior

When the project is a Git repository, ContextZIP uses Git to collect tracked files and unignored untracked files. This respects `.gitignore` without implementing a second ignore parser.

`--mode all` selects every eligible file.

`--mode current` selects files changed relative to `HEAD`, untracked files, and a small set of root context files such as `README.md`, `AGENTS.md`, `pyproject.toml`, and `package.json`.

Common generated directories are excluded, including:

```text
.git, .contextzip, node_modules, .venv, venv, __pycache__,
dist, build, target, .next, coverage, and common tool caches
```

Common sensitive paths are blocked, including `.env*`, private keys, credential files, and service-account secrets. This is a path-based guardrail, not a full content secret scanner. Review the output before uploading it.

## Supported files

The default allowlist covers common source code, configuration, text, research, office, notebook, and PDF formats. Use repeated `--include` patterns to include additional paths explicitly, and repeated `--exclude` patterns to remove paths.

Examples:

```bash
python3 scripts/pack.py --root . --include 'notes/**' --include '*.log'
python3 scripts/pack.py --root . --exclude 'outputs/**' --exclude '**/fixtures/**'
```

Explicit includes do not override the sensitive-file blocklist.

## What ContextZIP intentionally does not do

- It does not summarize or rewrite files.
- It does not concatenate a repository into one generated document.
- It does not semantically rank files with an LLM.
- It does not upload anything to ChatGPT automatically.
- It does not claim to reduce the token count of the original file contents.

## Development

Run the tests with:

```bash
python3 -m unittest discover -s tests -v
```
73 changes: 73 additions & 0 deletions SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
name: contextzip
description: Prepare a local project for ChatGPT web by copying selected original files byte-for-byte into a flat upload folder. Use when the user wants to move project context from Codex or another local workspace into ChatGPT, create a drag-and-drop context pack, or avoid concatenating and summarizing project files.
---

# ContextZIP

Create a lightweight upload pack from the current local project.

## Core contract

- Never summarize, concatenate, compress, normalize, or rewrite source file contents.
- Do not read file bodies to decide relevance unless the user explicitly requests content-based selection.
- Prefer path names, extensions, Git status, `.gitignore`, file sizes, and explicit user scope.
- Copy selected files byte-for-byte into a flat output directory.
- Keep `manifest.json` outside the upload directory so it does not add context unless the user chooses to upload it.
- Never upload files automatically.
- Never bypass the sensitive-path blocklist unless the user explicitly edits the script themselves.

## Workflow

1. Determine the project root.
- Prefer `git rev-parse --show-toplevel` when available.
- Otherwise use the current working directory.
2. Resolve `scripts/pack.py` relative to this `SKILL.md` file.
3. Choose a mode.
- Use `current` when the user says current, changed, recent, debug, or working files.
- Otherwise use `all`.
4. Run a dry-run first with a 40-file upload budget unless the user specifies another limit.

```bash
python3 <skill-directory>/scripts/pack.py \
--root <project-root> \
--mode <all-or-current> \
--max-files 40 \
--dry-run
```

5. If `all` exceeds the file budget and the user did not explicitly request every file, retry the dry-run with `--mode current`.
6. Do not silently truncate files. If the selected mode still exceeds the requested budget, report the count and ask the user to narrow the scope or provide include/exclude patterns.
7. Create the pack. Open the output folder unless the user asks not to.

```bash
python3 <skill-directory>/scripts/pack.py \
--root <project-root> \
--mode <all-or-current> \
--max-files 40 \
--open
```

8. Report:
- selected and copied file counts
- skipped and blocked counts
- total copied bytes
- output directory
- whether integrity verification passed

## Output

```text
<project-root>/.contextzip/
├── upload/
│ ├── README.md
│ ├── src__router.py
│ └── tests__test_router.py
└── manifest.json
```

The flattened filename encodes the original relative path with `__`. Extensionless files receive a `.txt` suffix for web upload compatibility. The manifest records the exact source-to-output mapping and SHA-256 hashes.

## Important interpretation

ContextZIP avoids generated wrapper text and unnecessary files. It does not compress or reduce the original tokens inside selected files. Describe the benefit as low-overhead context packaging, not token compression.
Loading
Loading