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.
- scribe_llm-0.4.0/.github/workflows/ci.yml +35 -0
- scribe_llm-0.4.0/.github/workflows/publish.yml +38 -0
- scribe_llm-0.4.0/.gitignore +37 -0
- scribe_llm-0.4.0/CHANGELOG.md +118 -0
- scribe_llm-0.4.0/CONTRIBUTING.md +62 -0
- scribe_llm-0.4.0/LICENSE +21 -0
- scribe_llm-0.4.0/PKG-INFO +266 -0
- scribe_llm-0.4.0/PLAN.md +825 -0
- scribe_llm-0.4.0/README.md +228 -0
- scribe_llm-0.4.0/README.zh-CN.md +182 -0
- scribe_llm-0.4.0/config/config.example.toml +123 -0
- scribe_llm-0.4.0/docs/index.html +200 -0
- scribe_llm-0.4.0/docs/index.zh.html +134 -0
- scribe_llm-0.4.0/docs/open-knowledge-format.md +84 -0
- scribe_llm-0.4.0/docs/providers.md +149 -0
- scribe_llm-0.4.0/docs/providers.zh-CN.md +147 -0
- scribe_llm-0.4.0/docs/recursive-scaffold-hypothesis.md +86 -0
- scribe_llm-0.4.0/docs/wsl_ollama_guide.md +95 -0
- scribe_llm-0.4.0/docs/wsl_ollama_guide.zh-CN.md +93 -0
- scribe_llm-0.4.0/promo/README.md +30 -0
- scribe_llm-0.4.0/promo/_demo_grammar.py +58 -0
- scribe_llm-0.4.0/promo/record-demo.sh +118 -0
- scribe_llm-0.4.0/promo/source.md +81 -0
- scribe_llm-0.4.0/pyproject.toml +83 -0
- scribe_llm-0.4.0/scribe/__init__.py +15 -0
- scribe_llm-0.4.0/scribe/cli.py +785 -0
- scribe_llm-0.4.0/scribe/compare.py +89 -0
- scribe_llm-0.4.0/scribe/config.py +362 -0
- scribe_llm-0.4.0/scribe/discovery.py +102 -0
- scribe_llm-0.4.0/scribe/documents.py +229 -0
- scribe_llm-0.4.0/scribe/evolve/__init__.py +1 -0
- scribe_llm-0.4.0/scribe/evolve/evaluate.py +317 -0
- scribe_llm-0.4.0/scribe/evolve/spi.py +181 -0
- scribe_llm-0.4.0/scribe/grammar.py +173 -0
- scribe_llm-0.4.0/scribe/llm_adapter.py +877 -0
- scribe_llm-0.4.0/scribe/mail.py +276 -0
- scribe_llm-0.4.0/scribe/memory/__init__.py +29 -0
- scribe_llm-0.4.0/scribe/memory/hybrid.py +102 -0
- scribe_llm-0.4.0/scribe/memory/rag.py +394 -0
- scribe_llm-0.4.0/scribe/memory/sme.py +364 -0
- scribe_llm-0.4.0/scribe/prompts.py +311 -0
- scribe_llm-0.4.0/scribe/pulse.py +111 -0
- scribe_llm-0.4.0/scribe/reasoning_gate.py +72 -0
- scribe_llm-0.4.0/scribe/seed/constitution.md +17 -0
- scribe_llm-0.4.0/scribe/seed/eval/MANIFEST.sha256 +2 -0
- scribe_llm-0.4.0/scribe/seed/eval/grounded.jsonl +8 -0
- scribe_llm-0.4.0/scribe/seed/eval/tasks.jsonl +20 -0
- scribe_llm-0.4.0/scribe/session.py +380 -0
- scribe_llm-0.4.0/scribe/skills/__init__.py +21 -0
- scribe_llm-0.4.0/scribe/skills/deep-research/SKILL.md +68 -0
- scribe_llm-0.4.0/scribe/skills/wiki-memory/SKILL.md +86 -0
- scribe_llm-0.4.0/scribe/skills/writer/SKILL.md +63 -0
- scribe_llm-0.4.0/scribe/skills_executor.py +285 -0
- scribe_llm-0.4.0/scribe/static/.gitkeep +0 -0
- scribe_llm-0.4.0/scribe/status.py +137 -0
- scribe_llm-0.4.0/scribe/templates/editor.html +636 -0
- scribe_llm-0.4.0/scribe/templates/index.html +632 -0
- scribe_llm-0.4.0/scribe/templates/print.html +43 -0
- scribe_llm-0.4.0/scribe/tools/__init__.py +103 -0
- scribe_llm-0.4.0/scribe/tools/checkpoint.py +190 -0
- scribe_llm-0.4.0/scribe/tools/fs.py +207 -0
- scribe_llm-0.4.0/scribe/tools/sandbox.py +162 -0
- scribe_llm-0.4.0/scribe/tools/shell.py +129 -0
- scribe_llm-0.4.0/scribe/tools/web.py +364 -0
- scribe_llm-0.4.0/scribe/trace.py +84 -0
- scribe_llm-0.4.0/scribe/tui.py +1075 -0
- scribe_llm-0.4.0/scribe/tui_app.py +415 -0
- scribe_llm-0.4.0/scribe/ui/__init__.py +22 -0
- scribe_llm-0.4.0/scribe/ui/console.py +139 -0
- scribe_llm-0.4.0/scribe/ui/logo.py +31 -0
- scribe_llm-0.4.0/scribe/ui/progress.py +144 -0
- scribe_llm-0.4.0/scribe/ui/theme.py +77 -0
- scribe_llm-0.4.0/scribe/vault.py +80 -0
- scribe_llm-0.4.0/scribe/web.py +643 -0
- scribe_llm-0.4.0/scribe/wiki.py +482 -0
- scribe_llm-0.4.0/scribe/worldmodel.py +104 -0
- scribe_llm-0.4.0/scripts/install.sh +79 -0
- scribe_llm-0.4.0/scripts/start-server.sh +55 -0
- scribe_llm-0.4.0/tests/conftest.py +4 -0
- scribe_llm-0.4.0/tests/test_core.py +293 -0
- scribe_llm-0.4.0/tests/test_discovery_compare.py +92 -0
- scribe_llm-0.4.0/tests/test_documents.py +96 -0
- scribe_llm-0.4.0/tests/test_evolve.py +59 -0
- scribe_llm-0.4.0/tests/test_grammar.py +220 -0
- scribe_llm-0.4.0/tests/test_hybrid.py +181 -0
- scribe_llm-0.4.0/tests/test_mail.py +51 -0
- scribe_llm-0.4.0/tests/test_memory.py +150 -0
- scribe_llm-0.4.0/tests/test_sandbox.py +183 -0
- scribe_llm-0.4.0/tests/test_session_resume.py +106 -0
- scribe_llm-0.4.0/tests/test_skills.py +67 -0
- scribe_llm-0.4.0/tests/test_spi.py +141 -0
- scribe_llm-0.4.0/tests/test_status_line.py +39 -0
- scribe_llm-0.4.0/tests/test_tools.py +214 -0
- scribe_llm-0.4.0/tests/test_trace_vault.py +142 -0
- scribe_llm-0.4.0/tests/test_wiki.py +311 -0
- 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.
|
scribe_llm-0.4.0/LICENSE
ADDED
|
@@ -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
|
+
[](https://github.com/pedjaurosevic/scribe-ai/actions/workflows/ci.yml)
|
|
44
|
+
[](https://www.python.org/downloads/)
|
|
45
|
+
[](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
|