self-hosted/ai
§01·recipe · multimodal

Fara1.5-4B on RTX 5060: Blackwell Browser Computer-Use Agent via llama.cpp

multimodaladvanced8GB+ VRAMJul 31, 2026

This advanced recipe sets up Fara1.5-4B on the RTX 5060, needing about 8 GB of VRAM.

models
tools
prerequisites
  • NVIDIA RTX 5060 (8GB VRAM) or equivalent
  • Python 3.10+
  • CUDA Toolkit 12.8 or newer — Blackwell sm_120 is gated behind it
  • llama.cpp built with CUDA (release b10087 or newer)
  • A disposable browser profile — fara-cli drives a plain local Playwright Chromium, unsandboxed

What You'll Build

A local browser computer-use agent (CUA): Microsoft's Fara1.5-4B served by llama-server on an RTX 5060, with the vision projector loaded so the model actually sees browser screenshots, driven by Microsoft's own fara-cli harness against a plain local Playwright Chromium.

Hardware data: RTX 5060 (8GB VRAM, Blackwell sm_120) · Q4_K_M + f16 mmproj = 3.313 GiB of weights, 4.509 GiB total at 32K context (derived below) · See benchmark data

⚠️ This model clicks, types and submits in a real browser — and fara-cli does not sandbox it. That is not boilerplate; it is the operating requirement, and it is the one thing to get right before anything else on this page. The model card is blunt: "Don't run this model with unrestricted browser access on a machine that has anything sensitive on it." Fara also reads whatever is on the page, so a hostile page is a prompt-injection surface.

Be clear about what the tooling gives you. fara-cli drives a plain local Playwright Chromium — no container, no allow-list, no pause control. The sandbox belongs to Magentic-UI, which the harness README describes as "a sandboxed browser environment with auditable action logging and user prompts at critical points" and offers as what you use "instead of fara-cli you can use Magentic-UI". The same README's own note is a recommendation, not a guarantee shipped in the CLI: "We recommend running it in a sandboxed environment, monitoring its execution, and avoiding sensitive data or high-risk domains."

So if you follow the fara-cli path below, you are the sandbox. Practically: run it on a throwaway OS user or VM, let Playwright use its own fresh browser profile (never your daily one), stay logged out of everything, keep tasks on low-stakes public sites, and watch the run rather than leaving it unattended. If you want the container, allow-lists, watch-mode and pause the model card asks for, use Magentic-UI instead — see Running.

ℹ️ Vision is the product, not a bonus. Per the model card, "The model is vision-only at perception time: it sees the browser through screenshots, not the DOM or accessibility tree." A Fara install that only serves text is a broken install — the --mmproj step below is mandatory, and Step 4 exists to prove an image really reached the model before you let it drive anything.

⚠️ Blackwell needs a new enough toolkit. This is the one part of the recipe that is genuinely card-specific: llama.cpp only emits sm_120 code when the CUDA Toolkit it finds is 12.8 or newer. On anything older the Blackwell target is never added at all. Read Installation step 1 before you start.

⚠️ Runtime status — read before you commit an evening to this. llama.cpp support for this architecture is verifiable statically and this recipe shows that evidence, but at the time of writing no published issue thread, user report, or docs entry shows Fara1.5 specifically captioning an image under llama-server or llama-mtmd-cli. The qwen35 text arch and the qwen3vl_merger projector are both first-class in llama.cpp master, and four independent quantisers have converted this model's vision tower successfully — but that is static evidence, not a tested path. Treat the first run as the test. There is also no published speed measurement for this pair (see Results).

What does exist, filed on Blackwell silicon, is llama.cpp #25717: an open, unanswered report of llama-server dying with CUDA error: an illegal memory access was encountered on vision requests, with an mmproj loaded, on an RTX 5070 Ti (Blackwell, sm_120). It is a different model — a 35B mixture-of-experts sibling, not this 4B dense one — and nobody has reproduced it on any Fara build. But the failure it describes lands in machinery this model shares, so Step 3 now passes --flash-attn off and Step 4 runs two vision tests instead of one. Troubleshooting sets out precisely what transfers and what does not; read it before you decide how much of your evening to risk.

Requirements

ComponentMinimumThis recipe
GPU8GB VRAM, CUDA compute 12.0not measured — contribute a run
RAM16GB
Storage3.56 GB (Q4_K_M + mmproj)3.56 GB decimal / 3.313 GiB
Softwarellama.cpp b10087+, CUDA Toolkit 12.8+, Python 3.10+, Playwright

The BF16 weights total 8.455 GiB across two safetensors shards — 5.551 + 2.904 GiB per the HF tree API, corroborated by model.safetensors.index.json's metadata.total_size of 9,078,531,072 bytes. (The whole repo is 8.483 GiB; the extra 0.028 GiB is tokenizer and config files, not weights.) Either way the unquantised path does not fit this card. Microsoft's own Quickstart targets datacenter hardware — the card's requirements line says "A6000, A100, H100, and B200 have been tested", and its highlights claim only that the model "runs on a single A100/H100/B200 with room for the screenshot history". The consumer route is the quantised one documented here.

The VRAM budget, derived

There is no benchmark for this pair yet, so every number below is arithmetic from the artifact's own metadata rather than a measurement.

Weights — byte counts from the bartowski GGUF tree:

ComponentBytesGiB
Fara1.5-4B-Q4_K_M.gguf2,884,850,7842.687
mmproj-Fara1.5-4B-f16.gguf672,423,5840.626
Weights total3,557,274,3683.313

KV cache — and this is where Fara1.5 is unusual. Its qwen35 architecture is a hybrid: llama.cpp's llm_arch_is_hybrid() in src/llama-arch.cpp returns true for LLM_ARCH_QWEN35, and llama-memory-hybrid.cpp splits layers with the filter !hparams.is_recr(il). The GGUF reports qwen35.block_count = 32 and qwen35.full_attention_interval = 4, and the source config.json spells the split out layer by layer: 24 of 32 layers are linear_attention, only 8 are full_attention. So only 8 layers carry a KV cache that grows with context.

With qwen35.attention.head_count_kv = 4 and attention.key_length = attention.value_length = 256:

per layer per token = (4 x 256) + (4 x 256)      = 2,048 elements
x 8 full-attention layers                        = 16,384 elements/token
at f16                                           = 32 KiB/token

The other 24 layers hold a fixed-size recurrent state, sized by llama.cpp's n_embd_r() / n_embd_s() in src/llama-hparams.cpp, fed by the GGUF's ssm.conv_kernel = 4, ssm.inner_size = 4096, ssm.group_count = 16, ssm.state_size = 128:

n_embd_r = (4-1) x (4096 + 2 x 16 x 128)  =    24,576
n_embd_s = 128 x 4096                     =   524,288
(24,576 + 524,288) x 24 layers x 4 bytes  = 50.25 MiB per sequence
x 4 sequences (llama-server's default)     = 201 MiB = 0.196 GiB

That last multiplication is easy to miss and it is not optional. src/llama-model.cpp sizes the recurrent state with /* recurrent_rs_size */ std::max((uint32_t) 1, cparams.n_seq_max) on the branch that names LLM_ARCH_QWEN35, cparams.n_seq_max comes from params.n_parallel, and tools/server/server.cpp resolves the server's auto default with params.n_parallel = 4 — so the allocation is four sequences' worth whether or not you use them. The KV cache is not multiplied: the same default also sets kv_unified = true, so the four slots share one context window rather than each getting their own. The recurrent term stays context-independent, which is what makes it easy to overlook.

Totals on an 8 GB card:

ContextWeightsKV (f16)Recurrent stateSum
16,3843.313 GiB0.500 GiB0.196 GiB4.009 GiB
32,7683.313 GiB1.000 GiB0.196 GiB4.509 GiB
65,5363.313 GiB2.000 GiB0.196 GiB5.509 GiB

The model's full 262,144-token context would need 8 GiB of KV alone — cap it. This recipe uses 32,768, roughly double the harness minimum, leaving ~3 GiB of the card for CUDA context, compute buffers and the vision graph. Those last terms are not in the table: they are allocated at load time and this recipe does not derive them. Read the CUDA0 compute buffer size lines that llama-server prints on startup for the real figures on your build, and report what you see.

One of those undisclosed terms is large, and this recipe deliberately makes it larger. Step 3 passes --flash-attn off (Troubleshooting explains why). With flash attention on, the attention score matrix never exists as a tensor. With it off, src/llama-graph.cpp takes its other branch and builds kq = ggml_mul_mat(ctx0, k, q), forced to GGML_PREC_F32 — an explicit n_kv × n_ubatch × n_head f32 tensor living in the compute buffer. With this model's 16 attention heads (text_config.num_attention_heads) and llama.cpp's default -ub 512, the worst case the graph reservation has to cover is:

32,768 (full attention cache) x 512 x 16 x 4 B  = 1.000 GiB

That is the same order as the entire f16 KV term, and it is the price of the flag. It is an upper bound at reservation time rather than a measurement, and it scales linearly with -ub: -ub 256 halves it, at some cost in prompt-processing speed. The card still has room — ~4.5 GiB of derived state plus ~1 GiB of this leaves over 2 GiB — but budget for it, and check it against the CUDA0 compute buffer size line instead of trusting the arithmetic.

How much context one screenshot costs

A CUA sends a screenshot every step, so this is the number that decides whether the context budget above is honest. It is not the 768 in the projector metadata — that value is derived from num_position_embeddings (√2304 × 16 = 768) as a reference for position-embedding interpolation, and llama.cpp treats this projector as dynamic-resolution: clip.cpp computes n_patches as (nx / (patch_size*2)) * (ny / (patch_size*2)), with a --image-min-tokens / --image-max-tokens pair documented as "only used by vision models with dynamic resolution".

The harness fixes the browser viewport at 1440×900 (fara15_agent.py: viewport_width: int = 1440, viewport_height: int = 900), matching the card's note that "The screen resolution Fara is most commonly trained with is" 1440×900. It then applies Qwen's smart_resize with patch_size=16, merge_size=2, so the factor is 32:

900 -> round(900/32)*32   = 896        1440 -> round(1440/32)*32 = 1440
patch grid  = (896/16) x (1440/16)     = 56 x 90 = 5,040
image tokens = 5,040 / (2 x 2)         = 1,260 tokens per screenshot

The harness keeps max_n_images: int = 3, so 3,780 tokens of any prompt are screenshots. Its own conservative default image_token_estimate: int = 1500 sits just above the derived 1,260, which is a useful sanity check on the arithmetic. Add the computer_use schema in the system prompt plus accumulated reasoning and action history and the harness's own floor makes sense — the repo asks that you "Please ensure that context length is set to at least 15000 tokens and temperature to 0 for best results."

Installation

1. Build llama.cpp for Blackwell (sm_120)

The RTX 5060 is Blackwell, compute capability 12.0sm_120. Everything else on this page is architecture-neutral; this step is not.

llama.cpp's CUDA build file, ggml/src/ggml-cuda/CMakeLists.txt, annotates the target as 120 == Blackwell, needs CUDA v12.8, FP4 tensor cores and then enforces exactly that: the Blackwell architecture is appended to its fallback architecture list only inside if (CUDAToolkit_VERSION VERSION_GREATER_EQUAL "12.8"). A CUDA Toolkit older than 12.8 will not produce sm_120 code, so check nvcc --version before anything else.

The same file also rewrites the number you pass:

# Replace any plain 12X CUDA architectures with their "architecture-specific" equivalents 12Xa.
# 12X is forwards-compatible, 12Xa is not.
# Notably the Blackwell FP4 tensor core instructions are not forwards compatible and therefore need 12Xa.

So 120 becomes 120a, and the configure step prints a Replacing 120 in CMAKE_CUDA_ARCHITECTURES with 120a status line followed by Using CMAKE_CUDA_ARCHITECTURES=.... Do not read those lines as confirmation that the build understood your card. That rewrite is unconditional — it runs on whatever architectures you passed, on any toolkit version — so it prints identically on a CUDA 12.4 install that cannot emit sm_120a at all. nvcc --version is the check that can actually fail; see Troubleshooting. Build from a release at or after b10087; that is the release the GGUF used here was quantised on, and it is an independent floor from the toolkit version.

git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp
cmake -B build -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=120 -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j

Naming the architecture explicitly is the form llama.cpp's build guide documents in its Override Compute Capability Specifications section; leave it out and the build targets whichever card happens to be attached at compile time.

One thing Blackwell adds that this page does not use: the FP4 tensor cores named in that comment. This recipe runs a Q4_K_M GGUF through llama.cpp's ordinary CUDA path and passes no FP4-specific flag anywhere, so nothing here depends on them.

2. Download the weights and the projector

Both files are required. The projector is a separate artifact — downloading only the text GGUF gives you a model that cannot see.

pip install -U huggingface_hub

hf download bartowski/Fara1.5-4B-GGUF \
  Fara1.5-4B-Q4_K_M.gguf mmproj-Fara1.5-4B-f16.gguf \
  --local-dir ~/models/fara1.5-4b

Microsoft publishes no first-party GGUF for Fara1.5 — the microsoft org ships safetensors for all three sizes (and an ONNX repo only for the previous-generation Fara-7B). Four independent community quantisers have converted the 4B including its vision tower — bartowski, prithivMLmods, DevQuasar and runanywhere all ship an mmproj file. Four independent conversions succeeding is the strongest available evidence that the vision path converts cleanly; it is still not a runtime test.

3. Serve it

./build/bin/llama-server \
  -m ~/models/fara1.5-4b/Fara1.5-4B-Q4_K_M.gguf \
  --mmproj ~/models/fara1.5-4b/mmproj-Fara1.5-4B-f16.gguf \
  -ngl 99 -c 32768 --flash-attn off --port 5000 \
  --image-min-tokens 1024 \
  --reasoning-format none \
  --temp 0

Four of those flags are load-bearing and worth understanding rather than pasting:

  • --flash-attn off. This is the Blackwell-specific one, and the reason it is written out rather than left alone is that the default is the risky setting. common/arg.cpp declares the flag as [on|off|auto] and fills its help text from the struct default, which common/common.h sets to LLAMA_FLASH_ATTN_TYPE_AUTO. auto is not "off unless needed": src/llama-context.cpp computes cparams.flash_attn = params.flash_attn_type != LLAMA_FLASH_ATTN_TYPE_DISABLED, so auto starts enabled and is only downgraded if a support probe finds the fused attention node landing on the wrong device. On a CUDA build for this card it does not get downgraded — it resolves to enabled and the startup log says so. Flash attention on is the single strongest trigger in #25717's crash matrix: the only variable there that crashed on its own, with a 19-token prompt. The flag is not free — see the compute-buffer term derived in the budget above — and it does not make you immune, which Troubleshooting is explicit about. What it does is remove the one condition in that matrix which failed unconditionally.
  • --image-min-tokens 1024. The projector ships no image_min_pixels key, so llama.cpp falls back to its Qwen-VL default floor of 8 tokens and prints a warning: "Qwen-VL models require at minimum 1024 image tokens to function correctly on grounding tasks". Fara is a grounding model — it emits pixel coordinates — so this is precisely the case the warning is about. At the harness's 1440×900 viewport the image is already 1,260 tokens and the floor never binds; it protects you if you shrink the viewport.
  • --reasoning-format none. Under llama-server's default reasoning extraction, <think> content is lifted out of the reply into a separate reasoning_content field. Fara's chat template opens every assistant turn with <think> and leaves it open for the model to close, so the default behaviour swallows the whole reply — <tool_call> included — and message.content comes back empty; the agent loop dies on round one. The harness parses the raw text itself: it splits on <tool_call> and feeds the preceding text back as the agent's thoughts. none is documented as "none: leaves thoughts unparsed in message.content", which is exactly what the harness expects.
  • -c 32768. See the budget table. Do not leave it at the model's native 262,144.

And one flag deliberately not added: --kv-unified. #25717's two surviving configurations both ran a unified KV cache, so it is tempting to spell it out. On llama-server it is already the default and adding it changes nothing. common/arg.cpp sets params.n_parallel = -1 (auto) for the server example, and tools/server/server.cpp turns that into n_parallel = 4 and kv_unified = true. What matters is the inverse: do not add --parallel. Passing any explicit value leaves kv_unified at its false default and gives you the split cache that #25717's crashing rows used — and --parallel 4 additionally divides your window, because llama-context.cpp sets n_ctx_seq = n_ctx only for a unified cache and n_ctx / n_seq_max otherwise. With -c 32768 that would hand each slot 8,192 tokens, below the harness's own 15,000-token floor.

4. Prove the vision path works before going further

First read three lines of the startup log: the CUDA0 device line (it must name your 5060 — if the model loaded on CPU, go back to step 1), the flash_attn line (it must report disabled; if it does not, your flag did not take), and the mmproj load stage.

Then check the server advertises multimodal and send a real image. The server README documents image_url as a first-class content part: "can be a remote URL, base64 (raw or URI-encoded via" a data URI "or path to local file".

Test A — is the projector wired up at all?

curl -s http://localhost:5000/v1/models | grep -o multimodal

curl -s http://localhost:5000/v1/chat/completions -H "Content-Type: application/json" -d '{
  "model": "fara",
  "temperature": 0,
  "messages": [{"role": "user", "content": [
    {"type": "text", "text": "Describe this image in one sentence."},
    {"type": "image_url", "image_url": {"url": "https://raw.githubusercontent.com/ggml-org/llama.cpp/master/media/llama0-logo.png"}}
  ]}]
}' | python3 -m json.tool

If the reply describes the picture, the projector is wired up. If it answers as though no image were present, or the server never logged an mmproj load, stop here — the agent loop below will silently produce nonsense actions rather than fail loudly.

Test B — and this is the one that earns its keep on Blackwell. Test A puts only a handful of text tokens in front of the image, the same shape as #25717's short-prompt rows (~19 tokens) — which is exactly what that report describes as passing once flash attention is off. The shape it describes as still crashing is a long text prefix, roughly 800 tokens, ahead of the image. A real agent prompt is the long one. So probe it before you trust the setup:

python3 - <<'PY'
import json, urllib.request
long_text = "Describe precisely. " * 200          # ~800 tokens of text, BEFORE the image
body = {"model": "fara", "temperature": 0, "max_tokens": 128,
        "messages": [{"role": "user", "content": [
            {"type": "text", "text": long_text},
            {"type": "image_url", "image_url": {"url":
                "https://raw.githubusercontent.com/ggml-org/llama.cpp/master/media/llama0-logo.png"}}]}]}
req = urllib.request.Request("http://localhost:5000/v1/chat/completions",
                            data=json.dumps(body).encode(),
                            headers={"Content-Type": "application/json"})
print(urllib.request.urlopen(req, timeout=600).read().decode()[:400])
PY

--image-min-tokens 1024 floors even that small logo at 1,024 image tokens, so the image batch is a realistic size rather than a toy. If Test B returns a description, you have cleared both reported triggers on a build newer than any in the report. If Test B kills the server while Test A passed, you have reproduced #25717 on a new model — check the log for find_slot: non-consecutive token position above the CUDA error, read the Troubleshooting entry, and please post it upstream.

5. Install the harness

git clone https://github.com/microsoft/fara.git
cd fara
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
playwright install

Running

Two client paths share the same llama-server endpoint. Path A (fara-cli) is the smoke test — unsandboxed. Path B (Magentic-UI) is what the vendor recommends for anything real. Pick deliberately; they are not equivalent in risk.

Path A — fara-cli, for a first smoke test

fara-cli speaks to any OpenAI-compatible endpoint. Point it at llama-server:

fara-cli \
  --base_url http://localhost:5000/v1 \
  --api_key sk-no-key-required \
  --model fara \
  --headful \
  --task "how many pages does wikipedia have" \
  --output_folder ./runs/first

Each run writes per-step screenshots and a data_point.json recording the task, actions, observations and outcome to --output_folder. Watch that folder on the first few runs — it is how you tell a grounding failure (clicks landing in the wrong place) from a reasoning failure.

⚠️ --headful is not a convenience flag. fara-cli defaults to headless: run_fara.py passes headless=not args.headful at both call sites (lines 321 and 334), and its argparse help reads "Run the browser in headful mode (show GUI, default is headless)". Drop the flag and a real Chromium still opens, still clicks and still submits — you simply cannot see it, which makes the supervision advice below impossible to follow.

With that flag the command opens a real, unsandboxed Chromium on your desktop — the playwright install in step 5 is what put it there. Keep the task on a low-stakes public site, stay signed out, and stay at the keyboard. Fara is trained to stop and ask before entering personal information, making payments, submitting forms, signing in or sending messages; if you see it sail through one of those, stop the run — that is a wiring problem in your prompt path, not a model quirk you should tolerate.

Path B — Magentic-UI, for the sandbox

Everything the model card asks for — the containerised browser, domain allow-lists, watch-mode and a pause control — lives in Magentic-UI, not in fara-cli. This is where a Docker requirement would come from; there is no Docker step in Path A because Path A genuinely does not use one.

Magentic-UI takes the same OpenAI-compatible endpoint you started above, so nothing on this page changes except the client: per the harness README, "instead of fara-cli you can use Magentic-UI". Its setup is documented in its own repository rather than reproduced here, because this recipe has not verified those steps end to end on this GPU — follow microsoft/magentic-ui and give it http://localhost:5000/v1 as the model endpoint.

Results

  • Speed: omitted — no published measurement exists for Fara1.5-4B on this card, or on any consumer GPU. The only hardware the vendor names is datacenter class, and borrowing a number from it would be misleading for an 8 GB Blackwell card. Note too that Step 3 deliberately runs with flash attention disabled, which costs prompt-processing throughput — so if you do contribute a number, say whether you measured it with the flag as documented or with flash attention on. If you run this, please contribute your numbers so this section can be replaced with a measurement.
  • VRAM usage: 3.313 GiB of weights; 4.509 GiB including KV and the four-sequence recurrent state at 32,768 context, derived above from the GGUF's own metadata and llama.cpp's memory formulas. This is a derivation, not an observed peak — compute and vision buffers are additional. See /check/fara1-5-4b/rtx-5060.
  • Quality notes: the vendor's published scores (80.8 WebVoyager, 57.3 Online-Mind2Web, 27.4 WebTailBench) are for the BF16 model on datacenter hardware. Q4_K_M is a lossy quantisation of a model whose main job is predicting exact pixel coordinates, and no published evaluation measures how much grounding accuracy that costs. If clicks land near-but-not-on targets, step up to Q6_K (3.425 GiB) or Q8_0 (4.185 GiB) before concluding the model is at fault — both still fit this card with the 32K budget above.
  • Language: English only, per the model card's out-of-scope list.

For the full benchmark data, see /check/fara1-5-4b/rtx-5060.

Troubleshooting

The build produced no Blackwell kernels

Check the toolkit itself with nvcc --version — it must report 12.8 or newer. Blackwell's FP4 tensor-core instructions are not forwards-compatible, so an older toolkit cannot produce sm_120a code at all.

Do not try to read this off the configure log. It is tempting to look for the Replacing 120 in CMAKE_CUDA_ARCHITECTURES with 120a status line, but that line proves nothing: in ggml/src/ggml-cuda/CMakeLists.txt the 12X → 12Xa rewrite is unconditional and runs on whatever architectures you passed, so it prints on every toolkit version. The if (CUDAToolkit_VERSION VERSION_GREATER_EQUAL "12.8") gate that appends 120a-real lives inside if (NOT DEFINED CMAKE_CUDA_ARCHITECTURES) — it only assembles the fallback list, and the -DCMAKE_CUDA_ARCHITECTURES=120 in step 1 above defines that variable and skips the whole branch. On too old a toolkit you get a compile error on the 120a target, not a silent omission. If the build fails there, upgrade CUDA and configure into a clean build/ directory rather than reusing the cached one.

CUDA error: an illegal memory access was encountered on a vision request

This is the Blackwell failure worth knowing about, and it is why Step 3 disables flash attention and Step 4 has two tests. llama.cpp #25717 reports llama-server dying with exactly that message on vision requests, preceded in the log by find_slot: non-consecutive token position 774 after 773 for sequence 0 with 2040 new tokens. The reporter bisected seven configurations on an RTX 5070 Ti 16 GB (Blackwell, sm_120), driver 610.74. Two of the seven completed: flash attention off with the default unified cache and a short text prefix, and one where the same long prompt was sent with the image as the first content part. Every row with flash attention on crashed, including one with a nineteen-token prompt. His reading of the mechanism is that Qwen3.5's M-RoPE 3D position ids are mishandled on the flash-attention path, and that the position bookkeeping requires consecutive positions an image batch violates.

What transfers, precisely. The report is about a different model, and the honest summary is same machinery, different model, unverified outcome. On the transfer side:

  • Fara1.5-4B genuinely uses M-RoPE. Its config.json carries rope_parameters.mrope_section = [11, 11, 10] with mrope_interleaved: true, and the GGUF's qwen35.rope.dimension_sections reads [11, 11, 10, 0] — the same section layout the reported model's GGUF carries.
  • Both load a qwen3vl_merger projector at patch_size = 16, spatial_merge_size = 2. Same projector implementation; only the tower's depth and width differ.
  • The warning that precedes the crash comes from src/llama-memory-recurrent.cpp — the recurrent half of the hybrid cache. Its find_slot compares the last position in a batch against cell.pos + n_seq_tokens and warns when they disagree, under the frank source comment "What should happen when the pos backtracks or skips a value?". That check exists because the architecture is hybrid, which is precisely why 24 of this model's 32 layers go through it. It is neither MoE-specific nor size-specific.

Against the transfer:

  • The reported model registers as qwen35moe — a different llama.cpp architecture from this model's qwen35 — with 40 layers to 32 and 2 KV heads to 4.
  • Every row of the matrix ran 24 layers' experts on the CPU (--n-cpu-moe 24) with -b 4096 -ub 4096. A fully-offloaded 4B at llama.cpp's defaults (-b 2048 -ub 512) is a different placement and a different batch split — and the reporter himself lists #19929, "batch-size dependent M-RoPE weirdness", as related.
  • It is one report from one person with no maintainer reply. The thread's only comment is his own follow-up adding reproducers; the only other timeline activity is a different user cross-referencing an unrelated Qwen3.6 bug. No pull request references it, so nothing has been fixed — and nothing has been ruled out either. Its newest build, b10016, is described in the report as "current latest" on 15 July, older than the b10087 floor this recipe builds from, and nobody has re-tested since.

What this recipe does about it. --flash-attn off removes the one condition that crashed unconditionally, and Test B probes the long-prefix trigger before you commit a run. Be clear that this is mitigation, not immunity: in the report, flash attention off still crashed once ~800 text tokens preceded the image, and adding --kv-unified did not save that case either. One piece of luck is on your side — the harness puts the screenshot first in every user turn and the text after it (content=[ImageObj.from_pil(scaled_screenshot), text_prompt] in fara15_agent.py; the opening turn has the same shape with the task instruction), which is the ordering of the row that completed. But Fara's system prompt is long text and still precedes that image in the flattened sequence, and the text history grows every round, so the real shape is neither reported case exactly. Test B is your detector; the first agent run is the experiment.

There is one earlier Blackwell precedent, worth reading for the variables it names rather than as corroboration: #21564, an Xid 43 illegal-memory-access on an RTX 5090 that a bisect pinned to a flash-attention kernel optimisation. It closed with nobody else having reproduced it — an NVIDIA engineer could not on a newer driver and CUDA toolkit, and a maintainer remarked that the report itself looked machine-written. Its durable lesson is that driver and toolkit version were the axis that moved the outcome, so record both if you end up filing anything.

ollama run fara does nothing — there is no Ollama entry

There is no Ollama library entry for Fara1.5 in any form: fara1.5, fara, fara1-5 and fara-7b all 404. The GGUF/LM Studio/Ollama line in the harness README refers to Fara-7B, the previous generation, reached with a --fara-7b flag — it is not about Fara1.5, and a lead aggregator has already mis-attributed it. Likewise, the "run them in your choice of tools" list on the quantiser's card is that quantiser's standard boilerplate, printed with the caveat that a newly supported model may need to wait for an update from the developers; it is not a statement that LM Studio or Jan has tested this model. llama.cpp built from source is the path this recipe verifies.

The model answers but ignores the screenshot

Almost always the projector. Confirm --mmproj is on the command line, that the server logged an mmproj load stage, and that Step 4's curl describes the image. A text-only GGUF paired with no projector loads and runs perfectly happily — it simply cannot see, which in a CUA presents as confidently wrong actions rather than an error.

Clicks land in the wrong place

Check the viewport first. The harness defaults to 1440×900 because that is what the model was mostly trained at; a different window size changes both the grounding distribution and the token cost derived above. Then confirm --image-min-tokens 1024 is set, since llama.cpp's own warning ties sub-1024-token images to degraded grounding. Only after both, suspect the quantisation and try a higher tier.

rope.dimension_sections has wrong array length; expected 4, got 3

This is a real open llama.cpp bug (PR #25334), but it belongs to Ollama-exported qwen35 blobs, not to the GGUF this recipe uses — the PR's own summary scopes it to "GGUF exports that are currently produced by Ollama". The bartowski artifact's metadata reads qwen35.rope.dimension_sections = [11, 11, 10, 0] — four entries — so it cannot hit this failure. If you see this error, you are loading a different file than the one downloaded in Step 2.

Generation is slower than a 4B model should be

There is an open, community-reported performance regression affecting exactly the SSM kernels this architecture leans on — llama.cpp issue #25162 reports a 24-42% loss on an RTX 2080 Ti (Turing, SM75) after commit 9e58d4d69, and notes the Qwen35 architecture uses linear-attention layers for about 75% of its blocks (which matches the 24-of-32 split derived above). Two caveats before you act on it: it still has no maintainer response — both replies on the thread are from community accounts asking whether PR #25185 fixes it — and it was measured only on Turing, while the RTX 5060 is Blackwell (SM120) and nobody has posted numbers for it. Treat it as a lead to check with llama-bench across a couple of builds, not as a known property of this card.

Out of memory at load

Do not reach for the usual --cache-type-k q8_0 --cache-type-v q8_0 here. With the --flash-attn off this recipe needs, a quantised V cache is not a slow path or a warning — it is a refusal to start. src/llama-context.cpp rejects the pair outright, logging "quantized V cache requires flash_attn to be enabled" and returning a null context; a second guard inside the constructor throws "quantized V cache was requested, but this requires Flash Attention". It is the most-copied OOM remedy on the internet and it is the one thing you must not paste here.

Quantising the K half alone is legal without flash attention and the gate confirms the dimensions work: block_q8_0 is one ggml_half scale plus 32 int8_t quants — 34 bytes per 32 values against f16's 64 — and n_embd_head_k of 256 divides the block size cleanly. Per token, across the 8 full-attention layers:

K: 8 x 4 x 256 = 8,192 elems -> f16 16.0 KiB  ->  q8_0 (8,192/32) x 34 B = 8.5 KiB
V: 8 x 4 x 256 = 8,192 elems -> f16 16.0 KiB  ->  unchanged            = 16.0 KiB
total per token                    32.0 KiB   ->                         24.5 KiB

so --cache-type-k q8_0 takes the KV term from 1.000 GiB to 0.766 GiB at this recipe's 32,768 context. In descending order of what the levers actually buy you on this card:

LeverFreesCosts you
-c 163840.500 GiBhalf the window; still above the harness's 15,000-token floor
-ub 256~0.500 GiBprompt-processing throughput — it halves the flash-attention-off score matrix
--cache-type-k q8_00.234 GiBa little K-cache precision; needs no flash attention
--no-mmproj-offload0.626 GiBslower image encoding, once per agent turn, on the CPU

Keep the f16 projector rather than swapping in a q8_0 one: at 0.626 GiB it is not where the savings are, and it trades vision fidelity in a model whose entire job is looking at pixels. If you need the projector out of VRAM, move it to the CPU with --no-mmproj-offload instead of quantising it.

common questions
How much VRAM does Fara1.5-4B need?

About 8 GB — the minimum this recipe targets.

Which GPUs is Fara1.5-4B tested on?

RTX 5060 (8 GB).

How hard is this setup?

Advanced — follow the steps above.