ethicallama 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,346 @@
1
+ # AGENTS.md — ethicallama Project Memory
2
+
3
+ > This file captures architecture, patterns, decisions, and constraints discovered during development.
4
+ > Update this file whenever you learn something important that future coding agents should know.
5
+
6
+ ---
7
+
8
+ ## Project Overview
9
+
10
+ **ethicallama** — ethical, local-only inference wrapper for llama.cpp and other engines.
11
+
12
+ - **Rust core** (`ethllama-core/`): PyO3 bindings to llama.cpp FFI
13
+ - **Python CLI/API** (`ethllama/`): Click CLI + optional FastAPI (OpenAI-compatible)
14
+ - **Linux-first, no Windows, no telemetry by default**
15
+
16
+ ---
17
+
18
+ ## Directory Layout
19
+
20
+ ```
21
+ ethicallama/
22
+ ├── ethllama-core/ # Rust crate (cdylib, PyO3)
23
+ │ ├── Cargo.toml # Dependencies: pyo3, serde, libloading, anyhow, cmake (build-dep)
24
+ │ ├── build.rs # Compiles llama.cpp via cmake crate (requires submodule)
25
+ │ └── src/
26
+ │ ├── lib.rs # PyO3 #[pymodule]: exports PyLlamaModel class
27
+ │ ├── llama.rs # FFI declarations (extern "C") matching real llama.h API
28
+ │ └── utils.rs # GPU detection (nvidia-smi, rocm-smi, vulkaninfo)
29
+
30
+ ├── pyproject.toml # maturin build config + Python deps (repo root)
31
+ ├── ethllama/ # Python package
32
+ │ ├── __init__.py # Re-exports from submodules
33
+ │ ├── cli.py # Click CLI (11 subcommands: run, pull, list, index, config, serve, engines, quantize, rm, info, transcribe)
34
+ │ ├── cli_mgmt.py # Model management subcommands (rm, info)
35
+ │ ├── cli_stt.py # Speech-to-text subcommand (transcribe)
36
+ │ ├── api.py # FastAPI (OpenAI-compatible, opt-in)
37
+ │ ├── config.py # Config load/save/init (~/.ethllama/config.yaml)
38
+ │ ├── engines.py # EngineConfig with Jinja2 templating for custom engine binaries
39
+ │ ├── index.py # Model index (~/.ethllama/index.json), path resolution
40
+ │ ├── pull.py # Model pulling from HuggingFace Hub (optional)
41
+ │ ├── convert.py # Opt-in Safetensors → GGUF conversion
42
+ │ └── tests/
43
+ │ └── test_cli.py # 14 CLI tests (pytest)
44
+
45
+ ├── docs/
46
+ │ ├── CREDITS.md # Dependency credits (llama.cpp, PyO3, FastAPI, whisper.cpp)
47
+ │ ├── PRIVACY.md # No telemetry policy
48
+ │ ├── USAGE.md # Full CLI/API/config documentation
49
+ │ └── examples/ # Example engine YAML configs
50
+ │ ├── llama-cpp.yaml
51
+ │ ├── whisper-cpp.yaml
52
+ │ ├── custom-engine.yaml
53
+ │ └── README.md
54
+
55
+ ├── scripts/
56
+ │ ├── setup.sh # Prerequisites + build + install
57
+ │ └── benchmark.sh # Timed inference benchmarking
58
+
59
+ ├── flake.nix # Nix development shell
60
+ ├── README.md # Project documentation
61
+ └── AGENTS.md # This file
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Architecture & Data Flow
67
+
68
+ ```
69
+ User CLI (click) FastAPI (uvicorn)
70
+ | |
71
+ v v
72
+ ethllama Python package
73
+ | |
74
+ v v
75
+ EngineConfig (Jinja2) OR PyLlamaModel (Rust/PyO3)
76
+ | |
77
+ v v
78
+ Custom binary (e.g., llama-cli) llama.cpp C library
79
+ ```
80
+
81
+ ### Two Inference Paths
82
+
83
+ 1. **Native Rust path**: `PyLlamaModel` class via PyO3 → calls llama.cpp FFI directly
84
+ 2. **Engine binary path**: `EngineConfig.render_command()` → Jinja2 template → shell command to external binary
85
+
86
+ The `run` CLI command tries native first, falls back to engine binary if the model isn't loadable via Rust.
87
+
88
+ ---
89
+
90
+ ## Key Patterns & Conventions
91
+
92
+ ### Rust Core (`ethllama-core/src/`)
93
+
94
+ - **FFI declarations go in `llama.rs`** — all `extern "C"` blocks are consolidated here, NOT in `lib.rs`
95
+ - **`llama.rs`** defines: `LlamaModel` (opaque, `#[repr(C)]` with `_private: [u8; 0]`), `LlamaModelParams` (with `Default` impl), and all unsafe FFI wrappers
96
+ - **`lib.rs`** only does: `mod llama; mod utils;`, PyO3 `#[pymodule]`, and `#[pyclass]` wrappers
97
+ - **`utils.rs`** is for system introspection: GPU detection, file system queries, etc.
98
+ - **Memory safety**: `PyLlamaModel` has a `Drop` impl that calls `llama_free`, and `unsafe impl Send` for PyO3 thread safety
99
+ - **Build**: `cmake` crate is a **build-dependency** (in `[build-dependencies]` in Cargo.toml). The `build.rs` uses the `cmake` crate to build the full llama.cpp library tree, and panics with a clear message if `llama.cpp/` submodule is missing — it does NOT auto-clone during build. Additional build-deps: `cc` for compiling any C shim sources if needed.
100
+
101
+ ### Rust Core (`ethllama-core/src/`) — Current State
102
+
103
+ - **`build.rs`** uses the `cmake` crate to build llama.cpp as a static library (replaced the old `cc`-based approach that only compiled a subset of source files)
104
+ - **`llama.rs`** contains complete FFI bindings matching the real `llama.h` API:
105
+ - 4 opaque types (`llama_model`, `llama_context`, `llama_vocab`, `llama_sampler`)
106
+ - 6 struct types with exact `#[repr(C)]` layouts: `llama_model_params`, `llama_context_params` (~35 fields), `llama_batch`, `llama_sampler_chain_params`, `llama_token_data`, `llama_token_data_array`
107
+ - 30+ `extern "C"` function declarations covering model loading, context creation, tokenization, decoding, and the backend sampling API
108
+ - Safe helper functions: `load_model()`, `tokenize()`, `detokenize()`, `infer_tokens()`
109
+ - **`lib.rs`** `PyLlamaModel` implements real inference:
110
+ - Constructor: calls `llama_backend_init()`, loads model via `llama_model_load_from_file()`, creates context via `llama_init_from_model()`
111
+ - `infer()` method: tokenizes prompt, runs `llama_decode()` for prefill, builds a sampler chain (greedy or temp+top_p+top_k+dist), loops token-by-token with `llama_sampler_sample()` and `llama_decode()`, detokenizes output
112
+ - `Drop`: frees context, model, and calls `llama_backend_free()`
113
+ - **Linking**: 4 static libraries — `libllama.a`, `libggml.a`, `libggml-cpu.a`, `libggml-base.a` — plus pthread, dl, stdc++
114
+ - **`llama_backend_init/llama_backend_free`** are called per-instance (not global); fine for typical single-model usage
115
+
116
+ ### Known Rust Core Limitations
117
+ - `llama_backend_free()` is called once per `PyLlamaModel::drop()`. If multiple models are created in the same Python process, the backend will be freed after the first model is destroyed. For multi-model workflows, a global reference-counted backend init/free should be implemented.
118
+ - The `llama_context_params` struct alignment depends on repr(C) matching the C compiler's layout. Verified on x86_64 Linux with GCC 16.
119
+
120
+ ### Python Package (`ethllama/`)
121
+
122
+ - **CLI**: click-based, single `@click.group()` entry point in `cli.py`, 8 subcommands (`run`, `pull`, `list`, `index`, `config`, `serve`, `engines`, `quantize`)
123
+ - **Config**: YAML at `~/.ethllama/config.yaml`, loaded via `config.load_config()`, defaults in `DEFAULT_CONFIG` dict
124
+ - **Engine configs**: YAML at `~/.ethllama/engines/*.yaml`, parsed by `EngineConfig` class with Jinja2 templating
125
+ - **Model index**: JSON at `~/.ethllama/index.json`, manages symlinks/hardlinks for storage efficiency
126
+ - **API**: FastAPI is **opt-in only** (extra dependency group `ethllama[api]`). Endpoints: `/v1/chat/completions`, `/v1/completions`, `/v1/models`, `/v1/embeddings`
127
+ - **Pulling**: HuggingFace Hub (`ethllama[pull]`) and Ollama registry (built-in, `requests`-based, no auth needed for public models). Ollama's `application/vnd.ollama.image.model` blob **IS a complete GGUF file** — no conversion needed.
128
+ - **Conversion**: torch+transformers is optional (`ethllama[convert]`)
129
+ - **Quantize**: `ethllama quantize <model>` command built-in (uses llama.cpp's `llama-quantize` binary, 11 quantization types supported, default q4_k_m)
130
+
131
+ ### Jinja2 Template Variables (for engine configs)
132
+
133
+ Available variables in `args_template`:
134
+ - `{{ binary }}` — engine binary path
135
+ - `{{ model_path }}` — model file path
136
+ - `{{ prompt }}` — input prompt
137
+ - `{{ temperature }}`, `{{ top_p }}`, `{{ top_k }}` — sampling params
138
+ - `{{ threads }}` — CPU threads
139
+ - `{{ n_gpu_layers }}` — GPU offload layers
140
+ - `{{ gpu_backend }}` — selected GPU backend
141
+ - `{{ output }}` — output file path
142
+
143
+ ### Engine Config YAML Schema
144
+
145
+ ```yaml
146
+ name: engine-name # Unique identifier
147
+ type: text|stt|tts|image # Engine type
148
+ binary: /path/to/binary # Executable path
149
+ args_template: "..." # Jinja2 template for CLI args
150
+ env: # Environment variables (optional)
151
+ KEY: value
152
+ pre_check: "..." # Shell command to verify engine (optional)
153
+ supports_streaming: true|false # Streaming support flag (optional)
154
+ model_extensions: # Supported file extensions (optional)
155
+ - .gguf
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Constraints & Decisions
161
+
162
+ ### Inviolable Rules
163
+
164
+ 1. **No Windows support** — reject any Windows-specific code
165
+ 2. **No telemetry by default** — telemetry requires explicit `telemetry.enabled: true` in config. The `config.py` init flow warns users before enabling.
166
+ 3. **No model duplication** — use symlinks/hardlinks for storage efficiency via model index
167
+ 4. **GPU backend choice** — user-selected (Vulkan/ROCm/CUDA/CPU), auto-detected as priority fallback
168
+ 5. **LLM inference is local-only** — no cloud inference calls, no API calls to external model providers
169
+
170
+ ### Build Dependencies
171
+
172
+ - `llama.cpp` is a **git submodule** at `ethllama-core/llama.cpp/`
173
+ - Must run `git submodule update --init --recursive` before building
174
+ - Build script (`build.rs`) uses `cmake` crate to build the full llama.cpp library tree
175
+ - Use `cargo build --release -p ethllama-core` for the Rust crate
176
+ - Use `maturin develop` or `pip install -e .` for the Python package
177
+
178
+ ### Development Setup with `uv`
179
+
180
+ `uv` is the recommended Python runtime/venv manager for this project. It works seamlessly with PyO3/maturin:
181
+
182
+ ```bash
183
+ # Create a virtual environment
184
+ uv venv
185
+
186
+ # Activate it (or use `uv run` for one-off commands)
187
+ source .venv/bin/activate
188
+
189
+ # Install maturin + all deps
190
+ uv pip install maturin ".[all]"
191
+
192
+ # Build the Rust crate and install Python package in one step
193
+ maturin develop
194
+
195
+ # Or equivalently, for production-style wheel:
196
+ uv pip install -e ".[all]"
197
+ ```
198
+
199
+ **Why uv works with PyO3**: `maturin develop` discovers the active Python interpreter from the venv. `uv`'s venvs are standard virtual environments — maturin sees them the same as any other venv. No special configuration needed.
200
+
201
+ Key commands during development:
202
+ - `uv run ethllama --help` — run CLI without activating venv
203
+ - `uv run pytest ethllama/tests/ -v` — run tests
204
+ - `uv pip install -e ".[all]"` — reinstall after Python-only changes
205
+ - `maturin develop --release` — rebuild Rust core
206
+
207
+ ### Ollama Registry Protocol
208
+
209
+ When implementing or modifying `pull_from_ollama()`:
210
+ - **The model blob IS a GGUF file** — `application/vnd.ollama.image.model` contains the raw GGUF bytes, no conversion needed. Verify with magic bytes `b"GGUF"` (0x46554747 LE) on download.
211
+ - **OCI Distribution Spec v2** — uses `/v2/<namespace>/<repo>/manifests/<tag>` for manifest and `/v2/<namespace>/<repo>/blobs/sha256:<digest>` for blobs.
212
+ - **No auth needed** for public models on `registry.ollama.ai`.
213
+ - **Accept header required** — must set `Accept: application/vnd.docker.distribution.manifest.v2+json` on manifest GET.
214
+ - **Hostname detection** in `_parse_model_ref`: dots in the first path component distinguish hostnames (e.g., `registry.ollama.ai/library/foo`) from namespaces (`foo/bar`).
215
+ - **Content-Type bug**: manifest returns `Content-Type: text/plain; charset=utf-8` (known Ollama issue), parse body as JSON regardless.
216
+ - **307 redirect**: blob GETs redirect to Cloudflare R2 (`*.r2.cloudflarestorage.com`). Standard `requests` follows it automatically.
217
+ - **Resumable downloads**: use `.partial` temp files with `Range` headers for resume. Verify SHA-256 after completion.
218
+ - Existing reference implementations: `iven86/ollama_gguf_downloader`, `olamide226/ollama-gguf-downloader`, `leeroopedia/workflow-ollama-ollama-model-registry-operations`.
219
+
220
+ ### Quantize Command
221
+
222
+ The `ethllama quantize <model>` command:
223
+ - Accepts `--type` (11 quantization types, default `q4_k_m`) and `--binary` (auto-detected from llama.cpp build dirs or PATH via `shutil.which()`)
224
+ - Resolves model from index, auto-generates output path (`<model>-<type>.gguf`)
225
+ - Runs `llama-quantize` via subprocess with progress logging
226
+
227
+ ### Embeddings Endpoint
228
+
229
+ The `/v1/embeddings` endpoint in `api.py`:
230
+ - Accepts `EmbeddingRequest` model with `input` (str or list) and `model` fields
231
+ - Returns deterministic pseudo-embeddings (fixed 768-dim vector) for now. When the Rust core is wired to the API, replace with real embeddings from llama.cpp.
232
+
233
+ ### Python Dependencies
234
+
235
+ - **Required**: click, pyyaml, jinja2, tqdm, requests
236
+ - **Optional (api)**: fastapi, uvicorn, pydantic
237
+ - **Optional (pull)**: huggingface_hub
238
+ - **Optional (convert)**: torch, transformers
239
+
240
+ ---
241
+
242
+ ## Testing
243
+
244
+ - Python tests: `pytest ethllama/tests/ -v` (14 CLI tests, covering basic CLI, pull, quantize, ollama pull)
245
+ - Rust tests: None yet (no test harness for FFI crate)
246
+ - Test the CLI via `click.testing.CliRunner` (already in test_cli.py)
247
+
248
+ ---
249
+
250
+ ## Project Skills
251
+
252
+ **Before every non-trivial implementation task, check `.agents/skills/` for a matching skill and load it with the `skill` tool.** Skills contain the exact workflow, code patterns, and reference files for recurring operations — loading them saves time and prevents mistakes.
253
+
254
+ | Skill | Load when... |
255
+ |-------|-------------|
256
+ | `rust-ffi-bind` | Adding new llama.cpp C API functions through Rust FFI → PyO3 (three-layer pattern: extern "C" → safe wrapper → pyclass) |
257
+ | `ollama-registry-pull` | Working with Ollama's OCI registry (pull, protocol quirks, SHA-256 verification, Content-Type bug, 307 redirects) |
258
+
259
+ If you encounter a new recurring workflow during development, write it as a skill in `.agents/skills/<name>/SKILL.md` so future agent sessions can reuse the pattern.
260
+
261
+ **Skills are living documents.** When executing a skill's workflow (or any undocumented workflow that should have had a matching skill), if you discover a new fact, edge case, gotcha, or improvement — update the `SKILL.md` to capture it. Skills degrade fast if they omit critical quirks; the first execution always finds something the skill author missed. If you found yourself doing a structured multi-step workflow that has no skill yet, write one. Future agents (and you) will benefit more from a rough-but-honest skill than from none.
262
+
263
+ ## Nix Development
264
+
265
+ The project ships a `flake.nix` that provides a reproducible dev shell with
266
+ the full Rust + Python + llama.cpp build chain pre-installed. Use it if you
267
+ are on NixOS or have the Nix package manager installed.
268
+
269
+ ### What the dev shell provides
270
+
271
+ - **Rust toolchain** (latest stable via `rust-overlay`) - `cargo`, `rustc`,
272
+ `clippy`, `rustfmt`, `rust-analyzer`
273
+ - **Python 3** + `maturin` + `pip` on `PATH` (so `pip install -e .` also works
274
+ without a separate venv install)
275
+ - **Native build deps** - `cmake`, `ninja`, `pkg-config`, `openssl`, `git`
276
+ - **C/C++ compilers** - `gcc` and `clang` (the `cc` and `cmake` crates pick
277
+ whichever is first on `PATH`)
278
+ - **Optional GPU** - `vulkan-headers`, `vulkan-loader` (only used when
279
+ building the standalone `llama.cpp` binaries with `-DLLAMA_VULKAN=ON`; the
280
+ bundled `ethllama-core` is CPU-only)
281
+ - **`PKG_CONFIG_PATH`** set so pkg-config consumers can find `openssl`
282
+
283
+ ### Entering the shell
284
+
285
+ ```bash
286
+ nix develop # default shell with everything
287
+ # or
288
+ nix develop .#default # same thing, explicit
289
+ ```
290
+
291
+ ### shellHook behavior
292
+
293
+ - If `.gitmodules` exists but the `ethllama-core/llama.cpp/common` directory
294
+ is missing, runs `git submodule update --init --recursive` automatically.
295
+ - Prints a banner with versions of all key tools.
296
+ - Prints a quickstart reminder (uv workflow + standalone llama.cpp build).
297
+
298
+ ### Quickstart (from inside the dev shell)
299
+
300
+ ```bash
301
+ uv venv
302
+ source .venv/bin/activate
303
+ uv pip install maturin '.[all]'
304
+ maturin develop --release
305
+ pytest ethllama/tests/ -v
306
+ ```
307
+
308
+ ### Formatter
309
+
310
+ The flake exposes `nixfmt-rfc-style` as the default formatter. Run
311
+ `nix fmt` to reformat the flake in place.
312
+
313
+ ### Adding new tools
314
+
315
+ When you discover a new build/runtime dependency that the shell is missing,
316
+ add it to the `buildInputs` list in `devShells.default`. Keep the comments
317
+ grouped by purpose (Rust / Python / native / compilers / GPU) so the list
318
+ stays readable as it grows.
319
+
320
+ ## Cross-Session Context Tips
321
+
322
+ - The `engines.py` `EngineConfig` class with Jinja2 templating is the **extension mechanism** for custom engines — this is the plugin system
323
+ - When adding new subcommands, add them to `cli.py`'s `@click.group()` and re-export from `__init__.py`
324
+ - When extending the Rust FFI, always add the `extern "C"` declaration to `llama.rs`, then wrap it in a safe function, then expose via PyO3 in `lib.rs`
325
+ - The `__all__` in `__init__.py` must be kept in sync with exports
326
+ - `pyproject.toml` at repo root uses maturin, and the `[tool.maturin]` section configures how the Rust crate is built (manifest-path points to `ethllama-core/Cargo.toml`)
327
+ - Always use `options = ["pyo3/extension-module"]` in `[features]` (no "pyo3" prefix for maturin — just the feature name)
328
+ - Run `pip install -e ".[all]"` to install all optional dependencies for development
329
+
330
+ ## Future Roadmap (from initial Mistral Vibe discussion)
331
+
332
+ These features were discussed and are planned for post-MVP phases:
333
+
334
+ ### Modality Expansion (Phase 2+)
335
+ - **whisper.cpp** — STT/TTS engine via `EngineConfig` (example YAML already in `docs/examples/whisper-cpp.yaml`)
336
+ - **stable-diffusion.cpp** — image generation (add as engine type `image`)
337
+ - General pattern: new backends = create `/path/to/engine.cpp` → write engine YAML → done
338
+
339
+ ### Multi-GPU Support
340
+ - Not yet implemented in the Rust core or CLI
341
+ - Important for larger models on multi-GPU workstations
342
+
343
+ ### Async Support
344
+ - Rust core could support async via `tokio` for concurrent inference
345
+ - Python side could use `asyncio` for non-blocking API endpoints
346
+ - Not yet implemented
@@ -0,0 +1,104 @@
1
+ # Changelog
2
+
3
+ All notable changes to **ethicallama** are documented in this file.
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+ - GitHub Actions CI workflow (`.github/workflows/ci.yml`) testing
11
+ Python 3.10 – 3.13 on `ubuntu-latest` (Rust + Python, with rustfmt/clippy lint job).
12
+ - GitHub Actions release workflow (`.github/workflows/release.yml`) that builds
13
+ manylinux + musllinux + macOS wheels via cibuildwheel, produces an sdist,
14
+ attaches everything to a GitHub Release, and publishes to PyPI using
15
+ **OIDC trusted publishing** (no API token in secrets).
16
+ - `[project.scripts]` entry exposing the `ethllama` CLI on `pip install`.
17
+ - `[project.urls]` block with Homepage / Repository / Issues / Changelog links.
18
+ - `[tool.cibuildwheel]` configuration in `pyproject.toml` (build matrix,
19
+ `MATH_BACKEND=openblas` for manylinux, pinned `pytest` test-requires).
20
+ - `[tool.pytest.ini_options]` section (`testpaths`, `asyncio_mode = "auto"`).
21
+ - PyPI / CI / License / Python-version badges at the top of `README.md`.
22
+ - `MANIFEST.in` controlling sdist contents (excludes `ethllama-core/target`,
23
+ `llama.cpp-build`, the bundled `ethllama-core/llama.cpp` submodule,
24
+ `.slim`, and `.benchmarks`).
25
+
26
+ ### Changed
27
+ - `pyproject.toml` moved from `ethllama/pyproject.toml` to the repository root
28
+ (the standard maturin layout). All `[tool.maturin]` paths were already
29
+ written relative to the project root, so no path edits were needed.
30
+ - `requires-python` bumped from `>=3.9` to `>=3.10` to match the CI matrix
31
+ and the README's stated prerequisites.
32
+
33
+ ## [0.1.0] - 2026-07-03
34
+
35
+ ### Added
36
+ - **CLI** (`ethllama.cli`) — 11 subcommands built on Click:
37
+ - `run` — run inference against a local GGUF model
38
+ - `pull` — pull a model from HuggingFace Hub
39
+ - `list` — list indexed models
40
+ - `index` — add / remove / list models in the local model index
41
+ - `config` — load, save, and initialise `~/.ethllama/config.yaml`
42
+ - `serve` — start the local FastAPI server
43
+ - `engines` — list and inspect configured engines
44
+ - `quantize` — quantise a GGUF model via `llama-quantize`
45
+ - `transcribe` — speech-to-text via a whisper.cpp engine
46
+ - `info` — show GGUF model metadata
47
+ - `rm` — remove a model from the index
48
+ - **FastAPI server** (`ethllama.api`) — opt-in OpenAI-compatible endpoints:
49
+ - `POST /v1/chat/completions`
50
+ - `POST /v1/completions`
51
+ - `POST /v1/embeddings`
52
+ - `GET /v1/models`
53
+ - `GET /health`
54
+ Supports optional bearer-token auth, streaming responses, and is gated
55
+ behind the `ethllama[api]` extra.
56
+ - **Real inference** — `ethllama.inference` shells out to `llama-cli` /
57
+ `llama-embedding` binaries when the Rust core is unavailable, so the
58
+ package works out-of-the-box for any user with a llama.cpp checkout.
59
+ - **Rust FFI core** (`ethllama-core/`) — PyO3 bindings to llama.cpp
60
+ covering model loading, context creation, tokenisation, and a full
61
+ sampler chain (greedy / temperature / top-p / top-k / dist).
62
+ - **Model pulling**:
63
+ - HuggingFace Hub backend (`ethllama[pull]`, `huggingface_hub`)
64
+ - Ollama registry backend (built-in, OCI Distribution Spec v2, no auth
65
+ required for public models on `registry.ollama.ai`; the
66
+ `application/vnd.ollama.image.model` blob is the raw GGUF, no
67
+ conversion needed).
68
+ - **Model quantisation** — built-in `ethllama quantize` command calling
69
+ `llama-quantize` (11 quant types, default `q4_k_m`).
70
+ - **Embeddings endpoint** — `POST /v1/embeddings` returning deterministic
71
+ 768-dim vectors (stub until the Rust core exposes a real embedding API).
72
+ - **GPU selection flags** — `--gpu {vulkan,rocm,cuda,cpu}` and
73
+ `--gpu-layers <N>` on the `run` command; auto-detection order
74
+ Vulkan → ROCm → CUDA → CPU.
75
+ - **Async API** — FastAPI endpoints are async; the API layer exposes
76
+ `async def` handlers and uses `uvicorn[standard]`.
77
+ - **Pluggable engine system** — `ethllama.engines.EngineConfig` loads
78
+ YAML files from `~/.ethllama/engines/` and renders CLI invocations via
79
+ Jinja2 templates; ships with examples for `llama-cpp`, `whisper-cpp`,
80
+ and a generic custom engine.
81
+ - **Engine YAML examples** in `docs/examples/` (`llama-cpp.yaml`,
82
+ `whisper-cpp.yaml`, `custom-engine.yaml`).
83
+ - **Nix development shell** (`flake.nix`) — reproducible dev environment
84
+ with Rust toolchain, Python 3, maturin, cmake/ninja, openssl, and
85
+ Vulkan headers pre-installed; auto-initialises the `llama.cpp`
86
+ submodule on first entry.
87
+ - **Documentation** — `README.md`, `docs/USAGE.md`, `docs/PRIVACY.md`,
88
+ `docs/CREDITS.md`, `AGENTS.md` (project memory for coding agents).
89
+ - **Python test suite** — 76 tests across `test_cli.py`, `test_api.py`,
90
+ `test_stt.py`, covering the CLI surface, the FastAPI server, the
91
+ whisper.cpp STT path, the model index, and the engine registry.
92
+ - **Setup / benchmark scripts** — `scripts/setup.sh` and
93
+ `scripts/benchmark.sh` for one-command environment bring-up and
94
+ timed inference benchmarking.
95
+
96
+ ### Notes
97
+ - This is the first public release of **ethicallama**.
98
+ - Inference runs **fully locally**. The only network calls the package
99
+ makes are to HuggingFace / Ollama when you explicitly invoke `pull`.
100
+ - Telemetry is **off by default**; the only outbound traffic is model
101
+ pulls, and they are user-initiated.
102
+
103
+ [Unreleased]: https://github.com/your-org/ethicallama/compare/v0.1.0...HEAD
104
+ [0.1.0]: https://github.com/your-org/ethicallama/releases/tag/v0.1.0
@@ -0,0 +1,16 @@
1
+ # Credits
2
+
3
+ ethicallama is built on the following open-source projects:
4
+
5
+ - **[llama.cpp](https://github.com/ggerganov/llama.cpp)** (MIT License)
6
+ - Used for GGUF model loading and inference.
7
+ - Original work by Georgi Gerganov.
8
+
9
+ - **[whisper.cpp](https://github.com/ggerganov/whisper.cpp)** (MIT License)
10
+ - Used for speech-to-text and text-to-speech (future).
11
+
12
+ - **[PyO3](https://github.com/PyO3/pyo3)** (Apache 2.0/MIT)
13
+ - Used for Rust-Python bindings.
14
+
15
+ - **[FastAPI](https://github.com/tiangolo/fastapi)** (MIT License)
16
+ - Used for the HTTP API.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 luluthehungrycat
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.