litmark 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 (129) hide show
  1. litmark-0.1.0/.gitignore +15 -0
  2. litmark-0.1.0/LICENSE +21 -0
  3. litmark-0.1.0/PKG-INFO +204 -0
  4. litmark-0.1.0/README.md +174 -0
  5. litmark-0.1.0/frontend/index.html +13 -0
  6. litmark-0.1.0/frontend/package-lock.json +2226 -0
  7. litmark-0.1.0/frontend/package.json +33 -0
  8. litmark-0.1.0/frontend/src/App.tsx +639 -0
  9. litmark-0.1.0/frontend/src/Sidebar.tsx +300 -0
  10. litmark-0.1.0/frontend/src/api.ts +374 -0
  11. litmark-0.1.0/frontend/src/chat/Chat.tsx +400 -0
  12. litmark-0.1.0/frontend/src/editor/MarkdownEditor.tsx +326 -0
  13. litmark-0.1.0/frontend/src/editor/livePreview.ts +497 -0
  14. litmark-0.1.0/frontend/src/events.ts +108 -0
  15. litmark-0.1.0/frontend/src/main.tsx +9 -0
  16. litmark-0.1.0/frontend/src/markdown.ts +190 -0
  17. litmark-0.1.0/frontend/src/pdf/PdfViewer.tsx +631 -0
  18. litmark-0.1.0/frontend/src/styles.css +1125 -0
  19. litmark-0.1.0/frontend/test/.gitignore +1 -0
  20. litmark-0.1.0/frontend/test/app-render.test.mjs +131 -0
  21. litmark-0.1.0/frontend/test/browser.test.mjs +350 -0
  22. litmark-0.1.0/frontend/test/build-app-bundle.mjs +18 -0
  23. litmark-0.1.0/frontend/test/marionette.mjs +181 -0
  24. litmark-0.1.0/frontend/test/markdown.test.mjs +95 -0
  25. litmark-0.1.0/frontend/test/url-suffix-plugin.mjs +14 -0
  26. litmark-0.1.0/frontend/tsconfig.json +23 -0
  27. litmark-0.1.0/frontend/vite.config.ts +41 -0
  28. litmark-0.1.0/pyproject.toml +84 -0
  29. litmark-0.1.0/spec.md +346 -0
  30. litmark-0.1.0/src/litmark/__init__.py +7 -0
  31. litmark-0.1.0/src/litmark/agent/__init__.py +1 -0
  32. litmark-0.1.0/src/litmark/agent/base.py +151 -0
  33. litmark-0.1.0/src/litmark/agent/claude_sdk.py +345 -0
  34. litmark-0.1.0/src/litmark/agent/fake.py +157 -0
  35. litmark-0.1.0/src/litmark/agent/prompts.py +74 -0
  36. litmark-0.1.0/src/litmark/agent/runner.py +470 -0
  37. litmark-0.1.0/src/litmark/agent/tools.py +689 -0
  38. litmark-0.1.0/src/litmark/api/__init__.py +1 -0
  39. litmark-0.1.0/src/litmark/api/app.py +229 -0
  40. litmark-0.1.0/src/litmark/api/routes.py +649 -0
  41. litmark-0.1.0/src/litmark/bibliography.py +334 -0
  42. litmark-0.1.0/src/litmark/cli.py +211 -0
  43. litmark-0.1.0/src/litmark/db.py +216 -0
  44. litmark-0.1.0/src/litmark/documents.py +470 -0
  45. litmark-0.1.0/src/litmark/errors.py +71 -0
  46. litmark-0.1.0/src/litmark/events.py +135 -0
  47. litmark-0.1.0/src/litmark/extraction.py +726 -0
  48. litmark-0.1.0/src/litmark/jobs.py +183 -0
  49. litmark-0.1.0/src/litmark/references.py +448 -0
  50. litmark-0.1.0/src/litmark/services.py +170 -0
  51. litmark-0.1.0/src/litmark/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  52. litmark-0.1.0/src/litmark/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  53. litmark-0.1.0/src/litmark/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  54. litmark-0.1.0/src/litmark/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  55. litmark-0.1.0/src/litmark/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  56. litmark-0.1.0/src/litmark/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  57. litmark-0.1.0/src/litmark/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  58. litmark-0.1.0/src/litmark/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  59. litmark-0.1.0/src/litmark/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  60. litmark-0.1.0/src/litmark/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  61. litmark-0.1.0/src/litmark/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  62. litmark-0.1.0/src/litmark/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  63. litmark-0.1.0/src/litmark/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  64. litmark-0.1.0/src/litmark/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  65. litmark-0.1.0/src/litmark/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  66. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  67. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  68. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  69. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  70. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  71. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  72. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  73. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  74. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  75. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  76. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  77. litmark-0.1.0/src/litmark/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  78. litmark-0.1.0/src/litmark/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  79. litmark-0.1.0/src/litmark/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  80. litmark-0.1.0/src/litmark/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  81. litmark-0.1.0/src/litmark/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  82. litmark-0.1.0/src/litmark/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  83. litmark-0.1.0/src/litmark/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  84. litmark-0.1.0/src/litmark/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  85. litmark-0.1.0/src/litmark/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  86. litmark-0.1.0/src/litmark/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  87. litmark-0.1.0/src/litmark/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  88. litmark-0.1.0/src/litmark/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  89. litmark-0.1.0/src/litmark/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  90. litmark-0.1.0/src/litmark/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  91. litmark-0.1.0/src/litmark/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  92. litmark-0.1.0/src/litmark/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  93. litmark-0.1.0/src/litmark/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  94. litmark-0.1.0/src/litmark/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  95. litmark-0.1.0/src/litmark/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  96. litmark-0.1.0/src/litmark/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  97. litmark-0.1.0/src/litmark/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  98. litmark-0.1.0/src/litmark/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  99. litmark-0.1.0/src/litmark/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  100. litmark-0.1.0/src/litmark/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  101. litmark-0.1.0/src/litmark/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  102. litmark-0.1.0/src/litmark/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  103. litmark-0.1.0/src/litmark/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  104. litmark-0.1.0/src/litmark/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  105. litmark-0.1.0/src/litmark/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  106. litmark-0.1.0/src/litmark/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  107. litmark-0.1.0/src/litmark/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  108. litmark-0.1.0/src/litmark/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  109. litmark-0.1.0/src/litmark/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  110. litmark-0.1.0/src/litmark/static/assets/editor-Bn9f9nF2.js +28 -0
  111. litmark-0.1.0/src/litmark/static/assets/editor-Bn9f9nF2.js.map +1 -0
  112. litmark-0.1.0/src/litmark/static/assets/index-BdJz60Ic.css +1 -0
  113. litmark-0.1.0/src/litmark/static/assets/index-C7zeCZgl.js +12 -0
  114. litmark-0.1.0/src/litmark/static/assets/index-C7zeCZgl.js.map +1 -0
  115. litmark-0.1.0/src/litmark/static/assets/katex-uLN8M5ZI.js +258 -0
  116. litmark-0.1.0/src/litmark/static/assets/katex-uLN8M5ZI.js.map +1 -0
  117. litmark-0.1.0/src/litmark/static/assets/pdf.worker.min-yatZIOMy.mjs +21 -0
  118. litmark-0.1.0/src/litmark/static/assets/pdfjs-BDm9ube5.js +13 -0
  119. litmark-0.1.0/src/litmark/static/assets/pdfjs-BDm9ube5.js.map +1 -0
  120. litmark-0.1.0/src/litmark/static/index.html +17 -0
  121. litmark-0.1.0/src/litmark/workspace.py +489 -0
  122. litmark-0.1.0/tests/conftest.py +175 -0
  123. litmark-0.1.0/tests/test_acceptance.py +966 -0
  124. litmark-0.1.0/tests/test_bibliography.py +262 -0
  125. litmark-0.1.0/tests/test_claude_adapter.py +216 -0
  126. litmark-0.1.0/tests/test_geometry.py +134 -0
  127. litmark-0.1.0/tests/test_packaging.py +205 -0
  128. litmark-0.1.0/tests/test_proxy_access.py +115 -0
  129. litmark-0.1.0/tests/test_smoke.py +61 -0
@@ -0,0 +1,15 @@
1
+ # Byte-compiled
2
+ __pycache__/
3
+ *.py[cod]
4
+ .venv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ node_modules/
9
+ frontend/dist/
10
+ src/litmark/static/
11
+ .pytest_cache/
12
+ .ruff_cache/
13
+ my-research/
14
+ *.sqlite*
15
+ frontend/test/bundle/
litmark-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thibaut Lamadon
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.
litmark-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,204 @@
1
+ Metadata-Version: 2.5
2
+ Name: litmark
3
+ Version: 0.1.0
4
+ Summary: Local research workspace: import papers, read cited summaries, write sourced Markdown notes, chat with a coding agent.
5
+ Project-URL: Homepage, https://github.com/tlamadon/litmark
6
+ Project-URL: Repository, https://github.com/tlamadon/litmark
7
+ Project-URL: Issues, https://github.com/tlamadon/litmark/issues
8
+ Author: Litmark contributors
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,bibtex,markdown,notes,pdf,research
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Web Environment
14
+ Classifier: Framework :: FastAPI
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: fastapi<1.0,>=0.115
22
+ Requires-Dist: pdfplumber<1.0,>=0.11
23
+ Requires-Dist: pydantic<3.0,>=2.7
24
+ Requires-Dist: pypdf<7.0,>=4.2
25
+ Requires-Dist: python-multipart>=0.0.9
26
+ Requires-Dist: uvicorn[standard]<1.0,>=0.30
27
+ Provides-Extra: claude
28
+ Requires-Dist: claude-agent-sdk<1.0,>=0.2; extra == 'claude'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # Litmark
32
+
33
+ A local research application: import papers, read short cited summaries, write
34
+ Markdown notes, inspect the cited PDF passages, and chat with a coding agent
35
+ that can search the project and edit its files.
36
+
37
+ **Import papers → ask questions → write a sourced note → inspect the evidence → refine the note.**
38
+
39
+ Everything you write stays as ordinary files in a movable project directory:
40
+ `notes/*.md`, `documents/<id>/original.pdf`, `references.json`. The application
41
+ is a convenient view onto those files, not their owner.
42
+
43
+ ## Install
44
+
45
+ ```bash
46
+ python -m pip install litmark # core reader and editor
47
+ python -m pip install 'litmark[claude]' # plus the agent adapter
48
+ ```
49
+
50
+ Requires Python 3.11+. Tested on macOS and Linux. The published wheel contains
51
+ the compiled browser assets — **you do not need Node, npm, or a second web
52
+ server to run this application.**
53
+
54
+ With `pipx` or `uv`:
55
+
56
+ ```bash
57
+ pipx install litmark
58
+ uv tool install litmark
59
+ ```
60
+
61
+ ## Use
62
+
63
+ ```bash
64
+ litmark init ./my-research
65
+ litmark serve ./my-research --open
66
+ ```
67
+
68
+ `serve` binds to `127.0.0.1`, prints the local URL, and serves exactly one
69
+ project per process. Reopening an existing project needs no initialization, and
70
+ `init` never overwrites existing material.
71
+
72
+ ### Reaching it through a proxy or port-forward
73
+
74
+ By default the server binds to loopback *and* rejects any `Host` header that is
75
+ not a loopback name. That second check is what stops a malicious page from
76
+ using DNS rebinding to talk to your local server — but behind a reverse proxy
77
+ or a port-forward the header carries the proxy's hostname, so the check would
78
+ reject every real request. Widen it explicitly:
79
+
80
+ ```bash
81
+ # Bind beyond loopback; any Host header is then accepted.
82
+ litmark serve ./my-research --host 0.0.0.0
83
+
84
+ # Or name the proxy's hostname and keep the check strict.
85
+ litmark serve ./my-research --host 0.0.0.0 --allow-host papers.internal
86
+ ```
87
+
88
+ The per-process session credential embedded in the served page remains the
89
+ access control in both cases. On an untrusted network prefer an SSH tunnel,
90
+ which keeps the default loopback binding intact:
91
+
92
+ ```bash
93
+ ssh -N -L 8765:127.0.0.1:8765 you@the-machine
94
+ ```
95
+
96
+ Check your environment at any time:
97
+
98
+ ```bash
99
+ litmark doctor ./my-research
100
+ ```
101
+
102
+ `doctor` reports on the workspace, the optional agent dependency, the runtime
103
+ it needs, and whether authentication is configured — without printing secrets.
104
+
105
+ ## Agent configuration
106
+
107
+ The agent backend is the [Claude Agent SDK for
108
+ Python](https://code.claude.com/docs/en/agent-sdk/python), behind a
109
+ provider-neutral adapter. Provider credentials and billing are separate from
110
+ installing this application; a consumer chat subscription does not by itself
111
+ grant SDK access.
112
+
113
+ The reader and editor work with no agent account at all. Import and text
114
+ extraction still run; automatic summaries wait until an agent is configured,
115
+ and the interface says so plainly.
116
+
117
+ ## Project layout
118
+
119
+ | Path | Purpose |
120
+ | --- | --- |
121
+ | `project.toml` | Schema version and non-secret project settings. |
122
+ | `documents/<id>/original.pdf` | Original immutable PDF. |
123
+ | `documents/<id>/metadata.json` | Identity, hash, filename, title, page count, status. |
124
+ | `documents/<id>/pages.json` | Per-page text, character geometry, offset mapping. |
125
+ | `documents/<id>/summary.md` | Editable, cited summary. |
126
+ | `notes/*.md` | User and agent notes. |
127
+ | `references.json` | Versioned source registry. |
128
+ | `references.bib` | Generated BibTeX bibliography of the imported documents. |
129
+ | `.research/state.sqlite` | Conversations, events, jobs, run state, change log. |
130
+ | `.research/history/` | Previous file contents, for review and undo. |
131
+ | `.research/runs/` | Staged agent edits and run diagnostics. |
132
+
133
+ ## Citations
134
+
135
+ A citation is an ordinary Markdown link with an application-specific
136
+ destination:
137
+
138
+ ```markdown
139
+ The identification argument relies on a mobility restriction.
140
+ [Assumption 2, p. 12](source:ref-001)
141
+ ```
142
+
143
+ `ref-001` resolves through `references.json`, which records the document, the
144
+ immutable PDF content hash, the one-based physical page number, the quoted
145
+ passage, and normalized highlight rectangles. Reference resolution validates
146
+ *where* a passage is, not whether it supports the claim — you assess that by
147
+ reading the evidence.
148
+
149
+ ## Bibliography
150
+
151
+ **Write .bib** in the sidebar generates `references.bib` in the project
152
+ directory, and **Download** fetches the same file without writing it. There is
153
+ one entry per imported document — a `.bib` entry is a work, so the page each
154
+ reference points at travels in the `\cite[p.~12]{key}` command the export
155
+ returns alongside the entries, not in the entry itself.
156
+
157
+ Entries carry only what the PDF actually supplies. A paper with no author
158
+ metadata gets an entry with no `author` field and a warning saying so; nothing
159
+ is filled in from general knowledge. The output is deterministic, so exporting
160
+ an unchanged bibliography rewrites nothing, and a `.bib` you edited by hand is
161
+ copied into `.research/history/` before it is replaced.
162
+
163
+ ## Development
164
+
165
+ ```bash
166
+ uv venv && uv pip install -e . --group dev
167
+ npm --prefix frontend install
168
+ npm --prefix frontend run build # writes src/litmark/static/
169
+ uv run pytest
170
+ uv run litmark serve ./my-research --reload
171
+ ```
172
+
173
+ `npm run dev` runs the frontend with hot reload against a server started
174
+ separately on port 8765.
175
+
176
+ ### Tests
177
+
178
+ ```bash
179
+ uv run pytest # server and acceptance criteria
180
+ uv run pytest --runslow # plus: build the wheel, install it clean, serve it
181
+ npm --prefix frontend test # renderer unit tests, and the bundle run in a DOM
182
+
183
+ # Real-browser checks (A2 live preview, A6 highlight geometry under zoom).
184
+ # Point it at a project whose open note contains a source: citation.
185
+ litmark serve ./my-research &
186
+ LITMARK_BASE_URL=http://127.0.0.1:8765/ npm --prefix frontend run test:browser
187
+ ```
188
+
189
+ The browser suite drives headless Firefox over Marionette. Headless Chromium is
190
+ deliberately not used: under some sandboxes it cannot reach loopback HTTP — it
191
+ returns an empty document where `curl` succeeds — so a Chromium suite passes
192
+ without having checked anything.
193
+
194
+ ## Scope
195
+
196
+ v0.1 covers ingestion of text-based PDFs, cited summaries, Markdown live-preview
197
+ editing, PDF evidence with highlights, chat with one agent backend, and manual
198
+ references. Deferred: OCR, URL downloads, Word/HTML ingestion, Zotero
199
+ integration, semantic search, multiple agent providers, arbitrary analysis
200
+ execution, multi-user collaboration, full mobile editing, and public hosting.
201
+
202
+ ## License
203
+
204
+ MIT.
@@ -0,0 +1,174 @@
1
+ # Litmark
2
+
3
+ A local research application: import papers, read short cited summaries, write
4
+ Markdown notes, inspect the cited PDF passages, and chat with a coding agent
5
+ that can search the project and edit its files.
6
+
7
+ **Import papers → ask questions → write a sourced note → inspect the evidence → refine the note.**
8
+
9
+ Everything you write stays as ordinary files in a movable project directory:
10
+ `notes/*.md`, `documents/<id>/original.pdf`, `references.json`. The application
11
+ is a convenient view onto those files, not their owner.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ python -m pip install litmark # core reader and editor
17
+ python -m pip install 'litmark[claude]' # plus the agent adapter
18
+ ```
19
+
20
+ Requires Python 3.11+. Tested on macOS and Linux. The published wheel contains
21
+ the compiled browser assets — **you do not need Node, npm, or a second web
22
+ server to run this application.**
23
+
24
+ With `pipx` or `uv`:
25
+
26
+ ```bash
27
+ pipx install litmark
28
+ uv tool install litmark
29
+ ```
30
+
31
+ ## Use
32
+
33
+ ```bash
34
+ litmark init ./my-research
35
+ litmark serve ./my-research --open
36
+ ```
37
+
38
+ `serve` binds to `127.0.0.1`, prints the local URL, and serves exactly one
39
+ project per process. Reopening an existing project needs no initialization, and
40
+ `init` never overwrites existing material.
41
+
42
+ ### Reaching it through a proxy or port-forward
43
+
44
+ By default the server binds to loopback *and* rejects any `Host` header that is
45
+ not a loopback name. That second check is what stops a malicious page from
46
+ using DNS rebinding to talk to your local server — but behind a reverse proxy
47
+ or a port-forward the header carries the proxy's hostname, so the check would
48
+ reject every real request. Widen it explicitly:
49
+
50
+ ```bash
51
+ # Bind beyond loopback; any Host header is then accepted.
52
+ litmark serve ./my-research --host 0.0.0.0
53
+
54
+ # Or name the proxy's hostname and keep the check strict.
55
+ litmark serve ./my-research --host 0.0.0.0 --allow-host papers.internal
56
+ ```
57
+
58
+ The per-process session credential embedded in the served page remains the
59
+ access control in both cases. On an untrusted network prefer an SSH tunnel,
60
+ which keeps the default loopback binding intact:
61
+
62
+ ```bash
63
+ ssh -N -L 8765:127.0.0.1:8765 you@the-machine
64
+ ```
65
+
66
+ Check your environment at any time:
67
+
68
+ ```bash
69
+ litmark doctor ./my-research
70
+ ```
71
+
72
+ `doctor` reports on the workspace, the optional agent dependency, the runtime
73
+ it needs, and whether authentication is configured — without printing secrets.
74
+
75
+ ## Agent configuration
76
+
77
+ The agent backend is the [Claude Agent SDK for
78
+ Python](https://code.claude.com/docs/en/agent-sdk/python), behind a
79
+ provider-neutral adapter. Provider credentials and billing are separate from
80
+ installing this application; a consumer chat subscription does not by itself
81
+ grant SDK access.
82
+
83
+ The reader and editor work with no agent account at all. Import and text
84
+ extraction still run; automatic summaries wait until an agent is configured,
85
+ and the interface says so plainly.
86
+
87
+ ## Project layout
88
+
89
+ | Path | Purpose |
90
+ | --- | --- |
91
+ | `project.toml` | Schema version and non-secret project settings. |
92
+ | `documents/<id>/original.pdf` | Original immutable PDF. |
93
+ | `documents/<id>/metadata.json` | Identity, hash, filename, title, page count, status. |
94
+ | `documents/<id>/pages.json` | Per-page text, character geometry, offset mapping. |
95
+ | `documents/<id>/summary.md` | Editable, cited summary. |
96
+ | `notes/*.md` | User and agent notes. |
97
+ | `references.json` | Versioned source registry. |
98
+ | `references.bib` | Generated BibTeX bibliography of the imported documents. |
99
+ | `.research/state.sqlite` | Conversations, events, jobs, run state, change log. |
100
+ | `.research/history/` | Previous file contents, for review and undo. |
101
+ | `.research/runs/` | Staged agent edits and run diagnostics. |
102
+
103
+ ## Citations
104
+
105
+ A citation is an ordinary Markdown link with an application-specific
106
+ destination:
107
+
108
+ ```markdown
109
+ The identification argument relies on a mobility restriction.
110
+ [Assumption 2, p. 12](source:ref-001)
111
+ ```
112
+
113
+ `ref-001` resolves through `references.json`, which records the document, the
114
+ immutable PDF content hash, the one-based physical page number, the quoted
115
+ passage, and normalized highlight rectangles. Reference resolution validates
116
+ *where* a passage is, not whether it supports the claim — you assess that by
117
+ reading the evidence.
118
+
119
+ ## Bibliography
120
+
121
+ **Write .bib** in the sidebar generates `references.bib` in the project
122
+ directory, and **Download** fetches the same file without writing it. There is
123
+ one entry per imported document — a `.bib` entry is a work, so the page each
124
+ reference points at travels in the `\cite[p.~12]{key}` command the export
125
+ returns alongside the entries, not in the entry itself.
126
+
127
+ Entries carry only what the PDF actually supplies. A paper with no author
128
+ metadata gets an entry with no `author` field and a warning saying so; nothing
129
+ is filled in from general knowledge. The output is deterministic, so exporting
130
+ an unchanged bibliography rewrites nothing, and a `.bib` you edited by hand is
131
+ copied into `.research/history/` before it is replaced.
132
+
133
+ ## Development
134
+
135
+ ```bash
136
+ uv venv && uv pip install -e . --group dev
137
+ npm --prefix frontend install
138
+ npm --prefix frontend run build # writes src/litmark/static/
139
+ uv run pytest
140
+ uv run litmark serve ./my-research --reload
141
+ ```
142
+
143
+ `npm run dev` runs the frontend with hot reload against a server started
144
+ separately on port 8765.
145
+
146
+ ### Tests
147
+
148
+ ```bash
149
+ uv run pytest # server and acceptance criteria
150
+ uv run pytest --runslow # plus: build the wheel, install it clean, serve it
151
+ npm --prefix frontend test # renderer unit tests, and the bundle run in a DOM
152
+
153
+ # Real-browser checks (A2 live preview, A6 highlight geometry under zoom).
154
+ # Point it at a project whose open note contains a source: citation.
155
+ litmark serve ./my-research &
156
+ LITMARK_BASE_URL=http://127.0.0.1:8765/ npm --prefix frontend run test:browser
157
+ ```
158
+
159
+ The browser suite drives headless Firefox over Marionette. Headless Chromium is
160
+ deliberately not used: under some sandboxes it cannot reach loopback HTTP — it
161
+ returns an empty document where `curl` succeeds — so a Chromium suite passes
162
+ without having checked anything.
163
+
164
+ ## Scope
165
+
166
+ v0.1 covers ingestion of text-based PDFs, cited summaries, Markdown live-preview
167
+ editing, PDF evidence with highlights, chat with one agent backend, and manual
168
+ references. Deferred: OCR, URL downloads, Word/HTML ingestion, Zotero
169
+ integration, semantic search, multiple agent providers, arbitrary analysis
170
+ execution, multi-user collaboration, full mobile editing, and public hosting.
171
+
172
+ ## License
173
+
174
+ MIT.
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <meta name="litmark-token" content="">
7
+ <title>Litmark</title>
8
+ <script type="module" src="/src/main.tsx"></script>
9
+ </head>
10
+ <body>
11
+ <div id="app"></div>
12
+ </body>
13
+ </html>