<?xml version="1.0" encoding="utf-8"?><rss version="2.0">
  <channel>
    <title>Liip Blog</title>
    <link>https://www.liip.ch/de/blog</link>
    <lastBuildDate>Wed, 04 Mar 2026 11:17:07 +0100</lastBuildDate>
            <item>
      <title>Einblicke in KI und Open Source f&#252;r Beh&#246;rden bei Drupal4Gov</title>
      <link>https://www.liip.ch/de/blog/einblicke-in-ki-und-open-source-fuer-behoerden-bei-drupal4gov</link>
      <guid>https://www.liip.ch/de/blog/einblicke-in-ki-und-open-source-fuer-behoerden-bei-drupal4gov</guid>
      <pubDate>Wed, 11 Mar 2026 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>Die Drupal4Gov-Konferenz war vollgepackt mit spannenden Vorträgen. Ich war auch dort, um unsere Arbeit am Projekt Kanton Basel-Stadt / Alva / blökkli vorzustellen. Darüber haben wir bereits geschrieben, aber es gibt bereits wieder neue Funktionen.</p>
<h2>GovNL: Von Monaten zu Minuten beim Aufbau von Websites</h2>
<p>GovNL kombiniert Open-Source-Drupal-Komponenten mit einem offenen Designsystem, um zahlreiche Websites der niederländischen Regierung zugänglich und skalierbar zu betreiben. Die Zeit für den Aufbau neuer Websites reduziert sich dadurch <strong>von etwa drei Monaten auf rund zehn Minuten</strong>. Beeindruckend, um es gelinde zu sagen. Das ist ein starkes Beispiel dafür, wie Design für Wiederverwendung in grossem Massstab funktionieren kann.</p>
<h2>Europäische Kommission: Koordination ist der Schlüssel zur Skalierung</h2>
<p>Die Europäische Kommission betreibt bereits <strong>770 Websites</strong> und investiert stark in das Drupal-Ökosystem. Besonders aufgefallen ist mir, wie stark der Fokus auf <strong>Koordination</strong> liegt. Man muss sicherstellen, dass die richtigen Inhalte über den richtigen Kanal innerhalb dieser grossen Website-Landschaft veröffentlicht werden. Open Source Program Offices (OSPOs) wurden eingerichtet, um Open-Source-Strategien sowohl auf Regierungsebene als auch innerhalb von Organisationen voranzutreiben.</p>
<figure><img alt="" src="https://liip.rokka.io/www_inarticle_5/ac3271/drupal4gov2026-josef.jpg" srcset="https://liip.rokka.io/www_inarticle_5/o-dpr-2/ac3271/drupal4gov2026-josef.jpg 2x"></figure>
<h2>Website des Kantons Basel-Stadt und Alva: ein Blueprint für lokale öffentliche Verwaltungen</h2>
<p>Kurz vor der Mittagspause war ich an der Reihe, <strong>die verschiedenen KI-Use-Cases</strong> vorzustellen, die wir für den <a href="https://www.liip.ch/de/work/projects/basel-stadt">Kanton Basel-Stadt</a> umgesetzt haben. Der Kanton setzte mit dem Relaunch von bs.ch neue Standards: mit einem nutzerorientierten Design, einem themenbasierten Zugang statt interner Organisationsstruktur und <a href="https://www.bs.ch/alva">Alva</a> als <strong>erstem KI-basierten Chatbot für einen Schweizer Kanton</strong>. Der Tech-Stack basiert auf Open-Source-Komponenten, und Liip hat im Rahmen des Relaunches stark zu Open Source beigetragen. Wir verwenden Drupal als CMS, Nuxt/Vue, den <a href="https://blokk.li/">bl&ouml;kkli-Editor</a> für das Headless-Frontend und Elasticsearch für die Suche. Die Inhalte werden von einem departementsübergreifenden Redaktionsteam erstellt, das einer klaren Content-Strategie folgt.</p>
<h2>KI zur Unterstützung der Öffentlichkeit und der Editor*innen</h2>
<p>Der Vortrag war auch eine Gelegenheit, mehr als 18 Monate nach dem Go-Live Zahlen zu teilen. Heute beantwortet Alva <strong>über 10 000 Fragen pro Monat</strong>, mit durchschnittlich <strong>1,36 Fragen pro Konversation und einem Wachstum von +44 % seit Alva 2.0</strong>. Dank API-Integrationen kann der Chatbot Fragen auf Basis von Echtzeitinformationen beantworten. Alva wird stark von internen Mitarbeitenden des Kantons sowie von der Öffentlichkeit genutzt. Der Chatbot zeigt und überprüft stets seine Quellen, was entscheidend ist, um Vertrauen aufzubauen.</p>
<p>Auf der Redaktionsseite arbeitet blökkli intensiv daran, Texte zu vereinfachen. Mit dem <strong>blökkli-Editor</strong> und integrierter KI können Editor*innen nun Lesbarkeitsanalysen durchführen, vorgeschlagene Vereinfachungen nebeneinander sehen und diese übernehmen oder anpassen. Alva und die KI-Funktionen auf bs.ch werden kontinuierlich weiterentwickelt, um Editor*innen und Bürger*innen vertrauenswürdige KI-Technologien bereitzustellen.</p>
<h2>KI-gestützte Technologien in der französischen Regierung</h2>
<p>Ein weiterer inspirierender Vortrag zeigte Use-Cases von KI auf der Plattform Services Publics+ der französischen Regierung. Mit über 140 000 geteilten Erfahrungen und mehr als einer Million Reaktionen nutzt das System KI-gestützte Technologien, um staatlichen Stellen dabei zu helfen, Feedback an Bürger*innen zu geben. Dazu gehören Speech-to-Text und Echtzeit-Zusammenfassungen als zentrale Technologien. C’est magnifique!</p>
<h2>Die EU vertraut Open Source mehr denn je</h2>
<p>Die Europäische Union hat den <strong>Website Evidence Collector</strong> eingeführt – ein Open-Source-Tool, das Websites auf Sicherheitsprobleme überprüft. Bemerkenswert ist, dass das Projekt unter der <strong>EUPL</strong> (European Union Public Licence) veröffentlicht wurde. Diese betont die Interoperabilität zwischen Ländern und Lizenzen und unterstützt mehrsprachige Zusammenarbeit. Ich frage mich, ob es in der Schweiz etwas Ähnliches gibt.</p>
<p>Mit Interoperable Europe bietet die EU ausserdem ein neues Portal mit einem hilfreichen <strong>Licensing Assistant</strong>. Damit kannst du <a href="https://interoperable-europe.ec.europa.eu/collection/eupl/solution/licensing-assistant/find-and-compare-software-licenses">Softwarelizenzen finden und vergleichen</a> sowie mit einem <a href="https://interoperable-europe.ec.europa.eu/collection/eupl/solution/licensing-assistant/compatibility-checker">Kompatibilit&auml;ts-Checker</a> prüfen, ob verschiedene Open-Source-Lizenzen kombiniert werden können und ob rechtliche Komplikationen entstehen könnten.</p>
<h2>Open Source zu nutzen reicht nicht - wir brauchen Champions</h2>
<p>Zum Abschluss betonte <strong>Tiffany Farris</strong> von der Strategieberatung <a href="https://www.palantir.net/">Palantir.net</a> (nicht zu verwechseln mit Palantir Technologies), dass <strong>die Nutzung von Open Source gut ist,  aber nicht ausreicht</strong>. Organisationen brauchen <strong>Champions</strong>, die Beiträge zur Community und die Gesundheit des Ökosystems aktiv vorantreiben. Design für Wiederverwendung sollte ein zentrales Prinzip sein. Aus US-Perspektive ist Beschaffung (Procurement) ein grosses Problem: Die Nutzung von Open Source wächst, aber Unterstützungsmechanismen oft nicht. Wenn Open Source als „kostenlos“ betrachtet wird, kann das dazu führen, dass Aufträge an Anbieter gehen, die ihre Arbeit zwar als Open Source vermarkten, aber kein nachhaltiges Ökosystem unterstützen. Sie schlug konkrete Anpassungen der öffentlichen Beschaffung im Sinne von <strong>„Public Money, Public Code“</strong> vor, um das Ökosystem besser zu unterstützen. Ein wirklich inspirierender Abschluss für einen intensiven Tag voller Lernen und Austausch.</p>
<p>Wenn du tiefer in die Inhalte eintauchen möchtest, kannst du dir <a href="https://www.youtube.com/playlist?list=PLNubpNMwP36QH5Y3RlbOiV4f9hjlrxCOo">die Playlist</a> der Präsentationen von Drupal4Gov EU 2026 ansehen.</p>]]></description>
    </item>
        <item>
      <title>Web Components: The Good, the Bad, and the Ugly</title>
      <link>https://www.liip.ch/de/blog/web-components-the-good-the-bad-and-the-ugly</link>
      <guid>https://www.liip.ch/de/blog/web-components-the-good-the-bad-and-the-ugly</guid>
      <pubDate>Wed, 11 Mar 2026 00:00:00 +0100</pubDate>
      <description><![CDATA[<h1>Introduction</h1>
<p>We created a fully themeable chat UI that can be embedded in any website and has no effect on the parent page. <a href="https://www.bs.ch/alva">Kanton Basel-Stadts Alva</a> and <a href="https://ramms.ch/">RAMMS' Rocky AI</a> are instances of that UI.</p>
<p>This blog post will show you what we learned about creating web components that do not influence the parent page. Here are the good, the bad and the ugly when working with web components.</p>
<h1>The Good</h1>
<p>These are the good parts of web components. They will lay the foundation for why you might use them.</p>
<h2>Portability</h2>
<p>Every system that can handle HTML can handle web components. A simple tag and a script will integrate it into any web framework. It doesn't even need to be a JavaScript framework.</p>
<pre><code class="language-html">&lt;body&gt;
  &lt;your-webcomponent&gt;&lt;/your-webcomponent&gt;
  &lt;script src="path/to/your-webcomponent.js"&gt;&lt;/script&gt;
&lt;/body&gt;</code></pre>
<h2>Native Feel</h2>
<p>IFrames are another way to embed UI into a page, and they are arguably easier to use. But the main difference is that web components feel more native to the page, since they directly integrate into the parent page's layout. This means you can use transparency, intrinsic sizing (size based on the web component's contents), and seamless event communication with the parent page.</p>
<h2>Slots</h2>
<p>With slots you can provide content that will be added at a specified point inside your web component.</p>
<p>In our chat UI, we used a slot to let integrators provide a custom loading spinner. This spinner needs to be visible immediately, before the full theme loads asynchronously.</p>
<h2>Shadow DOM - Isolating Styles</h2>
<p>A robust way to ensure that your styles do not affect the parent page is to use the Shadow DOM. Shadow DOM is a web component feature to add a boundary for styles. Styles applied inside the Shadow DOM never apply to the parent page.</p>
<h3>Caveat: Inheritable CSS Properties</h3>
<p>There is one exception to the isolation where CSS properties of the parent page apply to the web component.</p>
<p>These are the properties that pierce through the boundary:</p>
<ul>
<li>Inheritable CSS properties like <code>color</code>, <code>font-family</code>, <code>line-height</code></li>
<li>CSS custom properties like <code>--my-var</code></li>
</ul>
<p>In practice, we have found it helps to fully specify the common properties like fonts and color on every element. That way you will never be surprised by different styles on integration.</p>
<h1>Vite</h1>
<p>For bundling web components, we can highly recommend Vite. There are a lot of neat tricks you can apply while bundling. Here are the Vite features we used for our web component.</p>
<h2>Inlining Assets</h2>
<p>Vite's <a href="https://vite.dev/guide/assets#explicit-inline-handling">explicit inline handling</a> feature allowed us to inline our external CSS files into the JS bundle.</p>
<pre><code class="language-ts">import cssContentString from "./index.css?inline";</code></pre>
<p>This feature will not only inline the raw content of the imported <code>index.css</code>. It will also resolve all CSS imports, apply PostCSS transforms, and even work with CSS preprocessors like SASS. While inlined CSS is not the most efficient for browsers to render, the benefit is that we can ship a single JS file.</p>
<h2>Library Mode</h2>
<p>The Vite <a href="https://vite.dev/guide/build#library-mode">library mode</a> provides you with fine-grained control of how the bundle should behave. To enable the library mode just add the <code>build.lib</code> option in your Vite config.</p>
<h1>The Bad</h1>
<p>Not everything about web components is great though. Here are the bad parts.</p>
<h2>SSR - Hard to Get Working</h2>
<p>Server-side rendering will almost certainly not work. The rest of the page can still be rendered server-side, but the web component will only show up as a <code>&lt;your-webcomponent&gt;&lt;/your-webcomponent&gt;</code> tag. Its contents will only be rendered in the browser.</p>
<p>There is one <a href="https://lit.dev/docs/ssr/overview/">experimental package by Lit Labs</a> that tries to solve this, but we never tried it.</p>
<h2>Tailwind - Not a Great Fit</h2>
<p>Tailwind feels like a natural choice for web components, but it does not play well with them.</p>
<p>The core issue is twofold. First, Tailwind ships its own CSS reset (called Preflight), which overrides default browser styles. When injected into a page that does not use Tailwind, it potentially breaks the page. Shadow DOM could isolate this reset, but Tailwind is fundamentally not designed to work inside a Shadow DOM. Here is the <a href="https://github.com/tailwindlabs/tailwindcss/discussions/1935">discussion</a> if you are interested.</p>
<p>There are some hacky workarounds, but we tried them and had no success getting them to work reliably.</p>
<p>Our recommendation is to only use Tailwind if you are guaranteed that the parent page also uses it, and then use web components without Shadow DOM.</p>
<h1>The Ugly</h1>
<h2>Verbose Web Components API</h2>
<p>The native web component API is verbose and hard to read. A simple counter component, for example, requires manually defining a class, attaching a shadow root, setting up <code>innerHTML</code>, and wiring event listeners in <code>connectedCallback</code>. This boilerplate adds up quickly. You can see examples of the API <a href="https://github.com/mdn/web-components-examples">here</a>.</p>
<p>Fortunately, web components make for a great compile target. <a href="https://svelte.dev/docs/svelte/custom-elements">Svelte</a> and <a href="https://vuejs.org/api/custom-elements.html#definecustomelement">Vue</a> directly support compiling to web components. <a href="https://blog.logrocket.com/working-custom-elements-react/">React</a> is a bit trickier, but totally doable as well. We used this approach for our chat UI, where the first iteration was built with React and the current one with Svelte.</p>
<h1>Weird Quirks</h1>
<p>Advanced web component features come with edge cases<br />
that no documentation warns you about. Even Svelte,<br />
which has excellent web component support, ships with a<br />
notable <a href="https://svelte.dev/docs/svelte/custom-elements#Caveats-and-limitations">list of caveats</a>.</p>
<p>We even hit an undocumented edge case with slots in Svelte: the bundle script must<br />
load after the component markup, or slotted content will<br />
not render. An ugly <a href="https://github.com/FalkZ/svelte-web-components-starter/blob/main/src/slot.svelte">wrapper for slots</a> fixes the problem,<br />
but quirks like this add up and slow you down.</p>
<h2>Font Loading - Not Working Inside Shadow DOM</h2>
<p>When authoring web components, you get into the habit of defining all stylesheet links etc. in the web component body. As you should, so they do not affect the parent page. But there is another annoying detail here: @font-face will not work when defined in the Shadow DOM. If your web component needs a custom font, you need to inject the font CSS into the parent page to make it work.</p>
<h1>Conclusion</h1>
<p>I do not want to end on this ugly note though. I really think there are cases where web components are the right choice, and in our case we would choose Svelte &amp; web components again.</p>
<p>To help you get started, here is a <a href="https://github.com/FalkZ/svelte-web-components-starter">Svelte starter template</a>.</p>]]></description>
    </item>
        <item>
      <title>Der ConfIAnce-Chatbot, ein Jahr sp&#228;ter</title>
      <link>https://www.liip.ch/de/blog/der-confiance-chatbot-ein-jahr-spaeter</link>
      <guid>https://www.liip.ch/de/blog/der-confiance-chatbot-ein-jahr-spaeter</guid>
      <pubDate>Mon, 09 Mar 2026 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>Vor etwas weniger als einem Jahr haben wir den ConfIAnce-Chatbot vorgestellt. Im Auftrag der Genfer Universitätskliniken (HUG) haben wir diesen Chatbot entwickelt, um einen einfachen und interaktiven Zugang zu medizinischen Informationen über häufige chronische Krankheiten zu ermöglichen. Die Inhalte werden von der medizinischen Institution selbst erstellt und validiert.</p>
<p>Ein Artikel der Initiator*innen dieses Projekts, veröffentlicht in der neuesten Ausgabe der Revue Médicale Suisse, zieht nun eine erste Bilanz ein Jahr nach der öffentlichen Lancierung.</p>
<figure><img alt="" src="https://liip.rokka.io/www_inarticle_5/9661ee/rms-confiance.jpg" srcset="https://liip.rokka.io/www_inarticle_5/o-dpr-2/9661ee/rms-confiance.jpg 2x"></figure>
<h2>Ein offizielles Angebot statt fehlerhafter Antworten online</h2>
<p>Die medizinische Grundversorgung, ein zentraler Pfeiler eines funktionierenden Gesundheitssystems, steht zunehmend unter Druck, selbst in Städten. Wenn Patient*innen ihre Hausärzt*innen nicht schnell erreichen können, suchen sie oft im Internet nach Antworten. Die Informationen, die sie dort finden, sind jedoch häufig ungenau oder sogar potenziell gefährlich.</p>
<p>In diesem Kontext kann eine gut konzipierte KI-Lösung helfen, <strong>die richtige Information zur richtigen Zeit</strong> bereitzustellen.</p>
<p>Deshalb haben wir die HUG bei der Entwicklung eines RAG-basierten Chatbots (Retrieval Augmented Generation) unterstützt. ConfIAnce ist nicht der erste Chatbot für Patient*innen. Er unterscheidet sich jedoch durch seine institutionelle Wurzeln, die Nutzung lokal validierter medizinischer Inhalte sowie durch Kontrollmechanismen, die die Zuverlässigkeit der Antworten sicherstellen.</p>
<p>Um Sicherheit zu gewährleisten, integriert das System mehrere Kontrollmechanismen, darunter <strong>Matching, Groundedness, Harmfulness, automatisierte Tests und semantisches Routing.</strong></p>
<h2>Qualitätssicherung durch Kontrolle des Systems</h2>
<p>Eine zentrale Herausforderung besteht darin, die Kontrolle über das System zu behalten. Dafür braucht es geeignete Monitoring-Funktionen.</p>
<p>Automatisierte Tests prüfen sämtliche Antworten des Chatbots auf ihre faktische Übereinstimmung mit der Wissensbasis.</p>
<p>Zusätzlich sorgt ein von Administrator*innen anpassbares Routing dafür, dass Fragen gefiltert und bei Bedarf unter menschlicher Aufsicht weitergeleitet werden. Sie können den Chatbot zudem sofort offline nehmen, falls ein Fehlverhalten vermutet wird.</p>
<p>Themen, über die häufig gefragt wird, aber in den Ausgangsdokumenten noch wenig behandelt werden, werden identifiziert und weiter ausgebaut. So wird die Wissensbasis im Rahmen eines <strong>kontinuierlichen Verbesserungsprozesses erweitert</strong>.</p>
<h2>Selbst das beste Tool bringt nur etwas, wenn es genutzt wird</h2>
<p>Damit Patient*innen den Chatbot tatsächlich verwenden, haben die HUG eine öffentliche Informationskampagne gestartet. Ziel war es, das Tool bekannt zu machen und gleichzeitig realistische Erwartungen zu setzen.</p>
<p>ConfIAnce ist <strong>kein medizinisches Gerät und ersetzt keinen Arztbesuch</strong>. Vielmehr ist er ein Informationsangebot, das Fragen zu den häufigsten chronischen Erkrankungen bei Erwachsenen beantwortet.</p>
<p>Im Februar 2025 ging ConfIAnce in der Beta-Version online. Zwischen Anfang Februar und Ende Oktober 2025 haben 3’823 Nutzer*innen mit dem Chatbot interagiert. Daraus entstanden 5’969 Gespräche und <strong>11’781 Fragen</strong>, im Durchschnitt etwa zwei Fragen pro Gespräch.</p>
<p>Die direkt im Chatbot abgegebenen Rückmeldungen sind zu <strong>75 % positiv</strong>.</p>
<h2>Hohe Akzeptanz für einen etwas anderen Chatbot</h2>
<p>Chatbots im Gesundheitsbereich werden von Patient*innen meist gut angenommen, vor allem wegen ihrer ständigen Verfügbarkeit und der einfachen Nutzung. Studien zeigen jedoch auch wiederkehrende Probleme: eine uneinheitliche Qualität der Antworten sowie mangelnde Transparenz bei den verwendeten Quellen.</p>
<p>Genau hier unterscheidet sich ConfIAnce von vielen anderen medizinischen Chatbots.<br />
Der Chatbot wurde entwickelt, um <strong>die Beziehung zwischen Patient<em>innen und Ärzt\</em>innen zu unterstützen, nicht zu ersetzen</strong>. ConfIAnce entlastet Ärzt*innen in der Grundversorgung und schafft ihnen mehr Zeit für die menschliche Seite ihres Berufs.</p>
<p>Die Autor<em>innen des Artikels in der Revue Médicale Suisse betonen zudem, dass der Chatbot, der im spezifischen Kontext der HUG und ihrer Dokumente entwickelt wurde, auch in anderen institutionellen Umgebungen eingesetzt werden kann. Damit ein solches Projekt erfolgreich ist, braucht es zunächst hochwertige Daten, wie sie hier zur Verfügung standen. Darüber hinaus ermöglichen Kontrollmechanismen, automatisierte Tests und Nutzer\</em>innen-Feedback eine kontinuierliche Verbesserung – und sorgen für Sicherheit und Relevanz, die Vertrauen schaffen.</p>]]></description>
    </item>
        <item>
      <title>City of Zurich&#039;s 900+ Open Data Sets Now Have an MCP Server</title>
      <link>https://www.liip.ch/de/blog/city-of-zurich-s-900-open-data-sets-now-have-an-mcp-server</link>
      <guid>https://www.liip.ch/de/blog/city-of-zurich-s-900-open-data-sets-now-have-an-mcp-server</guid>
      <pubDate>Thu, 26 Feb 2026 00:00:00 +0100</pubDate>
      <description><![CDATA[<p><a href="https://www.linkedin.com/in/alexander-g%C3%BCntert-3379071b6/">Alexander Güntert</a> <a href="https://www.linkedin.com/posts/activity-7432101739589345280-0YcB">posted on LinkedIn</a> about a new open-source project his colleague <a href="https://www.linkedin.com/in/hayaloezkan/">Hayal Oezkan</a> had built: an <a href="https://github.com/malkreide/zurich-opendata-mcp">MCP server for Zurich's open data</a>. The post got quite some reactions and I liked the idea very much. But it still needed a local installation, not something non-developers easily know how to do. So I had it packaged and deployed on our servers, available for anyone to use as the "OGD City of Zurich" remote MCP server.</p>
<p>The City of Zurich publishes over 900 datasets as open data, spread across six different APIs. There's <a href="https://data.stadt-zuerich.ch">CKAN</a> for the main data catalog, a WFS Geoportal for geodata, the Paris API for parliamentary information from the Gemeinderat, a tourism API, SPARQL linked data, and ParkenDD for real-time parking data. All public, all freely available. But until now, making an AI assistant actually use these APIs meant writing custom integrations for each one.</p>
<p>The MCP server wraps all six APIs into 20 tools that any MCP-compatible AI assistant can call directly. Ask "How warm is it in Zurich right now?" and it queries the live weather stations. Ask about parking availability, and it pulls real-time data from 36 parking garages. It also covers parliamentary motions, tourism recommendations, SQL queries on the data store, and GeoJSON features for school locations, playgrounds, or climate data. All through a single, standardized <a href="https://modelcontextprotocol.io/">Model Context Protocol</a> interface.</p>
<p>Hayal Oezkan  built it in Python using FastMCP. One file for the server with all 20 tool handlers. The <a href="https://github.com/malkreide/zurich-opendata-mcp">repo</a> is on GitHub.</p>
<p>Deploying it on our side took very little effort. The server supports both stdio transport for local use (like in Claude Desktop or Claude Code) and SSE and HTTP Streaming for remote deployment. I packaged it with Docker, deployed it to our cluster, and now it's available as a remote MCP server that anyone can add to their AI tools without installing anything locally.</p>
<p>The natural next step was integrating this with <a href="https://zuericitygpt.ch/">ZüriCityGPT</a>. It happened, just not quite in the direction I originally had in mind.</p>
<p>ZüriCityGPT already had its own MCP server at zuericitygpt.ch/mcp, exposing tools for searching the city's website content, "Stadtratsbeschlüsse" and looking up waste collection schedules. Instead of wiring the open data tools into ZüriCityGPT, I went the other way: the open data MCP server now proxies tools from the ZüriCityGPT MCP server. A lightweight proxy client connects to the remote server via streamable-http and forwards calls. The whole thing is about 40 lines of Python.</p>
<p>So now, when you connect to the Zurich Open Data MCP server, you get 23 tools in one place. The 21 original open data tools across six APIs, plus <code>zurich_search</code> for querying the city's knowledge base and <code>zurich_waste_collection</code>  for waste pickup schedules (based on the <a href="https://openerz.metaodi.ch/documentation">OpenERZ API</a>). One MCP endpoint, many services behind it. </p>
<p>A city employee builds something useful in the open, publishes the code, and within a day it's deployed and available to a wider audience. Open data and open source working together, exactly as intended.</p>]]></description>
    </item>
        <item>
      <title>Der Kanton Graub&#252;nden bekommt eine neue Website</title>
      <link>https://www.liip.ch/de/blog/der-kanton-graubuenden-bekommt-eine-neue-website</link>
      <guid>https://www.liip.ch/de/blog/der-kanton-graubuenden-bekommt-eine-neue-website</guid>
      <pubDate>Wed, 25 Feb 2026 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>Der Kanton Graubünden entwickelt eine neue Website. Die heutige Struktur orientiert sich am Aufbau der Verwaltung und umfasst mehrere 10 000 Webseiten. Der Auftritt wird den aktuellen Anforderungen an Benutzerfreundlichkeit und dem veränderten Nutzungsverhalten nicht mehr gerecht.</p>
<p>Im Zentrum des Relaunchs steht die <strong>Nutzerzentrierung</strong>. Statt der Innenperspektive soll eine themenzentrierte Struktur entstehen – wie sie beispielsweise der Kanton Basel-Stadt (<a href="https://www.liip.ch/de/work/projects/basel-stadt" rel="noreferrer" target="_blank">mehr zum Projekt hier</a>) bereits erfolgreich etabliert hat.</p>
<p><strong>Das Vorhaben aus Content-Sicht? Ein Mammut-Projekt.</strong></p>
<h2>Was braucht es für ein Content-Projekt dieser Grösse?</h2>
<p>Organisch gewachsene Inhalte können nicht einfach migriert werden. Ein Relaunch ist meist der Moment, in dem Content nicht nur übertragen, sondern <strong>qualitativ neu gedacht</strong> wird.</p>
<p>Da dabei ein grosses Volumen an Content überarbeitet werden muss, braucht es ein <strong>dezentrales Redaktionsmodell</strong>. Zahlreiche Mitarbeitende – oft ohne vertiefte Content-Erfahrung – sind involviert. Gute Prozesse, klare Rollen und gezielte Unterstützung sind daher essenziell:</p>
<ul>
<li>Eine entscheidungsfreudige Projektleitung </li>
<li>Eine solide Bestandesaufnahme</li>
<li>Konzept und Strategie</li>
<li>Governance (Prozesse &amp; Verantwortlichkeiten)</li>
<li>Aufbau und Schulung der Webredaktion</li>
<li>Operative Content-Produktion</li>
<li>Qualitätssicherung</li>
</ul>
<p>Liip darf den Kanton Graubünden auf dieser Reise begleiten. Auf Basis unserer Erfahrungen aus den Projekten in Basel-Stadt, Solothurn und verschiedenen Bundesämtern ist eine vertrauensvolle, effiziente Zusammenarbeit entstanden.</p>
<h2>Wie wir zusammenarbeiten</h2>
<p>Zwei <a href="https://www.liip.ch/de/services/content/strategic-storytelling" rel="noreferrer" target="_blank">Content-Strateginnen</a> von Liip arbeiten eng mit der Projektleitung des Kantons zusammen. Die Projektleitung bringt internes Know-how und Entscheidungsstärke ein, Liip ergänzt operative Kapazität und viel Erfahrung aus ähnlichen Settings. Dieses Setup ermöglicht hohe Geschwindigkeit – und eine saubere Verzahnung von internem Wissen und externem Input.</p>
<p>Die Zusammenarbeit erstreckt sich über mehr als 1,5 Jahre.</p>
<h2>Was sind die konkreten Lieferobjekte?</h2>
<ul>
<li>Content Audit</li>
<li>Content Strategie &amp; Tonalität</li>
<li>Content Governance &amp; Redaktionsmodell (für die Projektphase und für den Betrieb danach)</li>
<li>Content Lifecycle Modell</li>
<li>Content Guidelines für die Redaktion</li>
<li>Seitentypen &amp; Beispieltexte (in Zusammenarbeit mit dem Design-Team)</li>
<li>Wordvorlagen für die Erstellung der Texte</li>
<li>Schulungen &amp; Support der Redaktionsmitglieder</li>
<li>KI-basiertes Schreibtool «GR-Editor» (basierend auf TextMate)</li>
<li>Qualitätssicherung</li>
</ul>
<figure><img alt="" src="https://liip.rokka.io/www_inarticle_5/1496b9/gr-work-layers-01-de.jpg" srcset="https://liip.rokka.io/www_inarticle_5/o-dpr-2/1496b9/gr-work-layers-01-de.jpg 2x"></figure>
<h3>Was bedeutet das im Detail? Vom Audit bis zur Qualitätssicherung</h3>
<p>Ein Relaunch mit über 120 involvierten Redaktor*innen und Tausenden Seiten Content braucht vor allem eines: einen klaren Plan für die Umsetzung und gute Vorbereitung. Jeder Schritt baut auf dem vorherigen auf:</p>
<ol>
<li><a href="https://www.liip.ch/de/services/content/content-audit" rel="noreferrer" target="_blank">Content Audit</a> – Klarheit schaffen</li>
</ol>
<p>Gestartet sind wir in das Projekt mit der Analyse einer repräsentativen Auswahl bestehender Inhalte. Der Audit half bei der Identifizierung von Optimierungspotenzialen und bildete das Fundament für alle weiteren Entscheidungen.</p>
<ol start="2">
<li>Das Redaktionsmodell – Rollen, Verantwortlichkeiten und Prozesse</li>
</ol>
<p>Die <strong><a href="https://www.liip.ch/de/services/content/content-governance" rel="noreferrer" target="_blank">Content Governance</a> und das entwickelte Redaktionsmodell</strong> haben einen grossen Teil der «Theorie» gelegt, auf der die operativen Arbeiten mit der Webredaktion dann aufgebaut wurden. Wir haben dabei ein Modell für das Projekt entworfen, ergänzt um einen Plan für nach dem Relaunch.</p>
<ol start="3">
<li>Content Strategie &amp; Tonalität – die Leitlinie</li>
</ol>
<p>Die Governance regelt Zusammenarbeit und Prozesse – die Content Strategie definiert die inhaltliche Ausrichtung. Sie richtet sich dabei weniger an die künftigen Redaktor*innen, sondern bildet die konzeptionelle und inhaltliche Grundlage für die operativen Elemente. Ergänzt wurden <strong>zwei Tonalitäten</strong> für den neuen Webauftritt.</p>
<p>Mit abgeschlossener Strategie begann die operative Phase.</p>
<ol start="4">
<li>Seitentypen &amp; Beispieltexte – das Konzept wird konkret</li>
</ol>
<p>Gemeinsam mit dem Designteam entwickelten wir die neuen Seitentypen. Unsere <a href="https://www.liip.ch/de/services/content/ux-writing" rel="noreferrer" target="_blank">UX Writerin</a> entwarf erste realistische Seiten, die als Referenz für die Finalisierung der Seitentypen dienten.</p>
<p>Arbeiten mit echten Texten ist entscheidend: Nur so lassen sich Struktur, Inhalt und Design sinnvoll aufeinander abstimmen.</p>
<p>Auch für die Schulung der Redaktor*innen sind die konkreten Text- und Seitenbeispiele wichtig.</p>
<ol start="5">
<li><a href="https://www.liip.ch/de/services/content/guidelines" rel="noreferrer" target="_blank">Content Guidelines</a> – das Handbuch für Redaktionsmitglieder</li>
</ol>
<p>Abgeleitet von der Content Strategie bündeln die Content Guidelines Regeln, Empfehlungen, Beispiele und konkrete Anleitungen – für verständliche, barrierefreie und konsistente Inhalte.</p>
<ol start="6">
<li>Wordvorlagen – weil das CMS parallel erst entsteht</li>
</ol>
<p>Da CMS-Entwicklung und Content-Entwicklung parallel laufen, müssen die Texte ausserhalb des CMS entstehen. Dafür erstellten wir Wordvorlagen, die:</p>
<ul>
<li>die neue Seitenstruktur abbilden,</li>
<li>alle relevanten Meta-Informationen integrieren,</li>
<li>Hinweise für Redaktor*innen enthalten.</li>
</ul>
<p>Die Wordvorlagen wurden um Visualisierungen der einzelnen Seitentypen ergänzt. Dabei wurde ein <strong>reales Textbeispiel pro Seitentyp in Figma gesetzt</strong> und mit den Redaktor*innen als PDF geteilt.</p>
<ol start="7">
<li>KI-Schreibtool «GR-Editor» – Unterstützung in Echtzeit</li>
</ol>
<p>Ein dezentrales Redaktionsmodell führt zwangsläufig zu variierender Textqualität. Der GR-Editor (basierend auf <a href="https://www.liip.ch/de/blog/textmate" rel="noreferrer" target="_blank">TextMate</a>) wirkt dem entgegen. Er prüft <strong>Verständlichkeit, Konsistenz und Tonalität</strong> direkt beim Schreiben.</p>
<p>Der Kanton hatte ideale Voraussetzungen: bestehende kantonale Schreibvorgaben, die neuen Content Guidelines und die zwei definierten Tonalitäten.</p>
<ol start="8">
<li>Aufbau der Redaktionen &amp; <a href="https://www.liip.ch/de/services/content/trainings" rel="noreferrer" target="_blank">Schulungen</a></li>
</ol>
<p>Zunächst wurden die Redaktionen zusammengestellt, passend zur neuen Website-Struktur: einem Themen- und einem Organisationsteil.</p>
<p>Für den Thementeil entstanden Themenredaktionen mit je einer Koordinator*in. Sie funktionieren als <strong>Schnittstelle zwischen den Redaktionen und der Projektleitung</strong>. Die Supportorganisation (Projektleitung + Liip) begleitet die Teams.</p>
<figure><img alt="" src="https://liip.rokka.io/www_inarticle_5/7226da/gr-editorial-team-02-de.jpg" srcset="https://liip.rokka.io/www_inarticle_5/o-dpr-2/7226da/gr-editorial-team-02-de.jpg 2x"></figure>
<p>Die Schulungen waren der erste praktische Einstieg. Vorgestellt wurden die neuen Seitentypen, die Guidelines und der GR-Editor.</p>
<ol start="9">
<li>Redaktionssupport – Begleitung im Alltag</li>
</ol>
<p>Die inhaltlichen Arbeiten laufen derzeit. Die Supportorganisation organisiert regelmässige Redaktionssitzungen, beantwortet Fragen und <strong>erarbeitet Lösungen</strong>. Jede Themenredaktion erhält individuelles Sparring zu ersten Texten.</p>
<ol start="10">
<li>Qualitätssicherung – bevor der Inhalt live geht</li>
</ol>
<p>Bei dieser Menge an Inhalten ist <strong>Eigenverantwortung</strong> zentral. Die Redaktor*innen erhalten Checklisten, mit denen sie ihre Texte selbst prüfen können. Strategisch ausgewählte Inhalte erhalten spezifisches Feedback.</p>
<p>Auch der GR-Editor trägt wesentlich zur Qualitätssicherung bei.</p>
<h2>Erste Learnings aus dem Projekt</h2>
<p>Ein Relaunch dieser Grösse strapaziert alle Beteiligten. Ein dezentrales Redaktionsmodell ist unvermeidlich. Verständnis für die Situation der Redaktionsmitglieder, Flexibilität bei der Umsetzung der Planung und pragmatische Lösungen unterwegs sind zentrale Zutaten für ein konstruktives Miteinander.  </p>
<p>Was bedeutet das konkret? Einige Beispiele:</p>
<ul>
<li>«Der Ton macht die Musik». Sich mit Respekt begegnen, offene Punkte benennen, Probleme ernst nehmen, Mitgestaltung zulassen.</li>
<li>Den Redaktionen Gestaltungsspielraum für ihr Timing geben – innerhalb des übergeordneten Projektzeitplans.</li>
<li>Tools flexibel einsetzen (z. B. Excel statt Miro, wenn es besser passt).</li>
</ul>
<p>Die Arbeit <strong>mit realen Textbeispielen in der Entwicklung der Seitentypen</strong> hat sich klar als wichtige Entscheidung erwiesen. Bei so vielen Beteiligten braucht es reife Vorlagen und klare Referenzen – um Qualität, Konsistenz und Tempo sicherzustellen. Auch die <strong>Visualisierungen der Seitentypen</strong> haben einen zentralen Stellenwert. Gerade für Menschen, die stark über das Visuelle funktionieren, ist das Texten in den Wordvorlagen ohne Vorschau des Frontends eine Herausforderung. Die Visualisierungen dienen immerhin als allgemeiner Referenzwert.</p>
<p>Externe Expert*innen können Spitzen brechen und in Diskussionen einen externen Blick beisteuern. Darüber hinaus ist es schön zu sehen, wie ein gemeinsames Team über Organisationsgrenzen hinaus entstehen kann - gemeinsam im Sinn der Sache.</p>
<p>..und genau in diesem Sinne freuen wir uns auf die nächsten, abschliessenden Prozessschritte. Und auf ein spannendes Jahr für den Relaunch :)</p>]]></description>
    </item>
        <item>
      <title>Blind testing your chatbot, Arena style</title>
      <link>https://www.liip.ch/de/blog/blind-testing-your-chatbot-arena-style</link>
      <guid>https://www.liip.ch/de/blog/blind-testing-your-chatbot-arena-style</guid>
      <pubDate>Tue, 24 Feb 2026 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>At Liip, we've been building and running AI-powered chatbots for organizations through our <a href="https://www.liip.ch/en/work/projects/liipgpt">LiipGPT</a> platform. Over time, we developed evaluation sets, automated scoring with LLM-as-a-Judge, and various ways to measure chatbot quality. Max wrote about this approach in <a href="https://www.liip.ch/en/blog/no-value-without-trust">No value without trust</a>. But when it comes to comparing two different configurations, like a new prompt versus the old one, or GPT-4o versus Claude Sonnet, automated metrics only get you so far. Sometimes you need actual humans reading actual answers and telling you which one is better.</p>
<h2>The Bias Problem</h2>
<p>The problem is bias. If you know that Response A comes from the expensive model and Response B from the cheaper one, you'll unconsciously read them differently. The idea behind our solution is borrowed from classic A/B testing: show two variants to evaluators without telling them which is which, and let the results speak. For RAG chatbots, the question isn't "which model is generally better?" It's "which configuration produces better answers for this specific knowledge base and these specific users?" That requires comparing pre-generated answers, not live model outputs.</p>
<h2>Side by Side, Let's Evaluate</h2>
<p>So we built Arena mode into the Admin UI. It works like this: you start by running your evaluation set against two different configurations. Maybe you're testing a new system prompt, or switching embedding models, or trying a different retrieval strategy. Each run produces answers for every question in the set. Then you create a comparison, selecting those two runs.</p>
<p>When an evaluator opens the comparison, they see one question at a time. Two answers, labeled A and B. No model names, no hints. The order is shuffled differently for each evaluator using a seeded randomization, so if Alice sees the Claude answer as "A" for question 3, Bob might see it as "B". This prevents evaluators from developing patterns like "A is always the better one."</p>
<p>For each answer, you rate it as Good, Neutral, or Bad. You can add a comment explaining why, which turns out to be incredibly valuable. The quantitative scores tell you which model wins, but the comments tell you why, and often reveal issues you wouldn't catch with automated evaluation.</p>
<figure><img alt="" src="https://liip.rokka.io/www_inarticle_5/3feb95/question-bad.jpg" srcset="https://liip.rokka.io/www_inarticle_5/o-dpr-2/3feb95/question-bad.jpg 2x"></figure>
<h2>More Feedback the Merrier</h2>
<p>Multiple evaluators can rate the same comparison independently. Getting people involved is easy: share links generate a temporary API key, so you can send a URL to a colleague or a client and they can evaluate in a protected area without needing an admin account. They just enter their name and start rating.</p>
<figure><img alt="" src="https://liip.rokka.io/www_inarticle_5/ade347/share.jpg" srcset="https://liip.rokka.io/www_inarticle_5/o-dpr-2/ade347/share.jpg 2x"></figure>
<h2>Understand the Results</h2>
<p>The results page shows a leaderboard: average score, win rate per model, and a breakdown per evaluator. That last part is where it gets interesting: it surfaces inter-annotator agreement, a standard measure of how much evaluators align in their ratings.</p>
<ul>
<li><strong>High agreement</strong>: the quality difference is clear and you can act on the result with confidence.</li>
<li><strong>Low agreement</strong>: the two configurations are close enough that the choice may come down to other factors like cost or latency.</li>
</ul>
<p>You can also drill into individual comments grouped by model, and export everything to Excel for reporting.</p>
<figure><img alt="" src="https://liip.rokka.io/www_inarticle_5/876023/arena-result.jpg" srcset="https://liip.rokka.io/www_inarticle_5/o-dpr-2/876023/arena-result.jpg 2x"></figure>
<h2>Calibrating AI with Human Truth</h2>
<p>Building this was a good reminder that evaluation tooling is never "done." Christian recently wrote about <a href="https://www.liip.ch/en/blog/using-claude-agent-sdk-to-analyse-chatbot-answers">using Claude Agent SDK to analyze chatbot answers</a> automatically, which is the other side of the coin: scaling evaluation with AI. Arena mode complements that by providing the human ground truth that automated evaluation needs to calibrate against.</p>
<p>We're using Arena now whenever we make significant changes to a chatbot's configuration. The signal-to-noise ratio is much better than staring at spreadsheets of automated scores. The feature is available in the Admin UI for any organization that uses our evaluation sets.</p>
<h2>The Next Steps of the Arena</h2>
<p>We're considering adding support for more than two models in a single comparison, and possibly integrating the Arena ratings as ground truth labels for training better LLM-as-a-Judge prompts. For now, blind human evaluation with a simple Good/Neutral/Bad rating scheme gives us exactly what we need: honest answers about which configuration actually works better.</p>]]></description>
    </item>
        <item>
      <title>WebMCP: Making LiipGPT Tools Discoverable by Browser AI Agents</title>
      <link>https://www.liip.ch/de/blog/webmcp-making-liipgpt-tools-discoverable-by-browser-ai-agents</link>
      <guid>https://www.liip.ch/de/blog/webmcp-making-liipgpt-tools-discoverable-by-browser-ai-agents</guid>
      <pubDate>Tue, 24 Feb 2026 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>Two weeks ago, Google shipped <a href="https://developer.chrome.com/blog/webmcp-epp">WebMCP in Chrome 146</a> as an early preview. It's a W3C standard, jointly developed with Microsoft, that lets websites expose structured tools to AI agents running in the browser. Instead of agents scraping your DOM or clicking buttons, they can call well-defined functions with typed parameters and get structured results back. Think of it as MCP, but for the browser.</p>
<p>We already had an <a href="https://www.linkedin.com/posts/chregu_z%C3%BCricitygpt-and-in-extension-liipgpt-is-activity-7407037094528819200-oDdw">MCP server</a> running on <a href="https://zuericitygpt.ch/">ZüriCityGPT</a> and other <a href="https://www.liipgpt.ch/">LiipGPT</a> deployments. Tools like knowledge base search, public transport timetables, and waste collection schedules were available to any MCP client, Claude Desktop, Cursor, or custom integrations. The tool definitions, schemas, and execution logic were all there. WebMCP just needed a bridge to bring them into the browser.</p>
<p>The implementation turned out to be surprisingly straightforward. When the page loads, a small script checks if <code>navigator.modelContext</code> exists. If it does, it fetches the available tools from our existing MCP endpoint using a standard JSON-RPC <code>tools/list</code> request and registers each one with <code>navigator.modelContext.registerTool()</code>. When an AI agent calls a tool, the <code>execute</code> handler sends a <code>tools/call</code> request back to the same endpoint. The entire client-side code is about 30 lines of vanilla JavaScript.</p>
<pre><code class="language-javascript">navigator.modelContext.registerTool({
  name: tool.name,
  description: tool.description,
  inputSchema: tool.inputSchema,
  execute: function(params) {
    return fetch(mcpUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        jsonrpc: '2.0',
        method: 'tools/call',
        params: { name: tool.name, arguments: params }
      })
    }).then(r =&gt; r.json()).then(d =&gt; d.result);
  }
});</code></pre>
<p>The beauty is that the tool set is dynamic and per site setup. ZüriCityGPT exposes search with a special mode for city council resolutions (Stadtratsbeschlüsse, see also <a href="https://strb.zuericitygpt.ch/">StrbGPT</a>), waste collection lookups via the <a href="https://openerz.metaodi.ch/">OpenERZ API</a>, and Swiss public transport departures. A different LiipGPT deployment would expose its own set of tools. The backend decides what's available, the browser just registers whatever comes back.</p>
<p>One thing worth noting: <code>navigator.modelContext</code> is behind a flag in Chrome Canary (<code>chrome://flags/#enable-webmcp-testing</code>) and not available in any stable browser yet. The script uses feature detection, so nothing happens in unsupported browsers. </p>
<p>To actually test it, you need Chrome Canary and the <a href="https://chromewebstore.google.com/detail/model-context-tool-inspec/gbpdfapgefenggkahfehlcenpd">Model Context Tool Inspector</a> extension (which requires a Gemini API key to do anything useful with the tools). But the registration itself works, and seeing "search", "get_waste_collection", and "get_timetable_info" show up in the inspector when visiting a chatbot page is a nice confirmation that everything clicks together.</p>
<p>Now, ZüriCityGPT is a page with essentially one big input field. It's already a chatbot. An AI agent visiting the site could just type into that field. Exposing structured tools on a page that is itself a tool feels a little redundant. But it does open up genuinely new possibilities. A browser agent could search the knowledge base, check the next tram departure, and look up waste collection dates in parallel, without ever touching the chat UI, and combine the results with data from other sites. The chatbot answers questions one at a time. WebMCP lets agents compose capabilities.</p>
<p>Is this useful today? Not really. No stable browser supports it, and the user base of Chrome Canary with experimental flags enabled is, let's say, select. Google and Microsoft are pushing it through the W3C, and <a href="https://venturebeat.com/infrastructure/google-chrome-ships-webmcp-in-early-preview-turning-every-website-into-a">formal browser support is expected by mid-to-late 2026</a>. When that happens, any AI agent visiting ZüriCityGPT will automatically discover what it can do, no documentation reading and UI guessing required.</p>
<p>The interesting part is the convergence. We now have the same tool definitions serving three purposes: LangChain tools for the chatbot's own RAG pipeline, an MCP server for "traditional" AI clients, and WebMCP for browser agents. One set of schemas, three integration points. Adding a new tool to any LiipGPT site automatically makes it available everywhere.</p>
<p>If you want to try it yourself, visit <a href="https://zuericitygpt.ch/">zuericitygpt.ch</a> with Chrome Canary, enable the WebMCP flag, and install the <a href="https://chromewebstore.google.com/detail/model-context-tool-inspec/gbpdfapgefenggkahfehlcenpd">Model Context Tool Inspector</a> extension. You'll see the three registered tools and can ask Gemini when your next paper collection is. Or just type the question into the chatbot, that still works too.</p>]]></description>
    </item>
        <item>
      <title>New OpenData API, New Scope, New MCP Server: Upgrading the Swiss Parliament Bot</title>
      <link>https://www.liip.ch/de/blog/new-api-new-scope-new-mcp-server-upgrading-the-swiss-parliament-bot</link>
      <guid>https://www.liip.ch/de/blog/new-api-new-scope-new-mcp-server-upgrading-the-swiss-parliament-bot</guid>
      <pubDate>Wed, 18 Feb 2026 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>It covers not just the federal parliament but cantonal and municipal ones too. And while I was at it, I added an MCP server so any AI assistant can query parliamentary data directly.</p>
<p>Almost a year ago, I wrote about <a href="https://www.liip.ch/en/blog/exploring-ai-workflows-and-agents-with-langgraph-and-langflow">building a Swiss Parliament Bot with LangGraph</a>. The bot answered questions about the federal parliament by constructing OData queries against the totally unofficial parlament.ch API. It worked, but the OData API had its quirks, was sometimes slow and totally unofficially used. I didn't work on it any further since then.</p>
<p>The migration was smooth. The LangGraph workflow itself didn't need to change at all. It's still the same boring four-step loop: generate API URLs, fetch data, evaluate whether the data is sufficient, and generate a response. If the evaluator says the data isn't enough, it loops back and tries different URLs. That architecture proved its worth here, because swapping out the underlying API was essentially a prompt and data-handling change, not a structural one. And that was the goal of this quick adjustment, not coming up with something totally new. Just use that new, more supported API.</p>
<p>What did change significantly was the prompt. The original prompt listed all OData entities with their fields and taught the LLM how to construct OData filter expressions. The new prompt does the same for OpenParlData's REST endpoints, with parameters like <code>search</code>, <code>search_mode=partial</code>, <code>sort_by=-begin_date</code>, and <code>expand=memberships</code>. The LLM had no trouble adapting. REST with query parameters is arguably more natural for it than OData's somewhat unusual syntax.</p>
<p>The biggest functional upgrade is the scope. The old bot only knew about the Nationalrat and Ständerat. Now it can answer questions about any parliament in the system. Ask "Welche Vorstösse gibt es zum Thema Künstliche Intelligenz?" and it searches across all parliaments. Ask about the "Finanzkommission des Nationalrats" and it narrows to <code>body_key=CHE</code>. Ask about the "Zürcher Kantonsrat" and it filters with <code>body_key=ZH</code>. </p>
<p>The bot is still a prototype and far from perfect. Not all cantonal parliaments have the same data coverage. Some queries work beautifully, others return empty results because the data simply isn't there yet. But the foundation is there, and as more parliaments feed data into OpenParlData, the bot will automatically benefit.</p>
<h2>An MCP Server on Top</h2>
<p>With the API migration done, I had a clean REST-based data layer sitting there. That made me think: why limit access to the chatbot? The <a href="https://modelcontextprotocol.io">Model Context Protocol (MCP)</a> has been getting a lot of attention as a way for AI assistants to call external tools directly. And a well-structured REST API is pretty much the ideal thing to wrap in MCP tools.</p>
<p>So I built an MCP server that exposes the OpenParlData endpoints as tools that any MCP-compatible client can call — Claude Desktop, Cursor, or anything else that speaks the protocol. Each API endpoint becomes a tool: <code>persons</code>, <code>affairs</code>, <code>votings</code>, <code>memberships</code>, and so on. The AI assistant can search for parliament members, look up voting records, or drill into affair details, all without going through the chatbot UI. </p>
<p>Of course the right place for that MCP would be directly at OpenParlData. I didn't see anything about that yet. Time will tell.</p>
<p>You can try the chatbot at <a href="https://swissparliamentbot.gpt.liip.ch/">swissparliamentbot.gpt.liip.ch</a>, or connect your MCP client to <code>https://swissparliamentbot.gpt.liip.ch/mcp</code>.</p>]]></description>
    </item>
        <item>
      <title>Syncing Databases</title>
      <link>https://www.liip.ch/de/blog/syncing-databases</link>
      <guid>https://www.liip.ch/de/blog/syncing-databases</guid>
      <pubDate>Tue, 10 Feb 2026 00:00:00 +0100</pubDate>
      <description><![CDATA[<p>I recently needed to sync two databases with similar content but different structures. Here is how I solved it, and what I discovered along the way.</p>
<p>To illustrate I will use the objects below.</p>
<pre><code class="language-ts">const sourceUser = {
    id: "94aef3ae-43d1-4847-b5c3-c2ea2d42c52a",
    email: "falk@liip.ch",
    rights: ["read", "write", "admin"],
    otherStuff: "whatever",
};

const targetUser = {
    id: "3",
    mail: "falk@liip.ch",
    rights: ["read", "admin", "write"],
};</code></pre>
<h2>Constraints</h2>
<p>I had three constraints for my solution:</p>
<ul>
<li>It should only use plain objects. No Sets, Maps or Classes. This keeps things simple if an API sits between.</li>
<li>The pattern should easily apply to any object once set up.</li>
<li>It should be built in TypeScript since the rest of the project uses TypeScript.</li>
</ul>
<p>Let's get right into it.</p>
<h2>Mapping the Structure</h2>
<p>The first step was to map the <code>sourceUser</code> into the same structure as the <code>targetUser</code>.</p>
<pre><code class="language-ts">const mapUser = ({ email, rights }) =&gt; ({ mail: email, rights });

const mappedSourceUser = mapUser(sourceUser);
// {
//    mail: "falk@liip.ch",
//    rights: ["read", "write", "admin"],
// };</code></pre>
<p>I could also have built a configuration based solution like below.</p>
<pre><code class="language-yaml">mappings:
    users:
        email: mail
        rights: rights</code></pre>
<p>But in practice, I found it is often easier to just use code. In most cases processing values (like <code>toLowerCase</code>) is needed at some point. At that point you will be better off with just code. The guiding principle here is <strong>plan for change</strong>.</p>
<h2>Comparing Objects</h2>
<p>Then I structurally compared the objects.</p>
<pre><code class="language-ts">const hasChanges = !equal(mappedSourceUser, targetUser);</code></pre>
<p>I chose structural comparison here, because it nicely fits the goal of easy application for any object.</p>
<h2>Full Update on Change</h2>
<p>Whenever a change was detected by the comparison, I updated the whole user in the target database.</p>
<p>I opted for full updates on purpose. While this is less efficient than partial updates, it also makes the system a whole lot simpler. The guiding principle here is KISS (Keep It Simple, Stupid).</p>
<p>Easy enough, right? Here come the problems.</p>
<h2>Problems</h2>
<p>The first problem is that <code>targetUser</code> contains an additional field <code>id</code> that <code>mappedSourceUser</code> does not have. This means a naive comparison would always find differences, even when the relevant data is identical. We only want to compare fields that are relevant.</p>
<p>The second problem involves the <code>rights</code> array. It is not sorted, but the order does not matter for our purposes. The arrays <code>["read", "write", "admin"]</code> and <code>["read", "admin", "write"]</code> should be considered equal.</p>
<p>Finally, there is the question of debugging. How would I troubleshoot this setup if a comparison always flags objects as different? I would need some way to see which fields differ and why.</p>
<h2>Conclusion</h2>
<p>So basically I need a comparison library that:</p>
<ul>
<li>allows picking fields to compare</li>
<li>ignores order of certain arrays</li>
<li>logs readable diffs for debugging</li>
</ul>
<p>Surely something like this exists, right?</p>
<p>Not to my knowledge. That is why I built <a href="https://www.npmjs.com/package/sameish">sameish</a>, a lightweight library that does exactly that. It works in both browser and server environments, with an optimized bundle size of 1.57 kB gzipped. The library is fully type-safe, including the picking of fields to compare.</p>
<p>You can try it out on the <a href="https://codesandbox.io/p/sandbox/yym9zq">playground</a>.</p>]]></description>
    </item>
        <item>
      <title>Digitales &#214;kodesign: ein Nullsummenspiel?</title>
      <link>https://www.liip.ch/de/blog/digitales-oekodesign-ein-nullsummenspiel</link>
      <guid>https://www.liip.ch/de/blog/digitales-oekodesign-ein-nullsummenspiel</guid>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0100</pubDate>
      <description><![CDATA[<h3>Ein Werkzeug, um digitale Nachhaltigkeit zu einem professionellen Standard zu machen</h3>
<p>Wir haben bereits letztes Jahr über <a href="https://www.liip.ch/en/blog/responsible-web-design-practices-at-liip" rel="noreferrer" target="_blank">ein Werkzeug zur Bewertung des Nachhaltigkeitsniveaus von Liips digitalen Projekten</a> gesprochen. Das Hauptziel unserer Plattform ist es: beim Aufbau von Websites und Apps zu helfen, die sowohl effizient als auch umweltfreundlich sind.</p>
<p>Wir wollen digitale Produkte schaffen, die effizient, zugänglich und verantwortungsvoll gestaltet sind. Da immer mehr Kund:innen Nachhaltigkeit inzwischen in ihre Anforderungen aufnehmen, sind wir bereit zu zeigen, dass wir das — und mehr — liefern können.</p>
<p>Die Entwicklung dieser Plattform ist eigentlich der einfache Teil. Die größte Herausforderung liegt im Change Management: <strong>Wie helfen wir Designer:innen, Entwickler:innen und Business Developer:innen bei Liip, Nachhaltigkeit in ihre tägliche Arbeit zu integrieren? Das bedeutet, einige unserer Prozesse anzupassen.</strong></p>
<p>Ein Ansatz, den wir gewählt haben, war die Entwicklung maßgeschneiderter Schulungen für jedes Produktionsteam. In der Theorie klang das großartig, in der Praxis war es jedoch komplexer. Obwohl Nachhaltigkeit fest in der Kultur und DNA von Liip verankert ist, mussten wir ein Gleichgewicht finden. Über 150 Personen jeweils 2–3 Stunden zu schulen bedeutet viel Zeit weg von der regulären Kundenarbeit. Und sofern ein Projekt nicht explizit Eco-Design verlangt, ist es normal, dass Menschen ihre Arbeitsgewohnheiten nicht vollständig aufgrund einer einzigen Schulung ändern. Das ist nachvollziehbar. Es ist sinnvoll, sich auf das zu konzentrieren, was nötig ist, um effizient zu bleiben und Projekte termingerecht umzusetzen. Deshalb haben wir uns entschieden, Schulungen nur dann anzubieten, wenn ein Projekt sie tatsächlich benötigt.</p>
<p>Dadurch ergab sich eine weitere Herausforderung: Um unsere Teams weiterzubilden, müssen Kund:innen offen dafür sein, ihre Projekte auditieren zu lassen. Anders gesagt: Wir müssen den echten Mehrwert von Eco-Design aufzeigen.</p>
<h3>Die „Nullsummen“-Denkweise rund um Web-Eco-Design</h3>
<p>Ein Nullsummenspiel bedeutet, dass der Gewinn der einen Person mit dem Verlust einer anderen einhergeht. Nach meinen bisherigen Erfahrungen wird digitale Nachhaltigkeit oft genau so dargestellt — als müsste man sich zwischen Ökologie und wirtschaftlicher Performance entscheiden, wie bei einem Zielkonflikt. Diese polarisierte Sichtweise erschwert Gespräche über Nachhaltigkeit. Manchmal vermeide ich sogar das Wort „Öko“, wenn ich über die Vorteile nachhaltigen Designs spreche, und konzentriere mich stattdessen auf greifbarere Nutzen.</p>
<p>Der Mehrwert von Eco-Design liegt in besserer Zugänglichkeit, besserem SEO und höherer Performance — all das unterstützt Nachhaltigkeit durch clevere technische Optimierungen und durchdachte Designentscheidungen.</p>
<p>Es gibt außerdem die hartnäckige Fehlannahme, dass eine eco-designte Website automatisch schlicht oder langweilig sein müsse: nur schwarz-weiß, keine Bilder, nichts Ansprechendes. Diese Vorstellung von Eco-Design könnte kaum weiter von der Realität entfernt sein.</p>
<p>Einfachheit und Nachhaltigkeit müssen nicht auf Kosten von Ästhetik oder Nutzer:innenbindung gehen. Im Gegenteil: Durchdachtes Design kann eine Website gleichzeitig attraktiv und effizient machen.</p>
<p><strong>Eco-Design — egal ob für eine Website oder ein physisches Produkt — umfasst Dutzende, wenn nicht Hunderte von Parametern, die berücksichtigt werden müssen, um begrenzte Ressourcen bestmöglich zu nutzen. Im Fall von Websites gibt es zudem viele Best Practices, die bereits angewendet wurden, als es noch kein 3G und keine leistungsstarken Smartphones gab.</strong></p>
<h3>Wo stehen wir heute?</h3>
<p>Ich hoffe, dass wir eines Tages nicht mehr fragen müssen, ob etwas nachhaltig ist — es wird einfach Teil des Prozesses sein, so wie Barrierefreiheit und Responsiveness. Unser Bewertungstool funktioniert wie eine Checkliste, mit der wir potenzielle Verbesserungen identifizieren können, die in zukünftigen Updates und Wartungsphasen der von uns gelieferten Projekte eingeplant werden.</p>
<p>Wir machen gute Fortschritte. Unterschiedliche Teams bei Liip arbeiten auf unterschiedliche Weise und mit verschiedenen Technologien. <strong>Aktuell integrieren bereits einige Teams bei Liip Nachhaltigkeitsbewertungen in ihre Angebote. Unser Ziel ist es, dies unternehmensweit zum Standard zu machen.</strong></p>
<p>Weitere Projekte unterstützen dieses Ziel. So verfeinern wir intern derzeit <a href="https://www.liip.ch/en/blog/shaping-ai-for-the-people-and-the-planet" rel="noreferrer" target="_blank">neue Kriterien f&uuml;r KI-basierte Funktionen und Produkte</a>, und wir untersuchen, wie wir mehr Designer:innen in den Prozess einbinden können — denn die Design-Spezifikationen, die sie den Entwickler:innen liefern, können einen positiven Einfluss auf die Gesamtbilanz haben.</p>
<figure><img alt="" src="https://liip.rokka.io/www_inarticle_5/3548e6/step-alt.jpg" srcset="https://liip.rokka.io/www_inarticle_5/o-dpr-2/3548e6/step-alt.jpg 2x"></figure>
<p>Wenn eine Bewertung Teil eines Projekts ist, arbeiten wir frühzeitig und eng mit den Stakeholdern zusammen, um zentrale Nachhaltigkeitsempfehlungen zu identifizieren und umzusetzen. Erfreulicherweise stellen wir fest, dass viele bewährte Praktiken bereits in unseren Prozessen verankert sind.</p>
<p>Am Ende eines Projekts, beim MVP oder Go-Live, führen wir eine abschließende Bewertung durch, um hervorzuheben, was gut funktioniert hat und wo weiteres Optimierungspotenzial besteht. Die Empfehlungen können anschließend für zukünftige Updates oder die Wartung priorisiert werden. Diese Verbesserungen reduzieren nicht nur die Umweltbelastung, sondern verbessern auch Barrierefreiheit, Geschwindigkeit und die gesamte User Experience.</p>
<p>Wenn Sie ein konkretes Beispiel sehen möchten, werfen Sie einen Blick auf IT4Future, für das wir eine vollständige Evaluation durchgeführt haben. Diese finden Sie auf <a href="https://it4future.org/eco-conception" rel="noreferrer" target="_blank">ihrer Eco-Design-Seite</a>.</p>
<h3>Und nicht zuletzt: Lernen Sie Lowwwimpact kennen</h3>
<p>Wir planen, in Kürze ein Update unserer Plattform zu veröffentlichen, das es uns ermöglicht, Bewertungen intern deutlich schneller durchzuführen und gleichzeitig unseren Kund:innen einen konkreteren Mehrwert zu bieten. Ich bin überzeugt, dass dies Liip dabei helfen wird, Eco-Design zu einem Standard zu machen.</p>
<p>Wir planen, unsere Plattform für alle zu öffnen — und das Beste daran: Sie können sich bereits jetzt auf unsere Warteliste setzen lassen, um <a href="https://lowwwimpact.com/" rel="noreferrer" target="_blank">zu unseren ersten Nutzer:innen zu geh&ouml;ren</a>.</p>
<figure><img alt="" src="https://liip.rokka.io/www_inarticle_5/0ba481/6.jpg" srcset="https://liip.rokka.io/www_inarticle_5/o-dpr-2/0ba481/6.jpg 2x"></figure>
<p>Haben Sie eine Frage, einen Kommentar oder eine Inspiration, die Sie teilen möchten? Zögern Sie nicht, <a href="mailto:&#x2e;&#108;&#97;&#x6e;&#116;&#104;&#x65;&#x6d;&#x61;&#x6e;&#110;&#x40;&#x6c;&#x69;&#x69;&#112;&#x2e;&#99;&#104;">Kontakt mit uns aufzunehmen</a>, wenn Sie mehr über unseren Ansatz im Bereich Eco-Design erfahren möchten.</p>]]></description>
    </item>
      </channel>
</rss>