Dinoer

Architecture

How a research campaign runs, and what leaves your machine by which door, with the file of the code behind each line.

How a research campaign runs

manifest.json
     │  campagne.py
     ▼
SearXNG  ── queries
     ▼
light HTTP fetch  ──►  real browser (only if the page does not suffice)
     ▼
collecte.jsonl  +  operations.jsonl
     ▼
OpenCode  ── ranking, then the report
     ▼
rapport_<timestamp>.md
  1. The manifest is a JSON file of targets: a query for SearXNG, a fixed url, a produit (find the one page that really is the product page), or a table_reference (a list of trusted domains for a subject). Only the campaign identifier and the targets are required.
  2. Discovery. A query target goes to the SearXNG instance you configured, which in turn queries other search engines that Dinoer does not control.
  3. Collection. Each page is fetched with a plain HTTP request, after its robots.txt has been read. Only a page whose text cannot be read that way goes to a real browser, one Playwright process per page. A target that fails does not stop the others.
  4. The corpus. One collecte.jsonl per campaign, one line per page retained, and operations.jsonl, which records every attempt, failed or not.
  5. The report. The pages are reordered (by time window and by local embeddings, when the manifest asks for it), cut to a size budget, and handed to OpenCode, which writes the body of rapport_<timestamp>.md. Dinoer appends the list of sources itself; the model never writes it.

shot.py and rpa.py work differently: each call is its own process and ends as soon as it has answered. Why →

What leaves your machine, and by which door

WhatWhere it goesWho decidesIn the code
Discovery queriesthe SearXNG instance you configured, which queries other engines in turnyou, with DINOER_SEARXNG_URLlib/searxng.py
Page requestseach site directly, its robots.txt read firstthe targets in your manifestlib/fetch_leger.py, rpa.py
Collected textthe OpenCode model you name, for the report, for targeted extraction, and to choose a product page (the first 1,500 characters of each candidate)you, with DINOER_OPENCODE_MODELlib/modeles.py, lib/synthese.py, lib/extraction.py, lib/selection_candidats.py
A subject, for a reference tablethe same OpenCode model, the subject only, when no table exists for it yetthe table_reference targetlib/tables_reference.py
Embeddingsyour local Ollama, http://localhost:11434: the text stays on the machine unless you point DINOER_OLLAMA_URL elsewhereyoulib/vector.py
A notificationa ntfy server, https://ntfy.sh unless you set another: the campaign identifier and the number of sources. Only when a ntfy topic is setyou, with ntfy_topic, DINOER_NTFY_TOPIC, DINOER_NTFY_URLcampagne.py, lib/ntfy.py
Your credentialsnowhere: resolved inside the Playwright process, from the encrypted directory—lib/repertoire_chiffre.py

Source: the code of version 1.0.1, read on 27 September 2026. The models listed under opencode/ are hosted by their provider (opencode.ai/zen, according to opencode models --verbose, OpenCode 1.18.32). What the model may do with the web is on the trust page.

In detail