Graph Engineering with AI: A Case from Our Own Operations
Graph engineering with AI is currently an absolute buzzword in the AI world. This real case documents something else: there is nothing mystical about it, and it has nothing whatsoever to do with rocket science. It is simply how you build an AI-supported process today when it has to run unattended.
Graph engineering sounds at first like a category of tools. In fact it is a precise decomposition: work is cut into individual steps, transitions are formulated as logical conditions, and state is stored explicitly. The result is a clearly defined graph of nodes and edges.
The real benefit only shows in the question that cannot even be asked without this decomposition: which node actually needs an AI agent, and which does not? That answer determines cost, runtime and the reliability of an unattended process.
A practical example from our own house shows how this works: a process that has been running since 2 June 2026 and has published on its own twice a day since 26 August.
The case
The AI news page on iconference.ch is not maintained by hand. The source list holds 40 entries, and it splits into two groups that arrive by different routes.
21 sources offer an RSS or Atom feed, among them OpenAI, Google DeepMind and several Swiss trade publications. A Python script fetches these deterministically, with a two-day window and at most five entries per source. Links already seen drop out through a state file. If a source fails, the script skips it and carries on.
The remaining 19 have no feed, the Anthropic news page for instance. For those the script only records a placeholder with the URL. They are fetched one step later by the AI agent, which retrieves the page over HTTP and reads the one to three newest items from it. It also searches the [email protected] mailbox for newsletters.
From these candidates the agent makes its selection and writes the bilingual news entries. After that, code takes over again: merge into a JSON file, build the static pages, commit, push. Two minutes later the content is online. As of today: 607 items from 94 runs.
Nodes, edges, state
The nodes are the concrete work steps: fetch sources, curate, publish.
The edges are deterministic conditions, not mere decorative arrows on a presentation slide. If the draft for a run already exists, the script stops immediately. If the candidates have already been fetched, they are reused rather than requested again. Every one of these rules sits in the script as an explicit check and can be traced.
State lives as a file on disk. That way it survives a crash. An aborted run costs a restart, but no lost work.
Only one node needs an AI
Exactly one node in this process requires a language model. It handles two tasks there for which no fixed algorithmic rules exist: selecting the candidates and writing the news entries in two languages. Both call for judgement and phrasing. Claude Fable handles this node, with a pinned model and a tightly restricted toolset: read, write, fetch from the web, search the mailbox, nothing more. Before the rebuild there were two model runs, because the publish step ran through a model as well.
This same node is also the only point where foreign text enters the system: feed titles, summaries, entire web pages, none of it vetted. The brief therefore treats that text explicitly as data and never as instruction. The agent follows no call to action from a news item, and the web fetch is limited to the URLs in the source list, never to a URL that appears in the content itself. A process that reads foreign pages and then writes unattended into a Git repository needs that boundary. Without it, one doctored feed entry is enough.
All remaining nodes work without an AI agent, because they are purely deterministic: fetch feeds, check duplicates against the last 14 days, merge JSON, generate the static pages, run the Git commit and push, and send the status report by email.
The last node is new and looks at first glance like a typical case for an AI. After every run a system email is generated: what went live, which commit hash, how large the total holding now is. Yet no language model is needed for it. The content is fixed the moment the run finishes, and the headlines were written two steps earlier. There is nothing left to phrase, only something to report.
This is exactly where the line runs in practice: it is not «produce text» that requires a language model, but «produce text for which there is no rigid rule».
On paper this decomposition takes half an hour: three columns for nodes, edges and state, followed by the question at each node of whether a simple condition would have done the job. That analysis belongs before the choice of tools, not after.
Who built the graph
I said what should be built and what it had to be able to do. The technical architecture comes from Claude: which node needs a model, which stays deterministic, and where the abort conditions have to sit. Claude then produced the code, meaning scripts, validations and prompts.
Claude therefore has two roles in this project. As the builder it designed and constructed the process. In live operation it is the decision maker at the single node that calls for judgement. That separation is not a detail: the builder worked under my review, the decision maker works without any intervention from me.
My role was that of client and reviewer: judging whether the concept holds, and granting approval. Testing ran against an isolated copy of the directory, covering dry runs, blocked runs, real commits with push, drafts already published, and drafts with nothing selected at all.
86 runs under supervision
From 2 June to 26 August the graph contained one additional node: human approval. The process prepared the draft and stopped. I reviewed the twelve bilingual news entries, made the selection and triggered publication by hand. That phase produced 1052 news entries, of which 550 were published.
The decision to fully automate rested on two factors. The first is capacity: manual approval does not scale, one run a day was the most I could manage, today there are two.
The second was the harder part, namely trust. Across 86 runs I never had to retract a published item: the selection was sound, the translations precise, the publication proposals correct. You do not release an automation with external visibility because the architecture convinces on paper, but because the results hold steady over months. A single flawless run proves nothing at all.
What the automation replaced
When a person reviews a draft, they do two things at once: they catch what must never leave the building, and they judge the quality of the content. To automate that control step, both tasks have to be separated. Hard program code takes over the catching, while the quality judgement is passed to the AI through sharpened prompts and guard rails.
The curation brief to the AI was tightened accordingly:
- At most twelve publications per run.
- A strict block on any warning about dates or duplicates.
- Every discarded entry is marked «not published» along with a one-sentence reason.
- Edge-case rule: when in doubt, an entry stays where it is.
The technical checks before and after generation are handled by Python, not by a language model. The publish step aborts immediately if:
- a text contains an internal keyword,
- the staged diff matches a secret pattern,
- the website repository holds uncommitted changes,
- no fast-forward against origin is possible.
Should anything unexpected happen during the merge, a try/except block automatically resets every file that was touched.
Three mechanisms round out the system, and they inform rather than replace the human. Every unpublished entry carries its reason, which produces a complete trail. After every run the email report arrives. And a published item can be removed afterwards through an ordinary publish.
The first run without approval failed
On 26 August at 12:08 the first unattended run started and failed. The script called node without a full path. Under launchd the default PATH is /usr/bin:/bin:/usr/sbin:/sbin, while node sat in /usr/local/bin. The manual test beforehand had succeeded because it ran in a shell with a complete PATH.
More serious than the error itself was its consequence: the exception had not been caught. The half-merged news.json stayed in the repository, which would have blocked the following run. A failure that drags the next run down with it is no longer a temporary error, it is a standstill.
On 27 August the midday run failed again, this time because of a network fault with failed name resolution across all 21 RSS sources. The evening run picked up the day without trouble, since the time window for candidates spans two days. The two daily slots were originally a capacity decision, but proved to be effective failover.
When approval remains indispensable
This particular process may run without human intervention because four conditions are met at the same time:
- The result is publicly visible and errors are noticed immediately.
- Every step is fully reversible.
- Neither money nor binding commitments depend on it.
- 86 supervised production runs stand as evidence.
If even one of these conditions is missing, human approval remains mandatory. A quotation, a payment, a message to a customer, a change to critical infrastructure: there the actions are irreversible and the risk calculation follows entirely different rules.
Removing the approval from the code was the smaller piece of work. The real achievement was understanding beforehand, precisely, what job it had been doing.
What would not exist without AI
It is unthinkable that I would have built this process without AI. Running it would be even further out of reach. Neither would have failed on the idea, but on my time and on the missing know-how to program Python and scripts myself.
That is exactly the point of graph engineering with AI: it is not only about making existing processes faster. Processes come into being that were not possible before.
Which business processes in your company could be improved this way, and which would become possible at all?