{"id":46618201,"url":"https://github.com/samuelfaj/distill","last_synced_at":"2026-05-13T01:06:39.831Z","repository":{"id":342633390,"uuid":"1174519898","full_name":"samuelfaj/distill","owner":"samuelfaj","description":"Distill large CLI outputs into small answers for LLMs and save tokens!","archived":false,"fork":false,"pushed_at":"2026-05-07T17:26:05.000Z","size":126,"stargazers_count":519,"open_issues_count":3,"forks_count":30,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-05-07T18:40:03.023Z","etag":null,"topics":["claude-code","codex","llm","tokens"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/samuelfaj.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-06T14:37:09.000Z","updated_at":"2026-05-07T18:19:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/samuelfaj/distill","commit_stats":null,"previous_names":["samuelfaj/distill"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/samuelfaj/distill","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuelfaj%2Fdistill","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuelfaj%2Fdistill/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuelfaj%2Fdistill/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuelfaj%2Fdistill/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/samuelfaj","download_url":"https://codeload.github.com/samuelfaj/distill/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samuelfaj%2Fdistill/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32963180,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-12T23:30:32.555Z","status":"ssl_error","status_checked_at":"2026-05-12T23:30:18.191Z","response_time":102,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["claude-code","codex","llm","tokens"],"created_at":"2026-03-07T20:33:45.077Z","updated_at":"2026-05-13T01:06:39.729Z","avatar_url":"https://github.com/samuelfaj.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# distill\n\nAgent command outputs are one of the biggest sources of token waste.\n\nLogs, test results, stack traces… thousands of tokens sent to an LLM just to answer a simple question.\n\n**🔥 `distill` compresses command outputs into only what the LLM actually needs.**\n\nSave **up to 99% of tokens** without losing the signal.\n\n## How to use\n\n```bash\nnpm i -g @samuelfaj/distill\n```\n\n`distill` speaks any OpenAI-compatible API. Point it at whatever endpoint you run locally (LM Studio, Jan, LocalAI, vLLM, SGLang, llama.cpp, MLX, Docker Model Runner, Ollama's `/v1`, DFlash, etc.) or a hosted provider (OpenAI, etc.) by setting `--host` to its base URL.\n\nAdd in your global agent instructions file:\n\n```md\nCRITICAL: Pipe every non-interactive shell command through `distill` unless raw output is explicitly required.\n\nCRITICAL: Your prompt to `distill` must be fully explicit. State exactly what you want to know and exactly what the output must contain. If you want only filenames, say `Return only the filenames.` If you want JSON, say `Return valid JSON only.` Do not ask vague questions.\n\nBad:\n- `distill \"Which files are shown?\"`\n\nGood:\n- `distill \"Which files are shown? Return only the filenames.\"`\n\nExamples:\n- `bun test 2\u003e\u00261 | distill \"Did the tests pass? Return only: PASS or FAIL, followed by failing test names if any.\"`\n- `git diff 2\u003e\u00261 | distill \"What changed? Return only the files changed and a one-line summary for each file.\"`\n- `terraform plan 2\u003e\u00261 | distill \"Is this safe? Return only: SAFE, REVIEW, or UNSAFE, followed by the exact risky changes.\"`\n- `npm audit 2\u003e\u00261 | distill \"Extract the vulnerabilities. Return valid JSON only.\"`\n- `rg -n \"TODO|FIXME\" . 2\u003e\u00261 | distill \"List files containing TODO or FIXME. Return only file paths, one per line.\"`\n- `ls -la 2\u003e\u00261 | distill \"Which files are shown? Return only the filenames.\"`\n\nYou may skip `distill` only in these cases:\n- Exact uncompressed output is required.\n- Using `distill` would break an interactive or TUI workflow.\n\nCRITICAL: Wait for `distill` to finish before continuing.\n```\n\n## Usage\n\n```bash\nlogs | distill \"summarize errors\"\ngit diff | distill \"what changed?\"\nterraform plan 2\u003e\u00261 | distill \"is this safe?\"\n```\n\nTranslate compressed `distill-talk` back to human language:\n\n```bash\ndistill translate \"X r=tests_passed ship\"\ndistill translate \"N r=missing_context ctx repo_state\" pt-BR\n```\n\nThe language argument is optional and defaults to `en-US`.\n\nPoint at any OpenAI-compatible endpoint:\n\n```bash\n# LM Studio\ndistill --host http://127.0.0.1:1234/v1 --model your-loaded-model \"what failed?\"\n\n# Ollama (via its OpenAI-compatible /v1 endpoint)\ndistill --host http://127.0.0.1:11434/v1 --model llama3.2 \"what failed?\"\n\n# OpenAI\ndistill --host https://api.openai.com/v1 --model gpt-4o-mini --api-key sk-... \"summarize\"\n\n# Docker Model Runner\ndistill --host http://127.0.0.1:12434/engines/v1 --model ai/llama3.2 \"what failed?\"\n```\n\n## Configurations\n\nYou can persist defaults locally:\n\n```bash\ndistill config host http://127.0.0.1:1234/v1\ndistill config model \"qwen3.5:2b\"\ndistill config api-key \"secret-key-123\"\ndistill config timeout-ms 90000\n```\n\nEnvironment variables override persisted config, and CLI flags override both:\n\n- `DISTILL_HOST`\n- `DISTILL_MODEL`\n- `DISTILL_API_KEY`\n- `DISTILL_TIMEOUT_MS`\n\nFor pipeline exit mirroring, use `pipefail` in your shell:\n\n```bash\nset -o pipefail\n```\n\nInteractive prompts are passed through when `distill` detects simple prompt patterns like `[y/N]` or `password:`.\n\n## Global agent instructions\n\nIf you want Codex, Claude Code, or OpenCode to prefer `distill` whenever they run a command whose output will be sent to a paid LLM, add a global instruction telling the agent to pipe command output through `distill`.\n\n- Codex reads global agent instructions from `~/.codex/AGENTS.md`.\n- Claude Code supports global settings in `~/.claude/settings.json`, and its official mechanism for custom behavior is global instructions via `CLAUDE.md`.\n- OpenCode supports global instruction files through `~/.config/opencode/opencode.json`. Point its `instructions` field at a markdown file with the same rule.\n- GitHub Copilot CLI supports local global instructions from `~/.copilot/copilot-instructions.md`.\n- GitHub Copilot CLI also reads repository instructions from .github/copilot-instructions.md, and it can read AGENTS.md files from directories listed in COPILOT_CUSTOM_INSTRUCTIONS_DIRS.\n\n## distill-talk skill\n\n`distill` ships `distill-talk` for both Codex and Claude:\n\n- Codex skill: `skills/distill-talk/SKILL.md`\n- Claude Code project skill: `.claude/skills/distill-talk/SKILL.md`\n\nBoth files use the `SKILL.md` frontmatter format with `name` and `description`, and both contain the same compact task DSL as `sam-compress-talk`, renamed for this package.\n\nInstall from this repository:\n\n```bash\nmkdir -p ~/.codex/skills ~/.claude/skills\ncp -R skills/distill-talk ~/.codex/skills/distill-talk\ncp -R .claude/skills/distill-talk ~/.claude/skills/distill-talk\n```\n\nInstall from the npm package:\n\n```bash\nnpm i -g @samuelfaj/distill\nDISTILL_PACKAGE=\"$(npm root -g)/@samuelfaj/distill\"\nmkdir -p ~/.codex/skills ~/.claude/skills\ncp -R \"$DISTILL_PACKAGE/skills/distill-talk\" ~/.codex/skills/distill-talk\ncp -R \"$DISTILL_PACKAGE/.claude/skills/distill-talk\" ~/.claude/skills/distill-talk\n```\n\nUse it when you want one-line compressed task state:\n\n```text\nX r=tests_passed parser e2e docs\nN r=missing_context repro files\n```\n\nUse `distill translate` to expand that DSL for a human reviewer:\n\n```bash\ndistill translate \"X r=tests_passed parser e2e docs\"\ndistill translate \"N r=missing_context repro files\" pt-BR\n```\n\n## Example:\n\n```sh \nrg -n \"terminal|PERMISSION|permission|Permissions|Plan|full access|default\" desktop --glob '!**/node_modules/**' | distill \"find where terminal and permission UI are implemented in chat screen\"\n```\n\n- **Before:** [7648 tokens 30592 characters 10218 words](./examples/1/BEFORE.md)\n- **After:** [99 tokens 396 characters 57 words](./examples/1/AFTER.md)\n\n**🔥 Saved ~98.7% tokens**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamuelfaj%2Fdistill","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsamuelfaj%2Fdistill","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamuelfaj%2Fdistill/lists"}