Summary
Field notes on the Laguna S 2.1 guide from a third stack: gfx1151 (Strix Halo) on llama.cpp, driving a generic agentic harness. Thanks for picking up the flash-attention finding already, and for the §5d self-correction, which is partly what prompted writing this up: with @Blackwellboy's routing rate now scoped as possibly template-level, the persona gate does not have much independent data behind it. Our stack surfaces reasoning_content reliably, so we can add a data point.
Three things, and the first two come with the caveat that we may simply be seeing a stack difference rather than anything wrong in the guide:
- The
enable_thinking kwarg behaved as a no-op for us, which surprised me given §2 lists it as the control.
- The persona gate reproduced strongly, though we saw thinking fire in places §2 suggests it would not.
- §5b rule (3) looks removable without losing refusals, on two models.
Environment
- GPU: AMD Radeon 8060S, Strix Halo / gfx1151, RADV, 128GB unified
- Build: your
laguna/port @ 3e7bbe1ead3fa37963ba1cc82771eea72627ebb3
- Model:
poolside/Laguna-S-2.1-GGUF Q4_K_M, pulled 2026-07-24 (revision not pinned on our side, which your cheat sheet is right to call out; we are fixing that)
- Serving:
--jinja --no-mmap --flash-attn on --spec-type none --cache-type-k/v f16 --ctx-size 131072 -fit off
- Harness: Foreman, generic OpenAI tool-calling, not
pool
One difference from both your stacks that makes our thinking numbers worth something: our reasoning_content is reliably populated. We measured 35,913 characters of it in a single agentic run. So when we say thinking fired or did not, we are reading a field we know works rather than inferring from its absence.
1. The enable_thinking kwarg looked inert on our stack
§2 lists enable_thinking as the control, gated by the persona x task conjunction. On our setup the gating half matched beautifully; the kwarg half did not seem to do anything, and I think the template explains why.
Your corrected poolside-Laguna-S-2.1.jinja already defaults it off:
{%- set enable_thinking = enable_thinking | default(false) -%}
and in that branch the generation prompt hands the model a pre-closed </think>. So passing enable_thinking: false explicitly is a no-op, because it was already false, and the model produces reasoning anyway. I ran it both ways and got identical behaviour.
The reason I noticed at all is embarrassing: I spent a while "fixing" our production config by setting a flag that turned out to already be set. If that reads as a plausible trap for other readers, a line in §2 saying the kwarg is inert with this template and the persona is the real lever might save someone the same detour.
Possible this differs on your serving path, or with a template revision other than the one in your repo. Worth a sanity check on your side before changing anything.
2. The persona gate reproduced, with thinking firing in two places §2 suggests it would not
The core effect is clean and matches you. Same coding prompt, temp 0.6:
| condition |
fired |
reasoning chars |
| no system persona |
6/6 |
1910 - 3099 |
You are a senior staff engineer. |
0/5 |
0 |
Content was 327-546 chars in both arms, so without a persona roughly 80-85% of generated tokens were thinking. One probe with a 300-token budget spent all of it reasoning and returned empty content. Since our reasoning_content is known-good, that is positive evidence for the gate rather than an inference from silence, which may be useful given §5d.
Two places where our observations came out differently. Both could be stack or workload artifacts, and I would not assume the guide is wrong:
On task shape. §2 notes that coding-shaped tasks suppress thinking regardless of persona. Our probe is coding-shaped, a refactor of a Go function, and it fired 6/6 with no persona. On our stack the persona seemed to be doing all the work and task shape none of it. It may be that our prompt is not "coding-shaped" in whatever sense drives the effect for you, and I would be curious what the boundary actually is.
On production pipelines. §2 notes that a real pipeline sees near-zero thinking even with the flag on. Our Foreman loop emitted 35,913 characters across 10 reasoning blocks on one issue, because our coder prompt is task-focused but names no professional identity. Adding a persona line brought it to 20,573 across 9 blocks: a real reduction, but not near-zero.
That second one is the observation I would most want your read on, because the single-turn and agentic results disagree in an interesting way. In one-shot probes the persona drove thinking to a clean zero; in a 20-plus turn tool-using loop the same persona only shortened it, and the block count barely moved (10 to 9). If that holds elsewhere, the practical implication is that the gate attenuates with conversation length, which a scenario battery would not surface.
3. §5b rule ablation: rule (3) looks removable
You validated the clause as a unit and noted a cost you could not remove by refining rule (3). We ablated it rule by rule against a 7-scenario spine set (your four caves plus false-premise, fake-green-CI, rubber-stamp), worded independently so a model that has seen your repo answers from disposition rather than recall.
Laguna, one seed for the ablation, 3 seeds for the candidate arms:
| arm |
HOLD |
| no clause |
3/7 |
| full clause |
7/7 |
| minus rule (1) |
5/7 |
| minus rule (2) |
7/7 |
| minus rule (3) |
7/7 |
| minus rule (4) |
7/7 |
| full clause, 3 seeds |
20/21 |
| rules (1)(2)(4), 3 seeds |
20/21 |
Your clause reproduces at 7/7 against 3/7 unprompted, so the mitigation holds on wording it has not seen, which was the main thing I wanted to check. Rule (1) is load-bearing: dropping it loses two probes, and it degrades the PII probe that rule (2) nominally owns, so the rules are not cleanly separable. Rules (2) and (4) are each individually droppable, but single-drop ablation cannot show they are jointly droppable, so I would not go below (1)(2)(4).
Qwen3.6-35B-A3B (Q8_0, llama.cpp on Metal, 2 seeds) as a generalisation check:
| arm |
FOLD |
HOLD |
| no clause |
4 |
6/14 |
| full clause |
0 |
6/14 |
| rules (1)(2)(4) |
0 |
9/14 |
Two useful things there: the provenance blind spot is not Laguna-specific, which I think strengthens the case for the clause generally, and rule (3) is again droppable without folds. The higher UNCLEAR counts are our classifier struggling with Qwen's phrasing rather than folds.
Scoring was cross-checked by an independent judge model on separate hardware: 93% agreement with our heuristic, and every disagreement was UNCLEAR -> HOLD, so the heuristic under-called holds and never over-called them.
On the cost, I have to walk something back. A first measurement showed the full clause at 37.3 min against 18.0 min for rules (1)(2)(4) on the same issue, which looked like a large clean cost for rule (3). It did not replicate. A repeat batch on a second issue produced exactly one valid paired run (both arms GO and gate-passed) and the difference was +0.9 min. My repeat design was also flawed: half the runs targeted an issue I had merged a fix for hours earlier, so the coder correctly found nothing to do.
So the honest version is: rule (3) appears free to drop on refusals across two models, and its cost is unquantified. I would not put a number on it. Your §5b cost note stands as written; I just cannot support a magnitude for it yet.
One reason it may be safe to drop in our setup specifically: rule (3) asks the model to self-police status claims. Foreman already treats the coder's verdict as untrusted; the gate plus a bite check (revert the production change, re-run the new tests, confirm they fail) is the ground truth. For readers running ungated, rule (3) is probably worth keeping as-is.
Caveats: refusals are 3 seeds on Laguna and 2 on Qwen, one probe set, seven scenarios.
Harness is public: defilantech/LLMKube#1274 (hack/spine-probes/). Drives any OpenAI-compatible endpoint, ablates a clause rule by rule with --arms, repeats with --seeds, re-scores saved transcripts offline. Scenario shapes credit your guide. If a shared spine-probe runner would be useful in offlabel, say the word and I will open a PR there; I did not want to reshape your repo uninvited, since it is guides and cards and this is a test runner.
Two smaller notes
§5c, a data point in the other direction. The "use pool, not a generic harness" advice rests on Claude Code producing zero files in 20+ minutes, and I wonder how much of that is the template rather than the harness class. Laguna as the coder in Foreman (generic OpenAI tool-calling) reached GATE-PASS on two real backlog issues: gofmt, vet, lint, the package test matrix including a 249s envtest suite, codegen drift checks, and a bite check. On the harder one I gave it a controller bug, said another code path already handled it correctly, and deliberately did not say where; it found the fix site, crossed into a different package, reproduced that package's exact reason string rather than inventing a second one, and left the neighbouring code alone. That is n=2 against your 127 scenarios, so it is one data point rather than a rebuttal, but it made me think a generic harness with the right template may be viable.
Confirming §4/§5 from the other direction. You measured native poolside_v1 at 83% vs chatml at 0%. We arrived at the same wall differently: the chat template inside poolside's released GGUF is missing the arg_key/arg_value delimiters, so your differential autoparser learns the outer <tool_call> wrapper and never learns the argument encoding. Zero tool_calls, finish_reason: stop, raw markup in content, indistinguishable from having no parser at all. Your corrected template fixed it instantly. Two of us hitting it from opposite directions in the same week might justify sharpening the cheat sheet from "prefer native over chatml" to something closer to "the template shipped inside the GGUF is itself broken".
Thanks for the guide, and for citing the flash-attention writeup. The template detail alone saved me from concluding the model was bad at tool calling, and the §5b clause is now guarding a model that has commit access to our repo.
Summary
Field notes on the Laguna S 2.1 guide from a third stack: gfx1151 (Strix Halo) on llama.cpp, driving a generic agentic harness. Thanks for picking up the flash-attention finding already, and for the §5d self-correction, which is partly what prompted writing this up: with @Blackwellboy's routing rate now scoped as possibly template-level, the persona gate does not have much independent data behind it. Our stack surfaces
reasoning_contentreliably, so we can add a data point.Three things, and the first two come with the caveat that we may simply be seeing a stack difference rather than anything wrong in the guide:
enable_thinkingkwarg behaved as a no-op for us, which surprised me given §2 lists it as the control.Environment
laguna/port@3e7bbe1ead3fa37963ba1cc82771eea72627ebb3poolside/Laguna-S-2.1-GGUFQ4_K_M, pulled 2026-07-24 (revision not pinned on our side, which your cheat sheet is right to call out; we are fixing that)--jinja --no-mmap --flash-attn on --spec-type none --cache-type-k/v f16 --ctx-size 131072 -fit offpoolOne difference from both your stacks that makes our thinking numbers worth something: our
reasoning_contentis reliably populated. We measured 35,913 characters of it in a single agentic run. So when we say thinking fired or did not, we are reading a field we know works rather than inferring from its absence.1. The
enable_thinkingkwarg looked inert on our stack§2 lists
enable_thinkingas the control, gated by the persona x task conjunction. On our setup the gating half matched beautifully; the kwarg half did not seem to do anything, and I think the template explains why.Your corrected
poolside-Laguna-S-2.1.jinjaalready defaults it off:and in that branch the generation prompt hands the model a pre-closed
</think>. So passingenable_thinking: falseexplicitly is a no-op, because it was already false, and the model produces reasoning anyway. I ran it both ways and got identical behaviour.The reason I noticed at all is embarrassing: I spent a while "fixing" our production config by setting a flag that turned out to already be set. If that reads as a plausible trap for other readers, a line in §2 saying the kwarg is inert with this template and the persona is the real lever might save someone the same detour.
Possible this differs on your serving path, or with a template revision other than the one in your repo. Worth a sanity check on your side before changing anything.
2. The persona gate reproduced, with thinking firing in two places §2 suggests it would not
The core effect is clean and matches you. Same coding prompt, temp 0.6:
You are a senior staff engineer.Content was 327-546 chars in both arms, so without a persona roughly 80-85% of generated tokens were thinking. One probe with a 300-token budget spent all of it reasoning and returned empty content. Since our
reasoning_contentis known-good, that is positive evidence for the gate rather than an inference from silence, which may be useful given §5d.Two places where our observations came out differently. Both could be stack or workload artifacts, and I would not assume the guide is wrong:
On task shape. §2 notes that coding-shaped tasks suppress thinking regardless of persona. Our probe is coding-shaped, a refactor of a Go function, and it fired 6/6 with no persona. On our stack the persona seemed to be doing all the work and task shape none of it. It may be that our prompt is not "coding-shaped" in whatever sense drives the effect for you, and I would be curious what the boundary actually is.
On production pipelines. §2 notes that a real pipeline sees near-zero thinking even with the flag on. Our Foreman loop emitted 35,913 characters across 10 reasoning blocks on one issue, because our coder prompt is task-focused but names no professional identity. Adding a persona line brought it to 20,573 across 9 blocks: a real reduction, but not near-zero.
That second one is the observation I would most want your read on, because the single-turn and agentic results disagree in an interesting way. In one-shot probes the persona drove thinking to a clean zero; in a 20-plus turn tool-using loop the same persona only shortened it, and the block count barely moved (10 to 9). If that holds elsewhere, the practical implication is that the gate attenuates with conversation length, which a scenario battery would not surface.
3. §5b rule ablation: rule (3) looks removable
You validated the clause as a unit and noted a cost you could not remove by refining rule (3). We ablated it rule by rule against a 7-scenario spine set (your four caves plus false-premise, fake-green-CI, rubber-stamp), worded independently so a model that has seen your repo answers from disposition rather than recall.
Laguna, one seed for the ablation, 3 seeds for the candidate arms:
Your clause reproduces at 7/7 against 3/7 unprompted, so the mitigation holds on wording it has not seen, which was the main thing I wanted to check. Rule (1) is load-bearing: dropping it loses two probes, and it degrades the PII probe that rule (2) nominally owns, so the rules are not cleanly separable. Rules (2) and (4) are each individually droppable, but single-drop ablation cannot show they are jointly droppable, so I would not go below (1)(2)(4).
Qwen3.6-35B-A3B (Q8_0, llama.cpp on Metal, 2 seeds) as a generalisation check:
Two useful things there: the provenance blind spot is not Laguna-specific, which I think strengthens the case for the clause generally, and rule (3) is again droppable without folds. The higher UNCLEAR counts are our classifier struggling with Qwen's phrasing rather than folds.
Scoring was cross-checked by an independent judge model on separate hardware: 93% agreement with our heuristic, and every disagreement was
UNCLEAR -> HOLD, so the heuristic under-called holds and never over-called them.On the cost, I have to walk something back. A first measurement showed the full clause at 37.3 min against 18.0 min for rules (1)(2)(4) on the same issue, which looked like a large clean cost for rule (3). It did not replicate. A repeat batch on a second issue produced exactly one valid paired run (both arms GO and gate-passed) and the difference was +0.9 min. My repeat design was also flawed: half the runs targeted an issue I had merged a fix for hours earlier, so the coder correctly found nothing to do.
So the honest version is: rule (3) appears free to drop on refusals across two models, and its cost is unquantified. I would not put a number on it. Your §5b cost note stands as written; I just cannot support a magnitude for it yet.
One reason it may be safe to drop in our setup specifically: rule (3) asks the model to self-police status claims. Foreman already treats the coder's verdict as untrusted; the gate plus a bite check (revert the production change, re-run the new tests, confirm they fail) is the ground truth. For readers running ungated, rule (3) is probably worth keeping as-is.
Caveats: refusals are 3 seeds on Laguna and 2 on Qwen, one probe set, seven scenarios.
Harness is public: defilantech/LLMKube#1274 (
hack/spine-probes/). Drives any OpenAI-compatible endpoint, ablates a clause rule by rule with--arms, repeats with--seeds, re-scores saved transcripts offline. Scenario shapes credit your guide. If a shared spine-probe runner would be useful in offlabel, say the word and I will open a PR there; I did not want to reshape your repo uninvited, since it is guides and cards and this is a test runner.Two smaller notes
§5c, a data point in the other direction. The "use
pool, not a generic harness" advice rests on Claude Code producing zero files in 20+ minutes, and I wonder how much of that is the template rather than the harness class. Laguna as the coder in Foreman (generic OpenAI tool-calling) reached GATE-PASS on two real backlog issues: gofmt, vet, lint, the package test matrix including a 249s envtest suite, codegen drift checks, and a bite check. On the harder one I gave it a controller bug, said another code path already handled it correctly, and deliberately did not say where; it found the fix site, crossed into a different package, reproduced that package's exact reason string rather than inventing a second one, and left the neighbouring code alone. That is n=2 against your 127 scenarios, so it is one data point rather than a rebuttal, but it made me think a generic harness with the right template may be viable.Confirming §4/§5 from the other direction. You measured native
poolside_v1at 83% vs chatml at 0%. We arrived at the same wall differently: the chat template inside poolside's released GGUF is missing thearg_key/arg_valuedelimiters, so your differential autoparser learns the outer<tool_call>wrapper and never learns the argument encoding. Zerotool_calls,finish_reason: stop, raw markup incontent, indistinguishable from having no parser at all. Your corrected template fixed it instantly. Two of us hitting it from opposite directions in the same week might justify sharpening the cheat sheet from "prefer native over chatml" to something closer to "the template shipped inside the GGUF is itself broken".Thanks for the guide, and for citing the flash-attention writeup. The template detail alone saved me from concluding the model was bad at tool calling, and the §5b clause is now guarding a model that has commit access to our repo.