{"id":50196541,"url":"https://github.com/yann83/ragcmdr","last_synced_at":"2026-06-07T09:02:22.660Z","repository":{"id":360253845,"uuid":"1249340607","full_name":"yann83/ragcmdr","owner":"yann83","description":"Lightweight local RAG CLI for querying documents with LM Studio","archived":false,"fork":false,"pushed_at":"2026-05-25T16:50:06.000Z","size":6826,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-25T18:07:30.057Z","etag":null,"topics":["chromadb","cli","command-line-tool","docling","document-qa","knowledge-base","llm","lm-studio","local-ai","offline-ai","python","rag","sentence-transformers"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yann83.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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-05-25T15:43:57.000Z","updated_at":"2026-05-25T16:53:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/yann83/ragcmdr","commit_stats":null,"previous_names":["yann83/ragcmdr"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/yann83/ragcmdr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yann83%2Fragcmdr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yann83%2Fragcmdr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yann83%2Fragcmdr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yann83%2Fragcmdr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yann83","download_url":"https://codeload.github.com/yann83/ragcmdr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yann83%2Fragcmdr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34014821,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-07T02:00:07.652Z","response_time":124,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["chromadb","cli","command-line-tool","docling","document-qa","knowledge-base","llm","lm-studio","local-ai","offline-ai","python","rag","sentence-transformers"],"created_at":"2026-05-25T18:03:42.103Z","updated_at":"2026-06-07T09:02:22.650Z","avatar_url":"https://github.com/yann83.png","language":"Python","funding_links":["https://www.buymeacoffee.com/yann83"],"categories":[],"sub_categories":[],"readme":"# Ragcmdr\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"img/banner.png\" width=\"720px\" border=\"0\" alt=\"banner\"\u003e\n  \u003cbr\u003e\n  \u003ca href=\"https://github.com/yann83/ragcmdr/releases/latest\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/yann83/ragcmdr\" alt=\"Version\"\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Python-3.12-blue\"\u003e\n\u003c/p\u003e\n\nA lightweight RAG (Retrieval-Augmented Generation) CLI for querying document collections\nusing a local AI server (LM Studio), with a rich terminal interface and minimal RAM footprint.\n\n---\n\nA small gesture, a big support! Buy me a coffee ☕ if you appreciate my work. Thanks in advance!\n\n[![\"Buy Me A Coffee\"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/yann83)\n\n[![Project demo](img/video_presentation.jpg)](https://app.videas.fr/955f596b-adea-4364-a8d5-8d22a4ea36df/)\n\n---\n\n## Requirements\n\n- Python 3.12+\n- Windows 11\n- A local LLM, I use [LM Studio](https://lmstudio.ai/) running locally (default: `http://127.0.0.1:1234`) but it may work with Ollama.\n\n---\n\n## Installation\n\nYou can use the setup and launch `ragcmdr` with console command.\n\nOr you could install il manually :\n\n```bash\npip install -r requirements.txt\n```\n\n---\n\n## Quick Start\n\n**From console command:**\n\n1. Like a library, a collection contains the files that will be used to populate the theme of your choice.\n\n`ragcmdr create collection my-docs`\n\n2. Then open your collection\n\n`ragcmdr open collection my-docs`\n\n3. Add a file, a folder, or an entire file tree.\n\n\u003e [!WARNING]  \n\u003e Close your LLM before indexing, especially if you don't have enough VRAM/RAM\n\n```bash\nragcmdr add C:\\temp\\report.pdf\nragcmdr add C:\\temp\\folder\\\nragcmdr add C:\\temp\\folder\\ --recursive\n```\n\n4. After the feeding process is complete, you can chat with your files\n\n`ragcmdr chat`\n\n5. When you done you can exit the chat then close your collection.\n\n```bash\nexit\nragcmdr close collection\n```\n\n\n**From source:**\n\nReplace `ragcmdr` by `python ragcmdr.py`\n\n---\n\n## Command Reference\n\n\u003e All examples below use `ragcmdr`. Replace with `python ragcmdr.py` if running from source.\n\n### Collection Management\n\n| Command | Description |\n|---|---|\n| `ragcmdr create collection \u003cname\u003e` | Create a new empty collection |\n| `ragcmdr open collection \u003cname\u003e` | Open a collection (closes any currently open one) |\n| `ragcmdr close collection` | Close the active collection |\n| `ragcmdr list collections` | List all collections with document count and status |\n| `ragcmdr info collection \u003cname\u003e` | Detailed info: docs, chunks, disk usage, embedding parameters, indexing date |\n| `ragcmdr update collection \u003cname\u003e \u003cfolder\u003e` | Wipe and re-index from a folder |\n| `ragcmdr delete collection \u003cname\u003e` | Delete a collection (with confirmation prompt) |\n\n### Document Management\n\nRequires an open collection.\n\n| Command | Description |\n|---|---|\n| `ragcmdr add \u003cpath\u003e` | Add a file or folder to the open collection |\n| `ragcmdr add \u003cpath\u003e --recursive` | Add a folder and all its sub-folders |\n| `ragcmdr list docs` | List indexed documents with chunk counts |\n| `ragcmdr remove doc \u003cfilename\u003e` | Remove a specific document from the collection |\n\n### Configuration\n\n| Command | Description |\n|---|---|\n| `ragcmdr status` | Show active collection and configuration summary |\n| `ragcmdr config show` | Display full `config.json` in the terminal |\n| `ragcmdr config set \u003ckey\u003e \u003cvalue\u003e` | Update a config value using dot-notation |\n\n**`config set` examples:**\n\n```bash\nragcmdr config set lmstudio.model mistral-7b\nragcmdr config set lmstudio.temperature 0.5\nragcmdr config set lmstudio.max_tokens 4096\nragcmdr config set lmstudio.base_url http://127.0.0.1:1234\nragcmdr config set retrieval.top_k 20\n```\n\n\u003e **Note:** `chunk_size`, `chunk_overlap`, and `model_name` changes only apply to newly created\n\u003e collections. Existing collections always use the embedding parameters that were active at\n\u003e first indexing (stored in `embedding_params.json` inside each collection folder).\n\u003e Use `ragcmdr update collection` to re-index with new parameters.\n\u003e `top_k` can be changed at any time with no re-indexing required.\n\n### Chat\n\nRequires an open collection with at least one indexed document.\n\n| Command | Description |\n|---|---|\n| `ragcmdr chat` | Start an interactive RAG chat session |\n| `ragcmdr chat --save-history` | Same, auto-exports the full conversation on exit |\n\n**Inside the chat session:**\n\n| Input | Action |\n|---|---|\n| Any text | Query the AI with RAG context from the collection |\n| `to copy` | Copy the last AI response to the clipboard |\n| `to save` | Save the last AI response as a Markdown file |\n| `to history` | Export the full conversation to a Markdown file |\n| `exit` / `quit` | Leave the chat session (collection stays open) |\n\n---\n\n## Configuration\n\nEdit `config.json` directly or use `ragcmdr config set`:\n\n```json\n{\n  \"lmstudio\": {\n    \"base_url\": \"http://127.0.0.1:1234\",\n    \"model\": \"local-model\",\n    \"system_prompt\": \"You are a helpful assistant. Answer only based on the provided context.\",\n    \"temperature\": 0.2,\n    \"max_tokens\": 2048\n  },\n  \"paths\": {\n    \"collections_dir\": \"./collections\",\n    \"output_dir\": \"./output\"\n  },\n  \"embedding\": {\n    \"model_name\": \"all-MiniLM-L6-v2\",\n    \"chunk_size\": 512,\n    \"chunk_overlap\": 64\n  },\n  \"retrieval\": {\n    \"top_k\": 5\n  }\n}\n```\n\n### Embedding Parameters Snapshot\n\nWhen a collection is indexed for the first time, the active embedding parameters\n(`chunk_size`, `chunk_overlap`, `model_name`) are saved in\n`collections/\u003cname\u003e/embedding_params.json`.\n\nThis snapshot is used automatically on subsequent operations, so changing the global\n`config.json` values never silently corrupts an existing collection. If the saved\nembedding model is no longer available, Ragcmdr will raise a blocking error rather\nthan index with a mismatched model.\n\nTo fully re-index a collection with new embedding parameters:\n\n```bash\nragcmdr update collection my-docs C:\\temp\\my-folder\\\n```\n\n---\n\n## Supported File Types (via Docling)\n\n| Format | Extensions |\n|---|---|\n| PDF | `.pdf` |\n| Word | `.docx`, `.doc` |\n| PowerPoint | `.pptx`, `.ppt` |\n| Excel | `.xlsx` |\n| HTML | `.html`, `.htm` |\n| Plain text | `.txt`, `.md` |\n| Images (OCR) | `.png`, `.jpg`, `.jpeg` |\n\nUnsupported files found in a folder are skipped with a warning and do not interrupt indexing.\n\n---\n\n## Memory Footprint\n\n| Phase | RAM usage |\n|---|---|\n| Idle (collection open, chat ready) | ~50 MB |\n| During indexing (`add` / `update`) | ~140 MB (embedding model loaded, then freed) |\n| Chat query | Stateless HTTP call — no extra RAM |\n\nDocling and the sentence-transformers model are loaded lazily only when needed,\nthen released immediately with `del` + `gc.collect()`.\n\n---\n\n## Output Files\n\nAll files are saved in `./output/` (configurable via `paths.output_dir` in `config.json`).\n\n| Command | Filename format |\n|---|---|\n| `to save` | `yy-mm-dd_hh-mm-ss.md` |\n| `to history` | `yy-mm-dd_hh-mm-ss_history.md` |\n| `ragcmdr chat --save-history` on exit | `yy-mm-dd_hh-mm-ss_history.md` |\n\nFiles are never overwritten: each name includes a timestamp with second precision.\n\n---\n\n## Backup \u0026 Restore\n\nCollections are fully portable. Each collection is a self-contained folder:\n\n```\ncollections/my-docs/\n```\n\nCopy it to back up, paste it back into `collections/` to restore. The `embedding_params.json`\nsnapshot inside the folder ensures the collection can be re-opened without any configuration\nchanges on the target machine.\n\n---\n\n## Project Structure\n\n```\nragstudio/\n├── ragcmdr.py                # Entry point (Typer app, multi-word command routing)\n├── config.json                 # Global configuration\n├── session.json                # Runtime session state (active collection)\n├── requirements.txt\n├── README.md\n├── commands/\n│   ├── __init__.py\n│   ├── collection.py           # create, open, close, update, delete, list, info\n│   └── document.py             # add, list-docs, remove-doc\n├── core/\n│   ├── __init__.py\n│   ├── config_manager.py       # Load/save config.json\n│   ├── state_manager.py        # Active collection state (session.json)\n│   ├── parser.py               # Docling wrapper (lazy load, chunkText)\n│   ├── embedder.py             # sentence-transformers wrapper (lazy load + GC)\n│   ├── vectorstore.py          # ChromaDB wrapper\n│   └── llm_client.py           # LM Studio HTTP client (httpx)\n├── chat/\n│   ├── __init__.py\n│   └── session.py              # Interactive REPL chat loop\n├── collections/                # Default ChromaDB storage directory\n│   └── \u003cname\u003e/\n│       ├── chroma/             # ChromaDB data files\n│       ├── embedding_params.json  # Embedding snapshot (locked at first indexing)\n│       └── doc_count.txt       # Fast document count cache\n└── output/                     # Default Markdown export directory\n```\n\n---\n\n## F.A.Q\n\n - Do I need administrator right to install `ragcmdr` ?\n\n \u003eNo, it's an user installer, I made this choice to avoid suspicions about my program, `ragcmdr` will never ask you for privilege elevation.\n\n - When I type `ragcmdr` in the console windows, I get `'ragcmdr' is not recognized as an internal command`, why ?\n\n \u003eThe installer add `ragcmdr` to the user path variable, if it's not enough add it to the system path too. You'll need administrator right.\n\n - Can I use Ollama with it ?\n\n \u003eThe URL to configure would be http://127.0.0.1:11434 via `ragcmdr config set lmstudio.base_url http://127.0.0.1:11434`. Tell me if it doesn't work.\n\n- Where is my data stored? \n  \n\u003eCollections are located in %LOCALAPPDATA%\\Ragcmdr\\collections\\ or the specified installation folder. Everything is local.\n\n - How do I update a collection after modifying files? \n \n\u003eYou muse use `ragcmdr update collection \u003cname\u003e \u003cfolder\u003e` command. Your collection content will be wiped then re-indexed from your source folder.\n\n - LM Studio is not connected, what to do? \n \n\u003eIs the server status is started (green button) ? Check for serveur response in Developer Logs.\n\n- Which LLM can I use ?\n\n\u003eThe most important criteria are: a large context window (minimum 32k tokens, 128k+ recommended) to absorb the retrieved chunks, and a good ability to follow instructions—the model must respond solely based on the provided snippets, without making things up. The model's language must match that of your documentation and questions.\n\n - Why is indexing slow the first time? \n \n\u003eDocling and the embedding template are downloaded on the first launch (~300 MB). \n\n - Can I index files in multiple languages? \n \n\u003eThe `all-MiniLM-L6-v2` model is multilingual but optimized for English. For dense French, for example, the results may be less accurate.\n\n - My documents are in French (or another language), should I change the embedding model?\n\n\u003eThe default model `all-MiniLM-L6-v2` works in French but is optimized for English. For better results with French documents, use `paraphrase-multilingual-MiniLM-L12-v2`, use \n`ragcmdr config set embedding.model_name paraphrase-multilingual-MiniLM-L12-v2`\nThen re-index your existing collections with `ragcmdr update collection \u003cname\u003e \u003cfolder\u003e`.\n\n- Could you explain the embedding parameters: `chunk_size`, `chunk_overlap` and the retrieval parameter: `top_k` ?\n\n`chunk_size` — Chunk Size\n\n\u003eWhen you index a 30-page PDF, Docling converts it to plain text (approximately 50,000 to 90,000 characters depending on the density). This text is then broken down into small chunks. `chunk_size = 512` means that each chunk is a maximum of 512 characters.\n\u003eWhy not send the entire PDF to the LLM? Because ChromaDB needs to compare your query to each chunk individually. The smaller the chunks, the more accurate the comparison—but if they're too small, they lose their context.\n\n`chunk_overlap` — Overlap\n\n\u003eImagine a sentence split precisely between two chunks: *\"The maximum temperature is\"* in chunk 1, and *\"25°C according to regulations\"* in chunk 2. Without overlap, if you search for \"maximum temperature,\" chunk 1 would be selected but would be incomplete.\n\u003eWith `chunk_overlap = 64`, the last 64 characters of chunk 1 are copied to the beginning of chunk 2. The two chunks then contain the complete sentence. This is essential for protecting information that overlaps a chunk.\n\n`top_k` — the number of chunks sent to the LLM\n\n\u003eAfter indexing, ChromaDB contains hundreds of chunks. When you ask a question, it is transformed into a vector and compared to all the chunks using cosine distance. `top_k = 50` means that the 50 semantically closest chunks are sent to the LLM prompt as context. The default value in `config.json` is `5`.\n\n - Can you give me an example ?\n\n\u003eWith `gpt-oss-20b` with 100k+ context windows :\na `chunk_size 1024` provides chunks richer in context, perfect for dense technical or legal documents.\na `chunk_overlap 200` (≈20% of the chunk) better preserves continuity between paragraphs.\na `top_k 20` sends more relevant context to the LLM without overloading the prompt.\n\n\u003eIf your documents are very short (forms, emails), you can lower `chunk_size` to 512 for greater precision. For long and dense reports, increase it to 2048.\n\n - I asked something but the answer was out of context or limited. Does it really work ?\n\n\u003eYou must be precise in your questions, starting by indicating which files are relevant to your search and using the exact words found in those files. If you are asking for information about a blue car, but the word \"car\" is not mentioned in your files and is replaced by \"automobile,\" then you must use the same terms.\n---\n\n## Acknowledgements\n\n- **[Docling](https://github.com/DS4SD/docling)** — the document parser\n- **[ChromaDB](https://github.com/chroma-core/chroma)** — the local vector base\n- **[sentence-transformers](https://github.com/UKPLab/sentence-transformers)** — embeddings (`all-MiniLM-L6-v2`)\n- **[Typer](https://github.com/fastapi/typer)** — the CLI framework\n- **[Rich](https://github.com/Textualize/rich)** — terminal rendering","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyann83%2Fragcmdr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyann83%2Fragcmdr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyann83%2Fragcmdr/lists"}