smolcoder 0.4.1 → 0.4.3
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 +75 -156
- package/dist/index.js +6 -6
- package/dist/web/page.js +6 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,196 +1,115 @@
|
|
|
1
1
|
# smolcoder
|
|
2
2
|
|
|
3
|
-
A smol
|
|
3
|
+
A smol coding agent for the models already running on your machine.
|
|
4
|
+
|
|
5
|
+
If you have Ollama or LM Studio installed, you are two commands away from an AI pair programmer that reads your code, edits files, runs your tests and starts your dev server, all without an API key, a config file, or a single question about base URLs.
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
8
|
npm install -g smolcoder
|
|
7
9
|
smol
|
|
8
10
|
```
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
That is the whole setup. smolcoder finds your local server, lists the models you already have, and drops you into a session.
|
|
11
13
|
|
|
12
|
-
##
|
|
14
|
+
## Why you might like it
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
Most coding agents are built for big cloud models and treat local ones as an afterthought. They ship huge system prompts, dozens of tools and plugin systems, then wonder why a 7B model with a 16k window gets lost. smolcoder goes the other way.
|
|
15
17
|
|
|
16
|
-
-
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
19
|
-
-
|
|
20
|
-
-
|
|
18
|
+
- **Zero config.** It probes the standard Ollama and LM Studio ports and uses whatever it finds. Docker-hosted Ollama with the usual port mapping works too.
|
|
19
|
+
- **Built for small context windows.** A two-paragraph system prompt, seven flat tools, and hard caps on every tool output. Nothing else competes for the model's attention.
|
|
20
|
+
- **Context handled for you.** It reads the real token counts from the backend, shows a live context meter, and compacts old tool output before it ever has to summarise your conversation.
|
|
21
|
+
- **Small-model-friendly tools.** Every tool has an example call in its description, error messages coach the model toward the fix, and the edit tool forgives whitespace drift. That last one is the difference between a local model that can edit files and one that cannot.
|
|
22
|
+
- **A plan the model cannot lose.** For multi-step work the agent keeps a checklist that lives in the harness, not the transcript, so it survives compaction and keeps the model on track.
|
|
23
|
+
- **Runs anywhere Node runs.** Windows, macOS and Linux. Zero runtime dependencies.
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
## Setup
|
|
23
26
|
|
|
24
|
-
|
|
27
|
+
You need two things.
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
1. **Node.js 18 or newer.** Get it from [nodejs.org](https://nodejs.org) if you do not have it.
|
|
30
|
+
2. **A local model server**, either:
|
|
31
|
+
- [Ollama](https://ollama.com) with a tool-capable model pulled, for example `ollama pull qwen3`, or
|
|
32
|
+
- [LM Studio](https://lmstudio.ai) with a model loaded and its local server running (Developer tab, then Start Server).
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
- **Tiny context footprint.** A two-paragraph system prompt, exactly seven flat tools, hard caps on every tool output, and no MCP, no skills, no subagents.
|
|
30
|
-
- **Context windows handled properly.** For Ollama, smolcoder respects the server's own configured context length (the Ollama app's setting) — it preloads the model and reads the effective window from `/api/ps`, sending an explicit `num_ctx` only on old Ollama versions where the silent tiny default would truncate prompts, or when you pass `--ctx`. For LM Studio it reads the loaded context length from `/api/v0/models` and budgets within it. Real token usage reported by the backend drives a live context meter and automatic compaction (old tool output is evicted first — nearly free — and the conversation is summarized only when that's not enough).
|
|
31
|
-
- **Small-model-friendly tools.** Flat string parameters, an example call in every description, and error messages written as coaching (a failed edit shows the closest real snippet to copy). The edit tool forgives whitespace drift — the difference between usable and unusable local editing.
|
|
34
|
+
Then install and start:
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g smolcoder
|
|
38
|
+
cd your-project
|
|
39
|
+
smol
|
|
40
|
+
```
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|------|-------|----------|
|
|
37
|
-
| `ro` (read-only) | read/search only | none |
|
|
38
|
-
| `edit` (default) | read/write/edit | runs freely inside the workspace (`npm install`, tests, scripts); a command that reaches outside it asks y/n (or **a**lways-allow that program for the session) |
|
|
39
|
-
| `bypass` (bypass permissions) | read/write/edit | never asks for approval |
|
|
42
|
+
Prefer not to install anything globally? `npx smolcoder` works too.
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
## Your first session
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
smolcoder opens straight into a chat with the last model you used, or the first one it detects. Type what you want done and press enter. The agent reads files, makes edits, and runs commands inside your project folder, telling you what it is doing as it goes.
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
A few keys worth knowing from the start:
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
| Key | What it does |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `/` | Opens the slash-command menu with autocomplete |
|
|
53
|
+
| `shift+tab` | Cycles the permission mode: read-only, edit, bypass |
|
|
54
|
+
| `esc` | Cancels the running turn, or clears the input |
|
|
55
|
+
| `ctrl+c` twice | Quits |
|
|
51
56
|
|
|
52
|
-
|
|
57
|
+
The status line under the input shows the current mode, model, reasoning effort, how full the context window is, and any background tasks you have running.
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
## Slash commands
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
| Command | What it does |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `/models` | Switch model. Type to filter the list. |
|
|
64
|
+
| `/mode` | Set the permission mode (`ro`, `edit`, `bypass`) |
|
|
65
|
+
| `/effort` | Set reasoning effort (`off`, `low`, `medium`, `high`, `default`) |
|
|
66
|
+
| `/plan` | Show the agent's current checklist |
|
|
67
|
+
| `/context` | Show context window usage |
|
|
68
|
+
| `/compact` | Compact the conversation now |
|
|
69
|
+
| `/tasks`, `/logs <id>`, `/stop <id>` | Inspect and stop background tasks such as dev servers |
|
|
70
|
+
| `/clear` | Start a fresh conversation |
|
|
71
|
+
| `/help`, `/exit` | Help and quit |
|
|
57
72
|
|
|
58
|
-
|
|
73
|
+
## Modes
|
|
59
74
|
|
|
60
|
-
|
|
75
|
+
The mode decides which tools the model even knows about. In read-only mode it is never told a write tool exists.
|
|
61
76
|
|
|
62
|
-
|
|
77
|
+
| Mode | Files | Commands |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `ro` | read and search only | none |
|
|
80
|
+
| `edit` (default) | read, write, edit | runs freely inside the project folder. Anything reaching outside it asks you first. |
|
|
81
|
+
| `bypass` | read, write, edit | never asks |
|
|
82
|
+
|
|
83
|
+
File tools are sandboxed to the project folder, symlinks included. In edit mode each command is scanned before it runs, and paths outside the folder, home-directory or temp-directory references, and global package installs all trigger an approval prompt that shows the reason. This is a text scan rather than an OS sandbox, so a script the model runs could still reach outside. Use read-only mode for code you do not trust, and bypass when you want no prompts at all.
|
|
84
|
+
|
|
85
|
+
## Handy options
|
|
63
86
|
|
|
64
87
|
```bash
|
|
65
|
-
smol
|
|
66
|
-
smol path/to/project
|
|
67
|
-
smol --
|
|
68
|
-
smol --
|
|
69
|
-
smol --
|
|
70
|
-
smol
|
|
88
|
+
smol # current folder, remembers your last model and mode
|
|
89
|
+
smol path/to/project # a specific project
|
|
90
|
+
smol --model qwen3 # pick a model by partial name
|
|
91
|
+
smol --effort off # no thinking: the fastest setting for long tool loops
|
|
92
|
+
smol --mode bypass # never ask for approval
|
|
93
|
+
smol --ctx 16384 # cap the context window
|
|
94
|
+
smol --web # also serve the session as a local web page
|
|
95
|
+
smol -p "fix the failing test" # headless: run one prompt, print the transcript, exit
|
|
71
96
|
```
|
|
72
97
|
|
|
73
|
-
|
|
98
|
+
Headless mode is for scripts and automation. It suppresses reasoning noise and the exit code tells you whether the run succeeded.
|
|
74
99
|
|
|
75
|
-
##
|
|
100
|
+
## Tips
|
|
76
101
|
|
|
77
|
-
|
|
78
|
-
(the model is a hybrid recurrent `qwen35` build; Ollama 0.33, LM Studio 0.4.21):
|
|
102
|
+
**Turn thinking off for long tasks.** `/effort off` disables reasoning on qwen3-class models, which makes each step several times faster. Thinking helps with planning and tricky bugs, but for a twenty-step build the model rarely needs it. Models without a thinking switch fall back silently.
|
|
79
103
|
|
|
80
|
-
|
|
81
|
-
|---|---|---|
|
|
82
|
-
| prompt processing (6.7k-token cold prompt) | ~3,300 tok/s | ~3,000–3,400 tok/s |
|
|
83
|
-
| generation, 400 tokens of prose, thinking off | ~120 tok/s | ~68 (4 slots + MTP) / ~76 (1 slot, no MTP) tok/s |
|
|
84
|
-
| generation, 1,200 tokens of JavaScript, thinking off | ~170 tok/s | ~110 (1 slot + MTP) / ~76 (no MTP) tok/s |
|
|
85
|
-
| one agent step (plan + write call), thinking off | 0.9 s | 1.5–1.8 s |
|
|
86
|
-
| one agent step with thinking, same prompt | 0.8–10 s (38–3,500 reasoning chars) | 1.8–85 s (250–19,000 reasoning chars) |
|
|
87
|
-
|
|
88
|
-
The engine is the same llama.cpp on both, so the differences come from what the
|
|
89
|
-
harness sends and from load settings:
|
|
90
|
-
|
|
91
|
-
- **Reasoning effort was the whole story behind "LM Studio is slow".** LM Studio's
|
|
92
|
-
API takes `reasoning_effort` none/minimal/low/medium/high/xhigh, but each model only
|
|
93
|
-
supports some of them and a value the model lacks is silently replaced by the
|
|
94
|
-
model's *default* — which for current qwen3.x builds is **xhigh**, the maximum.
|
|
95
|
-
Asking for `high` therefore produced 8,000-token thinking bursts before single
|
|
96
|
-
tool calls. smolcoder now reads the model's supported levels and default from
|
|
97
|
-
`/api/v1/models`, sends `none` for `off` (measured: fully disables thinking), and
|
|
98
|
-
snaps other levels to the nearest one the model has (`high` → `medium` on qwen;
|
|
99
|
-
ties go to the cheaper level). The status line shows the mapping (`high → medium`,
|
|
100
|
-
`default → xhigh`), and a warning is printed when the default is the maximum.
|
|
101
|
-
On Ollama, `off` is a real `think: false` and any other level is `think: true`
|
|
102
|
-
(levels only exist for gpt-oss there).
|
|
103
|
-
- **Thinking is unpredictable on local models.** The same prompt at the same level
|
|
104
|
-
thought for 250 characters one run and 19,000 the next. For long tool loops,
|
|
105
|
-
`--effort off` is the reliable setting on both backends; `low`/`medium` are fine
|
|
106
|
-
for questions and planning.
|
|
107
|
-
- **Generation is ~1.5× faster on Ollama** with default settings (Ollama also
|
|
108
|
-
drafts 4 tokens per step with the model's MTP head; LM Studio drafts 2). On LM
|
|
109
|
-
Studio, keep MTP speculative decoding ON for coding — it took code generation from
|
|
110
|
-
76 to ~110 tok/s (it slightly slows prose, which is what most benchmarks measure) —
|
|
111
|
-
and load with a single slot, which is another ~10%:
|
|
112
|
-
`lms load <model> --context-length 65536 --parallel 1 --speculative-draft-mtp`.
|
|
113
|
-
Prompt caching works on both (only the new tail of the prompt is processed).
|
|
114
|
-
- **Ollama keeps the model resident** for 30 minutes between calls (its own default
|
|
115
|
-
unloads after 5 min — a long approval pause used to cost a 10–20 s reload).
|
|
116
|
-
Override with `SMOLCODER_KEEP_ALIVE=1h`.
|
|
117
|
-
- **Reasoning traces are not replayed** for finished turns (the qwen templates drop
|
|
118
|
-
them anyway); only the current turn's traces travel with the tool loop. On a
|
|
119
|
-
thinking model this is the largest single prompt-size saving.
|
|
120
|
-
|
|
121
|
-
## End-to-end: the same Minecraft build on both backends
|
|
122
|
-
|
|
123
|
-
One headless run each (`smol -p "<prompt>" --mode bypass --effort off`), same
|
|
124
|
-
model weights, same prompt (procedural voxel terrain, first-person controls, block
|
|
125
|
-
place/remove, three.js from a CDN, then serve it). Nobody typed "continue".
|
|
126
|
-
|
|
127
|
-
| | Ollama | LM Studio (1 slot, MTP on) |
|
|
128
|
-
|---|---|---|
|
|
129
|
-
| wall clock | 64 s | 85 s |
|
|
130
|
-
| tool calls | 20 (5 files) | 14 (3 files) |
|
|
131
|
-
| tokens generated | 9.4k @ 171 tok/s | 7.4k @ 96 tok/s |
|
|
132
|
-
| plan | 6/6 done | 3/3 done |
|
|
133
|
-
| syntax warnings from the write hook | 0 | 0 |
|
|
134
|
-
| result in the browser | loads, no console errors; one mesh-winding bug | loads, no console errors; terrain not visible |
|
|
135
|
-
|
|
136
|
-
Both agents finished on their own, checked their files with `node --check`, and
|
|
137
|
-
started a static server to prove the page served. Reproduce with `bench/run.sh`
|
|
138
|
-
(the prompt is `bench/minecraft-prompt.txt`; every headless run ends with a
|
|
139
|
-
`[stats]` JSON line on stderr). Both first drafts had one real bug
|
|
140
|
-
(this is a 27B model writing a voxel engine with thinking off); each was fixed with
|
|
141
|
-
a second headless turn carrying a one-paragraph, symptom-only bug report:
|
|
142
|
-
|
|
143
|
-
| fix turn | Ollama | LM Studio |
|
|
144
|
-
|---|---|---|
|
|
145
|
-
| wall clock | 42 s | 100 s |
|
|
146
|
-
| tool calls | 27 (reads, searches, 3 edits, node one-liners) | 27 (7 reads, 3 edits, 10 commands, 6 plan) |
|
|
147
|
-
| tokens generated | 4.8k @ 165 tok/s | 6.9k @ 79 tok/s |
|
|
148
|
-
| outcome | solid terrain; face vertex order fixed | terrain renders; spawn height + camera pitch fixed |
|
|
104
|
+
**Give the agent a memory.** If your project has an `AGENTS.md` file, its contents are injected after the system prompt and survive compaction. Put your conventions, commands and quirks there.
|
|
149
105
|
|
|
150
|
-
|
|
106
|
+
**Let it run things in the background.** The agent can start dev servers and watchers as background tasks, check their logs, and stop them. They show up in the status line and are killed when smolcoder exits.
|
|
151
107
|
|
|
152
|
-
|
|
153
|
-
ties snap to the cheaper neighbour) and to `think: true` on Ollama.
|
|
108
|
+
**Curious about the numbers?** Benchmarks, Ollama versus LM Studio tuning notes, and what happens when the context window is squeezed are all in [docs/backend-notes.md](docs/backend-notes.md).
|
|
154
109
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
| tool calls | 16 | 28 |
|
|
159
|
-
| tokens generated | 10.6k @ 146 tok/s, ~2.6k of them reasoning | 22.5k @ 84 tok/s, ~12.2k of them reasoning |
|
|
160
|
-
| plan | 4/4 | 5/5 |
|
|
161
|
-
| result in the browser | correct on the first try: terrain, hills, controls, no console errors | correct on the first try: terrain, hills, controls, no console errors |
|
|
162
|
-
|
|
163
|
-
Reasoning bought correctness: both first drafts worked, where both effort-off drafts had
|
|
164
|
-
needed a bug-fix turn. The price is time — the model's per-step thinking is where the
|
|
165
|
-
backends differ most (Ollama's `think: true` produced a quarter as many reasoning
|
|
166
|
-
tokens as LM Studio's `medium`), and LM Studio's default `xhigh` would have been far
|
|
167
|
-
slower still. Note that the two effort-off runs plus their fix turns (106 s on Ollama,
|
|
168
|
-
185 s on LM Studio) still beat the reasoning runs on wall clock.
|
|
169
|
-
|
|
170
|
-
### Forcing compaction
|
|
171
|
-
|
|
172
|
-
The same build with the window capped at 12k tokens (`--ctx 12000`, output budget
|
|
173
|
-
3k) is the stress test for everything above: Ollama finished the whole game in
|
|
174
|
-
104 s and 28 tool calls with context management kicking in five times, the plan
|
|
175
|
-
reported 5/5, and the page rendered. On LM Studio the same run went through a tier-1
|
|
176
|
-
eviction (7.4k → 5.1k tokens) and then a real tier-2 compaction (7.5k → 2.1k tokens:
|
|
177
|
-
system prompt + plan + model-written hand-over notes + the working tail), after which
|
|
178
|
-
the model carried on with the remaining steps — syntax check, serve, summarize. (That
|
|
179
|
-
LM Studio build parses and serves but throws a runtime TypeError on load — a file
|
|
180
|
-
assembled in five pieces under a 3k output cap is where a 27B model starts to slip,
|
|
181
|
-
and a parse check cannot catch runtime errors.) Two things made the runs work at all:
|
|
182
|
-
|
|
183
|
-
- when a whole-file `write_file` overflows the output cap, the model is told the call
|
|
184
|
-
was **not executed** and coached to write the file in parts (first part with
|
|
185
|
-
`write_file`, then `edit_file` appends) — before that coaching existed the model
|
|
186
|
-
retried the same oversized write three times in a row;
|
|
187
|
-
- the plan and the hand-over notes are re-injected after every compaction, so the
|
|
188
|
-
model resumes at the right step instead of starting over.
|
|
189
|
-
|
|
190
|
-
## Requirements
|
|
191
|
-
|
|
192
|
-
- Node.js 18+
|
|
193
|
-
- [Ollama](https://ollama.com) with at least one tool-capable model pulled (e.g. `ollama pull qwen3`), **or** LM Studio with its local server running (Developer tab → Start Server).
|
|
110
|
+
## Contributing
|
|
111
|
+
|
|
112
|
+
Issues and pull requests are welcome at [github.com/leonvanzyl/smolcoder](https://github.com/leonvanzyl/smolcoder). Clone it, run `npm install`, then `npm test`.
|
|
194
113
|
|
|
195
114
|
## License
|
|
196
115
|
|
package/dist/index.js
CHANGED
|
@@ -256,12 +256,12 @@ function sessionLine(m, mode) {
|
|
|
256
256
|
}
|
|
257
257
|
const MODE_ORDER = ["ro", "edit", "bypass"];
|
|
258
258
|
const LOGO_ROWS = [
|
|
259
|
-
"
|
|
260
|
-
"
|
|
261
|
-
" ██║
|
|
262
|
-
" ██║
|
|
263
|
-
"
|
|
264
|
-
"
|
|
259
|
+
"███████╗ ███╗ ███╗ ██████╗ ██╗ ",
|
|
260
|
+
"██╔════╝ ████╗ ████║ ██╔═══██╗ ██║ ",
|
|
261
|
+
"███████╗ ██╔████╔██║ ██║ ██║ ██║ ",
|
|
262
|
+
"╚════██║ ██║╚██╔╝██║ ██║ ██║ ██║ ",
|
|
263
|
+
"███████║ ██║ ╚═╝ ██║ ╚██████╔╝ ███████╗",
|
|
264
|
+
"╚══════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝",
|
|
265
265
|
];
|
|
266
266
|
function printLogo() {
|
|
267
267
|
const cols = process.stdout.columns || 80;
|
package/dist/web/page.js
CHANGED
|
@@ -88,12 +88,12 @@ exports.PAGE_HTML = `<!doctype html>
|
|
|
88
88
|
</head>
|
|
89
89
|
<body>
|
|
90
90
|
<div id="wrap">
|
|
91
|
-
<div id="logo"
|
|
92
|
-
|
|
93
|
-
██║
|
|
94
|
-
██║
|
|
95
|
-
|
|
96
|
-
|
|
91
|
+
<div id="logo">███████╗ ███╗ ███╗ ██████╗ ██╗
|
|
92
|
+
██╔════╝ ████╗ ████║ ██╔═══██╗ ██║
|
|
93
|
+
███████╗ ██╔████╔██║ ██║ ██║ ██║
|
|
94
|
+
╚════██║ ██║╚██╔╝██║ ██║ ██║ ██║
|
|
95
|
+
███████║ ██║ ╚═╝ ██║ ╚██████╔╝ ███████╗
|
|
96
|
+
╚══════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ <span class="coder">coder — web</span></div>
|
|
97
97
|
<div id="log"></div>
|
|
98
98
|
<div id="busy"><span class="spin">⠋</span> <span id="busylabel">thinking…</span> <span id="busysecs"></span></div>
|
|
99
99
|
</div>
|