scribe-llm 0.4.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 (96) hide show
  1. scribe_llm-0.4.0/.github/workflows/ci.yml +35 -0
  2. scribe_llm-0.4.0/.github/workflows/publish.yml +38 -0
  3. scribe_llm-0.4.0/.gitignore +37 -0
  4. scribe_llm-0.4.0/CHANGELOG.md +118 -0
  5. scribe_llm-0.4.0/CONTRIBUTING.md +62 -0
  6. scribe_llm-0.4.0/LICENSE +21 -0
  7. scribe_llm-0.4.0/PKG-INFO +266 -0
  8. scribe_llm-0.4.0/PLAN.md +825 -0
  9. scribe_llm-0.4.0/README.md +228 -0
  10. scribe_llm-0.4.0/README.zh-CN.md +182 -0
  11. scribe_llm-0.4.0/config/config.example.toml +123 -0
  12. scribe_llm-0.4.0/docs/index.html +200 -0
  13. scribe_llm-0.4.0/docs/index.zh.html +134 -0
  14. scribe_llm-0.4.0/docs/open-knowledge-format.md +84 -0
  15. scribe_llm-0.4.0/docs/providers.md +149 -0
  16. scribe_llm-0.4.0/docs/providers.zh-CN.md +147 -0
  17. scribe_llm-0.4.0/docs/recursive-scaffold-hypothesis.md +86 -0
  18. scribe_llm-0.4.0/docs/wsl_ollama_guide.md +95 -0
  19. scribe_llm-0.4.0/docs/wsl_ollama_guide.zh-CN.md +93 -0
  20. scribe_llm-0.4.0/promo/README.md +30 -0
  21. scribe_llm-0.4.0/promo/_demo_grammar.py +58 -0
  22. scribe_llm-0.4.0/promo/record-demo.sh +118 -0
  23. scribe_llm-0.4.0/promo/source.md +81 -0
  24. scribe_llm-0.4.0/pyproject.toml +83 -0
  25. scribe_llm-0.4.0/scribe/__init__.py +15 -0
  26. scribe_llm-0.4.0/scribe/cli.py +785 -0
  27. scribe_llm-0.4.0/scribe/compare.py +89 -0
  28. scribe_llm-0.4.0/scribe/config.py +362 -0
  29. scribe_llm-0.4.0/scribe/discovery.py +102 -0
  30. scribe_llm-0.4.0/scribe/documents.py +229 -0
  31. scribe_llm-0.4.0/scribe/evolve/__init__.py +1 -0
  32. scribe_llm-0.4.0/scribe/evolve/evaluate.py +317 -0
  33. scribe_llm-0.4.0/scribe/evolve/spi.py +181 -0
  34. scribe_llm-0.4.0/scribe/grammar.py +173 -0
  35. scribe_llm-0.4.0/scribe/llm_adapter.py +877 -0
  36. scribe_llm-0.4.0/scribe/mail.py +276 -0
  37. scribe_llm-0.4.0/scribe/memory/__init__.py +29 -0
  38. scribe_llm-0.4.0/scribe/memory/hybrid.py +102 -0
  39. scribe_llm-0.4.0/scribe/memory/rag.py +394 -0
  40. scribe_llm-0.4.0/scribe/memory/sme.py +364 -0
  41. scribe_llm-0.4.0/scribe/prompts.py +311 -0
  42. scribe_llm-0.4.0/scribe/pulse.py +111 -0
  43. scribe_llm-0.4.0/scribe/reasoning_gate.py +72 -0
  44. scribe_llm-0.4.0/scribe/seed/constitution.md +17 -0
  45. scribe_llm-0.4.0/scribe/seed/eval/MANIFEST.sha256 +2 -0
  46. scribe_llm-0.4.0/scribe/seed/eval/grounded.jsonl +8 -0
  47. scribe_llm-0.4.0/scribe/seed/eval/tasks.jsonl +20 -0
  48. scribe_llm-0.4.0/scribe/session.py +380 -0
  49. scribe_llm-0.4.0/scribe/skills/__init__.py +21 -0
  50. scribe_llm-0.4.0/scribe/skills/deep-research/SKILL.md +68 -0
  51. scribe_llm-0.4.0/scribe/skills/wiki-memory/SKILL.md +86 -0
  52. scribe_llm-0.4.0/scribe/skills/writer/SKILL.md +63 -0
  53. scribe_llm-0.4.0/scribe/skills_executor.py +285 -0
  54. scribe_llm-0.4.0/scribe/static/.gitkeep +0 -0
  55. scribe_llm-0.4.0/scribe/status.py +137 -0
  56. scribe_llm-0.4.0/scribe/templates/editor.html +636 -0
  57. scribe_llm-0.4.0/scribe/templates/index.html +632 -0
  58. scribe_llm-0.4.0/scribe/templates/print.html +43 -0
  59. scribe_llm-0.4.0/scribe/tools/__init__.py +103 -0
  60. scribe_llm-0.4.0/scribe/tools/checkpoint.py +190 -0
  61. scribe_llm-0.4.0/scribe/tools/fs.py +207 -0
  62. scribe_llm-0.4.0/scribe/tools/sandbox.py +162 -0
  63. scribe_llm-0.4.0/scribe/tools/shell.py +129 -0
  64. scribe_llm-0.4.0/scribe/tools/web.py +364 -0
  65. scribe_llm-0.4.0/scribe/trace.py +84 -0
  66. scribe_llm-0.4.0/scribe/tui.py +1075 -0
  67. scribe_llm-0.4.0/scribe/tui_app.py +415 -0
  68. scribe_llm-0.4.0/scribe/ui/__init__.py +22 -0
  69. scribe_llm-0.4.0/scribe/ui/console.py +139 -0
  70. scribe_llm-0.4.0/scribe/ui/logo.py +31 -0
  71. scribe_llm-0.4.0/scribe/ui/progress.py +144 -0
  72. scribe_llm-0.4.0/scribe/ui/theme.py +77 -0
  73. scribe_llm-0.4.0/scribe/vault.py +80 -0
  74. scribe_llm-0.4.0/scribe/web.py +643 -0
  75. scribe_llm-0.4.0/scribe/wiki.py +482 -0
  76. scribe_llm-0.4.0/scribe/worldmodel.py +104 -0
  77. scribe_llm-0.4.0/scripts/install.sh +79 -0
  78. scribe_llm-0.4.0/scripts/start-server.sh +55 -0
  79. scribe_llm-0.4.0/tests/conftest.py +4 -0
  80. scribe_llm-0.4.0/tests/test_core.py +293 -0
  81. scribe_llm-0.4.0/tests/test_discovery_compare.py +92 -0
  82. scribe_llm-0.4.0/tests/test_documents.py +96 -0
  83. scribe_llm-0.4.0/tests/test_evolve.py +59 -0
  84. scribe_llm-0.4.0/tests/test_grammar.py +220 -0
  85. scribe_llm-0.4.0/tests/test_hybrid.py +181 -0
  86. scribe_llm-0.4.0/tests/test_mail.py +51 -0
  87. scribe_llm-0.4.0/tests/test_memory.py +150 -0
  88. scribe_llm-0.4.0/tests/test_sandbox.py +183 -0
  89. scribe_llm-0.4.0/tests/test_session_resume.py +106 -0
  90. scribe_llm-0.4.0/tests/test_skills.py +67 -0
  91. scribe_llm-0.4.0/tests/test_spi.py +141 -0
  92. scribe_llm-0.4.0/tests/test_status_line.py +39 -0
  93. scribe_llm-0.4.0/tests/test_tools.py +214 -0
  94. scribe_llm-0.4.0/tests/test_trace_vault.py +142 -0
  95. scribe_llm-0.4.0/tests/test_wiki.py +311 -0
  96. scribe_llm-0.4.0/tests/test_worldmodel.py +135 -0
@@ -0,0 +1,35 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.10", "3.11", "3.12"]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Set up Python ${{ matrix.python-version }}
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+ cache: pip
25
+
26
+ - name: Install package + dev deps
27
+ run: pip install -e ".[dev]"
28
+
29
+ - name: Lint (ruff)
30
+ run: ruff check scribe tests
31
+
32
+ - name: Run tests
33
+ # Integration tests need a live llama-server / model downloads, which
34
+ # aren't available on CI runners — they run locally instead.
35
+ run: pytest -q -m "not integration"
@@ -0,0 +1,38 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes the package whenever a GitHub Release is published.
4
+ # Uses PyPI Trusted Publishing (OIDC) — no API token is stored in the repo.
5
+ #
6
+ # One-time setup on PyPI (https://pypi.org/manage/account/publishing/):
7
+ # Add a "pending publisher" for project `scribe-llm` with:
8
+ # Owner: pedjaurosevic
9
+ # Repository: scribe-ai
10
+ # Workflow name: publish.yml
11
+ # Environment: pypi
12
+ # After the first successful run the project exists and the publisher is permanent.
13
+
14
+ on:
15
+ release:
16
+ types: [published]
17
+
18
+ jobs:
19
+ build-and-publish:
20
+ runs-on: ubuntu-latest
21
+ environment: pypi
22
+ permissions:
23
+ id-token: write # required for trusted publishing (OIDC)
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: actions/setup-python@v5
27
+ with:
28
+ python-version: "3.12"
29
+ - name: Build sdist and wheel
30
+ run: |
31
+ python -m pip install --upgrade build
32
+ python -m build
33
+ - name: Verify metadata
34
+ run: |
35
+ python -m pip install --upgrade twine
36
+ python -m twine check dist/*
37
+ - name: Publish to PyPI
38
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,37 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ .eggs/
7
+ build/
8
+ dist/
9
+ wheels/
10
+ *.egg
11
+
12
+ # Virtual environments
13
+ .venv/
14
+ venv/
15
+ env/
16
+
17
+ # Testing / tooling
18
+ .pytest_cache/
19
+ .mypy_cache/
20
+ .ruff_cache/
21
+ .coverage
22
+ htmlcov/
23
+
24
+ # Scribe local state & data (per-user, never commit)
25
+ .scribe/
26
+ scribe-workspace/
27
+ *.lance/
28
+ *.db
29
+
30
+ # Editor / OS
31
+ .vscode/
32
+ .idea/
33
+ *.swp
34
+ .DS_Store
35
+
36
+ # Local config with real endpoints/keys
37
+ config/config.toml
@@ -0,0 +1,118 @@
1
+ # Changelog
2
+
3
+ All notable changes to Scribe are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.4.0] - 2026-06-16
10
+
11
+ A web release: a studio for writing books with your local model, and an open
12
+ format for the knowledge Scribe distills.
13
+
14
+ ### Added
15
+ - **Web Book Studio** (`scribe/templates/editor.html`, `scribe/documents.py`):
16
+ a dark, VSCode/Antigravity-style web UI with three resizable panes
17
+ (Explorer · Editor · Assistant). Books are a table of contents plus one
18
+ markdown file per chapter; the model drafts a TOC, then writes chapter by
19
+ chapter straight into the page. Exports to Markdown, EPUB (pandoc, one
20
+ section per chapter + title page) and PDF (browser print view).
21
+ - **Integrated terminal** (`/ws/terminal`): a real login shell in a PTY bridged
22
+ to xterm.js, toggled with `Ctrl+\``, PIN-gated like the rest of the UI.
23
+ - **Open Knowledge Format wiki**: `scribe wiki distill` now stores pages as OKF
24
+ markdown — YAML frontmatter (`type/title/description/tags/timestamp/source`),
25
+ `index.md` + `log.md`, inter-page links. `ensure_frontmatter` backfills a
26
+ valid block when the model omits one. SME/RAG are framed as derived indexes
27
+ over these files. See `docs/open-knowledge-format.md`.
28
+
29
+ ### Changed
30
+ - The web UI now binds to **`127.0.0.1`** by default (was `0.0.0.0`); the
31
+ integrated shell terminal should not be network-reachable without an explicit
32
+ `--host 0.0.0.0` (which prints a warning).
33
+ - PyPI distribution renamed `scribeai` → **`scribe-llm`** (import package and
34
+ CLI remain `scribe`).
35
+
36
+ ## [0.3.0] - 2026-06-13
37
+
38
+ A synthesis release: the strongest mechanisms from sibling local-agent
39
+ projects (Synap, Konok, ExoLab, CANYON) and Odysseus, folded into Scribe.
40
+
41
+ ### Added
42
+ - **GBNF tool-call enforcement** (`scribe/grammar.py`): a grammar generated
43
+ from the tool schemas makes a malformed tool call grammatically impossible
44
+ on llama.cpp; `tool_grammar = "auto"` re-asks a fumbled call under the
45
+ grammar, `"force"` constrains every forced call.
46
+ - **Reasoning gate** (`scribe/reasoning_gate.py`): `reasoning = "auto"` enables
47
+ server-side thinking only for prompts that benefit (code, debugging,
48
+ multi-step, long), bilingual EN/SR heuristic.
49
+ - **Execution sandbox** (`scribe/tools/sandbox.py`): destructive-command gate,
50
+ Python AST gate, and a bubblewrap container (read-only root, writable
51
+ workspace, no network) with CPU/memory limits; degrades without bwrap.
52
+ - **Git checkpoint/rollback** (`scribe/tools/checkpoint.py`): `workspace_checkpoint`
53
+ / `workspace_rollback` tools and a verify-then-roll-back loop; snapshots as
54
+ git tree objects that leave history untouched.
55
+ - **Hybrid retrieval** (`scribe/memory/hybrid.py`): SQLite FTS5 lexical branch
56
+ fused with vector search via Reciprocal Rank Fusion. `rag search` is hybrid
57
+ by default; new `rag ask` (grounded Q&A) and `rag reindex`.
58
+ - **Citation grounding** (`scribe/prompts.py`): numbered sources, mandatory
59
+ `[n]` citations, `[CONTRADICTION]` tagging, refusal outside the sources.
60
+ - **SPI grounding metric** (`scribe/evolve/spi.py`) and **`scribe bench`**:
61
+ deterministic Source-Presence Index over a checksum-locked grounded suite.
62
+ - **ORORO traces** (`scribe/trace.py`): append-only canonical-JSON event log
63
+ per session; `scribe trace`.
64
+ - **Status contract** (`scribe/status.py`): machine-readable `scribe status --json`.
65
+ - **Project vaults** (`scribe/vault.py`): `scribe init` for isolated per-project
66
+ RAG/SME stores.
67
+ - **WorldModel** (`scribe/worldmodel.py`): a persona always injected into the
68
+ system prompt; `scribe remember`.
69
+ - **Pulse & Diary** (`scribe/pulse.py`): heartbeat log and nightly reflection.
70
+ - **Model discovery & blind compare** (`scribe/discovery.py`, `scribe/compare.py`):
71
+ `scribe discover` and `scribe compare`.
72
+
73
+ ### Changed
74
+ - `LLMAdapter` gained `thinking_mode` and `tool_grammar`; `_with_thinking`
75
+ is now message-aware for the reasoning gate.
76
+ - `verify_manifest` covers multiple held-out suite files.
77
+
78
+ ## [0.2.1] - 2026-06-09
79
+
80
+ ### Added
81
+ - GitHub Actions CI: runs `ruff` lint and the unit `pytest` subset
82
+ (`-m "not integration"`) on Python 3.10 / 3.11 / 3.12 for every push and PR.
83
+ - `integration` pytest marker for tests that need a live llama-server or model
84
+ downloads, so the unit suite stays fast and runnable anywhere.
85
+ - `CONTRIBUTING.md` with the local dev / test workflow.
86
+ - Status badges in the README.
87
+
88
+ ### Changed
89
+ - Clarified the install steps in the README and landing page: `./scripts/install.sh`
90
+ already installs the package, so the extra `pip install -e .` is now shown only
91
+ as the manual alternative.
92
+
93
+ ### Fixed
94
+ - Cleaned up the codebase so `ruff` passes on the full lint rule set
95
+ (import order, unused imports, f-strings, modern type hints) — no behavior change.
96
+ - Declared previously-undeclared runtime dependencies that a clean install was
97
+ missing: `textual` (Textual UI import), and `pandas` + `pylance` (required by
98
+ the LanceDB-backed memory layer — without them `list_sources`/search silently
99
+ returned empty results).
100
+
101
+ ## [0.2.0] - 2026-06-08
102
+
103
+ ### Added
104
+ - Initial public release.
105
+ - Universal LLM adapter for any OpenAI-compatible (llama.cpp) endpoint.
106
+ - Rich-based TUI with a streaming chat, plus an experimental Textual full-screen UI.
107
+ - FastAPI web UI (`scribe web`).
108
+ - Cross-session memory via the Semantic Memory Engine (SME).
109
+ - RAG over a local document library (multilingual-e5 embeddings + LanceDB).
110
+ - Modular skills: deep-research, writer, wiki-memory.
111
+ - Sandboxed workspace file tools (read / write / list, scoped to the workspace).
112
+ - Email bridge: send notifications and accept commands from one approved
113
+ address, using only the Python standard library.
114
+ - Held-out fitness suite (`scribe evolve eval`).
115
+
116
+ [Unreleased]: https://github.com/pedjaurosevic/scribe-ai/compare/v0.2.1...HEAD
117
+ [0.2.1]: https://github.com/pedjaurosevic/scribe-ai/compare/v0.2.0...v0.2.1
118
+ [0.2.0]: https://github.com/pedjaurosevic/scribe-ai/releases/tag/v0.2.0
@@ -0,0 +1,62 @@
1
+ # Contributing to Scribe
2
+
3
+ Thanks for your interest in improving Scribe. This is a small, focused project —
4
+ the aim is a simple, dependable local-LLM agent, not a heavy framework.
5
+
6
+ ## Development setup
7
+
8
+ ```bash
9
+ git clone https://github.com/pedjaurosevic/scribe-ai.git
10
+ cd scribe-ai
11
+ pip install -e ".[dev]"
12
+ ```
13
+
14
+ This installs Scribe in editable mode together with the dev tools
15
+ (`pytest`, `ruff`, `mypy`).
16
+
17
+ ## Running the checks
18
+
19
+ ```bash
20
+ ruff check scribe tests # lint
21
+ pytest -q # full suite (incl. integration tests)
22
+ pytest -q -m "not integration" # unit subset — what CI runs
23
+ ```
24
+
25
+ Tests are split into two groups:
26
+
27
+ - **Unit tests** — fast, self-contained, no network. CI runs these
28
+ (`pytest -m "not integration"`) on Python 3.10, 3.11 and 3.12.
29
+ - **Integration tests** (`@pytest.mark.integration`) — exercise the real
30
+ stack: the LLM adapter against a running llama-server, and the LanceDB
31
+ memory layer (which downloads an embedding model). Run them locally with a
32
+ server up; they're excluded from CI because runners have neither.
33
+
34
+ ## Pull requests
35
+
36
+ - Keep changes small and focused; one logical change per PR.
37
+ - Run `ruff check` and `pytest` before pushing — CI runs both.
38
+ - Use English for code, identifiers, comments and commit messages.
39
+ - Update `CHANGELOG.md` under `## [Unreleased]` when you add or change behavior.
40
+
41
+ ## Project layout
42
+
43
+ ```
44
+ scribe/
45
+ cli.py # Click entry point (the `scribe` command)
46
+ session.py # session manager / cross-session continuity
47
+ llm_adapter.py # OpenAI-compatible adapter for llama.cpp
48
+ memory/ # SME (semantic memory) + RAG
49
+ tools/ # sandboxed fs + shell tools
50
+ skills/ # modular skill loaders
51
+ ui/ # Rich theme, console, progress, logo
52
+ web.py # FastAPI web UI
53
+ mail.py # stdlib-only email bridge
54
+ evolve/ # held-out fitness evaluation
55
+ tests/ # pytest suite
56
+ docs/ # GitHub Pages landing page
57
+ ```
58
+
59
+ ## License
60
+
61
+ By contributing you agree that your contributions are licensed under the MIT
62
+ License, the same as the rest of the project.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Peterofovik
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,266 @@
1
+ Metadata-Version: 2.4
2
+ Name: scribe-llm
3
+ Version: 0.4.0
4
+ Summary: Universal TUI agent for autonomous research and writing, powered by llama.cpp
5
+ Project-URL: Homepage, https://pedjaurosevic.github.io/scribe-ai/
6
+ Project-URL: Repository, https://github.com/pedjaurosevic/scribe-ai
7
+ Project-URL: Issues, https://github.com/pedjaurosevic/scribe-ai/issues
8
+ Author-email: Pedja Urosevic <pedjaurosevic@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,autonomous,llama.cpp,llm,research,tui,writing
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: click>=8.0.0
20
+ Requires-Dist: fastapi>=0.100.0
21
+ Requires-Dist: httpx>=0.24.0
22
+ Requires-Dist: jinja2>=3.0.0
23
+ Requires-Dist: lancedb>=0.4.0
24
+ Requires-Dist: openai>=1.0.0
25
+ Requires-Dist: pandas>=2.0.0
26
+ Requires-Dist: pylance>=0.9.0
27
+ Requires-Dist: rich>=13.0.0
28
+ Requires-Dist: sentence-transformers>=2.2.0
29
+ Requires-Dist: textual>=0.40.0
30
+ Requires-Dist: toml>=0.10.0
31
+ Requires-Dist: uvicorn>=0.23.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
34
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
35
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
36
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # Scribe
40
+
41
+ 🌐 English · [简体中文](README.zh-CN.md)
42
+
43
+ [![CI](https://github.com/pedjaurosevic/scribe-ai/actions/workflows/ci.yml/badge.svg)](https://github.com/pedjaurosevic/scribe-ai/actions/workflows/ci.yml)
44
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
45
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
46
+
47
+ > Local-first chat + research + coding agent. Connects to **any** OpenAI-compatible server (llama.cpp, Ollama, LM Studio, or a cloud API key) and uses web search, RAG and semantic memory to research, write, and remember — across sessions. Runs comfortably on a 12 GB VRAM machine with Gemma 4 12B at 128k context.
48
+
49
+ ## Why Scribe
50
+
51
+ Three properties that hold by construction, not by prompt-tuning:
52
+
53
+ 1. **The tool call cannot break.** On a llama.cpp server Scribe enforces tool
54
+ calls with a GBNF grammar generated from the tool schemas — a malformed
55
+ call is *grammatically impossible*, and a model that fumbles is re-asked
56
+ under the grammar. ([scribe/grammar.py](scribe/grammar.py))
57
+ 2. **Answers cite their sources, or say they can't.** Grounded Q&A maps every
58
+ claim to a numbered source `[n]`, tags `[CONTRADICTION]` when sources
59
+ disagree, and refuses to answer outside the sources. ([scribe/prompts.py](scribe/prompts.py))
60
+ 3. **Grounding is measured, not asserted.** `scribe bench` reports a
61
+ deterministic Source-Presence Index (SPI) over a checksum-locked held-out
62
+ suite — on Gemma 4 12B it scores **SPI 1.00**. ([scribe/evolve/spi.py](scribe/evolve/spi.py))
63
+
64
+ > **Honest scope:** GBNF and constrained decoding aren't new — llama.cpp added
65
+ > grammars in 2023, and the same idea ships elsewhere as "structured outputs".
66
+ > Scribe's contribution is the *integration*: auto-generating the grammar from
67
+ > your tool schemas and wiring it as an automatic tool-call safety net for small
68
+ > local models. Guarantees 1–3 hold on llama.cpp; other backends degrade to a
69
+ > best-effort text parser. The grammar guarantees a call's *form*, not the
70
+ > model's *judgment* (it can still pick the wrong tool — it just can't emit a
71
+ > malformed one).
72
+
73
+ 📖 Full overview on the [project site](https://pedjaurosevic.github.io/scribe-ai/).
74
+
75
+ ## Features
76
+
77
+ - **Universal LLM Adapter** — llama.cpp, Ollama, LM Studio, or any OpenAI-compatible cloud API (OpenRouter, Groq, ...) — see [docs/providers.md](docs/providers.md)
78
+ - **GBNF Tool Enforcement** — grammar-constrained tool calls on llama.cpp; auto-repair when a model emits a malformed call
79
+ - **Grounded Q&A** — hybrid retrieval (FTS5 + vectors, RRF) with mandatory citations and contradiction tagging
80
+ - **Quality Gate** — `scribe bench` runs a judge-scored fitness suite and the deterministic SPI grounding metric
81
+ - **Safe Code Mode** — `/code` with a destructive-command gate, Python AST gate, bubblewrap sandbox, and git checkpoint/rollback
82
+ - **Internet Research** — `web_search` + `web_fetch` tools; DuckDuckGo out of the box, Brave with a key
83
+ - **Writing Agent** — deep-research and writer skills for books, papers and reports, with sandboxed workspace file tools
84
+ - **Persistent Self** — a WorldModel persona injected into every prompt, plus pulse heartbeat and nightly diary
85
+ - **Observability** — ORORO session traces and a machine-readable `scribe status --json` contract
86
+ - **Project Vaults** — `scribe init` gives a directory its own isolated RAG/SME stores
87
+ - **Model Discovery & Blind Compare** — auto-find local servers; A/B two models without bias
88
+ - **Cross-Session Memory** — SME (Semantic Memory Engine) for seamless session continuity
89
+ - **Email Bridge** — get results by email and send commands from one approved address (stdlib only)
90
+ - **Wittgenstein + Peirce** — philosophy-inspired harness design for stable LLM behavior
91
+
92
+ ## Installation
93
+
94
+ ### From PyPI
95
+ ```bash
96
+ pip install scribe-llm # provides the `scribe` command
97
+ ```
98
+ > The PyPI distribution is named `scribe-llm` (the import package and CLI stay `scribe`).
99
+
100
+ ### From source (🐧 Linux)
101
+ ```bash
102
+ # Clone the repository
103
+ git clone https://github.com/pedjaurosevic/scribe-ai.git
104
+ cd scribe-ai
105
+
106
+ # Run the install script: installs the package (editable), creates the
107
+ # config, and scaffolds ~/scribe-workspace.
108
+ ./scripts/install.sh
109
+ ```
110
+
111
+ ### 🪟 Windows (WSL)
112
+ Scribe runs seamlessly on Windows via **WSL (Windows Subsystem for Linux)**.
113
+ 1. Open your WSL terminal (e.g., Ubuntu).
114
+ 2. Run the Linux installation commands shown above.
115
+ 3. To configure Scribe to work with **Ollama** (either running natively on Windows or inside WSL), check out the [WSL & Ollama Integration Guide](docs/wsl_ollama_guide.md).
116
+
117
+ ---
118
+
119
+ Or install by hand (skip the script):
120
+
121
+ ```bash
122
+ pip install -e .
123
+ ```
124
+
125
+ > Requires Python 3.10+. The install is editable, so `git pull` updates Scribe in place.
126
+
127
+ ## Quick Start
128
+
129
+ 1. Start your llama-server:
130
+ ```bash
131
+ ./scripts/start-server.sh
132
+ ```
133
+
134
+ 2. Start Scribe:
135
+ ```bash
136
+ scribe chat
137
+ ```
138
+
139
+ 3. Scribe will automatically recall your last session and ask if you want to continue.
140
+
141
+ ## Configuration
142
+
143
+ Edit `~/.config/scribe/config.toml`:
144
+
145
+ ```toml
146
+ [scribe]
147
+ base_url = "http://127.0.0.1:18083/v1" # llama.cpp / Ollama / LM Studio / cloud
148
+ model = "default" # auto-detects the loaded model
149
+ api_key = "not-needed" # set a real key for cloud providers
150
+ ```
151
+
152
+ Or use environment variables:
153
+
154
+ ```bash
155
+ export SCRIBE_BASE_URL=http://localhost:11434/v1 # e.g. Ollama
156
+ export SCRIBE_MODEL=gemma4:12b
157
+ export SCRIBE_API_KEY=sk-... # cloud providers only
158
+ ```
159
+
160
+ **Full provider guide** — llama.cpp, Ollama, LM Studio, OpenRouter/Groq, plus
161
+ a recipe for **Gemma 4 12B with 128k context on a 12 GB GPU**:
162
+ [docs/providers.md](docs/providers.md).
163
+
164
+ **Web search** needs no setup (DuckDuckGo). For Brave Search, set
165
+ `BRAVE_API_KEY` or `brave_api_key` under `[scribe]`.
166
+
167
+ ## CLI Commands
168
+
169
+ ```bash
170
+ scribe chat # Interactive TUI chat (streaming by default)
171
+ scribe chat --textual # Full-screen Textual UI (experimental)
172
+ scribe chat --resume TAG # Resume a past session (no TAG = last one)
173
+ scribe web # Web UI at http://localhost:8765
174
+
175
+ scribe memory recall "query" # Recall from semantic memory
176
+ scribe rag search "query" # Hybrid search (FTS5 + vectors); --semantic-only to opt out
177
+ scribe rag ask "question" # Grounded Q&A — answers cite sources or refuse
178
+ scribe rag reindex # Rebuild the lexical (FTS5) index
179
+ scribe session last # Show last session
180
+ scribe session list # List all sessions
181
+ scribe session search "query" # Full-text search across all session transcripts
182
+
183
+ scribe init [DIR] # Create a project-local vault (config + ./.scribe)
184
+ scribe discover [--tailscale] # Find OpenAI-compatible model servers
185
+ scribe compare "q" --a M1 --b M2 # Blind A/B two models on one prompt
186
+ scribe bench [--fitness|--spi] # Quality gate: judge fitness + SPI grounding
187
+ scribe trace [ID] [--json] # Show a session's ORORO trace
188
+
189
+ scribe pulse # Record one heartbeat (wire to a systemd timer)
190
+ scribe diary # Reflect on today's sessions
191
+ scribe remember "fact" # Add a durable fact to the WorldModel
192
+
193
+ scribe config show # Show current config
194
+ scribe status [--json] # System status (--json = machine-readable contract)
195
+ scribe evolve eval # Run the held-out fitness suite (Phase 0)
196
+
197
+ scribe mail send "Subj" "Body" # Email yourself a notification
198
+ scribe mail watch # Accept commands by email (see below)
199
+ ```
200
+
201
+ ## Email bridge
202
+
203
+ Scribe can email you results and accept commands by email — using only the
204
+ Python standard library (no extra dependencies).
205
+
206
+ ```toml
207
+ [scribe.email]
208
+ enabled = true
209
+ address = "you@gmail.com"
210
+ approved_sender = "you@gmail.com" # the ONLY address allowed to command Scribe
211
+ secret = "pick-a-token" # must appear in command subjects
212
+ ```
213
+
214
+ ```bash
215
+ export SCRIBE_EMAIL_PASSWORD="your-gmail-app-password" # never in the config file
216
+
217
+ scribe mail send "Done" "The report is ready." # send a notification
218
+ scribe mail watch # poll inbox, run commands, reply
219
+ ```
220
+
221
+ To run a command, email yourself with the secret in the subject:
222
+
223
+ > **Subject:** `[scribe:pick-a-token] summarize the notes in research/`
224
+
225
+ Scribe runs it with the **sandboxed workspace tools** (read/write/list files,
226
+ no shell) and replies with the answer.
227
+
228
+ **Security:** commands are accepted only when both the sender matches
229
+ `approved_sender` **and** the subject carries `[scribe:secret]`. Since `From:`
230
+ headers can be spoofed, the secret is the real gate — leave it empty to keep
231
+ command intake off (sending still works). Gmail requires an
232
+ [App Password](https://myaccount.google.com/apppasswords) (with 2-Step
233
+ Verification enabled).
234
+
235
+ ## Architecture
236
+
237
+ ```
238
+ ┌─────────────────────────────────────────┐
239
+ │ SCRIBE TUI │
240
+ │ (Rich-based interface) │
241
+ ├─────────────────────────────────────────┤
242
+ │ CORE KERNEL │
243
+ │ Session Manager │ Skills │ Config │
244
+ ├─────────────────────────────────────────┤
245
+ │ LLM ADAPTER LAYER │
246
+ │ OpenAI-compatible (llama.cpp) │
247
+ ├─────────────────────────────────────────┤
248
+ │ MEMORY LAYER │
249
+ │ SME (cross-session) │ RAG (documents) │
250
+ ├─────────────────────────────────────────┤
251
+ │ TOOLS LAYER │
252
+ │ web_search │ web_fetch │ bash │
253
+ └─────────────────────────────────────────┘
254
+ ```
255
+
256
+ ## Philosophy
257
+
258
+ Scribe is built on two philosophical pillars:
259
+
260
+ 1. **Wittgenstein** — Language games define meaning. Scribe uses explicit command vocabularies so the model knows exactly what each action means.
261
+
262
+ 2. **Peirce** — Signs gain meaning through interpretation chains. Scribe maintains semiotic continuity: every response becomes the next sign in the chain.
263
+
264
+ ## License
265
+
266
+ MIT