What You'll Build
A local browser computer-use agent (CUA) on AMD hardware: Microsoft's Fara1.5-4B served by llama-server built against ROCm/HIP on an RX 7900 XTX, 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: RX 7900 XTX (24GB VRAM) · BF16 weights + f16 mmproj = 8.472 GiB, 10.668 GiB total at 65,536 context (derived below) · See benchmark data
⚠️ This model clicks, types and submits in a real browser — and
fara-clidoes 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-clidrives a plain local Playwright Chromium — no container, no allow-list, no pause control. The isolation belongs to Magentic-UI / MagenticLite: the harness README describes it as "a sandboxed browser environment with auditable action logging and user prompts at critical points" and offers it as what you use "instead of fara-cli you can use Magentic-UI", while the model card attributes the Docker-contained browser — "the browser runs in a Docker container with no access to host files or environment variables" — to MagenticLite and then says plainly: "If you integrate Fara1.5-4B directly, you're responsible for these controls."So if you follow the
fara-clipath below, you are the boundary. 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
--mmprojstep below is mandatory, and Step 4 exists to prove an image really reached the model, on the GPU, before you let it drive anything.
⚠️ This is the first AMD/ROCm recipe for this model — read what is and is not established. llama.cpp's multimodal layer is backend-agnostic by construction:
tools/mtmd/clip.cppis 260 KB of source containing zero occurrences ofcuda,hip,rocmor any backend#ifdef. It asks ggml for whatever GPU backend exists (ggml_backend_init_by_type(GGML_BACKEND_DEVICE_TYPE_GPU, ...)) and always puts the CPU backend into the same scheduler as a per-op fallback. The backend HIP compiles —ggml/src/ggml-cuda/ggml-cuda.cu— carries only 13GGML_USE_HIPguards across 221 KB, all in the vendor-API shim near the top of the file, none of them in the op dispatch or in thesupports_optable. There is no separate "HIP op set"; it is one backend compiled twice.What is not established to the standard of a benchmark: there is exactly one public report of a
qwen3vl_mergerprojector decoding correctly on an AMD device, and it is a passing remark. In llama.cpp issue #20081 the reporter — a community user, not a maintainer — writes "ROCm (over RPC) works perfectly fine with the same image", contrasting it against the Vulkan failure that thread is actually about. Two caveats: it went through the RPC backend rather than a plain local ROCm build, and the same thread's logs show this projector loading and encoding under Vulkan, a different non-CUDA backend. So: the structural argument above is strong, one real run agrees with it, and nobody has published a measurement. Treat your first run as the test and use Step 4, which reads llama.cpp's own load-time self-report rather than asking you to trust this paragraph. There is also no published speed measurement for this pair (see Results).
Requirements
| Component | Minimum | This recipe |
|---|---|---|
| GPU | 16GB VRAM, officially ROCm-supported RDNA3 | RX 7900 XTX (24GB) — not measured; budget below is derived (/contribute) |
| RAM | 16GB | — |
| Storage | 9.10 GB (BF16 + mmproj) | 9.10 GB decimal / 8.472 GiB, plus the harness and Playwright's Chromium |
| Software | Linux, ROCm, llama.cpp b10087+ (HIP), Python 3.10+, Playwright | — |
Two notes on that table. min_vram_gb is 16, not 24 — it is the filter floor for the install documented here, not this card's capacity. The BF16 configuration below accounts for 10.668 GiB at 65,536 context, which clears a 16GB RDNA3 card comfortably; on the 16GB RX 7800 XT the only change is -DGPU_TARGETS=gfx1101 at build time, since that die is Navi 32. And the GPU cell is not a measurement — /check/fara1-5-4b/rx-7900-xtx has zero benchmarks and nothing on this page was run on hardware by us.
Why this card runs the model at the vendor's own precision
The 8GB RTX 3060 Ti recipe for this model has to quantise to Q4_K_M, and it says openly that no evaluation exists for what 4-bit costs a model whose entire job is predicting pixel coordinates. That trade-off does not exist here. The model card's Requirements section asks for "A GPU with enough memory for a 4B model in bf16 (A6000, A100, H100, and B200 have been tested)" — and a 24GB RDNA3 card has that. The BF16 GGUF is 7.846 GiB; the projector adds 0.626 GiB. So this recipe runs the model unquantised, at the precision the vendor specifies, and still has room for the model's full 262,144-token native context.
The precision is also a good fit for the silicon rather than a compromise on it. RDNA3's WMMA units take FP16 and BF16 natively, and llama.cpp names the architecture explicitly in its BF16 matrix-multiply path: at ggml-cuda.cu:1511 a BF16 compute type keeps BF16 output on RDNA3 and CDNA while every other architecture is downgraded to an F32-output fallback, and common.cuh:79 defines that architecture constant as 0x1100 — this card's exact gfx target — with the comment "RX 7000, minimum for WMMA". BF16 is not merely tolerated on gfx1100; it is one of two architectures special-cased in its favour.
Two file-level choices follow from the artifacts rather than from taste. The text weights are BF16 because the source model is BF16 ("dtype": "bfloat16"), so Fara1.5-4B-bf16.gguf is a file-format conversion with no numeric loss — bartowski's card calls it "Full BF16 weights." The projector is the f16 build, not the bf16 one, on precision grounds: at equal size F16 carries 10 mantissa bits against BF16's 7, and the projector is the stage that turns patch embeddings into the coordinates this model clicks on — the half where you would rather spend precision than range. (Do not justify this from vision_config.dtype: "float32" in config.json. That field does not describe what is in the repo — text_config.dtype says float32 too, while the dtype census over the actual weights is {"BF16": 4539265536}, one dtype across all 723 tensors. The stored weights are BF16 throughout, vision included, which makes mmproj-Fara1.5-4B-bf16.gguf the byte-faithful build and the f16 taken here a deliberate re-encode.)
The VRAM budget, derived
There is no benchmark for this pair, so every number below is arithmetic from the artifacts' own metadata rather than a measurement.
Weights — byte counts from the bartowski GGUF tree:
| Component | Bytes | GiB |
|---|---|---|
Fara1.5-4B-bf16.gguf | 8,424,393,568 | 7.846 |
mmproj-Fara1.5-4B-f16.gguf | 672,423,584 | 0.626 |
| Weights total | 9,096,817,152 | 8.472 |
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). Reading the GGUF header of the exact file downloaded below gives qwen35.block_count = 32 and qwen35.full_attention_interval = 4, and the source config.json spells the split out layer by layer: its layer_types array is 24 linear_attention entries and only 8 full_attention. So only 8 of 32 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 a 24 GiB card, BF16 weights throughout:
| Context | Weights | KV (f16) | Recurrent state | Sum | Slack |
|---|---|---|---|---|---|
| 32,768 | 8.472 GiB | 1.000 GiB | 0.196 GiB | 9.668 GiB | 14.3 GiB |
| 65,536 | 8.472 GiB | 2.000 GiB | 0.196 GiB | 10.668 GiB | 13.3 GiB |
| 131,072 | 8.472 GiB | 4.000 GiB | 0.196 GiB | 12.668 GiB | 11.3 GiB |
| 262,144 (native) | 8.472 GiB | 8.000 GiB | 0.196 GiB | 16.668 GiB | 7.3 GiB |
That last row is the point of a 24GB card on a 4B model: the architecture's full native context fits alongside unquantised weights, which no 8GB or 12GB card can do at any quantisation. This recipe uses 65,536 — four times the harness's documented floor, with a very large margin — because a CUA's context is dominated by accumulated action history, not by screenshots (only three are ever kept), and there is no reason to spend 6 GiB of KV you will not fill. Move up if your trajectories are long.
The slack column is not free space you can plan against to the last byte: compute buffers, the HIP context and the vision encoder's working set are allocated at load time and this recipe does not derive them. Read the buffer-size lines llama-server prints on startup for the real figures on your build, and report what you see.
If you would rather trade precision for footprint, the same repo's Fara1.5-4B-Q8_0.gguf is 4.185 GiB and Fara1.5-4B-Q4_K_M.gguf is 2.687 GiB; both are one-word substitutions in Step 2 and Step 3, and both leave the derivation above unchanged except for the weights row.
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: --image-min-tokens is documented as the "minimum number of tokens each image can take, 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. The projector's own GGUF header gives clip.vision.patch_size = 16 and clip.vision.spatial_merge_size = 2, so Qwen's smart_resize 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."
Keep that 1,260 in mind for the ROCm section below: it means every single agent step submits a prompt-processing batch well over a thousand tokens. This workload never sits in the "small request" regime, which is exactly the regime where one gfx1100 ROCm bug reported working behaviour.
Installation
1. Build llama.cpp with ROCm/HIP for gfx1100
Build from a release at or after b10087 — that is the release the GGUFs used here were quantised on. The gfx target is not optional to get right: llama.cpp's build documentation states that "The above example uses gfx1100 that corresponds to Radeon RX 7900XTX/XT/GRE."
git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp
HIPCXX="$(hipconfig -l)/clang" HIP_PATH="$(hipconfig -R)" \
cmake -S . -B build -DGGML_HIP=ON -DGPU_TARGETS=gfx1100 -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -- -j 16
Three things this build deliberately does not do, all of them habits carried over from CUDA recipes:
- No
flash-attnpackage, noxformers. llama.cpp's attention lives inside ggml; there is no Python attention library to install, and the CK build of the standalone FlashAttention project does not target consumer RDNA3 anyway. The vision tower probes its own flash-attention support against whichever backend it got and reports the result — Step 4 shows you where. - No quantisation-kernel extras. No CUDA-only INT4 kernel path applies here and none is needed: BF16 is a first-class ggml type on this architecture.
-DCMAKE_BUILD_TYPE=Release, notDebug. See the first troubleshooting entry; a Debug build has been reported to emit invalid device code on Radeon under some ROCm versions.
HSA_OVERRIDE_GFX_VERSION is not needed on this card — the RX 7900 XTX is an officially supported gfx1100 target. Configs that set it for a 7900 XTX are copying a workaround meant for cards ROCm does not ship kernels for.
There is also an official prebuilt image, ghcr.io/ggml-org/llama.cpp:server-rocm, if you would rather not build a toolchain. Read llama.cpp's own caveat before relying on it — "The GPU enabled images are not currently tested by CI beyond being built." — and note that it pins its own ROCm version (ROCM_VERSION=7.2.1 in .devops/rocm.Dockerfile), which is the variable the first troubleshooting entry is about.
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-bf16.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, a different model). Four independent community quantisers have converted the 4B including its vision tower — bartowski, prithivMLmods, DevQuasar and runanywhere all ship an mmproj file, and three of them ship a full-precision text GGUF as well. Four independent conversions succeeding is the strongest available evidence that the vision path converts cleanly; it is still not a runtime test on this backend.
3. Serve it
./build/bin/llama-server \
-m ~/models/fara1.5-4b/Fara1.5-4B-bf16.gguf \
--mmproj ~/models/fara1.5-4b/mmproj-Fara1.5-4B-f16.gguf \
-ngl 99 -c 65536 --port 5000 \
--image-min-tokens 1024 \
--reasoning-format none \
--temp 0
Three of those flags are load-bearing and worth understanding rather than pasting:
--image-min-tokens 1024. The projector ships noimage_min_pixelskey, 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. By defaultllama-serverextracts<think>content out of the reply and into a separatereasoning_contentfield. Fara's chat template opens every assistant turn with<think>and never closes it, so under that default the whole reply — including the<tool_call>block the harness needs — lands inreasoning_contentandmessage.contentcomes back empty, killing the agent loop on round one. The harness parses the raw text itself, splitting on<tool_call>.noneis documented as "none: leaves thoughts unparsed inmessage.content", which is exactly what the harness expects.-c 65536. See the budget table. Do not leave it at the model's native 262,144 unless you have decided to spend 8 GiB on KV.
Leave --flash-attn alone. The vision context probes flash-attention support against the backend it actually got and falls back with a warning if the backend cannot serve it, which is the behaviour you want on a platform where that answer is build-dependent.
4. Prove the vision path is running, and running on the GPU
This step matters more on AMD than it does on CUDA, because it is where the open question of this recipe gets answered on your machine in about ten seconds. llama.cpp reports its own multimodal wiring at load. In the startup log, find three things:
- A line of the form
clip_ctx: CLIP using <backend> backend—clip.cppemits this as"CLIP using %s backend"with the backend's own name. If it saysCPU, the projector is not on the GPU at all and image encoding will be slow. flash attention is enabledorflash attention is disabled. Either is fine.disabledcosts memory, not correctness.- Whether the warning block "WARNING: the CLIP graph uses unsupported operators by the backend" appears.
clip.cppwalks every op in the vision graph after warmup and lists any the chosen backend cannot accelerate, naming the backend. Absence of that block is a direct, first-party statement that the ROCm backend accelerates the wholeqwen3vl_mergergraph on your card — which is the claim this recipe deliberately does not make on your behalf. If the block appears, it also prints the exact op names and shapes, and asks you to file them upstream; please do, and tell us too.
Then send a real image. The server README documents image_url as a first-class content part, accepting a remote URL, base64, or a local path:
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, stop here — the agent loop below will silently produce nonsense actions rather than fail loudly.
5. Install the harness
The harness is hardware-neutral: it is a Python client that speaks to any OpenAI-compatible endpoint over HTTP and drives Playwright locally, with nothing vendor-specific anywhere in it. Its documented primary platform is also Linux — the README's Installation section leads with "The following instructions are for Linux systems, see the Windows section below for Windows instructions." — which is the same platform ROCm requires, so there is no impedance mismatch to work around.
git clone https://github.com/microsoft/fara.git
cd fara
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
playwright install
Skip the [vllm] extra the README offers. You are hosting with llama-server, and it pulls a large dependency tree you will not use.
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.
⚠️
--headfulis not a convenience flag.fara-clidefaults to headless:run_fara.pypassesheadless=not args.headfulat 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. 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, on any AMD GPU, or on any consumer GPU at all. The only hardware the vendor names is datacenter class, and borrowing a number from it would be misleading here. If you run this, please contribute your numbers so this section can be replaced with a measurement.
- VRAM usage: 8.472 GiB of weights; 10.668 GiB including KV and the four-sequence recurrent state at 65,536 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/rx-7900-xtx.
- Quality notes: unlike the smaller-card recipes for this model, nothing here is quantised, so the usual "does 4-bit hurt a coordinate-predicting model" caveat does not apply — this is the vendor's own BF16 precision. The vendor's published scores for this size — 80.8 ± 2.3 WebVoyager, 57.3 ± 4.3 Online-Mind2Web, 27.4 ± 2.8 WebTailBench v1.5, averaged over three runs — are therefore at the same precision you are running, which is not something the quantised recipes for this model can say. The paper does not state which hardware produced those evals, so treat the precision match as the only transferable part; nothing about them speaks to an RDNA3 card.
- What ROCm changes, and what it does not. The architecture is fully registered in mainline llama.cpp and its multimodal layer contains no backend-specific code, so nothing about this model is CUDA-dependent by design. What ROCm changes is the maturity of the stack under ggml — see Troubleshooting, where the one gfx1100-specific failure this workload can actually hit is a ROCm toolchain issue rather than anything to do with Fara.
- Language: English only, per the model card's out-of-scope list.
For the full benchmark data, see /check/fara1-5-4b/rx-7900-xtx.
Troubleshooting
ROCm error: device kernel image is invalid — the one gfx1100 trap this workload triggers by design
This is worth knowing about before you start, and it has nothing to do with Fara. llama.cpp issue #23934 reports it on an RX 7900 XTX (gfx1100, ROCm 7.11, clang 22, Ubuntu 22.04): small requests completed fine, larger ones aborted in the HIP runtime. One scoping caveat that cuts in this recipe's favour: every instance reported in that thread involves a quantised model, and the closing comment scopes its own fix to "with quantized models" — this recipe leads unquantised BF16, so it may well never see this. Read the entry as a trap to recognise rather than one to expect. Two community answers, in order:
- Build Release, not Debug. A commenter identified "with ROCm 7.11 on Radeon GPUs where the LLVM backend emits invalid instructions at -O0" as a known ROCm-side defect, hitting only larger matrix kernels — which is why small requests looked healthy. Use
RelWithDebInfoif you need symbols. - Upgrade ROCm. Release alone did not fix it for the reporter, who later closed the issue with: "If you're hitting
ROCm error: device kernel image is invalidon gfx1100 (RX 7900 XTX) with quantized models, this is the fix." — the fix being a move from ROCm 7.11 / clang 22 to a newer ROCm and clang, plus a current amdgpu DKMS driver. Both answers are from community accounts, not llama.cpp maintainers.
Why this matters more here than for a chat model: a CUA submits a 1,260-token screenshot on every single step, so this workload is permanently outside the "small request" regime where the bug stays hidden. If you are going to hit it, you will hit it on step one rather than discovering it a week later. That makes a current ROCm the cheapest insurance on this page.
Don't reach for Vulkan to fix the vision half
For text generation on gfx1100 the Vulkan backend is a legitimate thing to A/B against ROCm, and sometimes wins. That advice does not transfer to the projector. llama.cpp issue #20081 reports vision output badly degraded on Vulkan versus CUDA for specific images with a qwen3vl_merger projector — the reporter's log shows projector: qwen3vl_merger under CLIP using Vulkan0 backend. Read it as a caution rather than a verdict: the Vulkan backend maintainer could not reproduce it, and the reporter's Vulkan device was an RDNA3 integrated GPU, not this card. Still, if you are going to move the vision half off ROCm, check its output rather than assuming parity. You can move the projector independently of the text model with the MTMD_BACKEND_DEVICE environment variable, which clip.cpp reads to pick a named backend for the CLIP context only.
You do not need HSA_OVERRIDE_GFX_VERSION on this card
It appears in a lot of copy-pasted AMD configs, sometimes with a comment claiming it is critical for the 7900 XTX. It is not. The override exists to make ROCm treat an unsupported die as a supported one; gfx1100 is an officially supported target and ships real kernels. Setting it here changes nothing at best.
Do not enable MTP speculative decoding
The qwen35 architecture carries a multi-token-prediction layer (mtp_num_hidden_layers: 1 in this model's config.json), and llama.cpp can use it as a self-draft with --spec-type draft-mtp. Don't, for now: issue #23244 collects OOM-on-first-decode reports with MTP enabled, including one on an RX 7900 XTX / gfx1100. Note carefully that this is not an AMD bug despite the issue's title — the same thread has reporters hitting it on NVIDIA hardware too, and the suspected cause is the memory-fit estimator undercounting MTP. Nothing in this recipe enables it.
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 a CLIP using … line, 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. On this card there is no third suspect to reach for — you are already running unquantised weights, which is the step a smaller-VRAM install has to hold in reserve.
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. Reading the header of Fara1.5-4B-bf16.gguf directly gives qwen35.rope.dimension_sections = [11, 11, 10, 0] — four entries — so this file cannot hit that failure. If you see this error, you are loading a different file than the one downloaded in Step 2.
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, fara1.5-4b 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. Likewise, the "run them in your choice of tools" list on the quantiser's card is that quantiser's standard boilerplate, not a statement that any of those runtimes has tested this model. llama.cpp built from source is the path this recipe documents. That is a slightly bigger loss on AMD than elsewhere, since Ollama is usually the cleanest ROCm on-ramp — but it does not exist for this model, so llama-server it is.
Out of memory at load
You have a lot of levers here, in order of preference: drop to -c 32768 (saves 1.0 GiB of KV, still far above the harness's 15,000-token floor), step the text weights down to Fara1.5-4B-Q8_0.gguf (saves 3.66 GiB), or add --no-mmproj-offload to keep the vision projector in system RAM (saves 0.626 GiB at the cost of slower image encoding). Keep the f16 projector rather than 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.