papers-app 0.2.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 (140) hide show
  1. papers_app-0.2.0/.gitignore +10 -0
  2. papers_app-0.2.0/CONTRIBUTING.md +126 -0
  3. papers_app-0.2.0/LICENSE +21 -0
  4. papers_app-0.2.0/PKG-INFO +138 -0
  5. papers_app-0.2.0/README.md +109 -0
  6. papers_app-0.2.0/papers/__init__.py +2 -0
  7. papers_app-0.2.0/papers/__main__.py +3 -0
  8. papers_app-0.2.0/papers/agent/__init__.py +2 -0
  9. papers_app-0.2.0/papers/agent/loop.py +295 -0
  10. papers_app-0.2.0/papers/agent/mcp_server.py +65 -0
  11. papers_app-0.2.0/papers/agent/tools.py +329 -0
  12. papers_app-0.2.0/papers/ai/__init__.py +67 -0
  13. papers_app-0.2.0/papers/ai/anthropic_api.py +53 -0
  14. papers_app-0.2.0/papers/ai/claude_code.py +126 -0
  15. papers_app-0.2.0/papers/ai/codex.py +66 -0
  16. papers_app-0.2.0/papers/ai/errors.py +13 -0
  17. papers_app-0.2.0/papers/ai/openai_compat.py +124 -0
  18. papers_app-0.2.0/papers/ai/providers.py +112 -0
  19. papers_app-0.2.0/papers/ai/streaming.py +111 -0
  20. papers_app-0.2.0/papers/bibtex.py +28 -0
  21. papers_app-0.2.0/papers/chat/__init__.py +1 -0
  22. papers_app-0.2.0/papers/chat/answer.py +92 -0
  23. papers_app-0.2.0/papers/chat/store.py +178 -0
  24. papers_app-0.2.0/papers/cli.py +50 -0
  25. papers_app-0.2.0/papers/config.py +52 -0
  26. papers_app-0.2.0/papers/db.py +120 -0
  27. papers_app-0.2.0/papers/figures.py +234 -0
  28. papers_app-0.2.0/papers/folders.py +56 -0
  29. papers_app-0.2.0/papers/index.py +96 -0
  30. papers_app-0.2.0/papers/ingest.py +128 -0
  31. papers_app-0.2.0/papers/keys.py +103 -0
  32. papers_app-0.2.0/papers/library.py +208 -0
  33. papers_app-0.2.0/papers/llm.py +428 -0
  34. papers_app-0.2.0/papers/main.py +73 -0
  35. papers_app-0.2.0/papers/notes.py +73 -0
  36. papers_app-0.2.0/papers/pdf.py +116 -0
  37. papers_app-0.2.0/papers/routes/__init__.py +4 -0
  38. papers_app-0.2.0/papers/routes/chat.py +166 -0
  39. papers_app-0.2.0/papers/routes/goals.py +65 -0
  40. papers_app-0.2.0/papers/routes/learning.py +195 -0
  41. papers_app-0.2.0/papers/routes/notes.py +92 -0
  42. papers_app-0.2.0/papers/routes/papers.py +213 -0
  43. papers_app-0.2.0/papers/routes/reading.py +114 -0
  44. papers_app-0.2.0/papers/routes/recall.py +34 -0
  45. papers_app-0.2.0/papers/routes/settings.py +133 -0
  46. papers_app-0.2.0/papers/scholar.py +128 -0
  47. papers_app-0.2.0/papers/static/css/base.css +109 -0
  48. papers_app-0.2.0/papers/static/css/chat.css +241 -0
  49. papers_app-0.2.0/papers/static/css/components.css +285 -0
  50. papers_app-0.2.0/papers/static/css/goals.css +85 -0
  51. papers_app-0.2.0/papers/static/css/library.css +142 -0
  52. papers_app-0.2.0/papers/static/css/map.css +182 -0
  53. papers_app-0.2.0/papers/static/css/paper.css +138 -0
  54. papers_app-0.2.0/papers/static/css/reader.css +256 -0
  55. papers_app-0.2.0/papers/static/css/recall.css +69 -0
  56. papers_app-0.2.0/papers/static/css/settings.css +36 -0
  57. papers_app-0.2.0/papers/static/css/tokens.css +129 -0
  58. papers_app-0.2.0/papers/static/index.html +44 -0
  59. papers_app-0.2.0/papers/static/js/chat/answer.js +130 -0
  60. papers_app-0.2.0/papers/static/js/chat/canvas.js +24 -0
  61. papers_app-0.2.0/papers/static/js/chat/conversation.js +345 -0
  62. papers_app-0.2.0/papers/static/js/chat/render.js +230 -0
  63. papers_app-0.2.0/papers/static/js/chat/stream.js +39 -0
  64. papers_app-0.2.0/papers/static/js/chat/widgets.js +161 -0
  65. papers_app-0.2.0/papers/static/js/components/combobox.js +91 -0
  66. papers_app-0.2.0/papers/static/js/components/folderpicker.js +95 -0
  67. papers_app-0.2.0/papers/static/js/core.js +358 -0
  68. papers_app-0.2.0/papers/static/js/covers.js +74 -0
  69. papers_app-0.2.0/papers/static/js/highlights.js +181 -0
  70. papers_app-0.2.0/papers/static/js/main.js +115 -0
  71. papers_app-0.2.0/papers/static/js/notes.js +160 -0
  72. papers_app-0.2.0/papers/static/js/pages/goals.js +149 -0
  73. papers_app-0.2.0/papers/static/js/pages/library.js +144 -0
  74. papers_app-0.2.0/papers/static/js/pages/map.js +84 -0
  75. papers_app-0.2.0/papers/static/js/pages/recall.js +70 -0
  76. papers_app-0.2.0/papers/static/js/pages/settings.js +225 -0
  77. papers_app-0.2.0/papers/static/js/pages/shared.js +46 -0
  78. papers_app-0.2.0/papers/static/js/paper/figures.js +62 -0
  79. papers_app-0.2.0/papers/static/js/paper/overview.js +291 -0
  80. papers_app-0.2.0/papers/static/js/paper/reader/bar.js +50 -0
  81. papers_app-0.2.0/papers/static/js/paper/reader/cite.js +36 -0
  82. papers_app-0.2.0/papers/static/js/paper/reader/finish.js +54 -0
  83. papers_app-0.2.0/papers/static/js/paper/reader/highlighter.js +132 -0
  84. papers_app-0.2.0/papers/static/js/paper/reader/keys.js +30 -0
  85. papers_app-0.2.0/papers/static/js/paper/reader/layout.js +69 -0
  86. papers_app-0.2.0/papers/static/js/paper/reader/panel.js +105 -0
  87. papers_app-0.2.0/papers/static/js/paper/reader/progress.js +71 -0
  88. papers_app-0.2.0/papers/static/js/paper/reader/route.js +17 -0
  89. papers_app-0.2.0/papers/static/js/paper/reader/selection.js +113 -0
  90. papers_app-0.2.0/papers/static/js/paper/reader/state.js +22 -0
  91. papers_app-0.2.0/papers/static/js/paper/reader/terms.js +85 -0
  92. papers_app-0.2.0/papers/static/js/paper/reader/views.js +126 -0
  93. papers_app-0.2.0/papers/static/js/paper/reader/vocab.js +122 -0
  94. papers_app-0.2.0/papers/static/js/paper/reader/zoom.js +29 -0
  95. papers_app-0.2.0/papers/static/js/paper/reader.js +92 -0
  96. papers_app-0.2.0/papers/static/js/paper/review.js +109 -0
  97. papers_app-0.2.0/papers/static/js/paper/shared.js +23 -0
  98. papers_app-0.2.0/papers/static/js/pdfview.js +128 -0
  99. papers_app-0.2.0/papers/static/js/readprefs.js +123 -0
  100. papers_app-0.2.0/papers/static/js/speech.js +39 -0
  101. papers_app-0.2.0/papers/static/js/textview.js +52 -0
  102. papers_app-0.2.0/papers/static/js/theme.js +52 -0
  103. papers_app-0.2.0/papers/static/js/tracker.js +97 -0
  104. papers_app-0.2.0/papers/store.py +100 -0
  105. papers_app-0.2.0/pyproject.toml +65 -0
  106. papers_app-0.2.0/tests/__init__.py +0 -0
  107. papers_app-0.2.0/tests/conftest.py +54 -0
  108. papers_app-0.2.0/tests/test_abstract_figures.py +88 -0
  109. papers_app-0.2.0/tests/test_add_link.py +65 -0
  110. papers_app-0.2.0/tests/test_agent.py +164 -0
  111. papers_app-0.2.0/tests/test_agent_actions.py +104 -0
  112. papers_app-0.2.0/tests/test_ai.py +75 -0
  113. papers_app-0.2.0/tests/test_capture.py +50 -0
  114. papers_app-0.2.0/tests/test_claude_code.py +119 -0
  115. papers_app-0.2.0/tests/test_conversations.py +178 -0
  116. papers_app-0.2.0/tests/test_folders.py +44 -0
  117. papers_app-0.2.0/tests/test_frontend.py +14 -0
  118. papers_app-0.2.0/tests/test_highlights_notes.py +99 -0
  119. papers_app-0.2.0/tests/test_keys.py +72 -0
  120. papers_app-0.2.0/tests/test_learning.py +47 -0
  121. papers_app-0.2.0/tests/test_library_covers.py +18 -0
  122. papers_app-0.2.0/tests/test_library_folder.py +107 -0
  123. papers_app-0.2.0/tests/test_metadata.py +74 -0
  124. papers_app-0.2.0/tests/test_never_stuck.py +113 -0
  125. papers_app-0.2.0/tests/test_notes_ask.py +38 -0
  126. papers_app-0.2.0/tests/test_papers.py +166 -0
  127. papers_app-0.2.0/tests/test_prepare.py +80 -0
  128. papers_app-0.2.0/tests/test_progress.py +35 -0
  129. papers_app-0.2.0/tests/test_prompts.py +61 -0
  130. papers_app-0.2.0/tests/test_provider_list.py +102 -0
  131. papers_app-0.2.0/tests/test_providers.py +104 -0
  132. papers_app-0.2.0/tests/test_recall_refs.py +56 -0
  133. papers_app-0.2.0/tests/test_review.py +50 -0
  134. papers_app-0.2.0/tests/test_scaffold.py +11 -0
  135. papers_app-0.2.0/tests/test_search.py +49 -0
  136. papers_app-0.2.0/tests/test_streaming.py +90 -0
  137. papers_app-0.2.0/tests/test_tracker.py +66 -0
  138. papers_app-0.2.0/tests/test_triage.py +59 -0
  139. papers_app-0.2.0/tests/test_upload.py +64 -0
  140. papers_app-0.2.0/tests/test_vocabulary.py +80 -0
@@ -0,0 +1,10 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .pytest_cache/
5
+ data/
6
+ .env
7
+ dist/
8
+ build/
9
+ .ruff_cache/
10
+ *.egg-info/
@@ -0,0 +1,126 @@
1
+ # Contributing to Papers
2
+
3
+ Thanks for helping. Papers is a small app on purpose: a Python server (FastAPI) and a web page made of plain
4
+ JavaScript modules, with no build step. If you can read Python and JavaScript, you can change any part of it.
5
+
6
+ ## Set up
7
+
8
+ ```bash
9
+ git clone https://github.com/hBouanane/papers && cd papers
10
+ python -m venv .venv
11
+ .venv/Scripts/pip install -e ".[dev]" # macOS/Linux: .venv/bin/pip
12
+ .venv/Scripts/uvicorn papers.main:app --reload # http://localhost:8000; restarts when Python changes
13
+ ```
14
+
15
+ The web files are served as they are: edit them and reload the page. To try things without touching your own
16
+ library, point the app at another folder: `PAPERS_DATA=./scratch` (or `papers --data ./scratch`).
17
+
18
+ Before sending a pull request:
19
+
20
+ ```bash
21
+ .venv/Scripts/ruff check papers tests # style and common mistakes (`--fix` repairs most)
22
+ .venv/Scripts/pytest -q # all AI and network calls are faked; no keys needed
23
+ ```
24
+
25
+ CI runs both on Python 3.11 to 3.13 and checks that the Docker image starts.
26
+
27
+ ## How the code is laid out
28
+
29
+ ```
30
+ papers/
31
+ cli.py the `papers` command: options, then starts the server and opens the browser
32
+ config.py where data lives and every environment variable
33
+ main.py builds the app: the routers below, error handling, the web files, the Inbox watcher
34
+
35
+ routes/ the HTTP API, one file per part of the app
36
+ papers.py add (search result, link, PDF), list, edit, delete, the PDF file, prepare
37
+ goals.py goals (stored as "topics"), finding papers for them, BibTeX export
38
+ reading.py progress, finishing, figures and tables, references, the chain a paper is in
39
+ learning.py key points, vocabulary, explain/translate/ask (streamed), quiz and spaced review
40
+ notes.py notes and highlights
41
+ recall.py full-text search and "which paper had this idea?"
42
+ settings.py name, language, AI provider, library folder and the folder picker
43
+
44
+ store.py reading and writing papers; every change also updates the search index and the folder
45
+ ingest.py turning a PDF into a paper, the Inbox, and preparing papers ahead of time with the AI
46
+ llm.py every prompt: one function per task (skim, explain, glossary, quiz, grade, recall, ...), and the
47
+ tutor's rules for conversations (TUTOR, TASKS: how Explain, Simplify, Translate and questions answer)
48
+ ai/ getting a prompt to the chosen model and its answer back; streaming.py: thinking vs answer, Stop,
49
+ and giving up on a silent model
50
+ chat/ conversations: store.py (conversations and messages), answer.py (streams an answer and saves it)
51
+ agent/ Deep mode: tools.py (what the AI can look up and do), loop.py (the tool loop for each provider),
52
+ mcp_server.py (the same tools for Claude Code)
53
+ providers.py the provider list and which one is chosen, with its key, model and address
54
+ anthropic_api.py claude_code.py codex.py openai_compat.py one file per way of reaching a model
55
+
56
+ db.py SQLite schema, migrations and settings index.py full-text search (SQLite FTS5)
57
+ pdf.py text, titles and abstracts out of PDFs figures.py figures and tables cut out of PDFs
58
+ scholar.py Semantic Scholar and arXiv library.py the library folder (PDFs + Markdown notes)
59
+ notes.py notes and highlights storage folders.py the folder picker
60
+ bibtex.py BibTeX entries
61
+
62
+ static/ the web app (no build step; ES modules loaded by the browser)
63
+ index.html the page shell; links the stylesheets below in order
64
+ css/ styles by area, each file building on the ones before it:
65
+ tokens (colours, shadows, fonts for light, dim and dark), base (type, page, top bar,
66
+ theme switch, toast), components (buttons, cards, menus, covers, notes, vocabulary,
67
+ combobox, folder picker), then one per screen: library, goals, recall, map, paper
68
+ (overview, figures, review), reader, settings
69
+ js/main.js routes each #/address to a page; paste and drop anywhere to add papers
70
+ js/core.js shared helpers: api(), toast(), paper rows, markdown, the top bar
71
+ js/pages/ one file per screen: library, goals, recall, map, settings (+ shared.js)
72
+ js/paper/ a paper's screens: overview, reader, review, figures (+ shared.js)
73
+ js/paper/reader/ the reader's parts, wired together by readerPage() in reader.js; they share one
74
+ state object (state.js: the paper, the page's elements, the open view):
75
+ layout (markup), bar (one-row bar and its ⋯ menu), route (the pill at the bottom),
76
+ views (PDF or Text, Go to…, back to where you stopped), progress (what you've read,
77
+ skimming), selection (the bar on selected text), highlighter, panel (Ask, Words,
78
+ Notes; streamed answers), finish, zoom, keys (shortcuts), terms + vocab (the Words switch:
79
+ hard words marked in the page, with a card for each)
80
+ js/components/ reusable widgets: combobox (searchable dropdown), folderpicker
81
+ js/chat/ the conversation panel: conversation.js (History, composer, Quick/Deep), answer.js (an answer
82
+ being written), stream.js, render.js (Markdown, math, citations, visuals), widgets.js,
83
+ canvas.js (a visual opened large)
84
+ js/*.js shared by the paper screens: pdfview (PDF.js), textview, highlights, notes, tracker,
85
+ speech, readprefs (font, size, page tone), covers (first-page thumbnails), theme
86
+
87
+ tests/ one file per feature, using FastAPI's test client against a temporary database
88
+ ```
89
+
90
+ Two rules keep it easy to follow:
91
+
92
+ - **Routes stay thin.** A route checks its input (the pydantic `...In` classes), calls `store`, `ingest` or
93
+ `llm`, and returns JSON. Logic that isn't about HTTP goes in a module next to them.
94
+ - **The AI is only reached through `llm.py`.** Pages and routes never build prompts; tests replace the `llm`
95
+ functions with fakes (see `tests/conftest.py`, which also blocks any real AI call).
96
+
97
+ ## Common changes
98
+
99
+ | You want to | Look at |
100
+ | --- | --- |
101
+ | Change what the AI writes (key points, quiz, ...) | the prompt in `papers/llm.py` |
102
+ | Change how Explain or Simplify answer | `TASKS` in `papers/llm.py` (the rules all answers follow are `TUTOR`) |
103
+ | Give the AI a new tool in Deep mode | a function and an entry in `TOOLS`, `papers/agent/tools.py` (`"act": True` if it changes the library, with `data` for Undo) |
104
+ | Add a kind of visual | a fenced block in `papers/static/js/chat/render.js` (or a widget in `widgets.js`), and a line in `TUTOR` |
105
+ | Add a provider that speaks the OpenAI chat API | one line in `PROVIDERS`, `papers/ai/providers.py` |
106
+ | Add a provider with its own API | a module in `papers/ai/` with `parse()` and `stream()`, and a branch in `ai/__init__.py` |
107
+ | Add an API endpoint | the matching file in `papers/routes/` (a new area gets a new file, added to `routes/__init__.py`) |
108
+ | Add a column or table | `SCHEMA` and the migrations in `papers/db.py` |
109
+ | Add a screen | a file in `static/js/pages/` and a line in the `routes` list of `static/js/main.js` |
110
+ | Change colours or spacing | `static/css/tokens.css` (see [DESIGN.md](DESIGN.md)) |
111
+ | Change how a screen looks | its file in `static/css/`; shared pieces are in `components.css` |
112
+ | Change something in the reader | its part in `static/js/paper/reader/` (each file says what it does at the top) |
113
+
114
+ ## Style
115
+
116
+ - Python: `ruff` settings in `pyproject.toml` (120 columns). Type hints on public functions; a docstring when
117
+ the name doesn't say it all.
118
+ - JavaScript: ES modules, no framework, no build. Keep markup in template strings next to the code that
119
+ wires it up, and escape anything from the server or the user with `esc()`.
120
+ - Text the user reads: short, plain sentences; say what to do, not what went wrong inside.
121
+ - Light, dim and dark themes all need to look right, and motion respects `prefers-reduced-motion`.
122
+
123
+ ## Releasing
124
+
125
+ Bump `__version__` in `papers/__init__.py` and push a tag like `v0.2.0`. The release workflow publishes to PyPI
126
+ and pushes the Docker image to `ghcr.io`.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 hBouanane
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,138 @@
1
+ Metadata-Version: 2.5
2
+ Name: papers-app
3
+ Version: 0.2.0
4
+ Summary: An AI reading companion for research papers: skim, read, ask, recall. Runs on your computer.
5
+ Project-URL: Homepage, https://github.com/hBouanane/papers
6
+ Project-URL: Issues, https://github.com/hBouanane/papers/issues
7
+ Author: hBouanane
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: ai,llm,papers,pdf,reading,research
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Web Environment
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Scientific/Engineering
16
+ Requires-Python: >=3.11
17
+ Requires-Dist: anthropic>=0.40
18
+ Requires-Dist: fastapi>=0.115
19
+ Requires-Dist: httpx>=0.27
20
+ Requires-Dist: keyring>=24
21
+ Requires-Dist: pdfplumber>=0.11
22
+ Requires-Dist: pypdf>=5
23
+ Requires-Dist: python-multipart>=0.0.9
24
+ Requires-Dist: uvicorn>=0.30
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=8; extra == 'dev'
27
+ Requires-Dist: ruff>=0.6; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # Papers
31
+
32
+ An AI reading companion for research papers. Define what you are working on, get relevant
33
+ papers, skim them Andrew Ng–style, read with an explainer that knows the whole paper, track
34
+ where you stopped, quiz yourself when you finish, ask "where did I read this idea?", and follow
35
+ reference chains. It runs on your computer; your papers and notes stay there.
36
+ See [SPEC.md](SPEC.md) for the design.
37
+
38
+ ## Install
39
+
40
+ With Python 3.11 or newer, one command (like `npx` for Node):
41
+
42
+ ```bash
43
+ uvx papers-app
44
+ ```
45
+
46
+ or install it to keep it around, then start it with `papers`:
47
+
48
+ ```bash
49
+ pipx install papers-app
50
+ ```
51
+
52
+ `papers` opens http://localhost:8000 in your browser. Options: `--port 9000`, `--data D:\Papers` (where the
53
+ database and PDFs live), `--no-browser`, `--host 0.0.0.0` (reach it from other devices on your network; there
54
+ is no login, so only on networks you trust).
55
+
56
+ ### With Docker
57
+
58
+ ```bash
59
+ docker compose up -d
60
+ ```
61
+
62
+ Then open http://localhost:8000. Your library is kept in the `papers-data` volume. See
63
+ [docker-compose.yml](docker-compose.yml) to use a folder on your computer for the library folder, or a model
64
+ running on your computer (Ollama, LM Studio). Subscriptions (Claude, ChatGPT) need their app on the same
65
+ computer, so in Docker use an API key or a local model.
66
+
67
+ ### From the source
68
+
69
+ ```bash
70
+ git clone https://github.com/hBouanane/papers && cd papers
71
+ python -m venv .venv
72
+ .venv/Scripts/pip install -e ".[dev]" # macOS/Linux: .venv/bin/pip
73
+ .venv/Scripts/papers
74
+ ```
75
+
76
+ ## Choosing an AI model
77
+
78
+ Settings > AI model has one list of providers; each is set up the same way (key if it needs one, then
79
+ **List models** and pick one). Each provider keeps its own key and model, so you can switch freely.
80
+
81
+ - **Use your subscription**: Claude (Pro, Max) through [Claude Code](https://claude.com/claude-code), or
82
+ ChatGPT (Plus, Pro) through OpenAI's [Codex CLI](https://developers.openai.com/codex/cli/reference)
83
+ (`npm install -g @openai/codex`, then `codex login`). Both run on your computer with your own account,
84
+ for your own use: don't host the app for others on your subscription.
85
+ - **Pay per use with an API key**: Anthropic, OpenAI, Google Gemini (has a free tier), Mistral, Groq, or
86
+ OpenRouter (hundreds of models).
87
+ - **On this computer**: [Ollama](https://ollama.com) or [LM Studio](https://lmstudio.ai). Free, and nothing
88
+ leaves your machine.
89
+ - **Other**: any OpenAI-compatible server (vLLM, llama.cpp, a company gateway), by its address.
90
+
91
+ Small local models can't read a whole paper; *More options* can send just its beginning.
92
+ Keys are kept in your system's keychain (Windows Credential Manager, macOS Keychain, or the Secret Service on Linux),
93
+ so you paste each one once; Settings shows which provider has a key saved (its last four characters) and can forget
94
+ it. Where there's no keychain (Docker, servers) they stay in the app's database. Keys are never sent back to the page.
95
+
96
+ With a subscription the app runs the official CLI on your computer (`claude -p` or `codex exec`, with no
97
+ tools), which signs in with your own account; usage counts toward your plan. The app never reads or stores
98
+ those credentials. `PAPERS_CLAUDE_BIN` and `PAPERS_CODEX_BIN` point at a specific binary if needed.
99
+
100
+ ## Asking the AI
101
+
102
+ Select text in a paper and press **Explain** (a short lesson: the problem, the idea, the formula read slowly, a worked
103
+ example, why it works, where it connects in the paper), **Simplify** (the same passage in plain English) or
104
+ **Translate**. Each starts a conversation you can keep going; **History** keeps them per paper, and **Add to chat**
105
+ attaches more passages.
106
+
107
+ Answers can contain formulas, clickable citations ([§3.4], [Fig. 1]), charts, diagrams, the paper's own figures with
108
+ "look here" boxes, and interactive widgets. Switch the chat to **Deep** and the AI first reads the sections, looks at
109
+ the figures and checks your notes and library before it answers; ask it to and it saves notes, words and
110
+ highlights, or adds a paper from the references (each with Undo). Deep mode works with Claude (subscription or API
111
+ key) and with models that support tool calling; in **More options**, tick *This model can see images* if yours does,
112
+ and *Interactive pages* to let the AI write small demos that run in a sealed frame.
113
+
114
+ ## Library folder
115
+
116
+ In Settings, choose a folder (**Choose…** opens a folder browser with your usual folders and drives) and the app keeps a copy of your
117
+ library there: one folder per goal (`Unsorted` for the rest), each paper as `Author et al. Year - Title.pdf`
118
+ with a `.md` notes file next to it (key points, explanations, quiz, `[[links]]` to related papers, so
119
+ Obsidian shows them as a graph). PDFs dropped into its `Inbox` folder are imported within about 10 seconds.
120
+
121
+ ## Settings from the environment
122
+
123
+ | Variable | What it does |
124
+ | --- | --- |
125
+ | `PAPERS_DATA` | Folder for the database, PDFs and figures (same as `--data`). Default: `%APPDATA%\Papers`, `~/Library/Application Support/Papers` or `~/.local/share/papers` |
126
+ | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY` | API keys, if you'd rather not type them in Settings |
127
+ | `S2_API_KEY` | A Semantic Scholar key; without one, search often falls back to arXiv because of rate limits |
128
+ | `PAPERS_MODEL` | The Claude model used by default (`claude-opus-5-5`) |
129
+ | `PAPERS_INBOX_POLL` | Seconds between Inbox checks (`0` turns it off) |
130
+
131
+ ## Contributing
132
+
133
+ See [CONTRIBUTING.md](CONTRIBUTING.md): how the code is laid out, how to run it and the tests, and where to
134
+ start for common changes.
135
+
136
+ ## License
137
+
138
+ [MIT](LICENSE)
@@ -0,0 +1,109 @@
1
+ # Papers
2
+
3
+ An AI reading companion for research papers. Define what you are working on, get relevant
4
+ papers, skim them Andrew Ng–style, read with an explainer that knows the whole paper, track
5
+ where you stopped, quiz yourself when you finish, ask "where did I read this idea?", and follow
6
+ reference chains. It runs on your computer; your papers and notes stay there.
7
+ See [SPEC.md](SPEC.md) for the design.
8
+
9
+ ## Install
10
+
11
+ With Python 3.11 or newer, one command (like `npx` for Node):
12
+
13
+ ```bash
14
+ uvx papers-app
15
+ ```
16
+
17
+ or install it to keep it around, then start it with `papers`:
18
+
19
+ ```bash
20
+ pipx install papers-app
21
+ ```
22
+
23
+ `papers` opens http://localhost:8000 in your browser. Options: `--port 9000`, `--data D:\Papers` (where the
24
+ database and PDFs live), `--no-browser`, `--host 0.0.0.0` (reach it from other devices on your network; there
25
+ is no login, so only on networks you trust).
26
+
27
+ ### With Docker
28
+
29
+ ```bash
30
+ docker compose up -d
31
+ ```
32
+
33
+ Then open http://localhost:8000. Your library is kept in the `papers-data` volume. See
34
+ [docker-compose.yml](docker-compose.yml) to use a folder on your computer for the library folder, or a model
35
+ running on your computer (Ollama, LM Studio). Subscriptions (Claude, ChatGPT) need their app on the same
36
+ computer, so in Docker use an API key or a local model.
37
+
38
+ ### From the source
39
+
40
+ ```bash
41
+ git clone https://github.com/hBouanane/papers && cd papers
42
+ python -m venv .venv
43
+ .venv/Scripts/pip install -e ".[dev]" # macOS/Linux: .venv/bin/pip
44
+ .venv/Scripts/papers
45
+ ```
46
+
47
+ ## Choosing an AI model
48
+
49
+ Settings > AI model has one list of providers; each is set up the same way (key if it needs one, then
50
+ **List models** and pick one). Each provider keeps its own key and model, so you can switch freely.
51
+
52
+ - **Use your subscription**: Claude (Pro, Max) through [Claude Code](https://claude.com/claude-code), or
53
+ ChatGPT (Plus, Pro) through OpenAI's [Codex CLI](https://developers.openai.com/codex/cli/reference)
54
+ (`npm install -g @openai/codex`, then `codex login`). Both run on your computer with your own account,
55
+ for your own use: don't host the app for others on your subscription.
56
+ - **Pay per use with an API key**: Anthropic, OpenAI, Google Gemini (has a free tier), Mistral, Groq, or
57
+ OpenRouter (hundreds of models).
58
+ - **On this computer**: [Ollama](https://ollama.com) or [LM Studio](https://lmstudio.ai). Free, and nothing
59
+ leaves your machine.
60
+ - **Other**: any OpenAI-compatible server (vLLM, llama.cpp, a company gateway), by its address.
61
+
62
+ Small local models can't read a whole paper; *More options* can send just its beginning.
63
+ Keys are kept in your system's keychain (Windows Credential Manager, macOS Keychain, or the Secret Service on Linux),
64
+ so you paste each one once; Settings shows which provider has a key saved (its last four characters) and can forget
65
+ it. Where there's no keychain (Docker, servers) they stay in the app's database. Keys are never sent back to the page.
66
+
67
+ With a subscription the app runs the official CLI on your computer (`claude -p` or `codex exec`, with no
68
+ tools), which signs in with your own account; usage counts toward your plan. The app never reads or stores
69
+ those credentials. `PAPERS_CLAUDE_BIN` and `PAPERS_CODEX_BIN` point at a specific binary if needed.
70
+
71
+ ## Asking the AI
72
+
73
+ Select text in a paper and press **Explain** (a short lesson: the problem, the idea, the formula read slowly, a worked
74
+ example, why it works, where it connects in the paper), **Simplify** (the same passage in plain English) or
75
+ **Translate**. Each starts a conversation you can keep going; **History** keeps them per paper, and **Add to chat**
76
+ attaches more passages.
77
+
78
+ Answers can contain formulas, clickable citations ([§3.4], [Fig. 1]), charts, diagrams, the paper's own figures with
79
+ "look here" boxes, and interactive widgets. Switch the chat to **Deep** and the AI first reads the sections, looks at
80
+ the figures and checks your notes and library before it answers; ask it to and it saves notes, words and
81
+ highlights, or adds a paper from the references (each with Undo). Deep mode works with Claude (subscription or API
82
+ key) and with models that support tool calling; in **More options**, tick *This model can see images* if yours does,
83
+ and *Interactive pages* to let the AI write small demos that run in a sealed frame.
84
+
85
+ ## Library folder
86
+
87
+ In Settings, choose a folder (**Choose…** opens a folder browser with your usual folders and drives) and the app keeps a copy of your
88
+ library there: one folder per goal (`Unsorted` for the rest), each paper as `Author et al. Year - Title.pdf`
89
+ with a `.md` notes file next to it (key points, explanations, quiz, `[[links]]` to related papers, so
90
+ Obsidian shows them as a graph). PDFs dropped into its `Inbox` folder are imported within about 10 seconds.
91
+
92
+ ## Settings from the environment
93
+
94
+ | Variable | What it does |
95
+ | --- | --- |
96
+ | `PAPERS_DATA` | Folder for the database, PDFs and figures (same as `--data`). Default: `%APPDATA%\Papers`, `~/Library/Application Support/Papers` or `~/.local/share/papers` |
97
+ | `ANTHROPIC_API_KEY`, `OPENAI_API_KEY` | API keys, if you'd rather not type them in Settings |
98
+ | `S2_API_KEY` | A Semantic Scholar key; without one, search often falls back to arXiv because of rate limits |
99
+ | `PAPERS_MODEL` | The Claude model used by default (`claude-opus-5-5`) |
100
+ | `PAPERS_INBOX_POLL` | Seconds between Inbox checks (`0` turns it off) |
101
+
102
+ ## Contributing
103
+
104
+ See [CONTRIBUTING.md](CONTRIBUTING.md): how the code is laid out, how to run it and the tests, and where to
105
+ start for common changes.
106
+
107
+ ## License
108
+
109
+ [MIT](LICENSE)
@@ -0,0 +1,2 @@
1
+ """Papers: an AI reading companion for research papers."""
2
+ __version__ = "0.2.0"
@@ -0,0 +1,3 @@
1
+ from papers.cli import main
2
+
3
+ main()
@@ -0,0 +1,2 @@
1
+ """Deep mode: the AI uses tools (tools.py) in a loop (loop.py) while it answers; mcp_server.py gives the same tools
2
+ to Claude Code."""