spawnllm 0.5.4__tar.gz → 0.5.5__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.
- spawnllm-0.5.5/PKG-INFO +129 -0
- spawnllm-0.5.5/README.md +82 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/pyproject.toml +2 -2
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/backends/codex.py +4 -1
- spawnllm-0.5.4/PKG-INFO +0 -174
- spawnllm-0.5.4/README.md +0 -127
- {spawnllm-0.5.4 → spawnllm-0.5.5}/LICENSE +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/__init__.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/__main__.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/backends/__init__.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/backends/base.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/backends/claude.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/backends/gemini.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/backends/mlx.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/backends/registry.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/call.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/cli.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/extract.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/mlx/__init__.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/mlx/codec.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/mlx/engine.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/mlx/fuse.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/mlx/patches.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/proc.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/py.typed +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/response.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/run.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/spec.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/structured.py +0 -0
- {spawnllm-0.5.4 → spawnllm-0.5.5}/spawnllm/types.py +0 -0
spawnllm-0.5.5/PKG-INFO
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spawnllm
|
|
3
|
+
Version: 0.5.5
|
|
4
|
+
Summary: Delete your subprocess wrappers around claude, codex, and gemini.
|
|
5
|
+
Keywords:
|
|
6
|
+
Author: Yasyf Mohamedali
|
|
7
|
+
Author-email: Yasyf Mohamedali <yasyfm@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Dist: click>=8
|
|
17
|
+
Requires-Dist: loguru>=0.7
|
|
18
|
+
Requires-Dist: pydantic>=2
|
|
19
|
+
Requires-Dist: openai>=2.43
|
|
20
|
+
Requires-Dist: anthropic>=0.111
|
|
21
|
+
Requires-Dist: zstandard>=0.25.0 ; extra == 'adapter'
|
|
22
|
+
Requires-Dist: numpy>=1.26 ; extra == 'adapter'
|
|
23
|
+
Requires-Dist: orjson>=3.10 ; extra == 'adapter'
|
|
24
|
+
Requires-Dist: anyio>=4 ; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8.0 ; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.8 ; extra == 'dev'
|
|
27
|
+
Requires-Dist: ty>=0.0.44 ; extra == 'dev'
|
|
28
|
+
Requires-Dist: zstandard>=0.25.0 ; extra == 'dev'
|
|
29
|
+
Requires-Dist: numpy>=1.26 ; extra == 'dev'
|
|
30
|
+
Requires-Dist: orjson>=3.10 ; extra == 'dev'
|
|
31
|
+
Requires-Dist: zstandard>=0.25.0 ; extra == 'mlx'
|
|
32
|
+
Requires-Dist: numpy>=1.26 ; extra == 'mlx'
|
|
33
|
+
Requires-Dist: orjson>=3.10 ; extra == 'mlx'
|
|
34
|
+
Requires-Dist: anyio>=4.4 ; extra == 'mlx'
|
|
35
|
+
Requires-Dist: huggingface-hub>=0.25 ; extra == 'mlx'
|
|
36
|
+
Requires-Dist: mlx-lm>=0.31.3 ; platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'mlx'
|
|
37
|
+
Requires-Python: >=3.13
|
|
38
|
+
Project-URL: Homepage, https://github.com/yasyf/spawnllm
|
|
39
|
+
Project-URL: Documentation, https://yasyf.github.io/spawnllm/
|
|
40
|
+
Project-URL: Repository, https://github.com/yasyf/spawnllm
|
|
41
|
+
Project-URL: Issues, https://github.com/yasyf/spawnllm/issues
|
|
42
|
+
Project-URL: Changelog, https://github.com/yasyf/spawnllm/blob/main/CHANGELOG.md
|
|
43
|
+
Provides-Extra: adapter
|
|
44
|
+
Provides-Extra: dev
|
|
45
|
+
Provides-Extra: mlx
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
|
|
48
|
+
# 
|
|
49
|
+
|
|
50
|
+
**Delete your subprocess wrappers around claude, codex, and gemini.** spawnllm subshells all three CLIs plus local MLX and returns one Pydantic-validated Response, so the per-model plumbing you hand-rolled goes away.
|
|
51
|
+
|
|
52
|
+
[](https://github.com/yasyf/spawnllm/actions/workflows/ci.yml)
|
|
53
|
+
[](https://pypi.org/project/spawnllm/)
|
|
54
|
+
[](https://github.com/yasyf/spawnllm/blob/main/LICENSE)
|
|
55
|
+
|
|
56
|
+
## Get started
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uvx spawnllm status
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
<img src="https://github.com/yasyf/spawnllm/raw/main/docs/assets/demo.png" alt="Terminal running 'uvx spawnllm status' — every backend reports ready and auto-selection picks claude" width="700">
|
|
63
|
+
|
|
64
|
+
Driving with an agent? Paste this:
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
Run `uv add spawnllm` in this project.
|
|
68
|
+
Replace our hand-rolled claude/codex subprocess code with spawnllm's `call_sync`,
|
|
69
|
+
or `extract_sync` with a Pydantic response model for structured output.
|
|
70
|
+
Verify available backends with `uvx spawnllm status`.
|
|
71
|
+
Docs: https://yasyf.github.io/spawnllm/
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Use cases
|
|
77
|
+
|
|
78
|
+
### Delete your hand-rolled claude/codex subprocess plumbing
|
|
79
|
+
|
|
80
|
+
Every small tool grows its own `subprocess.run(["claude", "-p", ...])` — argv quirks, stdin piping, exit-code guesswork — and each copy drifts. One call replaces all of it:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from spawnllm import call_sync
|
|
84
|
+
|
|
85
|
+
print(call_sync("Reply with just the word: pong"))
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Prints `pong`. With no `backend=`, spawnllm auto-selects the first installed, authenticated CLI, pipes the prompt over stdin, and retries transient 529/overloaded/rate-limit failures with capped backoff.
|
|
89
|
+
|
|
90
|
+
### Get a validated Pydantic object back, not a string to parse
|
|
91
|
+
|
|
92
|
+
Scraping JSON out of a model's stdout means regexes, code fences, and silent schema drift. `extract_sync` validates instead:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from pydantic import BaseModel
|
|
96
|
+
|
|
97
|
+
from spawnllm import extract_sync
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class Capital(BaseModel):
|
|
101
|
+
country: str
|
|
102
|
+
capital: str
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
result = extract_sync("What is the capital of France?", Capital)
|
|
106
|
+
print(result.capital) # Paris
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The backend turns `Capital` into a JSON-schema constraint on the call itself, and a non-conforming reply raises `pydantic.ValidationError` instead of sneaking downstream.
|
|
110
|
+
|
|
111
|
+
### Run Apple-Silicon MLX models with fused adapters and prompt-cache reuse
|
|
112
|
+
|
|
113
|
+
Shipping a LoRA-tuned local model means hand-rolling adapter fusion, model caching, and worker-thread lifecycle. The MLX extra owns all three:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
uv add "spawnllm[mlx]"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`AdapterFuser.ensure_fused` fuses your compressed adapter into the base model once and caches the result in the Hugging Face hub layout; `MlxEngine` loads it on a dedicated worker thread, precomputes a prompt cache for your shared prefix messages, and batches generation. Wrap the engine in an `MlxBackend` and the same `run_sync` call works.
|
|
120
|
+
|
|
121
|
+
## More in the docs
|
|
122
|
+
|
|
123
|
+
- **Spec-driven runs** — a literal model id, per-provider flag passthrough, and envelope-aware retry via `RunSpec` — [Running reference](https://yasyf.github.io/spawnllm/reference/#running)
|
|
124
|
+
- **Backend selection** — the priority chain, plus `specialty=` routing (`debugging` and `review` go to Codex, `general` to Claude) — [Backends reference](https://yasyf.github.io/spawnllm/reference/#backends)
|
|
125
|
+
- **Transport helpers** — `run_cli`, `collect_process`, and `map_concurrent`, the subprocess plumbing shared by every CLI backend — [Transport reference](https://yasyf.github.io/spawnllm/reference/#transport)
|
|
126
|
+
- **The CLI** — `spawnllm call`, `status`, and `backends` from any shell — [CLI reference](https://yasyf.github.io/spawnllm/reference/cli/)
|
|
127
|
+
- **MLX internals** — the adapter codec, fuser, and runtime patches behind the local engine — [MLX reference](https://yasyf.github.io/spawnllm/reference/#mlx)
|
|
128
|
+
|
|
129
|
+
Read the [docs](https://yasyf.github.io/spawnllm/) for the full guide and API reference. Licensed under [MIT](https://github.com/yasyf/spawnllm/blob/main/LICENSE).
|
spawnllm-0.5.5/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# 
|
|
2
|
+
|
|
3
|
+
**Delete your subprocess wrappers around claude, codex, and gemini.** spawnllm subshells all three CLIs plus local MLX and returns one Pydantic-validated Response, so the per-model plumbing you hand-rolled goes away.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/yasyf/spawnllm/actions/workflows/ci.yml)
|
|
6
|
+
[](https://pypi.org/project/spawnllm/)
|
|
7
|
+
[](https://github.com/yasyf/spawnllm/blob/main/LICENSE)
|
|
8
|
+
|
|
9
|
+
## Get started
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
uvx spawnllm status
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
<img src="https://github.com/yasyf/spawnllm/raw/main/docs/assets/demo.png" alt="Terminal running 'uvx spawnllm status' — every backend reports ready and auto-selection picks claude" width="700">
|
|
16
|
+
|
|
17
|
+
Driving with an agent? Paste this:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
Run `uv add spawnllm` in this project.
|
|
21
|
+
Replace our hand-rolled claude/codex subprocess code with spawnllm's `call_sync`,
|
|
22
|
+
or `extract_sync` with a Pydantic response model for structured output.
|
|
23
|
+
Verify available backends with `uvx spawnllm status`.
|
|
24
|
+
Docs: https://yasyf.github.io/spawnllm/
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Use cases
|
|
30
|
+
|
|
31
|
+
### Delete your hand-rolled claude/codex subprocess plumbing
|
|
32
|
+
|
|
33
|
+
Every small tool grows its own `subprocess.run(["claude", "-p", ...])` — argv quirks, stdin piping, exit-code guesswork — and each copy drifts. One call replaces all of it:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from spawnllm import call_sync
|
|
37
|
+
|
|
38
|
+
print(call_sync("Reply with just the word: pong"))
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Prints `pong`. With no `backend=`, spawnllm auto-selects the first installed, authenticated CLI, pipes the prompt over stdin, and retries transient 529/overloaded/rate-limit failures with capped backoff.
|
|
42
|
+
|
|
43
|
+
### Get a validated Pydantic object back, not a string to parse
|
|
44
|
+
|
|
45
|
+
Scraping JSON out of a model's stdout means regexes, code fences, and silent schema drift. `extract_sync` validates instead:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from pydantic import BaseModel
|
|
49
|
+
|
|
50
|
+
from spawnllm import extract_sync
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Capital(BaseModel):
|
|
54
|
+
country: str
|
|
55
|
+
capital: str
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
result = extract_sync("What is the capital of France?", Capital)
|
|
59
|
+
print(result.capital) # Paris
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The backend turns `Capital` into a JSON-schema constraint on the call itself, and a non-conforming reply raises `pydantic.ValidationError` instead of sneaking downstream.
|
|
63
|
+
|
|
64
|
+
### Run Apple-Silicon MLX models with fused adapters and prompt-cache reuse
|
|
65
|
+
|
|
66
|
+
Shipping a LoRA-tuned local model means hand-rolling adapter fusion, model caching, and worker-thread lifecycle. The MLX extra owns all three:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uv add "spawnllm[mlx]"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`AdapterFuser.ensure_fused` fuses your compressed adapter into the base model once and caches the result in the Hugging Face hub layout; `MlxEngine` loads it on a dedicated worker thread, precomputes a prompt cache for your shared prefix messages, and batches generation. Wrap the engine in an `MlxBackend` and the same `run_sync` call works.
|
|
73
|
+
|
|
74
|
+
## More in the docs
|
|
75
|
+
|
|
76
|
+
- **Spec-driven runs** — a literal model id, per-provider flag passthrough, and envelope-aware retry via `RunSpec` — [Running reference](https://yasyf.github.io/spawnllm/reference/#running)
|
|
77
|
+
- **Backend selection** — the priority chain, plus `specialty=` routing (`debugging` and `review` go to Codex, `general` to Claude) — [Backends reference](https://yasyf.github.io/spawnllm/reference/#backends)
|
|
78
|
+
- **Transport helpers** — `run_cli`, `collect_process`, and `map_concurrent`, the subprocess plumbing shared by every CLI backend — [Transport reference](https://yasyf.github.io/spawnllm/reference/#transport)
|
|
79
|
+
- **The CLI** — `spawnllm call`, `status`, and `backends` from any shell — [CLI reference](https://yasyf.github.io/spawnllm/reference/cli/)
|
|
80
|
+
- **MLX internals** — the adapter codec, fuser, and runtime patches behind the local engine — [MLX reference](https://yasyf.github.io/spawnllm/reference/#mlx)
|
|
81
|
+
|
|
82
|
+
Read the [docs](https://yasyf.github.io/spawnllm/) for the full guide and API reference. Licensed under [MIT](https://github.com/yasyf/spawnllm/blob/main/LICENSE).
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "spawnllm"
|
|
3
3
|
# Inert sentinel: the real version is set from the release tag (uv version --frozen).
|
|
4
|
-
version = "0.5.
|
|
5
|
-
description = "
|
|
4
|
+
version = "0.5.5"
|
|
5
|
+
description = "Delete your subprocess wrappers around claude, codex, and gemini."
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = "MIT"
|
|
8
8
|
license-files = ["LICENSE"]
|
|
@@ -23,7 +23,9 @@ class CodexCliBackend(CliBackend):
|
|
|
23
23
|
|
|
24
24
|
`build_command` translates a `RunSpec` into a `codex exec` argv that runs an
|
|
25
25
|
ephemeral session in a read-only sandbox; `invocation` resolves the schema to
|
|
26
|
-
a temp file and captures the final message to an `-o` file.
|
|
26
|
+
a temp file and captures the final message to an `-o` file. The argv carries
|
|
27
|
+
`--skip-git-repo-check` so a run in an untrusted or non-git `cwd` is not refused —
|
|
28
|
+
the sandbox already confines it, so the trust gate adds nothing here. An optional
|
|
27
29
|
`CodexConfig` overrides the sandbox and re-enables Codex hooks or MCP servers.
|
|
28
30
|
|
|
29
31
|
Attributes:
|
|
@@ -70,6 +72,7 @@ class CodexCliBackend(CliBackend):
|
|
|
70
72
|
"--ephemeral",
|
|
71
73
|
"--sandbox",
|
|
72
74
|
cfg.sandbox or "read-only",
|
|
75
|
+
"--skip-git-repo-check",
|
|
73
76
|
"--model",
|
|
74
77
|
model,
|
|
75
78
|
*(["-c", f"model_reasoning_effort={effort}"] if effort else []),
|
spawnllm-0.5.4/PKG-INFO
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: spawnllm
|
|
3
|
-
Version: 0.5.4
|
|
4
|
-
Summary: Subshell + MLX LLM-calling backends (Claude/Codex CLI, local MLX) shared across tools.
|
|
5
|
-
Keywords:
|
|
6
|
-
Author: Yasyf Mohamedali
|
|
7
|
-
Author-email: Yasyf Mohamedali <yasyfm@gmail.com>
|
|
8
|
-
License-Expression: MIT
|
|
9
|
-
License-File: LICENSE
|
|
10
|
-
Classifier: Development Status :: 3 - Alpha
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: Operating System :: OS Independent
|
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
-
Classifier: Typing :: Typed
|
|
16
|
-
Requires-Dist: click>=8
|
|
17
|
-
Requires-Dist: loguru>=0.7
|
|
18
|
-
Requires-Dist: pydantic>=2
|
|
19
|
-
Requires-Dist: openai>=2.43
|
|
20
|
-
Requires-Dist: anthropic>=0.111
|
|
21
|
-
Requires-Dist: zstandard>=0.25.0 ; extra == 'adapter'
|
|
22
|
-
Requires-Dist: numpy>=1.26 ; extra == 'adapter'
|
|
23
|
-
Requires-Dist: orjson>=3.10 ; extra == 'adapter'
|
|
24
|
-
Requires-Dist: anyio>=4 ; extra == 'dev'
|
|
25
|
-
Requires-Dist: pytest>=8.0 ; extra == 'dev'
|
|
26
|
-
Requires-Dist: ruff>=0.8 ; extra == 'dev'
|
|
27
|
-
Requires-Dist: ty>=0.0.44 ; extra == 'dev'
|
|
28
|
-
Requires-Dist: zstandard>=0.25.0 ; extra == 'dev'
|
|
29
|
-
Requires-Dist: numpy>=1.26 ; extra == 'dev'
|
|
30
|
-
Requires-Dist: orjson>=3.10 ; extra == 'dev'
|
|
31
|
-
Requires-Dist: zstandard>=0.25.0 ; extra == 'mlx'
|
|
32
|
-
Requires-Dist: numpy>=1.26 ; extra == 'mlx'
|
|
33
|
-
Requires-Dist: orjson>=3.10 ; extra == 'mlx'
|
|
34
|
-
Requires-Dist: anyio>=4.4 ; extra == 'mlx'
|
|
35
|
-
Requires-Dist: huggingface-hub>=0.25 ; extra == 'mlx'
|
|
36
|
-
Requires-Dist: mlx-lm>=0.31.3 ; platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'mlx'
|
|
37
|
-
Requires-Python: >=3.13
|
|
38
|
-
Project-URL: Homepage, https://github.com/yasyf/spawnllm
|
|
39
|
-
Project-URL: Documentation, https://yasyf.github.io/spawnllm/
|
|
40
|
-
Project-URL: Repository, https://github.com/yasyf/spawnllm
|
|
41
|
-
Project-URL: Issues, https://github.com/yasyf/spawnllm/issues
|
|
42
|
-
Project-URL: Changelog, https://github.com/yasyf/spawnllm/blob/main/CHANGELOG.md
|
|
43
|
-
Provides-Extra: adapter
|
|
44
|
-
Provides-Extra: dev
|
|
45
|
-
Provides-Extra: mlx
|
|
46
|
-
Description-Content-Type: text/markdown
|
|
47
|
-
|
|
48
|
-
# spawnllm
|
|
49
|
-
|
|
50
|
-

|
|
51
|
-
|
|
52
|
-
[](https://pypi.org/project/spawnllm/)
|
|
53
|
-
[](https://pypi.org/project/spawnllm/)
|
|
54
|
-
[](https://yasyf.github.io/spawnllm/)
|
|
55
|
-
[](https://github.com/yasyf/spawnllm/blob/main/LICENSE)
|
|
56
|
-
|
|
57
|
-
Subshell + MLX LLM-calling backends (Claude/Codex CLI, local MLX) shared across tools.
|
|
58
|
-
|
|
59
|
-
spawnllm centralizes the LLM-calling plumbing that small tools keep re-inventing: driving the
|
|
60
|
-
`claude` and `codex` CLIs as subshells — with structured Pydantic output, model tiers, and
|
|
61
|
-
faithful error capture — and running local Apple-Silicon MLX models with adapter fusion,
|
|
62
|
-
prompt-cache reuse, and batched generation. Depend on it once and each tool keeps only its
|
|
63
|
-
domain logic instead of its own copy of the backends.
|
|
64
|
-
|
|
65
|
-
## Install
|
|
66
|
-
|
|
67
|
-
Run the CLI with [uvx](https://docs.astral.sh/uv/):
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
uvx spawnllm --help
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
For the local MLX engine (Apple Silicon only), pull the extra: `uv add "spawnllm[mlx]"`.
|
|
74
|
-
|
|
75
|
-
## Quickstart
|
|
76
|
-
|
|
77
|
-
See which backends are installed and authenticated, and which one auto-selection picks:
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
uvx spawnllm status
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
claude: ready
|
|
85
|
-
codex: ready
|
|
86
|
-
selected: claude
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Make a request by passing a prompt as the argument, or piping it over stdin:
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
uvx spawnllm call --backend claude "What is 2+2? Reply with just the number."
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
4
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
`--model small|medium|large` swaps the tier, which each backend maps to a concrete model — the
|
|
100
|
-
`claude` backend resolves `small` to Haiku, `medium` to Sonnet, and `large` to Opus. Add
|
|
101
|
-
`--agent` to let the call use tools. Run `uvx spawnllm --help` for the full flag list.
|
|
102
|
-
|
|
103
|
-
### From Python
|
|
104
|
-
|
|
105
|
-
`call_sync` runs one request and returns the response. With no `backend`, it auto-selects
|
|
106
|
-
the first installed, authenticated CLI (its async companion `call` mirrors the same
|
|
107
|
-
signature):
|
|
108
|
-
|
|
109
|
-
```python
|
|
110
|
-
from spawnllm import call_sync
|
|
111
|
-
|
|
112
|
-
print(call_sync("Reply with just the word: pong"))
|
|
113
|
-
# pong
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Pin a backend and tier explicitly, or pass a Pydantic model to get a validated object back
|
|
117
|
-
instead of text:
|
|
118
|
-
|
|
119
|
-
```python
|
|
120
|
-
from pydantic import BaseModel
|
|
121
|
-
|
|
122
|
-
from spawnllm import call_sync, ClaudeCliBackend
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
class Capital(BaseModel):
|
|
126
|
-
country: str
|
|
127
|
-
capital: str
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
result = call_sync(
|
|
131
|
-
"What is the capital of France?",
|
|
132
|
-
backend=ClaudeCliBackend(),
|
|
133
|
-
model="large",
|
|
134
|
-
response_model=Capital,
|
|
135
|
-
)
|
|
136
|
-
print(result.capital) # Paris
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
When you don't pin a backend, set `specialty=` to scope auto-selection by task. The
|
|
140
|
-
`debugging` and `review` specialties route to Codex, and `general` routes to Claude.
|
|
141
|
-
|
|
142
|
-
### Spec-driven runs
|
|
143
|
-
|
|
144
|
-
For full control, build a `RunSpec` and execute it with `run_sync` (or its async companion
|
|
145
|
-
`run`). A `RunSpec` takes a literal provider model id — no tier mapping — and per-provider
|
|
146
|
-
flag passthrough via `provider_configs`. The call returns a `RunResult` with raw stdout,
|
|
147
|
-
stderr, and exit code, retrying transient `529`/overloaded/rate-limit failures with backoff:
|
|
148
|
-
|
|
149
|
-
```python
|
|
150
|
-
from spawnllm import run_sync, RunSpec, ClaudeConfig, ClaudeCliBackend
|
|
151
|
-
|
|
152
|
-
result = run_sync(
|
|
153
|
-
RunSpec(
|
|
154
|
-
prompt="What is 2+2? Reply with just the number.",
|
|
155
|
-
model="opus",
|
|
156
|
-
provider_configs={"claude": ClaudeConfig(permission_mode="bypassPermissions")},
|
|
157
|
-
),
|
|
158
|
-
backend=ClaudeCliBackend(),
|
|
159
|
-
)
|
|
160
|
-
print(result.stdout) # 4
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
## How it works
|
|
164
|
-
|
|
165
|
-
Each backend holds plumbing that consumers would otherwise rebuild: the CLI backends own argv
|
|
166
|
-
construction, stdin/stdout piping, stderr teeing, and turning non-zero exits into useful errors,
|
|
167
|
-
and they turn a Pydantic model into a JSON-schema constraint plus a parsed, validated result. The
|
|
168
|
-
MLX engine wraps adapter fusion, prompt-cache reuse, worker-thread lifecycle, and batched
|
|
169
|
-
single-token generation. Tools that share the layer stay byte-for-byte consistent instead of
|
|
170
|
-
drifting across diverging copies.
|
|
171
|
-
|
|
172
|
-
## Docs
|
|
173
|
-
|
|
174
|
-
[Read the docs](https://yasyf.github.io/spawnllm/) for the full guide and API reference.
|
spawnllm-0.5.4/README.md
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
# spawnllm
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-
|
|
5
|
-
[](https://pypi.org/project/spawnllm/)
|
|
6
|
-
[](https://pypi.org/project/spawnllm/)
|
|
7
|
-
[](https://yasyf.github.io/spawnllm/)
|
|
8
|
-
[](https://github.com/yasyf/spawnllm/blob/main/LICENSE)
|
|
9
|
-
|
|
10
|
-
Subshell + MLX LLM-calling backends (Claude/Codex CLI, local MLX) shared across tools.
|
|
11
|
-
|
|
12
|
-
spawnllm centralizes the LLM-calling plumbing that small tools keep re-inventing: driving the
|
|
13
|
-
`claude` and `codex` CLIs as subshells — with structured Pydantic output, model tiers, and
|
|
14
|
-
faithful error capture — and running local Apple-Silicon MLX models with adapter fusion,
|
|
15
|
-
prompt-cache reuse, and batched generation. Depend on it once and each tool keeps only its
|
|
16
|
-
domain logic instead of its own copy of the backends.
|
|
17
|
-
|
|
18
|
-
## Install
|
|
19
|
-
|
|
20
|
-
Run the CLI with [uvx](https://docs.astral.sh/uv/):
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
uvx spawnllm --help
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
For the local MLX engine (Apple Silicon only), pull the extra: `uv add "spawnllm[mlx]"`.
|
|
27
|
-
|
|
28
|
-
## Quickstart
|
|
29
|
-
|
|
30
|
-
See which backends are installed and authenticated, and which one auto-selection picks:
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
uvx spawnllm status
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
claude: ready
|
|
38
|
-
codex: ready
|
|
39
|
-
selected: claude
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Make a request by passing a prompt as the argument, or piping it over stdin:
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
uvx spawnllm call --backend claude "What is 2+2? Reply with just the number."
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
4
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
`--model small|medium|large` swaps the tier, which each backend maps to a concrete model — the
|
|
53
|
-
`claude` backend resolves `small` to Haiku, `medium` to Sonnet, and `large` to Opus. Add
|
|
54
|
-
`--agent` to let the call use tools. Run `uvx spawnllm --help` for the full flag list.
|
|
55
|
-
|
|
56
|
-
### From Python
|
|
57
|
-
|
|
58
|
-
`call_sync` runs one request and returns the response. With no `backend`, it auto-selects
|
|
59
|
-
the first installed, authenticated CLI (its async companion `call` mirrors the same
|
|
60
|
-
signature):
|
|
61
|
-
|
|
62
|
-
```python
|
|
63
|
-
from spawnllm import call_sync
|
|
64
|
-
|
|
65
|
-
print(call_sync("Reply with just the word: pong"))
|
|
66
|
-
# pong
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Pin a backend and tier explicitly, or pass a Pydantic model to get a validated object back
|
|
70
|
-
instead of text:
|
|
71
|
-
|
|
72
|
-
```python
|
|
73
|
-
from pydantic import BaseModel
|
|
74
|
-
|
|
75
|
-
from spawnllm import call_sync, ClaudeCliBackend
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
class Capital(BaseModel):
|
|
79
|
-
country: str
|
|
80
|
-
capital: str
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
result = call_sync(
|
|
84
|
-
"What is the capital of France?",
|
|
85
|
-
backend=ClaudeCliBackend(),
|
|
86
|
-
model="large",
|
|
87
|
-
response_model=Capital,
|
|
88
|
-
)
|
|
89
|
-
print(result.capital) # Paris
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
When you don't pin a backend, set `specialty=` to scope auto-selection by task. The
|
|
93
|
-
`debugging` and `review` specialties route to Codex, and `general` routes to Claude.
|
|
94
|
-
|
|
95
|
-
### Spec-driven runs
|
|
96
|
-
|
|
97
|
-
For full control, build a `RunSpec` and execute it with `run_sync` (or its async companion
|
|
98
|
-
`run`). A `RunSpec` takes a literal provider model id — no tier mapping — and per-provider
|
|
99
|
-
flag passthrough via `provider_configs`. The call returns a `RunResult` with raw stdout,
|
|
100
|
-
stderr, and exit code, retrying transient `529`/overloaded/rate-limit failures with backoff:
|
|
101
|
-
|
|
102
|
-
```python
|
|
103
|
-
from spawnllm import run_sync, RunSpec, ClaudeConfig, ClaudeCliBackend
|
|
104
|
-
|
|
105
|
-
result = run_sync(
|
|
106
|
-
RunSpec(
|
|
107
|
-
prompt="What is 2+2? Reply with just the number.",
|
|
108
|
-
model="opus",
|
|
109
|
-
provider_configs={"claude": ClaudeConfig(permission_mode="bypassPermissions")},
|
|
110
|
-
),
|
|
111
|
-
backend=ClaudeCliBackend(),
|
|
112
|
-
)
|
|
113
|
-
print(result.stdout) # 4
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## How it works
|
|
117
|
-
|
|
118
|
-
Each backend holds plumbing that consumers would otherwise rebuild: the CLI backends own argv
|
|
119
|
-
construction, stdin/stdout piping, stderr teeing, and turning non-zero exits into useful errors,
|
|
120
|
-
and they turn a Pydantic model into a JSON-schema constraint plus a parsed, validated result. The
|
|
121
|
-
MLX engine wraps adapter fusion, prompt-cache reuse, worker-thread lifecycle, and batched
|
|
122
|
-
single-token generation. Tools that share the layer stay byte-for-byte consistent instead of
|
|
123
|
-
drifting across diverging copies.
|
|
124
|
-
|
|
125
|
-
## Docs
|
|
126
|
-
|
|
127
|
-
[Read the docs](https://yasyf.github.io/spawnllm/) for the full guide and API reference.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|