{"slug": "i-built-ctxstash-pack-a-codebase-into-one-llm-ready-file-with-a-token-count", "title": "I built ctxstash: pack a codebase into one LLM-ready file, with a token count", "summary": "A developer built ctxstash, a zero-dependency command-line tool that packs a codebase into a single Markdown file with a token count estimate, making it easier to share code with LLMs like ChatGPT and Claude. The tool is available on both npm and PyPI, supports file filtering, and automatically excludes junk files like node_modules and binary artifacts.", "body_md": "You're debugging something with ChatGPT, Claude, or Cursor, and you hit the wall every developer knows: the model needs to *see* your code. So you start the dance — open a file, copy, paste, type \"and here's the other file\", paste again, label it so the model doesn't get confused… five files later you paste the whole thing and get back **\"this conversation is too long.\"** Now you're trimming blind, with no idea how many tokens you actually sent.\n\nI got tired of doing this by hand, so I built **ctxstash**: one command that walks a directory and emits a single, tidy Markdown document with every file fenced and language-tagged, a file-tree overview at the top, and an approximate token count so you know up front whether it'll fit.\n\n```\nnpx ctxstash src > context.md\n✓ packed 23 files · 142.3 KB · ~38,210 tokens\n```\n\nPaste `context.md`\n\ninto the model. Done.\n\nThere's a great Python tool, `files-to-prompt`\n\n, that inspired this — but it's Python-only and doesn't estimate tokens. I wanted something with **zero dependencies**, a **token estimate built in**, and an **identical build on both npm and PyPI** so it doesn't matter which ecosystem you live in.\n\n```\nctxstash .                      # pack the current dir to stdout\nctxstash src tests -o ctx.md    # pack two dirs, write to a file\nctxstash . -i \"*.ts,*.tsx\"      # only TypeScript\nctxstash . -e \"*.test.js\"       # drop tests\nctxstash . --estimate           # just tell me the token cost, pack nothing\nctxstash src --tree             # just the file tree\n```\n\n`--estimate`\n\nis the one I reach for most — it answers \"will this fit in the context window?\" without producing a wall of text:\n\n```\nfiles    23\nsize     142.3 KB\n~tokens  38,210 (estimate, ~4 chars/token)\n\nlargest by tokens\n     ~6,210  src/bundle.ts\n     ~3,180  src/core.ts\n     ...\n```\n\nThe packed output looks like this:\n\n```\n# Repository context\n\n> Packed by ctxstash — 3 files, 4.1 KB, ~1,040 tokens (estimate).\n\n## File tree\n\nsrc/\n  core.ts\n  cli.ts\nREADME.md\n\n## Files\n\n### src/core.ts\n...fenced, language-tagged contents...\n```\n\nBy default it **skips the junk automatically** — `node_modules`\n\n, `.git`\n\n, `dist`\n\n, lockfiles, minified bundles, and binary files (images, fonts, compiled artifacts) never end up in your context. The summary always goes to **stderr**, so `ctxstash > context.md`\n\nkeeps the file clean while you still see the count.\n\n```\nnpx ctxstash .          # Node ≥ 18, nothing to install\npip install ctxstash    # Python ≥ 3.8\n```\n\nBoth builds are **zero-dependency** and behavior-identical.\n\n`````\n\nrun (hello, every Markdown file), ctxstash wraps it in a `.txt`\n\nname still gets skipped.`npx`\n\n/`pip install`\n\nand go.\n\n```\nnpx ctxstash . --estimate\n```\n\nIt's MIT-licensed and open source:\n\nHow are you feeding code to LLMs right now — manual copy-paste, a custom script, or something else? And what would make a tool like this actually fit your workflow? I'd genuinely like to know what to build next.", "url": "https://wpnews.pro/news/i-built-ctxstash-pack-a-codebase-into-one-llm-ready-file-with-a-token-count", "canonical_source": "https://dev.to/_06a3df6b50aec966668fb/i-built-ctxstash-pack-a-codebase-into-one-llm-ready-file-with-a-token-count-4n7l", "published_at": "2026-06-13 16:45:52+00:00", "updated_at": "2026-06-13 17:15:05.615623+00:00", "lang": "en", "topics": ["developer-tools", "large-language-models", "artificial-intelligence"], "entities": ["ctxstash", "ChatGPT", "Claude", "Cursor", "npm", "PyPI"], "alternates": {"html": "https://wpnews.pro/news/i-built-ctxstash-pack-a-codebase-into-one-llm-ready-file-with-a-token-count", "markdown": "https://wpnews.pro/news/i-built-ctxstash-pack-a-codebase-into-one-llm-ready-file-with-a-token-count.md", "text": "https://wpnews.pro/news/i-built-ctxstash-pack-a-codebase-into-one-llm-ready-file-with-a-token-count.txt", "jsonld": "https://wpnews.pro/news/i-built-ctxstash-pack-a-codebase-into-one-llm-ready-file-with-a-token-count.jsonld"}}