convo-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. convo_cli-0.1.0/.gitignore +9 -0
  2. convo_cli-0.1.0/CODE_OF_CONDUCT.md +5 -0
  3. convo_cli-0.1.0/CONTRIBUTING.md +26 -0
  4. convo_cli-0.1.0/LICENSE +21 -0
  5. convo_cli-0.1.0/PKG-INFO +160 -0
  6. convo_cli-0.1.0/README.md +120 -0
  7. convo_cli-0.1.0/alembic.ini +5 -0
  8. convo_cli-0.1.0/convo/__init__.py +3 -0
  9. convo_cli-0.1.0/convo/__main__.py +110 -0
  10. convo_cli-0.1.0/convo/bootstrap.py +273 -0
  11. convo_cli-0.1.0/convo/core/__init__.py +1 -0
  12. convo_cli-0.1.0/convo/core/config.py +53 -0
  13. convo_cli-0.1.0/convo/core/contracts.py +160 -0
  14. convo_cli-0.1.0/convo/core/exceptions.py +5 -0
  15. convo_cli-0.1.0/convo/db/__init__.py +1 -0
  16. convo_cli-0.1.0/convo/db/base.py +13 -0
  17. convo_cli-0.1.0/convo/db/chunks.py +132 -0
  18. convo_cli-0.1.0/convo/db/conversations.py +167 -0
  19. convo_cli-0.1.0/convo/db/documents.py +34 -0
  20. convo_cli-0.1.0/convo/db/models.py +81 -0
  21. convo_cli-0.1.0/convo/db/session.py +27 -0
  22. convo_cli-0.1.0/convo/llm/__init__.py +0 -0
  23. convo_cli-0.1.0/convo/llm/auth.py +504 -0
  24. convo_cli-0.1.0/convo/llm/client.py +207 -0
  25. convo_cli-0.1.0/convo/llm/credentials.py +192 -0
  26. convo_cli-0.1.0/convo/llm/models.py +71 -0
  27. convo_cli-0.1.0/convo/llm/streaming.py +62 -0
  28. convo_cli-0.1.0/convo/pipeline/__init__.py +0 -0
  29. convo_cli-0.1.0/convo/pipeline/chat.py +129 -0
  30. convo_cli-0.1.0/convo/pipeline/chunking.py +42 -0
  31. convo_cli-0.1.0/convo/pipeline/embeddings.py +83 -0
  32. convo_cli-0.1.0/convo/pipeline/index.py +160 -0
  33. convo_cli-0.1.0/convo/pipeline/ingestion.py +46 -0
  34. convo_cli-0.1.0/convo/pipeline/reranking.py +63 -0
  35. convo_cli-0.1.0/convo/pipeline/routing.py +64 -0
  36. convo_cli-0.1.0/convo/pipeline/sessions.py +40 -0
  37. convo_cli-0.1.0/convo/pipeline/worker.py +226 -0
  38. convo_cli-0.1.0/convo/prompts/__init__.py +0 -0
  39. convo_cli-0.1.0/convo/prompts/answers.py +97 -0
  40. convo_cli-0.1.0/convo/prompts/schema.py +97 -0
  41. convo_cli-0.1.0/convo/ui/__init__.py +1 -0
  42. convo_cli-0.1.0/convo/ui/app.py +752 -0
  43. convo_cli-0.1.0/convo/ui/commands.py +37 -0
  44. convo_cli-0.1.0/convo/ui/files.py +110 -0
  45. convo_cli-0.1.0/convo/ui/models.py +84 -0
  46. convo_cli-0.1.0/convo/ui/preview.py +20 -0
  47. convo_cli-0.1.0/convo/ui/sessions.py +97 -0
  48. convo_cli-0.1.0/convo/ui/theme.tcss +64 -0
  49. convo_cli-0.1.0/convo/ui/thinking.py +70 -0
  50. convo_cli-0.1.0/migrations/env.py +43 -0
  51. convo_cli-0.1.0/migrations/script.py.mako +22 -0
  52. convo_cli-0.1.0/migrations/versions/5c3b75f9c5c1_describe_your_schema_change.py +22 -0
  53. convo_cli-0.1.0/migrations/versions/732cf62e465c_create_rag_tables.py +49 -0
  54. convo_cli-0.1.0/migrations/versions/README.md +3 -0
  55. convo_cli-0.1.0/migrations/versions/a42e9d8f0b31_hybrid_search_and_chat_sessions.py +66 -0
  56. convo_cli-0.1.0/pyproject.toml +95 -0
  57. convo_cli-0.1.0/scripts/install.sh +23 -0
  58. convo_cli-0.1.0/tests/test_answers.py +169 -0
  59. convo_cli-0.1.0/tests/test_backend.py +562 -0
  60. convo_cli-0.1.0/tests/test_bootstrap.py +140 -0
  61. convo_cli-0.1.0/tests/test_cli.py +37 -0
  62. convo_cli-0.1.0/tests/test_database.py +397 -0
  63. convo_cli-0.1.0/tests/test_generation.py +264 -0
  64. convo_cli-0.1.0/tests/test_preparation.py +132 -0
  65. convo_cli-0.1.0/tests/test_retrieval.py +49 -0
  66. convo_cli-0.1.0/tests/test_ui.py +711 -0
@@ -0,0 +1,9 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .env
7
+ dist/
8
+ *.egg-info/
9
+ screenshots/
@@ -0,0 +1,5 @@
1
+ # Code of Conduct
2
+
3
+ We want Convo to be a welcoming project for contributors of every background and experience level. Be respectful, constructive, and considerate in issues, pull requests, and discussions.
4
+
5
+ Harassment, discrimination, personal attacks, and sharing another person's private information are not acceptable. Report concerns privately to the repository maintainers. Maintainers may remove content or restrict participation when behaviour violates this standard.
@@ -0,0 +1,26 @@
1
+ # Contributing to Convo
2
+
3
+ Contributions from students, researchers, and terminal-tool enthusiasts are welcome.
4
+
5
+ ## Before opening a pull request
6
+
7
+ 1. Fork the repository and create a focused branch.
8
+ 2. Install the project with `uv sync --python 3.12`.
9
+ 3. Keep changes focused: do not mix formatting, dependency upgrades, and unrelated features.
10
+ 4. Add or update tests for changed behaviour.
11
+ 5. Run the checks below from the repository root.
12
+
13
+ ```sh
14
+ uv run ruff format --check .
15
+ uv run ruff check .
16
+ uv run ty check
17
+ uv run pytest -q
18
+ ```
19
+
20
+ PostgreSQL and model checks are intentionally opt-in; see `ARCHITECTURE.md` for the required environment variables. Never commit `.env`, tokens, personal documents, model caches, or database dumps.
21
+
22
+ ## Pull requests
23
+
24
+ Explain the user-visible change, the design trade-off, and verification performed. Keep UI code independent of database and model implementation details. If you change the data model, include a reviewed Alembic migration and explain how existing local data is preserved.
25
+
26
+ By contributing, you agree that your contribution is licensed under the repository's MIT License.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mohit Sharma
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,160 @@
1
+ Metadata-Version: 2.5
2
+ Name: convo-cli
3
+ Version: 0.1.0
4
+ Summary: A local terminal RAG assistant for chatting with selected files.
5
+ Project-URL: Homepage, https://github.com/madvillax/convo
6
+ Project-URL: Repository, https://github.com/madvillax/convo
7
+ Project-URL: Issues, https://github.com/madvillax/convo/issues
8
+ Author: Mohit Sharma
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: cli,local-first,rag,terminal,textual
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Text Processing :: General
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: alembic>=1.20.0
23
+ Requires-Dist: docx2txt>=0.9
24
+ Requires-Dist: httpx>=0.28.1
25
+ Requires-Dist: keyring>=25.6
26
+ Requires-Dist: llama-index-core>=0.14.25
27
+ Requires-Dist: llama-index-readers-file>=0.7.0
28
+ Requires-Dist: numpy>=2.4.6
29
+ Requires-Dist: openai>=2.0
30
+ Requires-Dist: pgvector>=0.5.1
31
+ Requires-Dist: psycopg[binary]>=3
32
+ Requires-Dist: pydantic<3,>=2.0
33
+ Requires-Dist: pyjwt[crypto]>=2.10
34
+ Requires-Dist: python-dotenv>=1.2.4
35
+ Requires-Dist: sentence-transformers>=6.1.0
36
+ Requires-Dist: sqlalchemy<3,>=2.0
37
+ Requires-Dist: textual<9,>=8.2
38
+ Requires-Dist: transformers>=4.51
39
+ Description-Content-Type: text/markdown
40
+
41
+ # Convo
42
+
43
+ Convo is an open-source, local-first terminal app for chatting with a selected file. Qwen3 embeddings and PostgreSQL full-text search retrieve passages together; a local cross-encoder reranks them; your connected ChatGPT account returns a structured answer with supporting quotations.
44
+
45
+ It is released under the [MIT License](LICENSE). Contributions are welcome—see [CONTRIBUTING.md](CONTRIBUTING.md).
46
+
47
+ ## Install and start
48
+
49
+ The supported release install uses [uv](https://docs.astral.sh/uv/):
50
+
51
+ ```sh
52
+ uv tool install convo-cli
53
+ convo
54
+ ```
55
+
56
+ On first launch, `convo` creates a private settings file at `~/.config/convo/.env`, pulls `pgvector/pgvector:pg16`, starts a loopback-only `convo-postgres` container, and runs migrations before opening the terminal app. It generates a random database password and preserves existing data. Later launches restart Convo's local container if needed and apply pending migrations.
57
+
58
+ Local storage needs Docker Desktop or Podman installed. Start Docker Desktop first if you use Docker. On macOS, Convo starts or initializes a Podman machine when Podman is installed. First use downloads Python dependencies, a database image, and—when indexing your first file—the embedding/reranker models.
59
+
60
+ If you already use PostgreSQL, set `DATABASE_URL` to a `postgresql+psycopg://...` URL, run `convo --setup` once to migrate that database, then run `convo`. Explicit database connections are used as configured; startup only manages storage created by Convo.
61
+
62
+ For a one-command install on macOS/Linux, inspect and then run the repository installer:
63
+
64
+ ```sh
65
+ curl -LsSf https://raw.githubusercontent.com/madvillax/convo/main/scripts/install.sh | sh
66
+ ```
67
+
68
+ It installs uv if needed, installs `convo-cli`, and adds uv's tool directory to your shell path. Then type `convo` to start. Open a new terminal if `convo` is not immediately found.
69
+
70
+ To use an unreleased checkout while developing:
71
+
72
+ ```sh
73
+ uv sync --python 3.12
74
+ uv run convo
75
+ ```
76
+
77
+ `--directory ~/Documents` changes the file browser root. Environment variables always override the user settings file; `.env.example` is only for checkout-based development.
78
+
79
+ Optional model download/warmup outside the TUI:
80
+
81
+ ```sh
82
+ uv run convo --download-model
83
+ ```
84
+
85
+ This prepares both Qwen3 and `cross-encoder/ms-marco-MiniLM-L6-v2`. Models otherwise load/download on demand in an isolated process. File preparation shows stages and elapsed time; Esc cancels it. Download/native logs stay in `~/.cache/convo/rag-worker.log` (respecting `XDG_CACHE_HOME`). After storage preparation, startup restores account preferences locally; models and the account catalog load when needed.
86
+
87
+ For a UI preview without services or backend dependencies:
88
+
89
+ ```sh
90
+ uv run convo --shell
91
+ ```
92
+
93
+ ## Use
94
+
95
+ Type `/` for command suggestions. Filter by typing, use ↑/↓ to move, Tab to complete, Enter to run, and Esc to dismiss.
96
+
97
+ | Command/key | Action |
98
+ | --- | --- |
99
+ | `/login` | Connect your ChatGPT account through browser sign-in |
100
+ | `/models` | Search and select an account model |
101
+ | `/models <id>` | Select a model directly |
102
+ | Ctrl+T or Shift+Tab | Cycle auto and the model's supported thinking levels |
103
+ | F2 or `/thinking` | Choose a thinking level directly |
104
+ | `/thinking high`, `/thinking auto` | Set a supported level or restore the model default |
105
+ | `/file`, Ctrl+O | Select and index a file; create a saved conversation |
106
+ | `/sessions` | Search saved conversations by title, filename, or ID and resume one |
107
+ | `/sessions <uuid>` | Resume a conversation directly |
108
+ | `/new` | Create a new saved conversation, keeping the selected file |
109
+ | `/clear` | Same behavior as `/new`; previous conversations remain saved |
110
+ | `/reset` | Create a new saved conversation without a selected file |
111
+ | Esc during file preparation | Stop preparation and restore the input |
112
+ | `/help` | Show commands and keys |
113
+ | `/quit`, `/exit`, Ctrl+C | Exit |
114
+ | PageUp / PageDown | Scroll the transcript while keeping the input focused |
115
+
116
+ Questions appear in shaded blocks with a gold left edge. Answers use spaced Markdown with highlighted code, and source quotations appear in a separate subdued block. The composer groups your input with the gold model name and thinking level underneath. The ASCII title collapses once chatting starts and in smaller terminals, leaving more room to read. Long replies open at the question and the beginning of the answer; use PageUp/PageDown or the mouse wheel to keep reading.
117
+
118
+ Change the cycling shortcut with `convo --thinking-key ctrl+g` or set `CONVO_THINKING_KEY=ctrl+g` in `.env` (export it for `--shell`). The command-line flag takes precedence. Shift+Tab and F2 remain available. Choose a Ctrl/Alt letter or F3–F24; essential keys are reserved. `/help` shows the configured shortcut. Only thinking levels supported by the selected account model can be saved.
119
+
120
+ Sessions, completed message pairs, displayed source quotes, and structured answers persist in PostgreSQL. Use `/sessions` after restarting. Resuming uses the saved indexed snapshot, so the original file can have moved or disappeared. Use `/file` again to index changed content. A failed request never saves a partial turn. Account tokens remain in the OS keyring; model/thinking preferences remain in the local account profile.
121
+
122
+ Greetings such as `hello` and acknowledgements such as `thank you` receive a short local reply without retrieval or model calls. Mixed greetings and file questions still use retrieval. Specific questions use hybrid search, reciprocal rank fusion, cross-encoder reranking, and weak-match filtering. Broad file overviews sample sections across the snapshot and rerank their order without applying a QA relevance cutoff.
123
+
124
+ ChatGPT returns JSON sections containing text and citation objects. Python validates the schema, requires citations on answered sections, checks source IDs and exact supporting quotes, then renders readable Markdown with numbered citations. Only cited quotes appear under sources. An empty evidence set returns an insufficient-evidence response without an LLM call. These checks verify structure and quotations; they do not prove every generated claim is entailed by its quote.
125
+
126
+ Supported files: `.txt`, `.md`, `.pdf`, `.docx`, `.csv`, `.json`, `.py`, `.rst`, `.log`. Limits: 10 MB input, 500,000 extracted characters, and 2,000 chunks. LlamaIndex is used only for readers and chunking. The TUI supports terminals down to 50 columns × 18 rows.
127
+
128
+ ## Architecture
129
+
130
+ ```text
131
+ convo/
132
+ ├── core/ settings, shared values and UI/backend contracts
133
+ ├── ui/ Textual app, commands, file/model/session pickers
134
+ ├── llm/ ChatGPT connection, credentials, catalog and Responses transport
135
+ ├── pipeline/ chat flow, routing, ingestion, embeddings, reranking and worker
136
+ ├── prompts/ answer instructions, context builder and structured schema
137
+ └── db/ SQLAlchemy models, connections, document/search/session queries
138
+ ```
139
+
140
+ [ARCHITECTURE.md](ARCHITECTURE.md) explains the files, schema, data flow, tuning, and verification. [changes.md](changes.md) records implementation approaches and validation.
141
+
142
+ ## Checks
143
+
144
+ ```sh
145
+ uv run ruff format --check .
146
+ uv run ruff check .
147
+ uv run ty check
148
+ uv run pytest -q
149
+ ```
150
+
151
+ PostgreSQL integration checks use a disposable database, enabled explicitly with `CONVO_TEST_DATABASE_URL`. `CONVO_TEST_MODELS=1` also exercises real Qwen/reranking models. See [ARCHITECTURE.md](ARCHITECTURE.md) for these opt-in checks and their prerequisites.
152
+
153
+ ## Releasing to PyPI
154
+
155
+ Maintainers should test a release on TestPyPI first, then create a GitHub release. The included `Publish to PyPI` workflow uses PyPI Trusted Publishing, so it does not require a long-lived token in the repository. Configure the repository and `.github/workflows/publish.yml` as a Trusted Publisher in PyPI before publishing.
156
+
157
+ ```sh
158
+ uv build --no-sources
159
+ uv publish --token "$PYPI_TOKEN" # one-time/manual alternative
160
+ ```
@@ -0,0 +1,120 @@
1
+ # Convo
2
+
3
+ Convo is an open-source, local-first terminal app for chatting with a selected file. Qwen3 embeddings and PostgreSQL full-text search retrieve passages together; a local cross-encoder reranks them; your connected ChatGPT account returns a structured answer with supporting quotations.
4
+
5
+ It is released under the [MIT License](LICENSE). Contributions are welcome—see [CONTRIBUTING.md](CONTRIBUTING.md).
6
+
7
+ ## Install and start
8
+
9
+ The supported release install uses [uv](https://docs.astral.sh/uv/):
10
+
11
+ ```sh
12
+ uv tool install convo-cli
13
+ convo
14
+ ```
15
+
16
+ On first launch, `convo` creates a private settings file at `~/.config/convo/.env`, pulls `pgvector/pgvector:pg16`, starts a loopback-only `convo-postgres` container, and runs migrations before opening the terminal app. It generates a random database password and preserves existing data. Later launches restart Convo's local container if needed and apply pending migrations.
17
+
18
+ Local storage needs Docker Desktop or Podman installed. Start Docker Desktop first if you use Docker. On macOS, Convo starts or initializes a Podman machine when Podman is installed. First use downloads Python dependencies, a database image, and—when indexing your first file—the embedding/reranker models.
19
+
20
+ If you already use PostgreSQL, set `DATABASE_URL` to a `postgresql+psycopg://...` URL, run `convo --setup` once to migrate that database, then run `convo`. Explicit database connections are used as configured; startup only manages storage created by Convo.
21
+
22
+ For a one-command install on macOS/Linux, inspect and then run the repository installer:
23
+
24
+ ```sh
25
+ curl -LsSf https://raw.githubusercontent.com/madvillax/convo/main/scripts/install.sh | sh
26
+ ```
27
+
28
+ It installs uv if needed, installs `convo-cli`, and adds uv's tool directory to your shell path. Then type `convo` to start. Open a new terminal if `convo` is not immediately found.
29
+
30
+ To use an unreleased checkout while developing:
31
+
32
+ ```sh
33
+ uv sync --python 3.12
34
+ uv run convo
35
+ ```
36
+
37
+ `--directory ~/Documents` changes the file browser root. Environment variables always override the user settings file; `.env.example` is only for checkout-based development.
38
+
39
+ Optional model download/warmup outside the TUI:
40
+
41
+ ```sh
42
+ uv run convo --download-model
43
+ ```
44
+
45
+ This prepares both Qwen3 and `cross-encoder/ms-marco-MiniLM-L6-v2`. Models otherwise load/download on demand in an isolated process. File preparation shows stages and elapsed time; Esc cancels it. Download/native logs stay in `~/.cache/convo/rag-worker.log` (respecting `XDG_CACHE_HOME`). After storage preparation, startup restores account preferences locally; models and the account catalog load when needed.
46
+
47
+ For a UI preview without services or backend dependencies:
48
+
49
+ ```sh
50
+ uv run convo --shell
51
+ ```
52
+
53
+ ## Use
54
+
55
+ Type `/` for command suggestions. Filter by typing, use ↑/↓ to move, Tab to complete, Enter to run, and Esc to dismiss.
56
+
57
+ | Command/key | Action |
58
+ | --- | --- |
59
+ | `/login` | Connect your ChatGPT account through browser sign-in |
60
+ | `/models` | Search and select an account model |
61
+ | `/models <id>` | Select a model directly |
62
+ | Ctrl+T or Shift+Tab | Cycle auto and the model's supported thinking levels |
63
+ | F2 or `/thinking` | Choose a thinking level directly |
64
+ | `/thinking high`, `/thinking auto` | Set a supported level or restore the model default |
65
+ | `/file`, Ctrl+O | Select and index a file; create a saved conversation |
66
+ | `/sessions` | Search saved conversations by title, filename, or ID and resume one |
67
+ | `/sessions <uuid>` | Resume a conversation directly |
68
+ | `/new` | Create a new saved conversation, keeping the selected file |
69
+ | `/clear` | Same behavior as `/new`; previous conversations remain saved |
70
+ | `/reset` | Create a new saved conversation without a selected file |
71
+ | Esc during file preparation | Stop preparation and restore the input |
72
+ | `/help` | Show commands and keys |
73
+ | `/quit`, `/exit`, Ctrl+C | Exit |
74
+ | PageUp / PageDown | Scroll the transcript while keeping the input focused |
75
+
76
+ Questions appear in shaded blocks with a gold left edge. Answers use spaced Markdown with highlighted code, and source quotations appear in a separate subdued block. The composer groups your input with the gold model name and thinking level underneath. The ASCII title collapses once chatting starts and in smaller terminals, leaving more room to read. Long replies open at the question and the beginning of the answer; use PageUp/PageDown or the mouse wheel to keep reading.
77
+
78
+ Change the cycling shortcut with `convo --thinking-key ctrl+g` or set `CONVO_THINKING_KEY=ctrl+g` in `.env` (export it for `--shell`). The command-line flag takes precedence. Shift+Tab and F2 remain available. Choose a Ctrl/Alt letter or F3–F24; essential keys are reserved. `/help` shows the configured shortcut. Only thinking levels supported by the selected account model can be saved.
79
+
80
+ Sessions, completed message pairs, displayed source quotes, and structured answers persist in PostgreSQL. Use `/sessions` after restarting. Resuming uses the saved indexed snapshot, so the original file can have moved or disappeared. Use `/file` again to index changed content. A failed request never saves a partial turn. Account tokens remain in the OS keyring; model/thinking preferences remain in the local account profile.
81
+
82
+ Greetings such as `hello` and acknowledgements such as `thank you` receive a short local reply without retrieval or model calls. Mixed greetings and file questions still use retrieval. Specific questions use hybrid search, reciprocal rank fusion, cross-encoder reranking, and weak-match filtering. Broad file overviews sample sections across the snapshot and rerank their order without applying a QA relevance cutoff.
83
+
84
+ ChatGPT returns JSON sections containing text and citation objects. Python validates the schema, requires citations on answered sections, checks source IDs and exact supporting quotes, then renders readable Markdown with numbered citations. Only cited quotes appear under sources. An empty evidence set returns an insufficient-evidence response without an LLM call. These checks verify structure and quotations; they do not prove every generated claim is entailed by its quote.
85
+
86
+ Supported files: `.txt`, `.md`, `.pdf`, `.docx`, `.csv`, `.json`, `.py`, `.rst`, `.log`. Limits: 10 MB input, 500,000 extracted characters, and 2,000 chunks. LlamaIndex is used only for readers and chunking. The TUI supports terminals down to 50 columns × 18 rows.
87
+
88
+ ## Architecture
89
+
90
+ ```text
91
+ convo/
92
+ ├── core/ settings, shared values and UI/backend contracts
93
+ ├── ui/ Textual app, commands, file/model/session pickers
94
+ ├── llm/ ChatGPT connection, credentials, catalog and Responses transport
95
+ ├── pipeline/ chat flow, routing, ingestion, embeddings, reranking and worker
96
+ ├── prompts/ answer instructions, context builder and structured schema
97
+ └── db/ SQLAlchemy models, connections, document/search/session queries
98
+ ```
99
+
100
+ [ARCHITECTURE.md](ARCHITECTURE.md) explains the files, schema, data flow, tuning, and verification. [changes.md](changes.md) records implementation approaches and validation.
101
+
102
+ ## Checks
103
+
104
+ ```sh
105
+ uv run ruff format --check .
106
+ uv run ruff check .
107
+ uv run ty check
108
+ uv run pytest -q
109
+ ```
110
+
111
+ PostgreSQL integration checks use a disposable database, enabled explicitly with `CONVO_TEST_DATABASE_URL`. `CONVO_TEST_MODELS=1` also exercises real Qwen/reranking models. See [ARCHITECTURE.md](ARCHITECTURE.md) for these opt-in checks and their prerequisites.
112
+
113
+ ## Releasing to PyPI
114
+
115
+ Maintainers should test a release on TestPyPI first, then create a GitHub release. The included `Publish to PyPI` workflow uses PyPI Trusted Publishing, so it does not require a long-lived token in the repository. Configure the repository and `.github/workflows/publish.yml` as a Trusted Publisher in PyPI before publishing.
116
+
117
+ ```sh
118
+ uv build --no-sources
119
+ uv publish --token "$PYPI_TOKEN" # one-time/manual alternative
120
+ ```
@@ -0,0 +1,5 @@
1
+ [alembic]
2
+ script_location = %(here)s/migrations
3
+ prepend_sys_path = .
4
+ path_separator = os
5
+ # The URL is supplied by core/config.py in migrations/env.py; never commit credentials.
@@ -0,0 +1,3 @@
1
+ """A local terminal RAG assistant for chatting with selected files."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,110 @@
1
+ import argparse
2
+ import os
3
+ from pathlib import Path
4
+
5
+ from convo.ui.app import ConvoApp
6
+ from convo.ui.preview import ShellBackend
7
+ from convo.ui.thinking import thinking_key
8
+
9
+
10
+ def main() -> None:
11
+ parser = argparse.ArgumentParser(description="Chat with a file in your current directory.")
12
+ parser.add_argument("--directory", type=Path, default=None, help="Browse this folder instead")
13
+ parser.add_argument(
14
+ "--thinking-key",
15
+ type=thinking_key,
16
+ default=None,
17
+ help="Thinking cycle shortcut (default: CONVO_THINKING_KEY or ctrl+t)",
18
+ )
19
+ mode = parser.add_mutually_exclusive_group()
20
+ mode.add_argument(
21
+ "--shell",
22
+ action="store_true",
23
+ help="Run the UI preview without PostgreSQL, embeddings, or ChatGPT",
24
+ )
25
+ mode.add_argument(
26
+ "--download-model",
27
+ action="store_true",
28
+ help="Download and warm Qwen3 and the reranker outside the TUI, then exit",
29
+ )
30
+ mode.add_argument(
31
+ "--setup",
32
+ action="store_true",
33
+ help="Create and migrate Convo's local PostgreSQL/pgvector storage, then exit",
34
+ )
35
+ args = parser.parse_args()
36
+ directory = (args.directory or Path.cwd()).expanduser().resolve()
37
+ if not directory.is_dir():
38
+ parser.error(f"Not a directory: {directory}")
39
+ if args.shell:
40
+ try:
41
+ app = ConvoApp(directory, ShellBackend(), thinking_shortcut=args.thinking_key)
42
+ except ValueError as error:
43
+ parser.error(str(error))
44
+ app.run()
45
+ return
46
+
47
+ try:
48
+ from convo.core.config import load_settings
49
+ from convo.pipeline.chat import RagBackend
50
+ except ImportError as error:
51
+ parser.error(
52
+ f"Backend dependency {error.name} is missing. Install the published command with "
53
+ "`uv tool install --force convo-cli`; from a checkout run `uv run convo`."
54
+ )
55
+
56
+ if args.setup:
57
+ from convo.bootstrap import SetupError, setup
58
+
59
+ try:
60
+ settings_path = setup()
61
+ except (SetupError, ValueError) as error:
62
+ parser.error(str(error))
63
+ print(f"Convo storage is ready. Settings are in {settings_path}. Run `convo` to start.")
64
+ return
65
+
66
+ if args.download_model:
67
+ # Warming models does not require a running database or a container runtime.
68
+ from convo.core.config import Settings, load_environment
69
+ from convo.core.contracts import Hit
70
+ from convo.pipeline.embeddings import Embedder
71
+ from convo.pipeline.reranking import Reranker
72
+
73
+ load_environment()
74
+ settings = Settings(
75
+ "",
76
+ os.getenv("EMBEDDING_MODEL", "Qwen/Qwen3-Embedding-0.6B"),
77
+ reranker_model=os.getenv("RERANKER_MODEL", "cross-encoder/ms-marco-MiniLM-L6-v2"),
78
+ )
79
+ print(
80
+ "Downloading/loading Qwen3 embeddings. First use can take several minutes.", flush=True
81
+ )
82
+ Embedder(settings.embedding_model).query("warm up")
83
+ print("Downloading/loading the local reranker…", flush=True)
84
+ Reranker(settings.reranker_model).rerank(
85
+ "What is being cached?", [Hit("Model weights are cached locally.", "warmup", 0.0)]
86
+ )
87
+ print("Both models are ready. Run convo and choose a file with /file.")
88
+ return
89
+
90
+ from convo.bootstrap import SetupError, ensure_storage
91
+
92
+ try:
93
+ ensure_storage()
94
+ settings = load_settings()
95
+ except (SetupError, ValueError) as error:
96
+ parser.error(str(error))
97
+
98
+ backend = RagBackend(settings)
99
+ try:
100
+ try:
101
+ app = ConvoApp(directory, backend, thinking_shortcut=args.thinking_key)
102
+ except ValueError as error:
103
+ parser.error(str(error))
104
+ app.run()
105
+ finally:
106
+ backend.close()
107
+
108
+
109
+ if __name__ == "__main__":
110
+ main()