Qwen3.8-27B Fine-Tunes: A Coding Benchmark on a MacBook A developer benchmarked four popular Qwen3.8-27B fine-tunes and merges against the stock base model on Forge 2.0, a 300-call agentic coding task requiring an autonomous upgrade of a Jira app, run on a single 64 GB M3 Max MacBook. The stock base model scored a median of 0.1852, while the closest fine-tune, nightmedia's MindMeld-OneJev1.6, reached 0.1105 and two of the four candidates were cancelled before completing their call budgets. The results suggest model cards and download counts were poor predictors of agentic coding performance, with failures including malformed write tool calls and placeholder code. The stock Qwen3.8-27B is still the best local 27B we've measured on this benchmark. I'm a bit annoyed about it. Over two days we ran four popular Qwen3.8-27B fine-tunes and merges through Forge 2.0, our long agentic coding benchmark, on one 64 GB M3 Max MacBook, next to the stock base model. The base's median is 0.1852. The closest candidate, nightmedia's MindMeld-OneJev1.6, scored 0.1105 in its one build, which is level with the base's weaker build 0.1128 , so I'd call that one close. Two of the four never got a score. I cancelled both. If you run a local model for agentic coding, you probably picked it the way we did: by downloads, by the LiveCodeBench number on the card, by who made it. The fine-tunes arrive faster than anyone can test them, and people run them anyway, in big numbers: DavidAU's GGUF of one of the four showed 1,762,401 downloads on 18 October. Three of our four cards claim better scores than the base. On this task the cards told us little. In our setup one of the four had its write tool calls come back malformed. Another wrote careful code and then got stuck hunting for a method that doesn't exist. A third finished first, with placeholders where the grader looks. And the merge got the hardest parts right and still lost its admin page. So what is a card worth for this kind of work? What follows is one task and one build per candidate, on our own 8-bit conversions, our MTP heads and a goose build that isn't released yet. It says what each model did on a 300-call Jira app upgrade on a laptop. It doesn't say any of them is a bad model. Read it as that. Forge 2.0 hands goose, the open-source coding agent we build on, a working Jira app and a long written spec. Goose has to upgrade the app to v2 with no help. A scorer then runs 105 checks against three seeded Jira sites. The Forge 2.0 board https://leanzero.net/agentic-benchmarks/forge?utm source=devto&utm medium=referral&utm campaign=crosspost has the cloud models; the base pair sits on it as one local entry. | model Hugging Face repo | what it is, per its card | builds | score | how it ended | |---|---|---|---|---| | Qwen/Qwen3.8-27B https://huggingface.co/Qwen/Qwen3.8-27B , stock | the base | 2 | 0.2576, 0.1128 | finished both, 300 and 285 calls | | nightmedia/Qwen3.8-27B-MindMeld-OneJev1.6 https://huggingface.co/nightmedia/Qwen3.8-27B-MindMeld-OneJev1.6 | mergekit nuslerp merge | 1 | 0.1105 | used its 300-call budget in 1 h 50 m | | DavidAU/Qwen3.8-27B-TURBO-Fable-Cold-Fusion-735-882-Heretic-Uncensored-NM-DAU https://huggingface.co/DavidAU/Qwen3.8-27B-TURBO-Fable-Cold-Fusion-735-882-Heretic-Uncensored-NM-DAU | multi-stage tune, then Heretic | 1 | 0.0311 | stopped itself at call 162 | | ukisai/Swift-1.5-Qwen3.8-27b https://huggingface.co/ukisai/Swift-1.5-Qwen3.8-27b | RL and OPD post-train | 1 | none | we cancelled it at call 263 of 300 | | nerkyor/Qwen3.8-27B-Coder390-EfficientThink-Opus5.5-GPT6Astra-Grok4.7-DSV4Pro-K3-SFT-RLOO-MTP-DFlash2 https://huggingface.co/nerkyor/Qwen3.8-27B-Coder390-EfficientThink-Opus5.5-GPT6Astra-Grok4.7-DSV4Pro-K3-SFT-RLOO-MTP-DFlash2 | SFT and RLOO coding post-train | 1 | none | we cancelled it at call 165 | I picked all four by hand. I'll call them Coder390, Swift, DAU735 and MindMeld from here on. Hand the scorer the v1 starter app with no model work at all and it gives 0.0617, and one of the four finished under that. A Forge 2.0 score is three numbers multiplied. The first is the work: how much of the product passes, before penalties the base's builds earned 0.7079 and 0.7713 of it . The second is a critical multiplier, 0.6 for each class of serious failure such as a data leak or a forged request that changes something. The third is a reliability multiplier: in each of 19 groups of checks, the worst check that falls short costs up to 10%, and the multiplier never drops below 0.25. The base's 0.2576 is 67 of 105 checks fully passed; its 0.1128 is 69 of 105 with two criticals. We had two days, one Mac and 1 to 9 hours per build. So I set a rule: a candidate whose first build scored below the base's 0.1852 median got no second build. DAU735 and MindMeld fell under it. The base's own build 2 would have fallen under it too, which tells you how rough the rule is. We cancelled Coder390 and Swift before either finished a first build. The base's two builds have run pages: build 1 at 0.2576 https://leanzero.net/agentic-benchmarks/run/brun-4616377e-8e7f-4f34-9ca3-26c2dd8b7d46?utm source=devto&utm medium=referral&utm campaign=crosspost and build 2 at 0.1128 https://leanzero.net/agentic-benchmarks/run/brun-62279942-36e4-4a08-b6bb-6139dce59036?utm source=devto&utm medium=referral&utm campaign=crosspost . The four candidates aren't on the board, because single or cancelled builds aren't published, so their numbers come from our run ledger, their session logs and the verdict files. render at 14:34 and went on grepping for attach eleven more times. I kept the machine, the task and the settings the same for all five. The machine is a team MacBook Pro with an M3 Max and 64 GB of unified memory, with one model loaded at a time and no other apps running, and each build had a 300-call budget at reasoning effort medium with the same registered task payload the cloud baselines get. The agent was a goose test build with Compaction V3 branch t12/compaction-v3, based on 3.0.111, not in a release yet , and the engine was LeanZero's MLX engine, our fork of Rapid-MLX, text-only. We converted all four candidates the same way, from the publisher's full BF16 weights to MLX 8-bit with group size 64 mx.quantize https://ml-explore.github.io/mlx/build/html/python/ autosummary/mlx.core.quantize.html . Each ran with its own MTP weights, converted into our engine's format. MTP, multi-token prediction, is a small extra head trained to guess the next few tokens; the main model then checks the guesses in one pass. The method comes from Gloeckle et al. https://arxiv.org/abs/2404.19737 and DeepSeek-V3's MTP modules https://arxiv.org/abs/2412.19437 , and the checking step is speculative decoding, which Leviathan et al. https://arxiv.org/abs/2211.17192 describe as sampling "without any changes to the outputs". In the pre-launch smoke tests, MTP took Coder390 from 12.3 to 19.9 tokens per second, and Swift, DAU735 and MindMeld accepted about 2.6 to 2.8 tokens per verify step. Coder390's converted 4-bit MTP head was refused by our engine "7 tensor s whose shape disagrees" , so we rebuilt it by hand from the repo's own BF16 MTP weights. From Swift on, a smoke test made three write tool calls on the live engine before each launch; Swift, DAU735 and MindMeld passed 3 of 3. Coder390 ran before we had that test. While each build ran, a 10-minute check-up loop read the tool calls, diffed the model's changes against the starter and looked for broken imports. It grew during the day: the malformed-call check came in the middle of Coder390's run, after we spotted its broken writes by hand, and the repeat check during Swift's. The kill rule was mine: a run that loops or stops making progress gets cancelled. How we got the base to run at all on this Mac is in the compaction write-up https://leanzero.net/blog/compaction-27b-re-reads-keep-tail?utm source=devto&utm medium=referral&utm campaign=crosspost and the MLX MTP speed test https://leanzero.net/blog/llama-cpp-vs-mlx-mtp-apple-silicon?utm source=devto&utm medium=referral&utm campaign=crosspost . The benchmark's admin page has to refuse anyone who isn't a Jira administrator, checked on the server. So the natural call is GET /rest/api/3/mypermissions?permissions=ADMINISTER . Its schema https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-permissions/ says the answer is a map keyed by permission, and the flag is called havePermission . Four models wrote four readings. Swift, in src/admin.js : js const has = res?.permissions ?? .some p = p.permission === 'ADMINISTER' && p.hasPermission ; That treats the map as a list. On the real answer .some isn't a function, so the try catches the error and the check returns false, for real admins too. That's my reading of the code. Swift's build was never scored. Its reasoning before it wrote the line: "Also, I need to check the shape of the mypermissions response: {permissions: {permission: 'ADMINISTER', hasPermission: true} } ." It never did. Its OpenAPI scripts the first died on a missing bracket, the rewrites ran printed each endpoint's parameters and request body, and none of its later calls read a response schema. Coder390 got the map right and the field wrong, if res.permissions?.ADMINISTER?.hasPermission , with the same result by my reading. DAU735 wrote six admin resolvers with no check at all. MindMeld got it right: return res.permissions?.ADMINISTER?.havePermission === true; None of the four candidates printed the schema first, so MindMeld remembered it right and the other two remembered it wrong. My guess at why the wrong memory is hasPermission : Confluence's permission check uses that name, and so does plenty of example code. The transcripts can't show that. But the base did better in a way I like more than being right. Build 1 also believed the wrong format. It said so in a comment: "Real Jira answers an array of { permission, hasPermission }; some mirrors answer the OpenAPI map of key - { havePermission }. Accept both shapes." Then it accepted both, and the scorer gave it 1.0 on both admin checks admin actions apply, non-admin refused . That comment is the most useful line any of the five wrote. Our spec asks for the admin panel in UI Kit, Forge's own component system, where your code never touches the DOM. You build the component tree with @forge/react and hand it to the platform with ForgeReconciler.render