Skip to main content

Context digests for AI agents and humans. Snap, patch, ship.

This project has been archived.

The maintainers of this project have marked this project as archived. No new releases are expected.

Project description

Chuck

Give any agent or human the right context at the right time, and know when that context has changed.

Chuck is a standalone Python library and CLI that sits between raw project files and whatever consumes them — LLMs, agents, pipelines, humans. It ingests files, tracks changes, and produces clean, token-aware context digests in markdown, XML, or JSON.

Chuck is not a framework. No daemon, no server, no background process. Think of it like .gitignore — a simple standard anyone can adopt.

pip install chucky

chuck init
chuck snap | claude "review this codebase"

# ... make changes ...

chuck patch | claude "fix the bug in auth.py"

Why Chuck

Every AI-assisted workflow has the same bottleneck: context. Agents need to know what files exist, what changed, what matters, and how much fits in their window. Chuck is the standard.

  • Agnostic. No dependency on Claude, GPT, Ollama, Cursor, or any specific tool.
  • Standalone. pip install chuck. No daemon, no server, no background process.
  • Two speeds. snap for full baseline, patch for delta. The model always gets the right amount of context.
  • Persistent by convention. State lives in .chuck/ at the project root. Delete it and Chuck starts fresh. Commit it and your team shares context state.

Install

pip install chucky

Python 3.9+ required. No required dependencies — tiktoken is optional (falls back to a word-based estimator).

pip install "chucky[tiktoken]"  # For accurate token counting with cl100k_base

Core Workflow

Chuck uses a two-speed model:

  • snap — full baseline. Saves the current state and emits full context to stdout. Use after significant changes.
  • patch — partial delta. Emits only what changed since the last snap, without moving the baseline. Use for small iterative changes before prompting a model.
# First time — model gets the full picture
chuck snap | claude "review this codebase"

# Small changes — model gets only the delta
chuck patch | claude "fix the bug in auth.py"

# Silent snap for git hooks / CI
chuck snap --quiet

Concepts

Concept Description
Instance A directory tracked by Chuck. Created with chuck init.
Snap Full baseline snapshot. Saves state and emits complete context.
Patch Delta since the last snap. Emits only what changed; baseline unchanged.
Chunk A section of content sized to fit within a token budget.

The Git Mental Model

The directory is the context. Each directory that needs tracking gets its own chuck init, producing its own .chuck/ folder. There are no named contexts to define.

chuck init          # tracks everything here, no patterns needed

Use .chuckignore to exclude what you don't want:

# .chuckignore — same syntax as .gitignore
dist/
*.log
secrets.env

For a monorepo, initialize each subdirectory independently and ignore overlaps:

my-app/           ← chuck init (tracks README, root config, etc.)
my-app/backend/   ← chuck init (tracks backend only)
my-app/frontend/  ← chuck init (tracks frontend only)

Root .chuckignore:

/frontend/
/backend/

CLI Quickstart

# 1. Initialize
chuck init

# 2. Take a full snapshot (baseline) — outputs full context to stdout
chuck snap

# 3. Work on files...

# 4. Get only the delta — outputs changes to stdout
chuck patch

# 5. Check what changed (metadata only, no content)
chuck diff

# 6. Show instance status
chuck status

All CLI Commands

Command Description
chuck init [path] Initialize .chuck/ in a directory
chuck snap [path] Full baseline snapshot — saves and emits to stdout
chuck patch [path] Delta since last snap — emits to stdout, baseline unchanged
chuck diff [path] Show change summary (files/tokens) without emitting content
chuck status [path] Show instance metadata
chuck ls [path] List all Chuck instances found under a path
chuck reset [path] Clear snapshot history
chuck integrate <agent> [path] Generate agent-specific integration files

All [path] arguments default to the current directory.

Common Flags

chuck snap --quiet          # save only, no stdout output (for git hooks, CI)
chuck snap --format xml     # XML output instead of markdown
chuck snap --format json    # JSON output
chuck snap --budget 4000    # chunk output to fit token budget

chuck patch --quiet         # write patch.md only, no stdout
chuck diff --json           # machine-readable diff

Auto-snap Threshold

If the diff grows beyond a configurable threshold, patch automatically promotes to snap before outputting. The user never has to think about it.

// .chuck/config.json
{
  "settings": {
    "auto_snap_threshold": {
      "files": 10,
      "tokens": 2000
    }
  }
}

When auto-promoted, Chuck notifies on stderr:

auto-snapped: diff exceeded threshold. new baseline set.

Agent Integrations

Chuck generates thin integration glue per agent on request:

chuck integrate claude   # appends a Chuck section to CLAUDE.md
chuck integrate goose    # writes .goose/context.md
chuck integrate agents   # writes AGENTS.md (generic)

The generated content tells the agent where Chuck's state and patch files are and how to use them.


Aider Integration

Chuck ships two tools for seamless Aider sessions — no manual /read steps, no git requirement.

chuck-aider — launch Aider with Chuck context

chuck-aider                             # auto-selects patch.md or manifest.json
chuck-aider --model claude-sonnet-4-6  # all flags forwarded to aider

Before handing off to Aider, chuck-aider prints which file was loaded:

chuck-aider: loading patch → /path/to/.chuck/patch.md

Context selection logic:

Condition File passed to Aider
≤ 20 files changed AND patch.md ≤ 2000 words .chuck/patch.md
> 20 files changed OR patch.md too large .chuck/manifest.json
patch.md absent .chuck/manifest.json

Override the file-count threshold via env var:

CHUCK_AIDER_PATCH_THRESHOLD=10 chuck-aider

chuck-aider-init — generate .aider.conf.yml

chuck-aider-init

Writes .aider.conf.yml at the Chuck root:

# .aider.conf.yml — generated by chuck-aider-init
read:
  - .chuck/patch.md
auto-commits: false
gitignore: false

After chuck-aider-init runs, plain aider picks up Chuck context automatically on every subsequent invocation. Re-running overwrites with current values (idempotent).

If the project is a git repo, chuck-aider-init also appends .aider* and .chuck/ to .gitignore.


Python API

import chuck

# Initialize
c = chuck.init(".")

# Full snapshot — saves baseline and returns digest
digest = c.snap()                           # str
digest = c.snap(format="xml")              # XML format
digest = c.snap(budget=4000)               # list[str] if chunked
c.snap(quiet=True)                         # save only, no output

# Delta since last snap
output, auto_snapped = c.patch()           # (str, bool)
c.patch(quiet=True)                        # write patch.md only

# Diff metadata (no content)
diff = c.diff()
print(f"Changed: +{len(diff.added)} -{len(diff.removed)} ~{len(diff.modified)}")
print(f"Token delta: {diff.tokens_changed:+d}")

# Status
status = c.status()
print(f"Files: {status['file_count']}, Tokens: {status['total_tokens']:,}")

# Find all instances
instances = chuck.Chuck.ls(".")

# Reset
c.reset()

# Agent integration
written = c.integrate("claude")   # returns dict of paths written

Output Formats

Markdown (default)

# Context: my-project
## Snapshot: 2026-03-02T10:00:00Z | Files: 12 | Tokens: 3,847

### src/main.py (142 tokens)
​```python
[file content]
​```

XML

<chuck context="my-project" snapshot="2026-03-02T10:00:00Z" total_files="12" total_tokens="3847">
  <file path="src/main.py" tokens="142">
    <content><![CDATA[file content]]></content>
  </file>
</chuck>

JSON

{
  "context": "my-project",
  "snapshot": "2026-03-02T10:00:00Z",
  "files": [
    {"path": "src/main.py", "tokens": 142, "content": "..."}
  ],
  "meta": {"total_files": 12, "total_tokens": 3847}
}

Token Budget and Chunking

When content exceeds the token budget, Chuck splits into independent chunks:

chuck snap --budget 4000
result = c.snap(budget=4000)
if isinstance(result, list):
    for chunk in result:
        send_to_llm(chunk)
else:
    send_to_llm(result)

.chuck/ Folder Structure

Chuck stores metadata only — never copies of your files.

.chuck/
├── config.json        # Settings (auto_snap_threshold, etc.)
├── state.json         # Always-current lightweight state
├── patch.md           # Always-current delta content
├── manifest.json      # Latest full snapshot
└── snapshots/
    ├── 2026-03-02T10-00-00Z.json
    └── ...

state.json — machine-readable status for agent tools:

{
  "last_snap": "2026-03-02T10:00:00Z",
  "files": 42,
  "tokens": 8432,
  "changes_since_snap": { "files": 3, "tokens_delta": 210 },
  "paths": {
    "snap": ".chuck/manifest.json",
    "patch": ".chuck/patch.md"
  }
}

patch.md — always-current delta content. Agent models read this on demand instead of receiving content in every prompt.


Two Output Modes

Stdout (non-agent models) — default. Content piped directly into prompts.

chuck patch | llm "fix the auth bug"
chuck snap  | llm "review this codebase"

Files on disk (agent models) — agent reads files via tool calls on demand.

chuck patch --quiet  # writes .chuck/patch.md, no stdout
chuck snap --quiet   # writes .chuck/manifest.json, no stdout

Usage Patterns

Two-speed workflow

chuck snap          # Baseline before a big change
# ... refactor ...
chuck snap          # New baseline after the refactor

# ... small fix ...
chuck patch | claude "review my change"

Git hooks

# .git/hooks/post-commit
chuck patch --quiet

CI/CD

- name: Snapshot baseline
  run: chuck snap --quiet

- name: Run tests and build
  run: make test build

- name: Get changes for AI review
  run: chuck patch --format json > /tmp/patch.json

- name: AI review
  run: cat /tmp/patch.json | your-ai-review-tool

Monorepo

chuck snap backend    # full baseline for backend
chuck patch frontend  # delta for frontend
chuck ls .            # show all instances

.chuckignore

Uses gitignore syntax:

# .chuckignore
dist/
*.log
secrets.env
node_modules/

Default patterns (always applied):

.git/
.chuck/
node_modules/
__pycache__/
*.pyc
.env
.env.*

Development

git clone https://github.com/chuck-context/chuck
cd chuck
pip install -e ".[dev]"
pytest

Project structure

chuck/
├── pyproject.toml
├── chuck_aider.py        # chuck-aider entry point
├── chuck_aider_init.py   # chuck-aider-init entry point
├── src/
│   └── chuck/
│       ├── __init__.py   # Public API
│       ├── core.py       # Chuck class — main orchestrator
│       ├── snapshot.py   # Snapshot creation and diffing
│       ├── digest.py     # Digest generation and formatting
│       ├── chunker.py    # Token-aware content chunking
│       ├── tokens.py     # Token counting (tiktoken + fallback)
│       ├── ignore.py     # .chuckignore parser
│       ├── hasher.py     # File hashing (SHA-256)
│       ├── context.py    # File resolution utilities
│       └── cli.py        # CLI entry point
├── tests/                # 144 tests covering all modules
└── examples/

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chucky-1.0.0.tar.gz (112.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chucky-1.0.0-py3-none-any.whl (28.8 kB view details)

Uploaded Python 3

File details

Details for the file chucky-1.0.0.tar.gz.

File metadata

  • Download URL: chucky-1.0.0.tar.gz
  • Upload date:
  • Size: 112.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for chucky-1.0.0.tar.gz
Algorithm Hash digest
SHA256 fee621d647b6e68234f22c1be8528683eab3855c36bab6754a4339770f79dfa1
MD5 f92b54e2b62a61cdecbc2c68ed157c70
BLAKE2b-256 2576529f560c0f68d9dde36d91dfef73cdb65c3cca05b4b7738d59762a70e9ea

See more details on using hashes here.

File details

Details for the file chucky-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: chucky-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 28.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for chucky-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1597e6d41c340b2c475774052bbb32bff054e12d796a764ae3695b940d32764b
MD5 48fc936b741f0d857114c5894211509c
BLAKE2b-256 76482ea75899fdabe42d6b988c219db66a901f60a6445bbd4cf490ed4171e138

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page