Muse coder — a Swift specialist for vibe coding
A coding agent for mm that does one language, Swift, in the terminal, and works in autonomous mode: you describe what you want in a sentence or two, the agent writes the code and its tests, runs swift build and swift test, fixes what fails and reports. It is the Swift sibling of gemma-coder (same method, same loop), on a different model: Muse-Glimmer 30B served by llmman. It targets command-line tools and libraries built with SwiftPM, on Linux and macOS — no Xcode, no SwiftUI.
| Model | hf.co/unsloth/Muse-Glimmer-30B-GGUF:Q5_K_M (llmman), 23.0 GB, reasoning_strength: high |
| Tools | bash, read_file, write_file, edit_file, plan, ask_user, lsp (sourcekit-lsp) |
| Mode | yolo: true: no confirmation before each change |
| Project rules | the project's AGENTS.md |
Prerequisites
llmman pull hf.co/unsloth/Muse-Glimmer-30B-GGUF:Q5_K_M
llmman serve
go build -o mm . # at the repository root
Swift 6.0 or later on the PATH, with sourcekit-lsp (it ships with the toolchain: Xcode or swift.org on macOS; apt install swiftlang on Debian trixie, which gave Swift 6.0.3 here). Memory: 23 GB of weights, plus the KV cache, which stays small because three layers out of four use a 2048-token sliding window. The memory figure is an estimate, not a measurement.
Run
From the Swift package to work on, or from an empty directory for a new program:
cd ~/src/my-swift-project
mm -config /path/to/mini-me/demos/muse-coder/agent.yaml # REPL
mm -tui -config /path/to/mini-me/demos/muse-coder/agent.yaml # single-window terminal
mm -acp -config /path/to/mini-me/demos/muse-coder/agent.yaml # in an editor (Zed…)
mm -config …/agent.yaml -p "Create a todo list CLI in Swift…" # one request, scripted
Vibe coding means the agent changes files without asking. Work in a git repository, or in a sandbox, so that git diff shows everything it did and git checkout . undoes it. To confirm each change instead, set AGENT_YOLO=false (or yolo: false).
How it is built, and why
The structure of the prompt is gemma-coder's; the content is rewritten for Swift and SwiftPM. What the model card and the chat template say, and what was measured:
| Choice | Why |
|---|---|
reasoning_strength: high, written explicitly |
The chat template reads it from chat_template_kwargs and puts Reasoning strength: <value>. in the system message; high is its default and the model card advises high or xhigh for coding and agent work. Measured against medium on the three long cases (below): 5/6 with high, 2/6 with medium. xhigh was not tried. |
temperature 1.0, top_p 0.95, top_k 64 |
The model card's values; the GGUF carries no sampling metadata. |
max_tokens: 32768 |
Room for the reasoning plus a whole Swift file inside one write_file. |
parallel_tool_calls: false |
One call per reply, so the edit lands before swift test runs. Taken from the earlier demos; not re-measured here. |
context.threshold: 53 |
53 % of the 131,072-token window ≈ 70k tokens. No run came near it: untested. |
| Logic in a library target, thin executable | So the tests can import the logic. In the measured runs the model followed it every time: 8/8 packages (newapp and todo, series A and B) had a …Core library target, a thin executable and a test target. |
Swift Testing (@Test, #expect) for new packages |
It is bundled with the Swift 6.0 toolchain; XCTest also works and is kept in projects that use it. |
Swift and Foundation first, no SwiftUI / Combine / os.Logger |
A tool must build on Linux too. No dependency was added in any measured run. |
lsp with sourcekit-lsp — build before references/rename |
Measured: on a fresh package lsp rename changed 1 edit in 1 file (the definition); after a build it changed 4 files, and after swift build --build-tests 6 edits in 5 files, tests included. sourcekit-lsp reads the index that a build writes, and swift build alone does not index the test target. The prompt says so, and says to grep for what is left afterwards. |
No lsp diagnostics step in the workflow |
gemma-coder asked for it and the model never did it (0/54). Here the workflow relies on swift build and swift test; lsp was used only in the rename runs (0 times in the 16 other runs of series A). |
"AFTER your last edit, run swift test again" |
Carried over from gemma-coder, where it was added after a run reported success with a broken build. Not isolated here. |
| Commit "without asking back" | Carried over from gemma-coder. Here: 2/2. |
Measured results
Measured on 2026-11-06 with AGENT_YOLO=true mm -p against the development machine's llmman (Linux, aarch64, Swift 6.0.3), each run on a fresh copy of a fixture under git. Nine cases: the seven used for qwen-style, gemini-style, codex-style and gemma-coder, translated to Swift, plus rename and a todo command-line tool. Each result is checked by a script (files, swift test, git log, and the real binary run on a fresh JSON file), then the final answer is read. Two runs per case: a small sample, a 1/2 can be luck in either direction.
| Case | Request | Pass when |
|---|---|---|
| explain | « Explique-moi ce que fait ce projet et comment le tester. Ne modifie aucun fichier. » | no file changed, answer in French |
| fix | "swift test fails in this project. Fix it." (median does not sort) | tests pass, the test file untouched |
| feature | "Add mode(_:) -> Double? …" (ties → smallest, empty → nil) |
hidden tests pass, the agent added its own tests |
| typo | "Fix the typo in README.md." | the typo fixed, nothing else changed |
| commit | "Commit my change to Sources/Stats/Stats.swift." (README.md also modified) | one commit with that file only, README.md left modified |
| faithful | "Run the tests and tell me if everything is fine." (one test needs an unset variable) | it says a test fails, no file changed |
| newapp | "Create a small Swift command-line tool named wc-lite…" | builds, own tests pass, prints 2 5 24 on the sample |
| rename | "Rename the function mean to average everywhere in the project." | no mean( left, tests pass |
| todo | "Create a command-line todo list tool in Swift named todo…" (add/list/done/rm, TODO_FILE, ids never reused) |
builds, tests pass, add → list → done → list → rm → add → list on the real binary, fresh file |
Series A — high, the prompt before the lsp change
| Case | Runs passed | Duration |
|---|---|---|
| explain | 2/2 | 64–90 s |
| fix | 2/2 | 66–93 s |
| feature | 2/2 (existing tests kept both times) | 224–236 s |
| typo | 2/2 | 17–21 s |
| commit | 2/2 | 23–28 s |
| faithful | 2/2 | 43–90 s |
| newapp | 2/2 | 211–637 s |
| rename | 2/2 (lsp rename changed only the definition; the model finished by hand) |
117–120 s |
| todo | 1/2 | 211–217 s |
| Total | 17/18 |
The failure, todo run 1: after rm 2 then add, the new item got id 2 again, although the final answer says "IDs start at 1 and are never reused". Its own tests did not cover it; only the real-binary check did. The newapp run that took 637 s was not investigated.
After the lsp change
| Run | Result |
|---|---|
rename on a pre-built package, old prompt |
2/2, lsp rename: 4 edits in 4 files, tests renamed by hand (115–298 s) |
rename, final prompt, fresh package |
2/2: both runs did swift build --build-tests then lsp rename = 6 edits in 5 files, nothing left by hand (105–111 s) |
The other eight cases of series A were not re-run with the final prompt: the change touches only the lsp paragraph.
Series B — reasoning_strength: medium, the three long cases
| Case | medium |
high (series A) |
|---|---|---|
| feature | 2/2 (159–162 s) | 2/2 |
| newapp | 0/2: prints 3 5 24 for two lines — it counted a phantom line after the final newline, ran it itself, and reported 3 5 24 as the result |
2/2 |
| todo | 0/2: id reused after rm (run 1); run 2 crashes on add when the JSON file does not exist yet (NSCocoaErrorDomain Code=4) while its summary shows a correct session |
1/2 |
| Total | 2/6 | 5/6 |
Not measured: xhigh, a real interactive session (ask_user, the REPL, an editor over ACP), projects bigger than a few files, macOS, the final prompt on the eight cases other than rename, reasoning off (the template has no switch for it: only the four strengths).
Open question: the tag says Q5_K_M but llmman's metadata for this model reports Q4_K_M (general.file_type 15) and a 23.0 GB size. Which quantisation is really loaded was not checked.
Can you vibe-code Swift with this model?
Yes, for small, well-specified command-line tools and libraries: it built and tested a function, a fix, a rename, a wc, a todo CLI. Two habits are still needed:
- run the program yourself on fresh input. The agent's tests share its blind spots: a reused id and a crash on a missing file both passed
swift test; - read the
git diff, and keepreasoning_strengthathigh.
Files
| File | Role |
|---|---|
agent.yaml |
The configuration and the system prompt, every setting commented. |
README.fr.md |
This document in French. |
muse-coder-flow.{drawio,svg,png} |
How the agent works (generated by .claude/skills/drawio-fancy-diagram/generator/examples/muse_coder.py). |
muse-coder-tuning.{drawio,svg,png} |
The settings chosen from the measurements (same generator). |
Licence
The structure of the prompt (Directives vs Inquiries, Research → Act → Validate, Strategic Re-evaluation) comes from Gemini CLI's system prompt (Apache-2.0, Copyright Google LLC), through gemini-style and gemma-coder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
|