booksmart 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.
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ .pytest_cache/
5
+ .mypy_cache/
6
+ dist/
7
+ dist-core/
8
+ dist-cli/
9
+ *.egg-info/
10
+
11
+ # Object storage contents stay local; keep the layout tracked via .gitkeep
12
+ storage/*/*
13
+ !storage/*/.gitkeep
14
+
15
+ .env
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Patryk Dwórznik
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,86 @@
1
+ Metadata-Version: 2.4
2
+ Name: booksmart
3
+ Version: 0.1.0
4
+ Summary: Booksmart CLI — a local, single-user front end over booksmart-core (embedded storage, no server).
5
+ Author-email: Patryk Dwórznik <patryk@dworznik.com>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.12
9
+ Requires-Dist: booksmart-core<0.2.0,>=0.1.0
10
+ Requires-Dist: rich>=13.7.0
11
+ Requires-Dist: typer>=0.12.0
12
+ Description-Content-Type: text/markdown
13
+
14
+ # booksmart
15
+
16
+ The Booksmart CLI — turn books into queryable knowledge, locally.
17
+
18
+ A single-user front end over
19
+ [`booksmart-core`](https://github.com/dworznik/booksmart/tree/main/packages/core):
20
+ register PDFs/EPUBs, ingest them through the parsing → structure → profile →
21
+ extraction → summaries → embeddings pipeline, and browse the results. Everything
22
+ runs against an auto-migrated SQLite file and embedded Qdrant under
23
+ `~/.booksmart/` — no Docker, no Postgres, no server.
24
+
25
+ ## Install
26
+
27
+ **Not published to PyPI yet** — install from the repo, which is private, so this
28
+ needs an SSH key with access to it. `uv` clones the repo, resolves
29
+ `booksmart-core` from the same checkout, and puts a `booksmart` command on your
30
+ PATH:
31
+
32
+ ```console
33
+ $ uv tool install "git+ssh://git@github.com/dworznik/booksmart.git#subdirectory=packages/cli"
34
+ ```
35
+
36
+ Over HTTPS instead, with `gh auth login` (or a `repo`-scoped token) supplying git
37
+ credentials:
38
+
39
+ ```console
40
+ $ uv tool install "git+https://github.com/dworznik/booksmart.git#subdirectory=packages/cli"
41
+ ```
42
+
43
+ Re-run with `--force` to pick up new commits. Once the first `cli-v*` tag ships,
44
+ this becomes `uv tool install booksmart`, which pulls `booksmart-core` down as a
45
+ dependency.
46
+
47
+ ## Quickstart
48
+
49
+ ```console
50
+ $ booksmart add ./clean-code.pdf --title "Clean Code" --author "Robert C. Martin"
51
+ $ booksmart ingest <book-id>
52
+ $ booksmart structure <book-id>
53
+ $ booksmart knowledge list <book-id>
54
+ $ booksmart search all "how do deep modules reduce complexity"
55
+ ```
56
+
57
+ `ingest` calls an LLM and an embedding provider, so it needs credentials —
58
+ `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` by default. To drive the whole pipeline
59
+ with no keys, no network and no cost, select the deterministic fake providers:
60
+
61
+ ```console
62
+ $ BOOKSMART_LLM_PROVIDER=fake BOOKSMART_EMBEDDING_PROVIDER=fake booksmart ingest <book-id>
63
+ ```
64
+
65
+ ## Commands
66
+
67
+ `add`, `ingest`, `books list/show/update`, `runs list/show`, `structure`,
68
+ `profile`, `knowledge list/show`, `search`.
69
+
70
+ ### Search
71
+
72
+ `booksmart search <book-id|all> "<query>"` ranks the chapters, sections and
73
+ knowledge objects most similar to a natural-language query, over the embeddings
74
+ an ingest produced. Restrict it with `--type` (repeatable: `chapter`, `section`,
75
+ `knowledge_object`), cap it with `--limit`, and drop weak hits with
76
+ `--score-threshold` (a cosine similarity, `-1`–`1`).
77
+
78
+ The query is embedded with the model the vector collection is locked to; if that
79
+ is not the currently configured embedding model, search refuses rather than
80
+ return plausible, silently wrong rankings (ADR 0001).
81
+
82
+ ## Configuration
83
+
84
+ Providers and locations come from `BOOKSMART_*` environment variables (e.g.
85
+ `BOOKSMART_LLM_PROVIDER`, `BOOKSMART_HOME`). Set `BOOKSMART_QDRANT_URL` to use a
86
+ Qdrant server instead of the embedded on-disk store.
@@ -0,0 +1,73 @@
1
+ # booksmart
2
+
3
+ The Booksmart CLI — turn books into queryable knowledge, locally.
4
+
5
+ A single-user front end over
6
+ [`booksmart-core`](https://github.com/dworznik/booksmart/tree/main/packages/core):
7
+ register PDFs/EPUBs, ingest them through the parsing → structure → profile →
8
+ extraction → summaries → embeddings pipeline, and browse the results. Everything
9
+ runs against an auto-migrated SQLite file and embedded Qdrant under
10
+ `~/.booksmart/` — no Docker, no Postgres, no server.
11
+
12
+ ## Install
13
+
14
+ **Not published to PyPI yet** — install from the repo, which is private, so this
15
+ needs an SSH key with access to it. `uv` clones the repo, resolves
16
+ `booksmart-core` from the same checkout, and puts a `booksmart` command on your
17
+ PATH:
18
+
19
+ ```console
20
+ $ uv tool install "git+ssh://git@github.com/dworznik/booksmart.git#subdirectory=packages/cli"
21
+ ```
22
+
23
+ Over HTTPS instead, with `gh auth login` (or a `repo`-scoped token) supplying git
24
+ credentials:
25
+
26
+ ```console
27
+ $ uv tool install "git+https://github.com/dworznik/booksmart.git#subdirectory=packages/cli"
28
+ ```
29
+
30
+ Re-run with `--force` to pick up new commits. Once the first `cli-v*` tag ships,
31
+ this becomes `uv tool install booksmart`, which pulls `booksmart-core` down as a
32
+ dependency.
33
+
34
+ ## Quickstart
35
+
36
+ ```console
37
+ $ booksmart add ./clean-code.pdf --title "Clean Code" --author "Robert C. Martin"
38
+ $ booksmart ingest <book-id>
39
+ $ booksmart structure <book-id>
40
+ $ booksmart knowledge list <book-id>
41
+ $ booksmart search all "how do deep modules reduce complexity"
42
+ ```
43
+
44
+ `ingest` calls an LLM and an embedding provider, so it needs credentials —
45
+ `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` by default. To drive the whole pipeline
46
+ with no keys, no network and no cost, select the deterministic fake providers:
47
+
48
+ ```console
49
+ $ BOOKSMART_LLM_PROVIDER=fake BOOKSMART_EMBEDDING_PROVIDER=fake booksmart ingest <book-id>
50
+ ```
51
+
52
+ ## Commands
53
+
54
+ `add`, `ingest`, `books list/show/update`, `runs list/show`, `structure`,
55
+ `profile`, `knowledge list/show`, `search`.
56
+
57
+ ### Search
58
+
59
+ `booksmart search <book-id|all> "<query>"` ranks the chapters, sections and
60
+ knowledge objects most similar to a natural-language query, over the embeddings
61
+ an ingest produced. Restrict it with `--type` (repeatable: `chapter`, `section`,
62
+ `knowledge_object`), cap it with `--limit`, and drop weak hits with
63
+ `--score-threshold` (a cosine similarity, `-1`–`1`).
64
+
65
+ The query is embedded with the model the vector collection is locked to; if that
66
+ is not the currently configured embedding model, search refuses rather than
67
+ return plausible, silently wrong rankings (ADR 0001).
68
+
69
+ ## Configuration
70
+
71
+ Providers and locations come from `BOOKSMART_*` environment variables (e.g.
72
+ `BOOKSMART_LLM_PROVIDER`, `BOOKSMART_HOME`). Set `BOOKSMART_QDRANT_URL` to use a
73
+ Qdrant server instead of the embedded on-disk store.
@@ -0,0 +1,33 @@
1
+ [project]
2
+ name = "booksmart"
3
+ version = "0.1.0"
4
+ description = "Booksmart CLI — a local, single-user front end over booksmart-core (embedded storage, no server)."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Patryk Dwórznik", email = "patryk@dworznik.com" }]
10
+ dependencies = [
11
+ # Minor-pinned, and deliberately so: the CLI is a thin front end over core's
12
+ # public seams (Stage functions, Runner, search, VectorStore), and pre-1.0 a
13
+ # minor bump is where those may break. `[tool.uv.sources]` below only rewires
14
+ # this for local workspace development — the published wheel carries this
15
+ # constraint, so an unbounded requirement would let a future core install
16
+ # against a CLI that cannot drive it.
17
+ "booksmart-core>=0.1.0,<0.2.0",
18
+ "typer>=0.12.0",
19
+ "rich>=13.7.0",
20
+ ]
21
+
22
+ [project.scripts]
23
+ booksmart = "booksmart_cli.main:app"
24
+
25
+ [build-system]
26
+ requires = ["hatchling"]
27
+ build-backend = "hatchling.build"
28
+
29
+ [tool.hatch.build.targets.wheel]
30
+ packages = ["src/booksmart_cli"]
31
+
32
+ [tool.uv.sources]
33
+ booksmart-core = { workspace = true }
File without changes
@@ -0,0 +1,42 @@
1
+ """CLI-facing errors.
2
+
3
+ The pipeline's own failures are recorded on the Run (never raised out of
4
+ ``execute_run``); these cover the front-end concerns the removed HTTP layer used
5
+ to answer with 4xx — an unsupported file, a duplicate, an unknown book. ``main``
6
+ catches ``CliError`` and prints its message as one clean line, exit code 1."""
7
+
8
+
9
+ class CliError(Exception):
10
+ """Base for expected, user-facing CLI failures (rendered as one line)."""
11
+
12
+
13
+ class UnsupportedFileError(CliError):
14
+ """The file is not a supported format, by extension or by content (the old
15
+ ``415``)."""
16
+
17
+
18
+ class DuplicateBookError(CliError):
19
+ """A byte-identical book is already registered (the old ``409``)."""
20
+
21
+ def __init__(self, existing_book_id: str) -> None:
22
+ super().__init__(
23
+ f"This file is already registered as book {existing_book_id} "
24
+ f"(byte-identical content)."
25
+ )
26
+ self.existing_book_id = existing_book_id
27
+
28
+
29
+ class BookNotFoundError(CliError):
30
+ """No book with the given id (the old ``404``)."""
31
+
32
+
33
+ class RunNotFoundError(CliError):
34
+ """No run with the given id (the old ``404`` on /jobs/{id})."""
35
+
36
+
37
+ class KnowledgeNotFoundError(CliError):
38
+ """No knowledge object with the given id (the old ``404``)."""
39
+
40
+
41
+ class NoProfileError(CliError):
42
+ """The book has no generated profile yet (the old ``404`` on /profile)."""