Warum so viele?

Von außen sieht das hier nach einer Sammlung aus — nach Werkzeugen, die jemand über die Jahre angehäuft und nie aufgeräumt hat. Das ist der naheliegende Verdacht, und er ist falsch.

Kein Werkzeug auf dieser Seite stand am Anfang. Am Anfang stand jedes Mal etwas, das fehlte, während wir an etwas anderem gebaut haben. Drei Ausgangspunkte, und von dort aus eine Kette.

Ein System, das Kühlschränke überwacht

Das größte Stück Software hier überwacht Temperaturen, Lager und Räume — für Apotheken, Labore und Lebensmittelbetriebe, mit Audit-Trail und Berichten, die einer Prüfung standhalten. Vieles, was daneben steht, entstand, weil dieses System etwas brauchte, das es so nicht gab.

Messwerte, die man ein halbes Jahr später noch versteht

Einen Temperaturverlauf zu zeichnen ist keine Kunst. Einen zu zeichnen, an dem man Monate später noch erkennt, was in der Nacht zum Dienstag passiert ist, schon: dafür braucht es Schwellen, Zonen, Marker und Anmerkungen — genau das, was bei einer Störungsanalyse die eigentliche Arbeit ausmacht.

MLTimeGraph zeichnet dieselbe Kurve im Browser und auf dem Server, in TypeScript und in Go. Dass beide wirklich dasselbe zeichnen, prüft ein Test bei jedem Lauf. Für Belegungen und Verteilungen über eine Fläche kam die isometrische Heatmap dazu.

Sensor-MonitoringMesswerte müssen in den BerichtMLTimeGraphIsometric Heatmap

Jeder Fühler braucht einen Aufkleber

Messstellen, Geräte, Kalibrierscheine — alles will eindeutig gekennzeichnet und später wieder eingelesen werden. Die Bibliotheken dafür entstanden zuerst für den Eigenbedarf.

Dann bekam eine LLM einen MCP-Server dazu, damit sie Codes selbst erzeugen und lesen kann. Und die Oberfläche, die wir ursprünglich nur zum Testen gebaut hatten, war sichtbar auch für andere nützlich — also gibt es sie heute für iPhone, iPad und Android, als Desktop-App und auf der Kommandozeile.

Sensor-Monitoringkennzeichnen und wieder einleseninterne BibliothekMCP-Server für die LLMMLC Barcode

Ein Bericht, dem ein Prüfer glaubt

Ein Prüfbericht als PDF ist schnell erzeugt. Einer, bei dem sich Monate später belegen lässt, dass er seitdem nicht verändert wurde, braucht eine Unterschrift und einen Zeitstempel — und dafür ein Zertifikat, das jemand ausstellt.

Für unsere Kunden war das bisher ein eigenes Produkt: ein Vertrag mit einer Zertifizierungsstelle, monatliche Kosten, und dazu ein Programm, von dem sie vielleicht fünf Prozent benutzten. Für die Unterschrift unter einen Temperaturbericht ist das die falsche Rechnung.

Also stellen wir die Zertifikate selbst aus. Sie sind in den Produkten enthalten, ohne Jahresgebühr und ohne zweiten Vertrag. Dieselbe Technik versiegelt auf der anderen Seite des Hauses Fotos — Teile von OpticScript nutzen sie.

Prüfberichtemüssen nachweisbar unverändert seinfremdes Produkt, monatlich, zu 5 % genutzteigene PKI

Ein Werkzeug, das wir selbst kaum noch brauchen

Die Prüfberichte entstanden zuerst als HTML und wurden daraus in PDF gegossen. Das ist ein guter Weg, und der Dienst, der das tut, kann es bis heute.

Inzwischen läuft unsere Berichts-Engine auf Markdown. Daraus erzeugen wir die PDFs direkt — erheblich schneller als über ein eingebettetes Chrome. Der PDF Server ist damit bei uns intern fast arbeitslos geworden.

Freigegeben haben wir ihn trotzdem, statt ihn einzumotten. Er löst das Problem, für das er gebaut wurde, nach wie vor gut; dass wir es heute anders lösen, macht ihn für andere nicht schlechter.

PrüfberichteHTML zu PDFPDF ServerUmstieg auf Markdownbei uns kaum noch im Einsatz

Eine lokale LLM, die nichts anfassen konnte

Wir wollten eine LLM lokal für bestimmte Aufgaben nutzen — ohne dass Daten das Haus verlassen. Aufgesetzt war sie schnell. Dann stellten wir fest, dass hier etwas fehlt.

Reden reicht nicht

Ein Modell, das nur antworten kann, hilft im Arbeitsalltag begrenzt. Sobald es etwas tun soll — einen Code erzeugen, eine Messreihe zeichnen, eine Datei ablegen —, fehlt ihm der Weg dorthin. Das Model Context Protocol ist dieser Weg, aber die Server dafür muss jemand schreiben.

Also schrieben wir sie. Erst für das, was wir selbst täglich brauchten — der Barcode-Server weiter oben war einer der ersten —, dann für das, was sich darüber hinaus als nützlich herausstellte.

lokale LLMkann nichts anfasseneigene MCP-Server

Erklären war schwerer als bauen

Einen MCP-Server zu schreiben ist nicht schwer. Einen zu schreiben, den ein Modell auch so benutzt, wie man es sich gedacht hat, schon. Damit dieses Wissen nicht an einzelnen Köpfen hängt, haben wir aufgeschrieben, was wir gelernt hatten.

Von den Grundlagen bis zu agentischen Servern und Sampling — mit dem Teil, der uns am meisten gekostet hat: wie man einen Server so entwirft, dass er sich von selbst erklärt.

eigene MCP-ServerWissen im Haus verteilenDas MCP-Handbuch

Die Tests waren teurer als der Server

Unsere MCP-Server taten nicht immer, was sie sollten. Schlimmer: manche hörten von einem Tag auf den anderen auf, mit neueren Clients zu arbeiten — ohne dass sich bei uns etwas geändert hätte. Wir brauchten also etwas, das gegen die aktuelle Spezifikation prüft, nicht gegen die, die beim Schreiben galt.

Unit-Tests für MCP-Server waren aufwendig und kosteten bei jedem Lauf LLM-Aufrufe. Deshalb hat der Tester eine eigene Abfragesprache bekommen: ein Skript beschreibt, was ein Aufruf zurückgeben soll, und prüft das ohne ein einziges Modell. Und weil die Dokumentation von Hand genauso mühsam war, erzeugt er ein Dokument, das zeigt, wie eine LLM den Server sieht.

eigene MCP-Serverbrechen mit neuen ClientsMCP-Testereigene Abfragespracheerzeugte Doku

Drei Server, ein Datensatz — und nichts davon gehört ins Modell

Eine Frage wie „zeig mir diese Tabelle als Diagramm" geht durch mehrere Hände: ein Server holt die Daten, einer rechnet, einer zeichnet. Die Zwischenergebnisse müssen von einem zum nächsten — aber nicht durch das Modell hindurch.

Große Anbieter haben für genau das eigene Dienste. Lokal gibt es die nicht. Und Daten über den Kontext weiterzureichen ist nicht nur teuer: wenn auf der einen Seite eine Datenbank steht und auf der anderen ein Bildgenerator, ist es auch ein Sicherheitsproblem.

mlcartifact ist die Ablage dazwischen. Ein Server legt sein Ergebnis ab und gibt eine Kennung weiter, der nächste holt es sich darüber. Das Modell sieht die Kennung, nicht die Daten.

mehrere MCP-Server an einer AufgabeZwischenergebnisse weiterreichenaber nicht durch den Kontextmlcartifact

Modelle können nicht rechnen

„Wie lange war der Sensor außerhalb des zulässigen Bereichs?" klingt nach einer leichten Frage. Für ein Sprachmodell ist sie es nicht: die Antworten waren oft plausibel und falsch. Beim Durchschnitt einer Messreihe von–bis dasselbe Bild.

Statt dem Modell das Rechnen beizubringen, lassen wir es eine Funktion schreiben. Es formuliert das Problem als TypeScript, die Funktion läuft, und heraus kommt eine Zahl aus einer Rechnung statt eine aus einer Vorhersage. In der Praxis funktioniert das erstaunlich gut.

Fragen an MessreihenModell rechnet plausibel und falschModell schreibt die Funktion selbstWollmilchsau

Unser eigener Arbeitstag

Der dritte Ausgangspunkt ist der unspektakulärste. Wir entwickeln entfernt, dokumentieren in Markdown und brauchen dafür Bilder. Jedes dieser drei Dinge hat ein Werkzeug hervorgebracht.

Der Rechner, auf dem gebaut wird, steht woanders

Entwicklung findet bei uns fast immer entfernt statt, auf einem Server, der nur über SSH erreichbar ist. Ein Terminal allein reicht dafür nicht: man will Dateien sehen, eine davon schnell ändern, die Container danebenlaufen sehen — und das am liebsten in einem Fenster statt in sechs.

Der erste Versuch hieß MLCRemote und arbeitete wie VS Code: ein Agent wird auf dem entfernten Rechner installiert, alles weitere spricht mit ihm. Das funktionierte ausgezeichnet — nur nicht auf kleinen Servern, und schon gar nicht beim Kunden. Niemand möchte, dass auf seinem Produktivsystem etwas installiert wird, bloß weil wir es uns ansehen sollen.

Also noch einmal von vorn, diesmal über reines SSH: MLC Terminal. Weil sich damit auch Kundensysteme bequem unterstützen lassen, kam der Teil für Docker und Server-Überwachung dazu. Darauf aufbauend entstand ein kleines Tray-Symbol, das zeigt, wer gerade mit einem Rechner verbunden ist.

Entwicklung nur über SSHMLCRemoteAgent auf dem Zielsystembeim Kunden nicht machbarMLC TerminalSSH Tray Agent

Handbücher schreiben sich in Markdown

Wir dokumentieren fast alles in Markdown — Handbücher, Arbeitsanweisungen, interne Notizen. Was dabei fehlte, war ein Editor, der daraus auch etwas macht, das man jemandem in die Hand drücken kann, und der die Dokumente dabei auf dem eigenen Rechner lässt.

alles in Markdowndaraus muss ein Formular werdenMarkSafe

Bilder von Hand anzupassen ist Fleißarbeit

Zu guter Dokumentation gehören Bilder, und Bilder wollen zugeschnitten, skaliert, beschriftet und in drei Formaten abgelegt werden. Von Hand ist das jedes Mal dieselbe halbe Stunde.

OpticScript macht daraus ein Skript: zuschneiden, skalieren, beschriften, nach PNG, JPEG oder WebP schreiben — wiederholbar und ohne Maus. Unsere Unit-Tests nutzen es für Bildvergleiche. Und der Foto-Schutz, der auf derselben Engine sitzt, versiegelt und kennzeichnet Bilder so, dass sich später belegen lässt, von wem sie stammen.

Bilder für die Dokujedes Mal dieselbe halbe StundeMLC OpticScriptFoto-Schutz

Bilder, ohne sich ein Wochenende freizunehmen

Für lokale Bilderzeugung gibt es sehr gute Werkzeuge — ComfyUI und andere. Nur will und kann sich nicht jeder stundenlang einlesen, wie man so etwas aufbaut. Und es sollte auf einem Mitarbeiter-Laptop laufen, nicht nur auf einer Maschine mit teurer Grafikkarte.

Daraus wurden zwei Prototypen mit offenen Modellen, dazu ein Studio, das die erzeugten Bilder mit Stichwörtern und Stilen wieder auffindbar macht. Und weil sich zeigte, dass solche Bilder beim Vergrößern fürs Drucken Artefakte bekommen, kam ein eigener Dienst fürs Hochskalieren dazu.

Bilder für Handbücherkein Wochenende für die EinrichtungZ-ImageMLC SDOllama Studiobeim Drucken ArtefakteMLCUpscale

Habe ich vergessen, etwas einzuchecken?

Wer an mehreren Projekten gleichzeitig arbeitet, hat am Freitagnachmittag ein Dutzend Arbeitskopien auf der Platte und keine Vorstellung mehr davon, welche davon sauber ist. Die Frage ist banal, und die Antwort über zwölf Verzeichnisse hinweg mühsam.

GitPulseMLC beantwortet sie auf einen Blick, für lokale und entfernte Repositories zugleich. Das kleinste Werkzeug hier — und eines, das jeder im Haus benutzt.

ein Dutzend Arbeitskopienhabe ich alles eingecheckt?GitPulseMLC

Und warum immer dieselben drei Sprachen?

TypeScript, Go und Rust — fast alles hier ist in einer dieser drei geschrieben. Das ist keine Geschmacksfrage, sondern folgt aus derselben Not wie der Rest.

Wir entwickeln für Windows, macOS und Unix. Was wir bauen, soll auf allen dreien laufen, ohne dass daraus jedes Mal drei Projekte werden. Go und Rust übersetzen in eine einzelne Datei, die man hinlegt und startet — kein Laufzeitsystem, keine Abhängigkeit, die beim Anwender fehlt. TypeScript läuft ohnehin überall, wo ein Browser ist.

Python und C# sind gute Sprachen, daran liegt es nicht. Aber bei beiden beginnt die Arbeit für den Anwender mit einer Einrichtung, die auf jedem Betriebssystem anders aussieht — und bei einem Werkzeug, das jemand einmal im Monat braucht, ist genau das die Stelle, an der er aufgibt.

Was daraus folgt

Das meiste, was hier steht, benutzen wir täglich selbst. Es wird gepflegt und erweitert, wenn sich im Gebrauch zeigt, dass etwas fehlt. Nichts davon ist ein Wochenendprojekt, das seit zwei Jahren auf dieselbe Version zeigt — und wo ein Werkzeug bei uns aus dem Takt gefallen ist, steht das oben dabei.

Vieles ist offen im Quelltext, und zwar dann, wenn wir glauben, dass es auch anderen hilft. Das ist kein Altruismus: Rückmeldungen von Leuten, die ein Werkzeug anders benutzen als wir, haben hier schon mehr Fehler gefunden als jeder interne Test.

Diese Seite ist selbst ein Beispiel

Was Sie gerade lesen, ist mit denselben Werkzeugen gebaut. Die Produktseiten erzeugt mlcprodweb, ein eigenes Go-Programm, aus je einer meta.yaml, die im Repository des jeweiligen Projekts liegt — wer das Produkt ändert, ändert die Seite gleich mit. Die Anmeldung oben rechts läuft über mlcauth.

Die Abbildungen im MLCRough-Handbuch zeichnet die Bibliothek, die das Handbuch beschreibt. Beim MLTimeGraph-Handbuch dasselbe, dazu fünfzehn Demos, die im Browser laufen statt als Bildschirmfoto danebenzustehen.

Als Nächstes gehen die Bilder dieser Seite durch OpticScript — signiert und gekennzeichnet, so wie es auf den OpticScript-Seiten schon geschieht. Dass uns an unserem eigenen Auftritt zuerst auffällt, wenn etwas fehlt, ist kein Zufall: er ist der erste Kunde.

In eigener Sache

Vieles hier ist offen im Quelltext. Manches kostet eine kleine Gebühr, und dafür gibt es einen Grund, den wir lieber aufschreiben als verschweigen.

Ein internes Werkzeug ist fertig, wenn es bei uns läuft. Ein Produkt ist es erst, wenn es auch auf einem fremden Rechner läuft, eine Anleitung hat, signiert ausgeliefert wird und jemand antwortet, wenn etwas klemmt. Dieser Unterschied ist Arbeit, und er kostet laufend Geld — Hosting, Zertifikate fürs Signieren, Dateien, die irgendwo liegen und ausgeliefert werden müssen.

Die Preise sind so gerechnet, dass sie genau das abdecken, und nicht mehr. Software zu verkaufen ist nicht unser täglich Brot — wir verdienen unser Geld mit dem, wofür diese Werkzeuge gebaut wurden. Was Sie hier zahlen, hält das Werkzeug verfügbar.

Zum Katalog →