@spatz/cli 0.1.0 → 0.1.1
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.
- package/README.md +176 -152
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,227 +1,251 @@
|
|
|
1
1
|
# spatz
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Choose a model and effort for your coding task. Learn from the result.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://github.com/lorenzh/spatz/releases/latest)
|
|
7
|
+
[](https://bun.sh)
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
Do not use a cannon to shoot sparrows.
|
|
8
10
|
|
|
9
|
-
spatz
|
|
11
|
+
spatz ranks the model and effort pairs that you can use for a coding task.
|
|
12
|
+
It learns from task results to help choose cheaper pairs that succeed.
|
|
13
|
+
You or your coding agent run the task with the recommended pair.
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
[Quickstart](#quickstart) · [Documentation](#documentation) · [Contributing](#contributing) · [Releases](https://github.com/lorenzh/spatz/releases)
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
- Task classification with Jev, or with local keyword rules when Jev is off.
|
|
15
|
-
- Learning from Claude Code and Codex CLI hooks, and from `spatz report`.
|
|
16
|
-
- Statistics per task type with `spatz stats`.
|
|
17
|
+
## Why spatz?
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
Different tasks need different models and effort levels.
|
|
20
|
+
spatz combines task classification with results from your previous tasks.
|
|
19
21
|
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
+
- **Use your available models.** Pass the candidates with `--models`.
|
|
23
|
+
- **Learn from results.** Record outcomes through hooks or `spatz report`.
|
|
24
|
+
- **Compare performance.** Use `spatz stats` to see results per task type or routing scope.
|
|
25
|
+
- **Connect to coding agents.** Hooks support Claude Code and Codex CLI. Other agents can use the CLI directly.
|
|
26
|
+
- **Keep learning data local.** spatz stores results in `~/.spatz/spatz.db`. It does not store task text.
|
|
22
27
|
|
|
23
|
-
##
|
|
28
|
+
## Quickstart
|
|
29
|
+
|
|
30
|
+
### 1. Install
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
F -->|no secret, Jev on| J[Jev classification]
|
|
31
|
-
F -->|secret found, Jev off or no key| K[Keyword rules]
|
|
32
|
-
J -->|Jev error| K
|
|
33
|
-
J --> E[Learned estimates]
|
|
34
|
-
K --> E
|
|
35
|
-
E --> R[Ranking of --models candidates]
|
|
36
|
-
R --> U[You or your agent pick a pair]
|
|
37
|
-
U --> H[Claude Code or Codex hooks]
|
|
38
|
-
U --> S[spatz report]
|
|
39
|
-
H --> O[(Outcomes in ~/.spatz/spatz.db)]
|
|
40
|
-
S --> O
|
|
41
|
-
O --> E
|
|
32
|
+
Install the stable CLI with Node.js 18 or newer:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install -g @spatz/cli
|
|
36
|
+
spatz --version
|
|
42
37
|
```
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
The npm package includes the Bun runtime. Keep optional dependencies enabled.
|
|
40
|
+
Linux needs glibc. spatz does not support Alpine Linux.
|
|
41
|
+
Windows x64 support is experimental. Some releases omit it.
|
|
45
42
|
|
|
46
|
-
|
|
43
|
+
For installation without Node.js, use a [release archive](#releases).
|
|
44
|
+
For the unstable nightly version, use `npm install -g @spatz/cli@nightly`.
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
- Bun 1.4 for development or installation from source. Release archives include the runtime.
|
|
50
|
-
- Optional: a TypeSafe AI API key for Jev classification. Jev is in early access.
|
|
46
|
+
### 2. Ask for a recommendation
|
|
51
47
|
|
|
52
|
-
|
|
48
|
+
Pass the task and the model pairs that your agent can run:
|
|
53
49
|
|
|
54
|
-
|
|
50
|
+
```bash
|
|
51
|
+
spatz "Fix the off-by-one error in src/list.ts" \
|
|
52
|
+
--models claude-opus-5-5:high+medium,claude-sonnet-5-5:medium+low
|
|
53
|
+
```
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
Each candidate uses `<model-id>:<effort>+<effort>...`.
|
|
56
|
+
Use model IDs and efforts that your environment supports.
|
|
57
|
+
The output includes a `suggestion_id` and a ranked list of pairs.
|
|
58
|
+
Add `--json` for machine-readable output.
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
spatz works without an API key.
|
|
61
|
+
Without Jev or learned results, it recommends the most expensive candidate.
|
|
62
|
+
Jev is the TypeSafe AI model that classifies the task and estimates candidate suitability.
|
|
63
|
+
To enable Jev, set your TypeSafe AI key:
|
|
61
64
|
|
|
62
65
|
```bash
|
|
63
|
-
|
|
64
|
-
archive="spatz-cli-$version-linux-x64.tar.gz"
|
|
65
|
-
sha256sum --check "$archive.sha256"
|
|
66
|
+
export TYPESAFE_AI_API_KEY="<your-key>"
|
|
66
67
|
```
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
When you enable Jev, spatz sends task text and candidate details to TypeSafe AI.
|
|
70
|
+
Read [Privacy](#privacy) before using sensitive task text.
|
|
71
|
+
|
|
72
|
+
### 3. Run the task and report the result
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
Run the task with the chosen model and effort in your coding agent.
|
|
75
|
+
Then report the pair you actually used:
|
|
73
76
|
|
|
74
77
|
```bash
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
spatz --version
|
|
78
|
+
spatz report <suggestion_id> \
|
|
79
|
+
--model claude-sonnet-5-5 --effort medium --result pass
|
|
80
|
+
|
|
81
|
+
spatz stats
|
|
80
82
|
```
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
The Windows archive contains `spatz.exe` and the DuckDB Windows binding and DLL beside it.
|
|
86
|
-
On first use, it downloads DuckDB's SQLite extension into `~/.spatz/duckdb-extensions`.
|
|
87
|
-
Later runs can use that extension offline.
|
|
84
|
+
Replace `<suggestion_id>` with the ID from the recommendation.
|
|
85
|
+
Results can be `pass`, `partial`, or `fail`.
|
|
86
|
+
An explicit report overrides hook signals for that recommendation.
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
You can also start a manual workflow run with `force` enabled.
|
|
92
|
-
See [RELEASING.md](RELEASING.md) for the release procedure.
|
|
88
|
+
For experiments, add `--dry-run` to the recommendation command.
|
|
89
|
+
These suggestions never count toward learning or statistics.
|
|
93
90
|
|
|
94
|
-
##
|
|
91
|
+
## How it works
|
|
95
92
|
|
|
96
|
-
|
|
93
|
+
1. A local filter checks the task text for known secret patterns.
|
|
94
|
+
2. Jev classifies the task. Without Jev, spatz uses local keyword rules.
|
|
95
|
+
3. spatz ranks your candidates using classification and learned success estimates.
|
|
96
|
+
4. You or your agent choose a pair and run the task.
|
|
97
|
+
5. Hooks or `spatz report` record the outcome for future recommendations.
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
spatz --version
|
|
101
|
-
```
|
|
99
|
+
The CLI recommends pairs. The optional Claude Code mod can apply them automatically.
|
|
100
|
+
See [How it works](docs/how-it-works.md) and [Recommendation rules](docs/recommendation.md) for the decision process.
|
|
102
101
|
|
|
103
|
-
|
|
102
|
+
## Agent integrations
|
|
104
103
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
| Integration | What it does | Setup |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| Claude Code `spatz-hooks` plugin | Record task signals and model usage. | [Hooks guide](docs/hooks.md) |
|
|
107
|
+
| Codex `spatz-hooks` plugin | Record shell results and model usage. | [Hooks guide](docs/hooks.md) |
|
|
108
|
+
| Claude Code `spatz` plugin (mod) | Show recommendations or apply model and effort choices. | [Mod guide](docs/claude-mod.md) |
|
|
109
|
+
| Other agents | Request recommendations and report outcomes through the CLI. | [CLI reference](docs/cli.md) |
|
|
108
110
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
Windows x64 is experimental. Some releases omit it.
|
|
112
|
-
You can also [download a GitHub release archive](#releases). Archives need neither Node.js nor Bun installed.
|
|
111
|
+
The Claude Code mod supports `step`, `turn`, `subagent`, `session`, and `escalate` routing scopes.
|
|
112
|
+
Hooks and the mod can run together. The mod's `record: auto` avoids duplicate usage recording with the `spatz-hooks` plugin.
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
### Install the plugins
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
In Claude Code:
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
```text
|
|
119
|
+
/plugin marketplace add lorenzh/spatz
|
|
120
|
+
/plugin install spatz-hooks@spatz
|
|
121
|
+
/plugin install spatz@spatz
|
|
122
|
+
```
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
`spatz-hooks` records outcomes. `spatz` is the mod that recommends or applies model and effort. Install one or both.
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
mkdir -p ~/.local/bin
|
|
128
|
-
printf '#!/bin/sh\nexec bun "%s/packages/cli/src/cli.ts" "$@"\n' "$PWD" > ~/.local/bin/spatz
|
|
129
|
-
chmod +x ~/.local/bin/spatz
|
|
130
|
-
```
|
|
126
|
+
In Codex:
|
|
131
127
|
|
|
132
|
-
|
|
128
|
+
```bash
|
|
129
|
+
codex plugin marketplace add lorenzh/spatz
|
|
130
|
+
codex plugin add spatz-hooks@spatz
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Codex runs new hooks only after you trust them with `/hooks`.
|
|
133
134
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
Every plugin ships the `spatz` skill, which tells the agent when to ask spatz and how to report results, so you do not need to edit your agent instructions.
|
|
136
|
+
The plugins also ship a launcher. It uses `spatz` from your `PATH` if present. Otherwise it runs the matching `@spatz/cli` version through Bun or npx, which downloads about 60 MB on first use.
|
|
137
|
+
Codex hooks time out after 10 seconds, so run the launcher once before the first session: `"<plugin root>/bin/spatz" --version`.
|
|
138
|
+
The plugins need a POSIX shell. Native Windows is not supported yet.
|
|
139
|
+
If you added spatz hooks to `~/.claude/settings.json` or `~/.codex/hooks.json` by hand, remove them to avoid duplicate records.
|
|
140
|
+
See [Installation](docs/installation.md) for details.
|
|
137
141
|
|
|
138
|
-
|
|
142
|
+
## Privacy
|
|
139
143
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
--models claude-opus-5-5:high+medium,claude-sonnet-5-5:medium+low --dry-run
|
|
143
|
-
```
|
|
144
|
+
spatz stores learning data under `~/.spatz`. It does not store task text or tool output.
|
|
145
|
+
Hooks process task signals locally and make no network requests.
|
|
144
146
|
|
|
145
|
-
|
|
147
|
+
When you enable Jev, spatz sends task text and candidate details to TypeSafe AI.
|
|
148
|
+
The secret filter catches known patterns. It cannot detect every secret.
|
|
149
|
+
Do not put secrets in task text.
|
|
146
150
|
|
|
147
|
-
|
|
148
|
-
suggestion_id: fd8b7c1f-1f93-44f6-ac7b-b77ee287d1bb
|
|
149
|
-
1. anthropic/claude-opus-5.5:high estimate=0.50 n=0
|
|
150
|
-
reason: Without Jev and learned data the most expensive pair anthropic/claude-opus-5.5 (high) is recommended.
|
|
151
|
-
task_type: other difficulty: medium criticality: none
|
|
152
|
-
explored: false control: false fallback_used: true (dry-run)
|
|
153
|
-
```
|
|
151
|
+
To disable Jev:
|
|
154
152
|
|
|
155
|
-
|
|
153
|
+
```bash
|
|
154
|
+
export SPATZ_NO_JEV=1
|
|
155
|
+
```
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
For a project, put `{"jev": false}` in `.spatz.json` in the working directory.
|
|
158
|
+
Without `TYPESAFE_AI_API_KEY`, Jev is also disabled.
|
|
158
159
|
|
|
159
|
-
|
|
160
|
+
Disabling Jev still allows OpenRouter requests for model prices. These requests contain no task data.
|
|
161
|
+
spatz caches prices for 24 hours. When the network is unavailable, spatz can still use cached prices.
|
|
162
|
+
The first `spatz stats` run downloads DuckDB's SQLite extension.
|
|
160
163
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
```
|
|
164
|
+
See the [Privacy guide](docs/privacy.md) for data flows and deletion instructions.
|
|
165
|
+
See [Configuration](docs/configuration.md) for environment variables and local files.
|
|
164
166
|
|
|
165
|
-
|
|
167
|
+
## Releases
|
|
168
|
+
|
|
169
|
+
Download an archive and its matching `.sha256` file from [GitHub Releases](https://github.com/lorenzh/spatz/releases).
|
|
170
|
+
Archives include the runtime. You do not need Node.js or Bun installed.
|
|
166
171
|
|
|
167
|
-
|
|
172
|
+
Choose `linux` or `darwin` (macOS), then `x64` or `arm64`.
|
|
173
|
+
Apple Silicon uses `darwin-arm64`. Linux builds need glibc.
|
|
174
|
+
Windows x64 ZIP archives are experimental. The agent plugins do not support native Windows.
|
|
168
175
|
|
|
169
|
-
|
|
176
|
+
Check the checksum before extraction. This Linux x64 example uses version `0.1.0`:
|
|
170
177
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
178
|
+
```bash
|
|
179
|
+
version=0.1.0
|
|
180
|
+
archive="spatz-cli-$version-linux-x64.tar.gz"
|
|
181
|
+
sha256sum --check "$archive.sha256"
|
|
182
|
+
|
|
183
|
+
mkdir -p ~/.local/lib/spatz ~/.local/bin
|
|
184
|
+
tar -xzf "$archive" -C ~/.local/lib/spatz
|
|
185
|
+
ln -sfn "$HOME/.local/lib/spatz/${archive%.tar.gz}/spatz" ~/.local/bin/spatz
|
|
186
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
187
|
+
spatz --version
|
|
188
|
+
```
|
|
174
189
|
|
|
175
|
-
|
|
190
|
+
Use your downloaded version. On macOS, use `shasum -a 256 --check "$archive.sha256"`.
|
|
191
|
+
If your shell does not include `~/.local/bin`, add the `PATH` line to your shell profile.
|
|
192
|
+
Keep the executable and DuckDB libraries together. `spatz stats` needs these libraries beside the executable.
|
|
176
193
|
|
|
177
|
-
|
|
194
|
+
The [nightly release](https://github.com/lorenzh/spatz/releases/tag/nightly) is unstable.
|
|
195
|
+
See [Releasing spatz](RELEASING.md) for the release process.
|
|
178
196
|
|
|
179
|
-
|
|
197
|
+
## Install from source
|
|
180
198
|
|
|
181
|
-
|
|
182
|
-
| --- | --- |
|
|
183
|
-
| `spatz --version` | Print the CLI version. |
|
|
184
|
-
| `spatz "<task>" --models <list> [--scope <scope>] [--session <id>] [--turn <id>] [--agent-id <id>] [--source <agent>] [--dry-run]` | Rank candidate pairs and optionally store routing attribution. |
|
|
185
|
-
| `spatz report <suggestion_id> --model <m> --effort <e> --result pass\|partial\|fail [--rounds <n>] [--note <t>] [--turn <id> --source claude-code-mod]` | Record the pair that you used and the result. |
|
|
186
|
-
| `spatz usage <suggestion_id> ... --turn <id> --source claude-code-mod` | Record direct model usage and token counts. |
|
|
187
|
-
| `spatz link <suggestion_id> --agent-id <id> --session <id>` | Link a subagent suggestion after its id is known. |
|
|
188
|
-
| `spatz hook <event> [--agent codex]` | Read a Claude Code or Codex hook event from stdin. Prints nothing and always exits 0. |
|
|
189
|
-
| `spatz stats [--type <t>] [--by scope]` | Show results per task type or routing scope. |
|
|
199
|
+
Install Bun 1.4, then clone the repository:
|
|
190
200
|
|
|
191
|
-
|
|
201
|
+
```bash
|
|
202
|
+
git clone https://github.com/lorenzh/spatz.git
|
|
203
|
+
cd spatz
|
|
204
|
+
bun install
|
|
205
|
+
```
|
|
192
206
|
|
|
193
|
-
|
|
207
|
+
Put a wrapper on your `PATH` so hooks can find `spatz` in non-interactive shells:
|
|
194
208
|
|
|
195
|
-
|
|
209
|
+
```bash
|
|
210
|
+
mkdir -p ~/.local/bin
|
|
211
|
+
printf '#!/bin/sh\nexec bun "%s/packages/cli/src/cli.ts" "$@"\n' "$PWD" > ~/.local/bin/spatz
|
|
212
|
+
chmod +x ~/.local/bin/spatz
|
|
213
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
214
|
+
spatz --version
|
|
215
|
+
```
|
|
196
216
|
|
|
197
|
-
|
|
217
|
+
A shell alias does not work for hooks.
|
|
218
|
+
See [Contributing](CONTRIBUTING.md) for the full development setup.
|
|
198
219
|
|
|
199
220
|
## Documentation
|
|
200
221
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
222
|
+
| Guide | What you will find |
|
|
223
|
+
| --- | --- |
|
|
224
|
+
| [CLI reference](docs/cli.md) | Commands, flags, model IDs, output fields, and exit codes. |
|
|
225
|
+
| [How it works](docs/how-it-works.md) | Architecture and the flow from task to outcome. |
|
|
226
|
+
| [Recommendation rules](docs/recommendation.md) | Ranking, exploration, and control groups. |
|
|
227
|
+
| [Hooks](docs/hooks.md) | Claude Code and Codex CLI setup and recorded signals. |
|
|
228
|
+
| [Claude Code mod](docs/claude-mod.md) | Modes, routing scopes, and `/spatz` commands. |
|
|
229
|
+
| [Configuration](docs/configuration.md) | Environment variables and local files. |
|
|
230
|
+
| [Privacy](docs/privacy.md) | Network requests, stored data, and deletion. |
|
|
210
231
|
|
|
211
|
-
##
|
|
232
|
+
## Contributing
|
|
212
233
|
|
|
213
|
-
|
|
234
|
+
Bug reports and pull requests are welcome.
|
|
235
|
+
For larger changes, [open an issue](https://github.com/lorenzh/spatz/issues) first to agree on the scope.
|
|
236
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and the test-first workflow.
|
|
237
|
+
Changes to `main` must go through a pull request.
|
|
214
238
|
|
|
215
|
-
Run
|
|
239
|
+
Run the checks before submitting a change:
|
|
216
240
|
|
|
217
241
|
```bash
|
|
218
|
-
bun test
|
|
219
|
-
bun run typecheck
|
|
220
|
-
bun run lint
|
|
242
|
+
bun test
|
|
243
|
+
bun run typecheck
|
|
244
|
+
bun run lint
|
|
221
245
|
```
|
|
222
246
|
|
|
223
|
-
|
|
247
|
+
For vulnerabilities, follow [SECURITY.md](SECURITY.md). Do not open a public issue.
|
|
224
248
|
|
|
225
249
|
## License
|
|
226
250
|
|
|
227
|
-
MIT
|
|
251
|
+
[MIT](LICENSE) © 2026 Lorenz Hilpert.
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spatz/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Model and effort recommendations for coding agents",
|
|
5
5
|
"bin": {
|
|
6
6
|
"spatz": "bin/spatz.js"
|
|
7
7
|
},
|
|
8
8
|
"optionalDependencies": {
|
|
9
|
-
"@spatz/cli-linux-x64": "0.1.
|
|
10
|
-
"@spatz/cli-linux-arm64": "0.1.
|
|
11
|
-
"@spatz/cli-darwin-arm64": "0.1.
|
|
12
|
-
"@spatz/cli-darwin-x64": "0.1.
|
|
9
|
+
"@spatz/cli-linux-x64": "0.1.1",
|
|
10
|
+
"@spatz/cli-linux-arm64": "0.1.1",
|
|
11
|
+
"@spatz/cli-darwin-arm64": "0.1.1",
|
|
12
|
+
"@spatz/cli-darwin-x64": "0.1.1",
|
|
13
|
+
"@spatz/cli-win32-x64": "0.1.1"
|
|
13
14
|
},
|
|
14
15
|
"engines": {
|
|
15
16
|
"node": ">=18"
|