stabbur 0.6.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.
- stabbur-0.6.0/LICENSE +24 -0
- stabbur-0.6.0/PKG-INFO +232 -0
- stabbur-0.6.0/README.md +184 -0
- stabbur-0.6.0/pyproject.toml +258 -0
- stabbur-0.6.0/pyproject.toml.orig +295 -0
- stabbur-0.6.0/src/stabbur/__init__.py +37 -0
- stabbur-0.6.0/src/stabbur/agent.py +332 -0
- stabbur-0.6.0/src/stabbur/app.py +333 -0
- stabbur-0.6.0/src/stabbur/arch.py +49 -0
- stabbur-0.6.0/src/stabbur/attach.py +71 -0
- stabbur-0.6.0/src/stabbur/benchmark/__init__.py +70 -0
- stabbur-0.6.0/src/stabbur/benchmark/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/benchmark/app.py +58 -0
- stabbur-0.6.0/src/stabbur/benchmark/core.py +622 -0
- stabbur-0.6.0/src/stabbur/benchmark/dhis2_state.py +168 -0
- stabbur-0.6.0/src/stabbur/benchmark/plugin.py +269 -0
- stabbur-0.6.0/src/stabbur/benchmark/suites/python.toml +166 -0
- stabbur-0.6.0/src/stabbur/benchmark/suites/rust.toml +178 -0
- stabbur-0.6.0/src/stabbur/benchmark/suites/tools-datetime.toml +42 -0
- stabbur-0.6.0/src/stabbur/benchmark/suites/tools-dhis2-write.toml +104 -0
- stabbur-0.6.0/src/stabbur/benchmark/suites/tools-dhis2.toml +123 -0
- stabbur-0.6.0/src/stabbur/benchmark/suites/tools-exec.toml +22 -0
- stabbur-0.6.0/src/stabbur/benchmark/suites/tools-memory.toml +24 -0
- stabbur-0.6.0/src/stabbur/benchmark/suites/tools-search.toml +23 -0
- stabbur-0.6.0/src/stabbur/benchmark/suites/tools-utils.toml +50 -0
- stabbur-0.6.0/src/stabbur/benchmark/suites/tools-weather-yr.toml +24 -0
- stabbur-0.6.0/src/stabbur/benchmark/suites/tools-web.toml +25 -0
- stabbur-0.6.0/src/stabbur/capabilities.py +283 -0
- stabbur-0.6.0/src/stabbur/cards.py +95 -0
- stabbur-0.6.0/src/stabbur/catalog.py +88 -0
- stabbur-0.6.0/src/stabbur/chat_tui/__init__.py +12 -0
- stabbur-0.6.0/src/stabbur/chat_tui/_util.py +77 -0
- stabbur-0.6.0/src/stabbur/chat_tui/_widgets.py +254 -0
- stabbur-0.6.0/src/stabbur/chat_tui/app.py +1158 -0
- stabbur-0.6.0/src/stabbur/chatui.py +32 -0
- stabbur-0.6.0/src/stabbur/cli/__init__.py +38 -0
- stabbur-0.6.0/src/stabbur/cli/_app.py +216 -0
- stabbur-0.6.0/src/stabbur/cli/_common.py +312 -0
- stabbur-0.6.0/src/stabbur/cli/chat.py +726 -0
- stabbur-0.6.0/src/stabbur/cli/config.py +90 -0
- stabbur-0.6.0/src/stabbur/cli/ext_dev.py +108 -0
- stabbur-0.6.0/src/stabbur/cli/health.py +214 -0
- stabbur-0.6.0/src/stabbur/cli/library.py +840 -0
- stabbur-0.6.0/src/stabbur/cli/mcp.py +219 -0
- stabbur-0.6.0/src/stabbur/cli/project.py +440 -0
- stabbur-0.6.0/src/stabbur/cli/serve.py +211 -0
- stabbur-0.6.0/src/stabbur/cli/voice.py +275 -0
- stabbur-0.6.0/src/stabbur/config.py +314 -0
- stabbur-0.6.0/src/stabbur/consumers.py +264 -0
- stabbur-0.6.0/src/stabbur/doctor.py +452 -0
- stabbur-0.6.0/src/stabbur/fsatomic.py +35 -0
- stabbur-0.6.0/src/stabbur/hfcache.py +51 -0
- stabbur-0.6.0/src/stabbur/host.py +108 -0
- stabbur-0.6.0/src/stabbur/library/__init__.py +39 -0
- stabbur-0.6.0/src/stabbur/library/_manage.py +251 -0
- stabbur-0.6.0/src/stabbur/library/_model.py +185 -0
- stabbur-0.6.0/src/stabbur/library/_roots.py +92 -0
- stabbur-0.6.0/src/stabbur/library/_scan.py +252 -0
- stabbur-0.6.0/src/stabbur/locking.py +55 -0
- stabbur-0.6.0/src/stabbur/mcp_catalog.py +337 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/__init__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/datetime/__init__.py +28 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/datetime/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/datetime/app.py +329 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/datetime/plugin.py +30 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/exec/__init__.py +27 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/exec/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/exec/app.py +43 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/exec/plugin.py +29 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/files/__init__.py +27 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/files/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/files/app.py +60 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/files/core.py +153 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/files/plugin.py +52 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/git/__init__.py +23 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/git/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/git/app.py +250 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/git/plugin.py +43 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/http/__init__.py +23 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/http/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/http/app.py +282 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/http/plugin.py +50 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/memory/__init__.py +28 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/memory/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/memory/app.py +78 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/memory/core.py +119 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/memory/plugin.py +50 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/network/__init__.py +23 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/network/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/network/app.py +156 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/network/plugin.py +29 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/search/__init__.py +28 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/search/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/search/app.py +195 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/search/plugin.py +44 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/shell/__init__.py +23 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/shell/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/shell/app.py +230 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/shell/plugin.py +29 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/utils/__init__.py +27 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/utils/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/utils/app.py +306 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/utils/plugin.py +29 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/weather_yr/__init__.py +28 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/weather_yr/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/weather_yr/app.py +55 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/weather_yr/core.py +183 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/weather_yr/plugin.py +30 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/web/__init__.py +28 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/web/__main__.py +6 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/web/app.py +357 -0
- stabbur-0.6.0/src/stabbur/mcp_servers/web/plugin.py +48 -0
- stabbur-0.6.0/src/stabbur/mcpservers.py +177 -0
- stabbur-0.6.0/src/stabbur/models.py +234 -0
- stabbur-0.6.0/src/stabbur/plugins.py +168 -0
- stabbur-0.6.0/src/stabbur/project/__init__.py +630 -0
- stabbur-0.6.0/src/stabbur/project/scaffold.py +203 -0
- stabbur-0.6.0/src/stabbur/project/templates.py +674 -0
- stabbur-0.6.0/src/stabbur/routers/__init__.py +1 -0
- stabbur-0.6.0/src/stabbur/routers/catalog.py +37 -0
- stabbur-0.6.0/src/stabbur/routers/health.py +11 -0
- stabbur-0.6.0/src/stabbur/routers/serving/__init__.py +29 -0
- stabbur-0.6.0/src/stabbur/routers/serving/_base.py +88 -0
- stabbur-0.6.0/src/stabbur/routers/serving/assistant.py +611 -0
- stabbur-0.6.0/src/stabbur/routers/serving/chat.py +369 -0
- stabbur-0.6.0/src/stabbur/routers/serving/core.py +434 -0
- stabbur-0.6.0/src/stabbur/routers/serving/mcp.py +211 -0
- stabbur-0.6.0/src/stabbur/routers/serving/proxy.py +69 -0
- stabbur-0.6.0/src/stabbur/routers/serving/voice.py +286 -0
- stabbur-0.6.0/src/stabbur/runtime/__init__.py +317 -0
- stabbur-0.6.0/src/stabbur/runtime/sampling.py +99 -0
- stabbur-0.6.0/src/stabbur/runtime/serve_registry.py +122 -0
- stabbur-0.6.0/src/stabbur/runtime/supervisor.py +325 -0
- stabbur-0.6.0/src/stabbur/server.py +425 -0
- stabbur-0.6.0/src/stabbur/sources/__init__.py +5 -0
- stabbur-0.6.0/src/stabbur/sources/base.py +132 -0
- stabbur-0.6.0/src/stabbur/sources/huggingface.py +252 -0
- stabbur-0.6.0/src/stabbur/sources/lmstudio.py +128 -0
- stabbur-0.6.0/src/stabbur/sources/ollama.py +415 -0
- stabbur-0.6.0/src/stabbur/tags.py +163 -0
- stabbur-0.6.0/src/stabbur/targets.py +180 -0
- stabbur-0.6.0/src/stabbur/tools.py +657 -0
- stabbur-0.6.0/src/stabbur/transcript.py +45 -0
- stabbur-0.6.0/src/stabbur/userconfig.py +111 -0
- stabbur-0.6.0/src/stabbur/voice/__init__.py +25 -0
- stabbur-0.6.0/src/stabbur/voice/audio.py +64 -0
- stabbur-0.6.0/src/stabbur/voice/catalog.py +111 -0
- stabbur-0.6.0/src/stabbur/voice/importer.py +170 -0
- stabbur-0.6.0/src/stabbur/voice/kokoro.py +228 -0
- stabbur-0.6.0/src/stabbur/voice/registry.py +171 -0
- stabbur-0.6.0/src/stabbur/voice/runtime.py +133 -0
- stabbur-0.6.0/src/stabbur/voice/tts.py +48 -0
- stabbur-0.6.0/src/stabbur/wantlist.py +208 -0
stabbur-0.6.0/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
stabbur — Proprietary Software License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Morten Hansen. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and its source code (the "Software") are the exclusive property of
|
|
6
|
+
Morten Hansen (the "Owner"). The Software is made source-available for reference
|
|
7
|
+
and evaluation only. It is NOT open-source and is NOT licensed for use.
|
|
8
|
+
|
|
9
|
+
No license or right is granted, whether express or implied, to any person or
|
|
10
|
+
entity to use, copy, run, execute, deploy, host, modify, adapt, translate,
|
|
11
|
+
create derivative works of, distribute, sublicense, sell, or otherwise exploit
|
|
12
|
+
the Software, in whole or in part, for any purpose, without the prior written
|
|
13
|
+
permission of the Owner.
|
|
14
|
+
|
|
15
|
+
Viewing the source in the public repository does not grant any right to use it.
|
|
16
|
+
Any use of the Software requires a separate written license agreement with the
|
|
17
|
+
Owner. To request permission, contact morten@winterop.com.
|
|
18
|
+
|
|
19
|
+
Unless required by applicable law or agreed to in writing, the Software is
|
|
20
|
+
provided "AS IS", WITHOUT WARRANTY OF ANY KIND, express or implied, including
|
|
21
|
+
but not limited to the warranties of merchantability, fitness for a particular
|
|
22
|
+
purpose, and non-infringement. In no event shall the Owner be liable for any
|
|
23
|
+
claim, damages, or other liability arising from, out of, or in connection with
|
|
24
|
+
the Software or its use.
|
stabbur-0.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stabbur
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Stabbur — build a local LLM library, then run, chat, and serve it — fully on-box
|
|
5
|
+
Keywords: llm,local-llm,self-hosted,mcp,agent,dhis2,fastapi,huggingface
|
|
6
|
+
License-Expression: LicenseRef-Proprietary
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Operating System :: MacOS
|
|
11
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
15
|
+
Requires-Dist: fastapi[standard]>=0.138.2
|
|
16
|
+
Requires-Dist: fastmcp>=3.4.2
|
|
17
|
+
Requires-Dist: hf-xet>=1.5.1
|
|
18
|
+
Requires-Dist: httpx>=0.28.1
|
|
19
|
+
Requires-Dist: huggingface-hub>=1.21.0
|
|
20
|
+
Requires-Dist: pydantic>=2.0
|
|
21
|
+
Requires-Dist: kokoro-onnx>=0.4.9
|
|
22
|
+
Requires-Dist: pluginkit>=0.4.7
|
|
23
|
+
Requires-Dist: pydantic-settings>=2.14.2
|
|
24
|
+
Requires-Dist: soundfile>=0.13.1
|
|
25
|
+
Requires-Dist: textual>=0.85
|
|
26
|
+
Requires-Dist: typer>=0.25.1
|
|
27
|
+
Requires-Dist: uvicorn[standard]>=0.49.0
|
|
28
|
+
Requires-Dist: mlx-lm>=0.31.3 ; platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'mlx'
|
|
29
|
+
Requires-Dist: mlx-vlm>=0.6.3 ; platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'mlx'
|
|
30
|
+
Requires-Dist: transformers>=5.5,<5.13 ; platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'mlx'
|
|
31
|
+
Requires-Dist: mlx-audio>=0.4.4 ; platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'voice'
|
|
32
|
+
Requires-Dist: misaki[en]>=0.9.4 ; extra == 'voice'
|
|
33
|
+
Requires-Dist: soundfile>=0.13.1 ; extra == 'voice'
|
|
34
|
+
Requires-Dist: soxr>=0.5 ; extra == 'voice'
|
|
35
|
+
Requires-Dist: transformers>=5.5,<5.13 ; platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'voice'
|
|
36
|
+
Requires-Dist: playwright>=1.47 ; extra == 'web'
|
|
37
|
+
Requires-Dist: trafilatura>=1.12 ; extra == 'web'
|
|
38
|
+
Requires-Python: >=3.13
|
|
39
|
+
Project-URL: Homepage, https://github.com/winterop-com/stabbur
|
|
40
|
+
Project-URL: Repository, https://github.com/winterop-com/stabbur
|
|
41
|
+
Project-URL: Documentation, https://github.com/winterop-com/stabbur/tree/main/docs
|
|
42
|
+
Project-URL: Issues, https://github.com/winterop-com/stabbur/issues
|
|
43
|
+
Provides-Extra: benchmark
|
|
44
|
+
Provides-Extra: mlx
|
|
45
|
+
Provides-Extra: voice
|
|
46
|
+
Provides-Extra: web
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
<!-- Absolute URLs: this README is the PyPI long description, and PyPI does not rewrite
|
|
50
|
+
relative paths - a repo-relative src renders as a broken image on the project page. -->
|
|
51
|
+
<div align="center">
|
|
52
|
+
|
|
53
|
+
<img src="https://raw.githubusercontent.com/winterop-com/stabbur/main/docs/assets/logo.png" alt="stabbur" width="200">
|
|
54
|
+
|
|
55
|
+
# stabbur
|
|
56
|
+
|
|
57
|
+
[](https://github.com/winterop-com/stabbur/actions/workflows/ci.yml)
|
|
58
|
+
[](https://pypi.org/project/stabbur/)
|
|
59
|
+
[](https://www.python.org/)
|
|
60
|
+
[](https://docs.astral.sh/uv/)
|
|
61
|
+
[](https://github.com/winterop-com/stabbur/blob/main/LICENSE)
|
|
62
|
+
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
A tool for building and keeping a **full local library of LLM models**. It
|
|
66
|
+
discovers models from **Hugging Face**, **Ollama**, and **LM Studio**, pulls
|
|
67
|
+
them into a single library (browse via a **Typer CLI** or a **browser chat UI**),
|
|
68
|
+
and runs them from there. The library lives under one configurable root you point
|
|
69
|
+
at an external drive (e.g. a 5TB drive).
|
|
70
|
+
|
|
71
|
+
**Short form.** Every command is also available as `sb` — `sb chat`, `sb serve`, `sb library ls`.
|
|
72
|
+
|
|
73
|
+
**The name.** A *stabbur* is the Norwegian storehouse — raised on pillars, off the ground and
|
|
74
|
+
out of the damp, where a household kept what it had gathered and wanted to keep. That is what this
|
|
75
|
+
is: your models, pulled in from wherever they came from and kept somewhere of your own, on your own
|
|
76
|
+
box, rather than in someone else's cloud.
|
|
77
|
+
|
|
78
|
+
> **Proprietary, source-available.** stabbur is not open-source. Copyright (c) 2026 Morten
|
|
79
|
+
> Hansen, all rights reserved (see [`LICENSE`](LICENSE)). The source is published for
|
|
80
|
+
> reference and evaluation; running it requires a written license — contact
|
|
81
|
+
> <morten@winterop.com>. Install is from source with `uv` (there is no `pip install stabbur`).
|
|
82
|
+
|
|
83
|
+

|
|
84
|
+
|
|
85
|
+
## Layout
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
src/stabbur/
|
|
89
|
+
├── config.py # Pydantic settings (STABBUR_* env vars)
|
|
90
|
+
├── models.py # Catalog / entry / result models
|
|
91
|
+
├── catalog.py # Aggregates listing + pull across sources
|
|
92
|
+
├── library.py # Scans the on-drive library (gguf/ mlx/ voice/ ...)
|
|
93
|
+
├── capabilities.py # Detects per-model tools/vision/audio + context
|
|
94
|
+
├── runtime.py # Serves a model (llama.cpp / mlx_lm / mlx-vlm)
|
|
95
|
+
├── voice/ # Voice models: registry, import, TTS/STT runtime
|
|
96
|
+
├── cli/ # Typer CLI package, one module per command group (entry: `stabbur` → stabbur.cli:main)
|
|
97
|
+
├── app.py # FastAPI app factory
|
|
98
|
+
├── routers/ # health + catalog (browse/pull) + serving (load/chat/audio) endpoints
|
|
99
|
+
└── sources/ # huggingface / ollama / lmstudio adapters
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Setup
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
uv sync # stabbur itself (needs Python 3.13 + uv)
|
|
106
|
+
brew install llama.cpp # baseline runtime: GGUF chat + OuteTTS speech (build from source on Linux)
|
|
107
|
+
make install-mlx # optional: MLX runtimes (Apple Silicon)
|
|
108
|
+
uv sync --extra voice # optional: mlx-audio runtimes (Dia/Whisper, Apple Silicon)
|
|
109
|
+
make frontend # optional: build the web UI (needs Bun)
|
|
110
|
+
export STABBUR_LIBRARY_ROOT=/path/to/your/library # required: where your library lives
|
|
111
|
+
stabbur doctor # verify what's installed
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Point stabbur at a library.** stabbur won't guess a location — set `STABBUR_LIBRARY_ROOT`
|
|
115
|
+
(a per-machine shell/`.env` value; an external drive is the intended home). Without
|
|
116
|
+
it, library commands fail with a clear message instead of silently using `./data`.
|
|
117
|
+
|
|
118
|
+
**Install globally** (run `stabbur` from any directory):
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
uv tool install --editable ".[mlx,voice,web,benchmark]" # from a checkout: stabbur on your PATH, code edits live
|
|
122
|
+
uv tool install "git+https://github.com/winterop-com/stabbur" # or straight from git (requires repo access; core CLI)
|
|
123
|
+
# then put STABBUR_LIBRARY_ROOT in your shell profile (~/.zshrc) so it applies everywhere
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Only `uv sync` + llama.cpp are needed to run GGUF models; the rest are optional.
|
|
127
|
+
The `benchmark` extra adds the `stabbur benchmark` eval command; drop it if you don't need it.
|
|
128
|
+
See [getting started](docs/getting-started.md) for details.
|
|
129
|
+
|
|
130
|
+
stabbur is installed **from source** (`uv sync` / `uv tool install -e .`), not from PyPI. It builds
|
|
131
|
+
as a single self-contained wheel — the bundled first-party MCP servers are vendored into the `stabbur`
|
|
132
|
+
package (`src/stabbur/mcp_servers/*`) rather than published as separate packages — but stabbur is
|
|
133
|
+
proprietary/source-available and is not distributed on PyPI.
|
|
134
|
+
|
|
135
|
+
## CLI
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
stabbur library ls # your library (the models on your drive)
|
|
139
|
+
stabbur library sources # models in app caches (HF/Ollama/LM Studio) you could pull
|
|
140
|
+
stabbur library pull lmstudio lmstudio-community/gemma-4-12B-it-QAT-GGUF
|
|
141
|
+
stabbur library pull ollama gemma4:31b --move # copy to the library, then delete the local copy
|
|
142
|
+
stabbur doctor # pre-flight: runtimes, library, project
|
|
143
|
+
stabbur serve --ui # browse + chat in the browser (Chat · Voice · Library)
|
|
144
|
+
stabbur chat gemma-4-12B-it-QAT-GGUF -p "hi" # one-shot, scriptable
|
|
145
|
+
stabbur chat gemma-4-12B-it-QAT-GGUF -p "?" -i pic.jpg # image input (vision model)
|
|
146
|
+
stabbur voice ls # voice models (TTS/STT) in the library
|
|
147
|
+
stabbur voice import --all # import known voice models to the library
|
|
148
|
+
stabbur voice speak -v af_heart "hello there" # text-to-speech (Kokoro)
|
|
149
|
+
stabbur voice speak --model dia --seed 10 "hi there" # Dia (pin a seed for a stable voice)
|
|
150
|
+
stabbur project init # scaffold a project assistant (model + tools + prompt)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Two model families:** **Chat** (language models you talk to — text in/out; some
|
|
154
|
+
also read images/audio or call tools) and **Voice** (TTS speaks, STT transcribes).
|
|
155
|
+
stabbur detects each chat model's capabilities and runs the right runtime — GGUF via
|
|
156
|
+
llama.cpp (`llama-server`, `--mmproj` for vision/audio), MLX via `mlx_lm`/`mlx-vlm`.
|
|
157
|
+
The web UI's **Library** lists both families; the **Voice** studio does TTS/STT
|
|
158
|
+
(Kokoro, Dia with voice cloning, Whisper); in chat you can attach images/audio,
|
|
159
|
+
dictate with the mic (Whisper), and **read replies aloud** (Kokoro by default). See
|
|
160
|
+
the [voice guide](docs/guides/voice.md).
|
|
161
|
+
|
|
162
|
+
Full docs: **[`docs/`](docs/)** (run `make docs` to serve the site locally) —
|
|
163
|
+
getting started, the library, pulling, running & chatting, the web UI, the Chrome side panel,
|
|
164
|
+
the DHIS2 assistant, and the architecture.
|
|
165
|
+
|
|
166
|
+
## API
|
|
167
|
+
|
|
168
|
+
`stabbur serve` exposes an OpenAI-compatible surface plus browse/voice endpoints:
|
|
169
|
+
`/api/status`, `/api/library`, `/api/voice`, `/api/chat` (tool-aware SSE),
|
|
170
|
+
`/v1/*` (proxied to the loaded model), and `/v1/audio/speech` +
|
|
171
|
+
`/v1/audio/transcriptions`. See the [web UI guide](docs/guides/web-ui.md) for the
|
|
172
|
+
full endpoint table and the single-origin proxy design.
|
|
173
|
+
|
|
174
|
+
## Chrome side panel & the DHIS2 assistant
|
|
175
|
+
|
|
176
|
+
stabbur ships an **MV3 Chrome side panel** (`extension/`, built with WXT) — a thin client for
|
|
177
|
+
a local or remote `stabbur serve` that puts your own model + tools next to any page. It builds
|
|
178
|
+
in two flavors from one codebase: the generic **stabbur** panel and **stabbur for DHIS2**
|
|
179
|
+
(`STABBUR_FLAVOR=dhis2`).
|
|
180
|
+
|
|
181
|
+
Pointed at a DHIS2 project (`stabbur project new --template dhis2`), it becomes the north-star
|
|
182
|
+
assistant: chat grounded in the page you are viewing, a target banner (verify + tab
|
|
183
|
+
match/mismatch), and **"Use my login"** — mint a read-only, GET-scoped Personal Access Token
|
|
184
|
+
in the DHIS2 tab's own security context and hand it to stabbur once, so the tools act as *you*
|
|
185
|
+
(with a session-cookie fallback). Everything runs against your own local model; nothing
|
|
186
|
+
leaves the box.
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
cd extension && bun install && bun run build # -> extension/.output/chrome-mv3(-dhis2)
|
|
190
|
+
# chrome://extensions -> Load unpacked -> the built dir; then `stabbur serve` and open the panel
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
See the [Chrome side panel guide](docs/guides/extension.md) and
|
|
194
|
+
the [verified prompt catalog](docs/guides/extension-prompts.md).
|
|
195
|
+
|
|
196
|
+
## Configuration
|
|
197
|
+
|
|
198
|
+
Two separate concepts:
|
|
199
|
+
|
|
200
|
+
- **The library location** — where your models live. Set **`STABBUR_LIBRARY_ROOT`** (a
|
|
201
|
+
per-machine value; shell profile or `.env`). stabbur **requires** it — without one,
|
|
202
|
+
library/chat/serve commands fail with a clear message rather than silently using a
|
|
203
|
+
local folder. An external drive is the intended home:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
export STABBUR_LIBRARY_ROOT=/path/to/your/library # e.g. a mounted external drive
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
- **A project** (`stabbur.toml`, via `stabbur project init` / `stabbur project new <dir>`) — a
|
|
210
|
+
purpose-built **assistant**: `[project].model` + `system_prompt`, with tools in a sibling
|
|
211
|
+
`.mcp.json` (standard `mcpServers`). In a project, `stabbur serve` / `stabbur chat` bind to that
|
|
212
|
+
model (like `--model`, with its tools + prompt); **outside** a project it's free-play
|
|
213
|
+
(pick/switch any model). A project uses the machine library by default.
|
|
214
|
+
|
|
215
|
+
Precedence (high → low): CLI flags, `STABBUR_*` env vars, `stabbur.toml`, `.env`,
|
|
216
|
+
`~/.config/stabbur/config.toml` (machine defaults).
|
|
217
|
+
|
|
218
|
+
| Key / env var | Purpose |
|
|
219
|
+
| --------------------------------------------- | ----------------------------------- |
|
|
220
|
+
| `STABBUR_LIBRARY_ROOT` (or `library_root`) | the library location (**required**) |
|
|
221
|
+
| `STABBUR_OLLAMA_MODELS_DIR`, `STABBUR_LMSTUDIO_MODELS_DIR` | source caches to pull from |
|
|
222
|
+
| `STABBUR_HF_TOKEN` | HF token (uses your HF login if unset) |
|
|
223
|
+
| `STABBUR_DEFAULT_MAX_TOKENS` (or `default_max_tokens`) | per-turn `/api/chat` generation cap (default 4096; `0` = unbounded) |
|
|
224
|
+
|
|
225
|
+
## Develop
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
make lint # ruff format + check, mypy, pyright (mutates)
|
|
229
|
+
make check # same, read-only (CI gate) + tests
|
|
230
|
+
make test # pytest
|
|
231
|
+
make build # uv build (wheel + sdist)
|
|
232
|
+
```
|
stabbur-0.6.0/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
<!-- Absolute URLs: this README is the PyPI long description, and PyPI does not rewrite
|
|
2
|
+
relative paths - a repo-relative src renders as a broken image on the project page. -->
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
<img src="https://raw.githubusercontent.com/winterop-com/stabbur/main/docs/assets/logo.png" alt="stabbur" width="200">
|
|
6
|
+
|
|
7
|
+
# stabbur
|
|
8
|
+
|
|
9
|
+
[](https://github.com/winterop-com/stabbur/actions/workflows/ci.yml)
|
|
10
|
+
[](https://pypi.org/project/stabbur/)
|
|
11
|
+
[](https://www.python.org/)
|
|
12
|
+
[](https://docs.astral.sh/uv/)
|
|
13
|
+
[](https://github.com/winterop-com/stabbur/blob/main/LICENSE)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
A tool for building and keeping a **full local library of LLM models**. It
|
|
18
|
+
discovers models from **Hugging Face**, **Ollama**, and **LM Studio**, pulls
|
|
19
|
+
them into a single library (browse via a **Typer CLI** or a **browser chat UI**),
|
|
20
|
+
and runs them from there. The library lives under one configurable root you point
|
|
21
|
+
at an external drive (e.g. a 5TB drive).
|
|
22
|
+
|
|
23
|
+
**Short form.** Every command is also available as `sb` — `sb chat`, `sb serve`, `sb library ls`.
|
|
24
|
+
|
|
25
|
+
**The name.** A *stabbur* is the Norwegian storehouse — raised on pillars, off the ground and
|
|
26
|
+
out of the damp, where a household kept what it had gathered and wanted to keep. That is what this
|
|
27
|
+
is: your models, pulled in from wherever they came from and kept somewhere of your own, on your own
|
|
28
|
+
box, rather than in someone else's cloud.
|
|
29
|
+
|
|
30
|
+
> **Proprietary, source-available.** stabbur is not open-source. Copyright (c) 2026 Morten
|
|
31
|
+
> Hansen, all rights reserved (see [`LICENSE`](LICENSE)). The source is published for
|
|
32
|
+
> reference and evaluation; running it requires a written license — contact
|
|
33
|
+
> <morten@winterop.com>. Install is from source with `uv` (there is no `pip install stabbur`).
|
|
34
|
+
|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
## Layout
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
src/stabbur/
|
|
41
|
+
├── config.py # Pydantic settings (STABBUR_* env vars)
|
|
42
|
+
├── models.py # Catalog / entry / result models
|
|
43
|
+
├── catalog.py # Aggregates listing + pull across sources
|
|
44
|
+
├── library.py # Scans the on-drive library (gguf/ mlx/ voice/ ...)
|
|
45
|
+
├── capabilities.py # Detects per-model tools/vision/audio + context
|
|
46
|
+
├── runtime.py # Serves a model (llama.cpp / mlx_lm / mlx-vlm)
|
|
47
|
+
├── voice/ # Voice models: registry, import, TTS/STT runtime
|
|
48
|
+
├── cli/ # Typer CLI package, one module per command group (entry: `stabbur` → stabbur.cli:main)
|
|
49
|
+
├── app.py # FastAPI app factory
|
|
50
|
+
├── routers/ # health + catalog (browse/pull) + serving (load/chat/audio) endpoints
|
|
51
|
+
└── sources/ # huggingface / ollama / lmstudio adapters
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Setup
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
uv sync # stabbur itself (needs Python 3.13 + uv)
|
|
58
|
+
brew install llama.cpp # baseline runtime: GGUF chat + OuteTTS speech (build from source on Linux)
|
|
59
|
+
make install-mlx # optional: MLX runtimes (Apple Silicon)
|
|
60
|
+
uv sync --extra voice # optional: mlx-audio runtimes (Dia/Whisper, Apple Silicon)
|
|
61
|
+
make frontend # optional: build the web UI (needs Bun)
|
|
62
|
+
export STABBUR_LIBRARY_ROOT=/path/to/your/library # required: where your library lives
|
|
63
|
+
stabbur doctor # verify what's installed
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Point stabbur at a library.** stabbur won't guess a location — set `STABBUR_LIBRARY_ROOT`
|
|
67
|
+
(a per-machine shell/`.env` value; an external drive is the intended home). Without
|
|
68
|
+
it, library commands fail with a clear message instead of silently using `./data`.
|
|
69
|
+
|
|
70
|
+
**Install globally** (run `stabbur` from any directory):
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
uv tool install --editable ".[mlx,voice,web,benchmark]" # from a checkout: stabbur on your PATH, code edits live
|
|
74
|
+
uv tool install "git+https://github.com/winterop-com/stabbur" # or straight from git (requires repo access; core CLI)
|
|
75
|
+
# then put STABBUR_LIBRARY_ROOT in your shell profile (~/.zshrc) so it applies everywhere
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Only `uv sync` + llama.cpp are needed to run GGUF models; the rest are optional.
|
|
79
|
+
The `benchmark` extra adds the `stabbur benchmark` eval command; drop it if you don't need it.
|
|
80
|
+
See [getting started](docs/getting-started.md) for details.
|
|
81
|
+
|
|
82
|
+
stabbur is installed **from source** (`uv sync` / `uv tool install -e .`), not from PyPI. It builds
|
|
83
|
+
as a single self-contained wheel — the bundled first-party MCP servers are vendored into the `stabbur`
|
|
84
|
+
package (`src/stabbur/mcp_servers/*`) rather than published as separate packages — but stabbur is
|
|
85
|
+
proprietary/source-available and is not distributed on PyPI.
|
|
86
|
+
|
|
87
|
+
## CLI
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
stabbur library ls # your library (the models on your drive)
|
|
91
|
+
stabbur library sources # models in app caches (HF/Ollama/LM Studio) you could pull
|
|
92
|
+
stabbur library pull lmstudio lmstudio-community/gemma-4-12B-it-QAT-GGUF
|
|
93
|
+
stabbur library pull ollama gemma4:31b --move # copy to the library, then delete the local copy
|
|
94
|
+
stabbur doctor # pre-flight: runtimes, library, project
|
|
95
|
+
stabbur serve --ui # browse + chat in the browser (Chat · Voice · Library)
|
|
96
|
+
stabbur chat gemma-4-12B-it-QAT-GGUF -p "hi" # one-shot, scriptable
|
|
97
|
+
stabbur chat gemma-4-12B-it-QAT-GGUF -p "?" -i pic.jpg # image input (vision model)
|
|
98
|
+
stabbur voice ls # voice models (TTS/STT) in the library
|
|
99
|
+
stabbur voice import --all # import known voice models to the library
|
|
100
|
+
stabbur voice speak -v af_heart "hello there" # text-to-speech (Kokoro)
|
|
101
|
+
stabbur voice speak --model dia --seed 10 "hi there" # Dia (pin a seed for a stable voice)
|
|
102
|
+
stabbur project init # scaffold a project assistant (model + tools + prompt)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Two model families:** **Chat** (language models you talk to — text in/out; some
|
|
106
|
+
also read images/audio or call tools) and **Voice** (TTS speaks, STT transcribes).
|
|
107
|
+
stabbur detects each chat model's capabilities and runs the right runtime — GGUF via
|
|
108
|
+
llama.cpp (`llama-server`, `--mmproj` for vision/audio), MLX via `mlx_lm`/`mlx-vlm`.
|
|
109
|
+
The web UI's **Library** lists both families; the **Voice** studio does TTS/STT
|
|
110
|
+
(Kokoro, Dia with voice cloning, Whisper); in chat you can attach images/audio,
|
|
111
|
+
dictate with the mic (Whisper), and **read replies aloud** (Kokoro by default). See
|
|
112
|
+
the [voice guide](docs/guides/voice.md).
|
|
113
|
+
|
|
114
|
+
Full docs: **[`docs/`](docs/)** (run `make docs` to serve the site locally) —
|
|
115
|
+
getting started, the library, pulling, running & chatting, the web UI, the Chrome side panel,
|
|
116
|
+
the DHIS2 assistant, and the architecture.
|
|
117
|
+
|
|
118
|
+
## API
|
|
119
|
+
|
|
120
|
+
`stabbur serve` exposes an OpenAI-compatible surface plus browse/voice endpoints:
|
|
121
|
+
`/api/status`, `/api/library`, `/api/voice`, `/api/chat` (tool-aware SSE),
|
|
122
|
+
`/v1/*` (proxied to the loaded model), and `/v1/audio/speech` +
|
|
123
|
+
`/v1/audio/transcriptions`. See the [web UI guide](docs/guides/web-ui.md) for the
|
|
124
|
+
full endpoint table and the single-origin proxy design.
|
|
125
|
+
|
|
126
|
+
## Chrome side panel & the DHIS2 assistant
|
|
127
|
+
|
|
128
|
+
stabbur ships an **MV3 Chrome side panel** (`extension/`, built with WXT) — a thin client for
|
|
129
|
+
a local or remote `stabbur serve` that puts your own model + tools next to any page. It builds
|
|
130
|
+
in two flavors from one codebase: the generic **stabbur** panel and **stabbur for DHIS2**
|
|
131
|
+
(`STABBUR_FLAVOR=dhis2`).
|
|
132
|
+
|
|
133
|
+
Pointed at a DHIS2 project (`stabbur project new --template dhis2`), it becomes the north-star
|
|
134
|
+
assistant: chat grounded in the page you are viewing, a target banner (verify + tab
|
|
135
|
+
match/mismatch), and **"Use my login"** — mint a read-only, GET-scoped Personal Access Token
|
|
136
|
+
in the DHIS2 tab's own security context and hand it to stabbur once, so the tools act as *you*
|
|
137
|
+
(with a session-cookie fallback). Everything runs against your own local model; nothing
|
|
138
|
+
leaves the box.
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
cd extension && bun install && bun run build # -> extension/.output/chrome-mv3(-dhis2)
|
|
142
|
+
# chrome://extensions -> Load unpacked -> the built dir; then `stabbur serve` and open the panel
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
See the [Chrome side panel guide](docs/guides/extension.md) and
|
|
146
|
+
the [verified prompt catalog](docs/guides/extension-prompts.md).
|
|
147
|
+
|
|
148
|
+
## Configuration
|
|
149
|
+
|
|
150
|
+
Two separate concepts:
|
|
151
|
+
|
|
152
|
+
- **The library location** — where your models live. Set **`STABBUR_LIBRARY_ROOT`** (a
|
|
153
|
+
per-machine value; shell profile or `.env`). stabbur **requires** it — without one,
|
|
154
|
+
library/chat/serve commands fail with a clear message rather than silently using a
|
|
155
|
+
local folder. An external drive is the intended home:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
export STABBUR_LIBRARY_ROOT=/path/to/your/library # e.g. a mounted external drive
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- **A project** (`stabbur.toml`, via `stabbur project init` / `stabbur project new <dir>`) — a
|
|
162
|
+
purpose-built **assistant**: `[project].model` + `system_prompt`, with tools in a sibling
|
|
163
|
+
`.mcp.json` (standard `mcpServers`). In a project, `stabbur serve` / `stabbur chat` bind to that
|
|
164
|
+
model (like `--model`, with its tools + prompt); **outside** a project it's free-play
|
|
165
|
+
(pick/switch any model). A project uses the machine library by default.
|
|
166
|
+
|
|
167
|
+
Precedence (high → low): CLI flags, `STABBUR_*` env vars, `stabbur.toml`, `.env`,
|
|
168
|
+
`~/.config/stabbur/config.toml` (machine defaults).
|
|
169
|
+
|
|
170
|
+
| Key / env var | Purpose |
|
|
171
|
+
| --------------------------------------------- | ----------------------------------- |
|
|
172
|
+
| `STABBUR_LIBRARY_ROOT` (or `library_root`) | the library location (**required**) |
|
|
173
|
+
| `STABBUR_OLLAMA_MODELS_DIR`, `STABBUR_LMSTUDIO_MODELS_DIR` | source caches to pull from |
|
|
174
|
+
| `STABBUR_HF_TOKEN` | HF token (uses your HF login if unset) |
|
|
175
|
+
| `STABBUR_DEFAULT_MAX_TOKENS` (or `default_max_tokens`) | per-turn `/api/chat` generation cap (default 4096; `0` = unbounded) |
|
|
176
|
+
|
|
177
|
+
## Develop
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
make lint # ruff format + check, mypy, pyright (mutates)
|
|
181
|
+
make check # same, read-only (CI gate) + tests
|
|
182
|
+
make test # pytest
|
|
183
|
+
make build # uv build (wheel + sdist)
|
|
184
|
+
```
|