Technical choices
Eight decisions that shaped Diwall, each with the reason behind it and the price it costs. Including the one that makes your first run fail on purpose.
Every choice below costs something. Listing the benefit without the price would make this page an advertisement rather than a document you can evaluate.
A number instead of a description
Set-of-Mark numbers every interactive element and returns those numbers with
the capture. Acting means naming a number: {"id": 7}.
The alternative — asking a model to describe the element it wants, or to produce a CSS selector from an image — puts the identification burden on the weakest link. A number is unambiguous by construction: three identical buttons get three different numbers.
The price. Numbers are computed per capture and shift when the document
changes. A number is valid for the state it was read from, never across
sessions. Since v1.24.0 the resolver holds a number to its element when it
can: after a Set-of-Mark capture earlier in the same scenario, it resolves by
the data-dw-som-id marker that capture left; without one, it falls back to
re-indexing the live page. Any disagreement between the two paths is reported
in boussole.respect.som_derive_detectee, and --som-brut restores pure
re-indexing. The recipe It clicked, but not on the element you
meant shows it at work.
Local by default, remote only if you say so
Image analysis runs on your machine: --llm local, an Ollama instance on
localhost. --llm claude sends the image to a remote API instead — it exists,
it is documented, and it is never the default. This covers the image analysis
Diwall does itself; the model that drives Diwall reads the capture in any case,
and where that goes is on What Diwall does not do behind your
back.
The reason is simple: a screenshot of an authenticated interface is one of the most sensitive artefacts a tool can produce. Where it goes should be a decision, not an inherited setting.
The price. Local vision models are smaller than hosted ones. For the tasks Diwall actually needs — locating an element that has no semantic representation — that has been enough. For subtler visual reasoning, it is a real limit.
Declared identity, not disguise
Diwall does not pretend to be a human browser by default. --stealth exists
for the cases where you decide otherwise; it is opt-in and it is your call,
because you answer for the traffic you send.
The price, and it is not small. Some sites refuse an agent that announces itself, where they would have served a browser that said nothing. A real campaign across 23 commercial sites: 39 % blocked by a WAF. That is what the position costs, measured rather than assumed.
Signals, never verdicts
Diwall reports what it noticed and lets you decide. etat.pret_a_agir: false
means I saw something — a WAF signature, a session drift — not I refuse to
work. The WAF detection is keyword-based and can be wrong; it is exposed as a
count, never as an exception that halts the run.
The opposite design — a tool that blocks when it thinks something is off — turns every false positive into an outage, and teaches its users to disable the check.
The price. You have to read the answer. A caller that looks only at
succes gets no benefit from any of these signals.
The lock that makes your first run fail
Diwall refuses to execute until whoever drives it has read the guide and can quote its version number.
Diwall is not in any model’s training data, and a model that has not read the guide improvises. That is not hypothetical: it caused a documented security violation, and this lock is the answer. What improvising looks like, and the two rules that prevent it →
The price. Your first call fails, deliberately, with
{"succes": false, "erreur": "guide_non_lu"}. Every documented command carries
--guide-version. It is friction, it is on purpose, and it is the single most
questioned decision in the project.
The guide is never translated
The human-facing documentation exists in four languages. The guides that models read exist in English only, and that is not an oversight.
A translated guide can desynchronise silently. Its version number gets mechanically resynchronised while its content is still the previous version — and an agent then passes the lock having read obsolete instructions. That is precisely the failure the lock exists to prevent, reintroduced by the translation itself.
A model reads English natively and English costs fewer tokens: the benefit is nil, the risk is real.
The price. A non-English-reading operator who wants to understand what their agent was told has to read English. The human documentation covers that gap; the guide does not.
The order is declared once
The reference PDF assembles several documents. Their order is declared in a manifest, once, and shared by every language — never inferred from the filesystem.
An implicit order is never the pedagogical order. That is how a manual ends up presenting uninstallation before installation. And if each translation redeclared its own, four PDFs would end up with three different orders and nobody would notice until a reader followed the wrong one.
Any document in the perimeter that appears in neither the order nor the motivated exclusions fails the build. Loudly, rather than dropping out of the PDF in silence.
One process per call, not a server
Diwall is a command the model runs at each step, not a service it connects to. Between two calls, nothing is listening. The first question an engineer asks is why it is not a server — one speaking a protocol such as MCP, say.
What the choice gives: no service listening on a port; one call, one entry in
the operations log; the --guide-version lock checked on every call; any
model that can run a shell command drives Diwall, with no protocol client to
install; a scenario stays a declarative file, validated before the browser
starts.
The price. The live state of the page does not survive between two calls.
Cookies and storage do, through --sauver-session and --reprendre-session;
a ticked checkbox or a half-filled form does not. Hence the rule: a sequence
with state belongs in one scenario. → The session does not survive between
two calls
What the choice does not change, because the question tends to bring these along:
- The transport does not decide where a credential is resolved. A
depuis_secretsreference would stay a reference under any protocol. - A protocol decides nothing. The agent decides, either way.
- A hosted model that reads the capture receives it, whatever carries it.
In short
- A number is unambiguous; a description is not.
- Local by default because a screenshot of an authenticated page is sensitive.
- Declared identity, and 39 % of a real panel refused it.
- Signals rather than verdicts — you decide, so you must read.
- The first run fails on purpose, and that is the point.
- The guide is not translated, because a stale translation defeats the lock.
- The order of the documents is declared once, and a forgotten one fails the build.
- One process per call: nothing listens, and page state lives in one scenario.