Alain Lilic

Arbeitsweise

Ich arbeite mit Claude Code. Meine Zeit geht in Anforderung, Spezifikation, Review, Tests und Betrieb. Hier zeige ich die Werkzeuge und Regeln dafür, mit echten Auszügen und gemessenen Zahlen.

Erst die Spezifikation, dann der Plan, dann der Code

Bevor Code entsteht, schreibe ich eine Spezifikation: Kontext, Ziel, Entscheidungen mit Begründung und was bewusst nicht gebaut wird. Daraus wird ein Umsetzungsplan mit kleinen Schritten zum Abhaken, jeder mit Befehl und erwartetem Ergebnis. Erst dann wird gebaut, Schritt für Schritt. Größere Vorhaben teile ich in Phasen, und jede Phase bekommt ihre eigene Spezifikation. In meiner globalen Regeldatei stehen dazu vier Regeln nach Karpathy: erst denken, einfach bleiben, nur das Nötige ändern, gegen ein prüfbares Ziel arbeiten. Die Zahlen unten stammen aus einem Payload-Projekt vom 07.07.2026.

93
Zeilen Spezifikation, als erster Commit im Repo
1061
Zeilen Umsetzungsplan mit Schritten zum Abhaken
25 min
von der Spezifikation bis zum ersten Code-Commit

Eigene Hooks: Regeln, die nicht vergessen werden

Eine Regel in einer Textdatei ist eine Bitte. Ein Hook ist eine Grenze. Für alle meine Texte gelten Stilregeln, zum Beispiel verbotene Zeichen wie Gedankenstriche. Die Regel stand in mehreren Projektnotizen, trotzdem standen am 14.09.2026 solche Striche auf mehreren Live-Seiten. Seitdem prüft ein eigener PreToolUse-Hook jeden Schreibvorgang, jeden Shell-Befehl und jeden MCP-Aufruf, bevor er ausgeführt wird. Findet er ein verbotenes Zeichen, blockiert er den Aufruf und schickt dem Agenten die Fundstelle mit Ersatzvorschlag zurück. Der Agent korrigiert und sendet neu.

hooks/keine-gedankenstriche.py (gekürzt)Seitlich scrollenpython
MUSTER = re.compile(r"[...]|&[mn]dash;|&#821[12];|&#x201[34];", re.IGNORECASE)

def main():
    try:
        daten = json.load(sys.stdin)
    except Exception:
        return 0
    name = daten.get("tool_name") or ""
    ein = daten.get("tool_input") or {}
    if name == "Write":
        kandidaten = [ein.get("content") or ""]
    # ... Edit, MultiEdit, NotebookEdit und Bash analog
    elif name.startswith("mcp__"):
        kandidaten = list(texte(ein))
    else:
        return 0

    funde = []
    for text in kandidaten:
        for m in MUSTER.finditer(text):
            funde.append(text[max(0, m.start() - 40):m.end() + 25].replace("\n", " "))
    if not funde:
        return 0
    # ... Begründung mit Fundstellen nach stderr
    return 2
Der eigene PreToolUse-Hook, gekürzt. Exit-Code 2 blockiert den Aufruf, der Text auf stderr geht als Begründung an den Agenten. Die Zeichenklasse ist hier ausgelassen, in der Datei stehen die Zeichen selbst.

Skills mit gemessenen Evals

Ein Skill ist eine wiederverwendbare Anleitung, die mein Coding-Agent bei passenden Aufgaben lädt. Ich behandle Skills wie Code: Dieselben Testaufgaben laufen mit und ohne Skill, Prüfskripte bewerten jede Ausgabe gegen feste Kriterien, und das Ergebnis liegt als Benchmark-Datei im Eval-Ordner. So sehe ich, ob ein Skill hilft und was er kostet. Nicht jeder Skill gewinnt deutlich: ui-master lag in der ersten Runde nur leicht vorn und brauchte im Schnitt 57 % mehr Tokens. Die Messreihen sind klein, drei bis sechs Aufgaben je Runde. Sie ersetzen kein Urteil, aber sie verhindern, dass ich mir eine Verbesserung nur einbilde.

24 % / 94 %
ein Recherche-Skill: Bestehensquote ohne / mit Skill, 3 Aufgaben (03/2026)
89 % / 94 %
ui-master: ohne / mit Skill, 4 Aufgaben (05/2026)
+57 %
mehr Tokens pro Lauf mit ui-master in derselben Runde
37 / 37
ui-master: überarbeitete Fassung, alte Fassung 35 / 37, 6 Aufgaben (08/2026)

Ein Wiki als Langzeitgedächtnis

Ein Coding-Agent vergisst zwischen zwei Sitzungen fast alles. Deshalb führen meine Agenten ein Markdown-Wiki nach dem LLM-Wiki-Muster von Andrej Karpathy. Jedes Projekt hat eine kurze Steckbrief-Seite, nach größeren Arbeiten entsteht eine Synthese mit Entscheidungen und Funden, und jede Sitzung endet mit einem Eintrag im Tagesjournal, Sackgassen eingeschlossen. Den Katalog meiner Skills, Agenten, Plugins, MCP-Server und Hooks erzeugt ein Bash-Skript aus dem Dateisystem neu. Agenten lesen zuerst den Index und dann nur die Seiten, die sie brauchen. Das spart Tokens und hält den Kontext klein.

577
Markdown-Seiten im Wiki (18.10.2026)
317
davon automatisch erzeugte Katalogseiten
53
Tagesjournale seit dem 20.07.2026
35
Synthesen nach größeren Arbeiten

Multi-Agenten-Workflows mit klaren Rollen

Größere Aufgaben verteile ich auf mehrere Agenten, die parallel arbeiten. Jeder hat eine Rolle: Späher lesen nur, Bauer schreiben Code, Prüfer suchen gezielt Fehler in Fakten, Sicherheit und Oberfläche, danach folgt eine Fix-Runde. Am Ende schaue ich mir die Ergebnisse selbst an, und in Produktion geht nur, was ich freigebe. Ein Beispiel ist dieses Portfolio: Am 18.10.2026 hat ein Workflow mit fünf parallelen Lese-Agenten Stellenanzeigen, meine Projekte und den Stand der Domain inventarisiert. Am selben Tag liefen an meiner Agenten-Plattform vier Workflows mit je zehn Agenten. Vor dem Deploy war die Testsuite grün.

5
parallele Lese-Agenten für die Inventur dieses Portfolios
392 s
Laufzeit dieser Inventur
4 x 10
Agenten an meiner Agenten-Plattform am selben Tag

Erst das Bild, dann die Behauptung

Bis zum 01.08.2026 habe ich eine Website mit WebGL-Animationen über Messwerte geprüft. Die Zahlen stimmten, während die Seite auf dem Handy sichtbar kaputt war. Seitdem gilt: Jede Aussage über das Aussehen braucht ein Bild, das ein Mensch anschauen kann. Dafür gibt es einen Prüfstand mit Playwright: echter Browser mit WebGL, fünf Geräteprofile, Vergleich gegen Referenzbilder. Für Logik gilt dasselbe mit Tests. Ich sage erst, dass etwas funktioniert, wenn die Tests laufen und ich das Ergebnis gesehen habe.

pruefstand.mjs (gekürzt)Seitlich scrollenjavascript
/* Prüfstand: echter Browser, echte Geräteprofile, echte Bilder MIT WebGL-Ebene.
 *
 * Warum es diese Datei gibt: bis 2026-08-01 wurde die Choreografie über
 * `[...].state()` und Helligkeitsmittelwerte aus einem Canvas-Puffer
 * geprüft. Beides sind Stellvertreter. Sie haben bestätigt, dass Zahlen
 * stimmen, während die Seite auf dem Telefon sichtbar kaputt war: Körper auf
 * dem Fließtext, zerrissene Karten-Kompositionen, ein grauer Kasten um die
 * Schlusszeile. Kein Messwert hat davon etwas gemeldet.
 *
 * Regel, die daraus folgt: JEDE Behauptung über das Aussehen braucht ein Bild,
 * das ein Mensch anschauen kann. `state()` ist danach nützlich, um zu erklären
 * WARUM etwas so aussieht, nie, um zu behaupten, dass es gut aussieht.
 */
// ...
const PROFILE = {
  iphone: { ...devices["iPhone 13"] },
  pixel: { ...devices["Pixel 5"] },
  ipad: { ...devices["iPad (gen 7)"] },
  klein: { viewport: { width: 1000, height: 700 }, deviceScaleFactor: 1 },
  desktop: { viewport: { width: 1465, height: 900 }, deviceScaleFactor: 1 }
};
Kopf und Geräteprofile des Prüfstands, gekürzt. Ein Gedankenstrich im Original ist hier durch ein Komma ersetzt, ein Objektname ist ausgelassen.
5
Geräteprofile: iPhone 13, Pixel 5, iPad, 1000 px, 1465 px
45
Bilder je Profil und Durchlauf

Reverse Engineering nur im Clean-Room

Am 18.10.2026 habe ich REA eingerichtet, ein Reverse-Engineering-Werkzeug, das mein Coding-Agent als MCP-Server nutzt. Dazu kommt Ghidra, dessen arm64-Decompiler ich selbst kompiliert habe, weil das offizielle Release keinen mitbringt. Einen Projekteinsatz kann ich noch nicht zeigen. Die Grenzen habe ich vor dem ersten Einsatz schriftlich festgelegt: nur öffentliches Verhalten verstehen, nur öffentlich erreichbare Seiten und Open-Source-Demos, keine Logins umgehen, kein fremder Code, keine fremden Assets, kein fremder Markenauftritt, keine Testnachrichten in die Live-Chats meiner Projekte. REA soll eine Feature-Beschreibung liefern, gebaut wird danach mit eigenem Code.