yeet: Packaging Your Codebase for AI in One Command

March 4, 2026 5 min read

My workflow for AI-assisted development runs through the terminal. Most of what I build lives in git repositories. When I want to plan something, discuss architecture, or get a second opinion on a problem, I’ll drop into AI Studio — Gemini’s 1M context window is genuinely useful for large codebases.

The friction: I was dragging .zip files into the chat every time. Each session meant re-zipping, re-uploading, watching it land in Google Drive. And the only way to know how many tokens my project had grown to was to drop it in and check.

I wrote a bash script to handle it. The bash script grew legs and became unmaintainable. So I rewrote it properly as yeet — a Swift CLI that packages a codebase into clean AI-ready context and copies it to your clipboard. Context in your clipboard before the stats have finished printing.

The Problem with Raw Directories

When you feed a directory to an AI, you’re not feeding it your project. You’re feeding it your project plus everything that git already knows to ignore.

node_modules/. vendor/. dist/. Lock files. Build artifacts. .env files. Every binary that somehow ended up tracked.

This wastes tokens — but more importantly it makes your token count meaningless. You think you’re working with a 50K token project when 40K of that is composer dependencies. You can’t tune what you can’t measure.

bash - ~/projects/your-project
source waiting
$
your-project/
src/Controllers/BookingController.php
src/Controllers/PaymentController.php
src/Models/Booking.php
composer.json
git log -n 5
git diff --name-status HEAD
vendor/ gitignore
node_modules/ gitignore
dist/ gitignore
.env gitignore
filter idle
.gitignore 4 ignored
clipboard empty
src/Controllers/BookingController.php class BookingController extends Controller {
src/Controllers/PaymentController.php class PaymentController extends Controller {
src/Models/Booking.php class Booking extends Model {
composer.json { "name": "acme/app", "require": {
git log -n 5 <git-history><commit hash="a1b2c3d">
git diff --name-status HEAD <change status="M">src/Controllers/BookingController.php</change>
Context copied 18.4k tokens
yeet collects source plus git context, dissolves what git ignores, and formats everything into one clipboard-ready string

yeet respects your .gitignore by default. Whatever git already knows to skip, yeet skips too.

Per-Project Configuration

.gitignore gets you most of the way there, but not all the way. Some projects have directories you want to include that aren’t tracked. Others have source files you never want in context — fixtures, snapshots, generated code.

yeet looks for a .yeetconfig (TOML format) in your project root:

[defaults]
max_tokens = 8000
quiet = true

[exclude]
directories = ["node_modules", "dist", "coverage"]
patterns = ["public/**", "*.min.*"]

[include]
patterns = ["*.swift", "*.ts", "*.php"]

[token_limits]
"*.lock" = 500                  # Limit lock files
"*.min.*" = 0                   # Skip minified files
"database/migrations/**" = 800  # Limit migration files

The token_limits section lets you cap individual files rather than excluding them entirely — useful for lock files or generated code you want present but not dominating the budget. Set a limit to 0 to skip a file completely.

You configure it once per project and forget about it.

The Workflow

bash — ~/projects/your-project

The token count matters. It tells you immediately whether you’re being too broad or too narrow — and it gives you something to tune against. Too many tokens? Exclude the migrations folder. Want to add context from an external library? yeet ./src ../some-library/src and check the new total before you commit to the session.

The bar is measured against Gemini’s 1M context window. Token counts use Gemini’s SentencePiece tokenizer when available — exact counts, matching what AI Studio shows. Without it, yeet falls back to a byte approximation. Run yeet --tokenizer-status to see which mode you’re in.

When you need a per-file breakdown to find what’s eating your budget, --stats gives you that — sorted largest first, so the expensive files surface immediately:

yeet --stats   # per-file token breakdown, largest files first

This is the thing I was re-zipping files to find out. Now it’s one command.

yeet .                    # whole project, respects .gitignore + .yeetconfig
yeet ./src ./config       # specific directories only
yeet --list-only          # show what would be included, don't copy
yeet --stats              # per-file token breakdown for tuning
yeet --history-count 10   # include git history
yeet --diff               # only uncommitted changes — feed just your work to an agent or code review

Why Swift

The original bash script worked until it didn’t — slow on large projects, brittle to maintain, and increasingly painful to extend.

I wanted to rewrite it in something fast and see if I could build a clean CLI project entirely in Swift with AI assistance — iterating on tests, running commands, refining the binary from the terminal. Swift compiles to a native binary with no runtime overhead, has proper filesystem APIs, and ships cleanly via Homebrew.

The whole thing is designed around one UX constraint: clipboard copy happens first, before stats are computed. Context is in your clipboard before the token bar finishes printing — you can already paste into AI Studio while the stats are still rendering.

It also turned out to be a good test of the tool itself: using yeet to package the yeet source while developing it, watching the token count stay tight.

brew install j-shelfwood/tap/yeet

Or build from source:

git clone https://github.com/j-shelfwood/yeet
cd yeet && swift build -c release

Feeding AI Context Deliberately

The token count isn’t just a vanity metric. It changes how you work.

When you know exactly what’s in context, you can be intentional about it. The most useful pattern I’ve found: yeet your own source code alongside the library you’re integrating — not just the docs, the actual source. Drop both into AI Studio, ask it to plan the integration points and map out where things connect. Then pass that plan to an agent.

That agent has a much easier time when the implementation is already in context. It can trace through the real code rather than hallucinating based on documentation. If you task it to find integration points via string search before writing anything, it self-primes — it sees how the library actually works, not how the README says it works. The code it produces is more likely to be functional on the first pass.

That’s the core idea behind yeet: not just copying files, but curating what goes into an AI session the same way you’d curate what goes into a code review. Signal over noise, measured in tokens.


The repo is at github.com/j-shelfwood/yeet. Issues and PRs welcome.