So funktioniert es
Sie schreiben ein C#-Snippet. Was es zurückgibt, ist in wenigen Sekunden unter einer öffentlichen HTTPS-Adresse erreichbar. Hier steht alles Wichtige – in der Reihenfolge, in der Sie es brauchen.
Was ein Lambda ist
Ein Lambda ist ein Snippet, das einen GenHTTP-Handler zurückgibt. Die Plattform kompiliert es, lädt es und hängt das Ergebnis unter Ihrer eigenen Adresse ein. Kein Projekt, keine Build-Datei, keine using-Anweisungen: Alle GenHTTP-Module sind schon importiert.
return Content.From(Resource.FromString("hello"));
Das ist bereits ein vollständiges Lambda. Einmal deployt, antwortet es unter einer eigenen, nach seinem Schlüssel benannten Adresse, etwa your-key.genhttp.run, und jeder Request dort erhält das Wort „hello“.
Das Snippet besteht aus Anweisungen, nicht aus einer Klasse. Zum Schluss gibt es etwas zurück, das Requests beantworten kann: einen Handler oder einen Builder dafür.
Ihr erstes Lambda
- 1Klicken Sie auf Lambda erstellen. Sie bekommen eine öffentliche Adresse und einen Editor-Schlüssel. Der Schlüssel ist der einzige Weg zurück – heben Sie ihn auf. Niemand kann ihn für Sie wiederherstellen.
- 2Sie landen im Kontrollzentrum. Als erste Version ist schon ein kleiner REST-Dienst angelegt – nur als Startpunkt.
- 3Geben Sie den Editor-Schlüssel einem Agenten und sagen Sie ihm, was er bauen soll – er schreibt über MCP neue Versionen. Oder öffnen Sie Code und schreiben Sie selbst: Prüfen kompiliert, ohne etwas zu speichern, und zeigt die Meldungen des Compilers mit Datei und Zeile.
- 4Klicken Sie auf Deployen. Jetzt ist es online – vorher ist nichts erreichbar. Jedes weitere Deployment verlängert, wie lange es online bleibt.
Das Kontrollzentrum
Der Editor-Link öffnet ein Kontrollzentrum, kein Textfeld. Den meisten Code schreiben hier Agenten, also sehen Sie zuerst, wie es Ihrem Lambda geht. Die Seitenleiste zeigt, ob das Lambda online ist, seine Adresse und seine Bereiche. Wartet eine neuere Version darauf, online zu gehen, erscheint dort ein Button. Was Sie selten brauchen, etwa die Adresse ändern oder das Lambda löschen, steckt im Menü ⋯.
- Übersicht
- Was die App ist, ob sie online ist, wie viele Requests sie heute hatte und wie viele davon fehlschlugen, die letzte Änderung und wie viel Platz noch frei ist.
- Dokumentation
- Was die App ist, für wen sie gedacht ist und warum, und warum sie so gebaut ist, wie sie ist – von Agenten geschrieben, mit jeder Version gespeichert.
- Ändern
- Sagen Sie, was anders sein soll, und der Agent auf diesem Server setzt es um, während Sie zusehen. Er probiert die Änderung in einem Entwurf aus – einer Kopie mit eigener Adresse – und stellt sie online, sobald sie funktioniert. Schalten Sie Nach Abschluss online stellen aus, um den Entwurf zuerst selbst auszuprobieren. Er arbeitet nur an Ihrer App: Eine Bitte, die nichts mit ihr zu tun hat oder Schaden anrichten soll, lehnt er ab und sagt, warum.
- Entwürfe
- Änderungen, die ausprobiert werden, bevor sie online gehen, jede unter einer eigenen Adresse und mit eigenen Testdaten. Geöffnet hat ein Entwurf eigenen Code, eigene Testdaten und eigene Logs. Der Bereich erscheint, sobald es einen Entwurf gibt.
- Daten
- Was das Lambda zur Laufzeit aufbewahrt, für alle Versionen gemeinsam: die Datenbank, der Workspace und die Secrets, jeweils mit eigenem Reiter. In Tabellen und Dateien hineinsehen, Dateien hochladen, Secrets setzen oder eine Art ein- und ausschalten. Die einfache Ansicht zeigt den Bereich, sobald die App etwas aufbewahrt.
- Versionen
- Was jede Version geändert hat, worum gebeten wurde und der Diff zur vorherigen. Von hier aus deployen oder zurückrollen – oder aus jeder von ihnen einen Entwurf beginnen.
- Deployments
- Was wann online war und warum es offline ging.
- Statistik
- Requests, Fehler, Antwortzeiten und die meistgefragten Pfade der letzten Stunde oder des letzten Tages.
- Logs
- Requests, Ausgaben und Stacktraces von allem, was schiefging – live.
- Code
- Jede Datei einer Version, ihr Code und ihre Ressourcen, in einem Baum neben dem Editor – mit dem Platz, den sie belegen, und ob sie öffentlich erreichbar sind. Wählen Sie darüber eine ältere Version, um sie zu lesen. Prüfen kompiliert, Speichern legt eine Version an, Deployen stellt sie online. In einem Entwurf behält Speichern den Code im Entwurf und zeigt ihn unter der Adresse des Entwurfs.
Strg+Sspeichert,F12springt zur Deklaration. - Tests
- Wie die App automatisch getestet wird, mit den Scripts und Testdaten dafür. Nur in der vollständigen Ansicht.
Alle Bereiche funktionieren gleich: oben der Titel, ein ⓘ mit Erklärung, rechts die Aktionen und – wo es mehrere Ansichten gibt – darunter eine Reihe von Tabs. Die vollständige Ansicht fasst die Bereiche in Gruppen zusammen: wie Leute es finden, wo eine Änderung entsteht, die Versionen und die Daten und wie es läuft.
Traffic und Log liegen im Arbeitsspeicher. Sie sind zum Beobachten da, nicht zum Aufbewahren: Nach einem Neustart des Servers beginnen sie von vorn. Versionen und der Deployment-Verlauf werden gespeichert.
Das Warum festhalten
Eine Version ist der Code plus zwei optionale Notizen: die Spezifikation – was der Nutzer möchte und warum, möglichst in seinen Worten – und die Änderung, eine Zeile dazu, was die Version tut. Beide stehen im Versionsverlauf neben dem Diff. So bleibt das Warum neben dem Was erhalten – für Sie und für den nächsten Agenten, der den Verlauf liest, bevor er etwas ändert.
POST /api/v1/lambdas/{editorKey}/versions { "files": [ { "name": "lambda.cs", "code": "..." } ], "specification": "Ein Gästebuch zum Eintragen; Einträge müssen einen Neustart überstehen", "change": "Speichert Einträge in der Datenbank, damit sie einen Neustart überstehen" }
Agenten übergeben dieselben beiden Felder an write_code. Unter Code wird beim Speichern nach der Änderung gefragt. Beides ist optional. Zu lange Texte werden gekürzt statt abgelehnt: die Spezifikation nach 4000 Zeichen, die Änderung nach 500. Ein Entwurf hat seine eigenen beiden; wird er übernommen, gehen sie an die neue Version über.
Dokumentation und Tests
Jede Version bewahrt neben ihrem Programm auf, was über sie geschrieben ist: ihre Dokumentation – was die App ist, für wen sie gedacht ist und warum, und warum sie so gebaut ist, wie sie ist – und ihre Tests: wie sich automatisch prüfen lässt, dass sie funktioniert, mit den Scripts und Testdaten dafür. Agenten schreiben beides mit einem neuen Lambda und halten es mit jeder Änderung aktuell. Der nächste Agent, der das Lambda ändert, liest es zuerst – so weiß er, wofür die App da ist und was weiter funktionieren muss. Das sagt der Code allein nicht.
- docs/product.md
- was die App ist, für wen sie gedacht ist, was Leute damit tun und warum
- docs/decisions.md
- die technischen Entscheidungen und warum sie getroffen wurden
- tests/README.md
- wie die App automatisch getestet wird und wie die Tests ausgeführt werden
- tests/…
- die Scripts und Testdaten, die die Tests verwenden
Sie sind Dateien seines Codes wie alle anderen, in den Ordnern docs und tests: Der Verlauf zeigt, was eine Version daran geändert hat, Zurückrollen bringt die Dokumentation zurück, die für diese Version galt, und ein Entwurf hat eine eigene Kopie, die mit ihm online geht. Sie werden nie kompiliert und nie ausgeliefert und zählen zu dem, was eine Version umfassen darf.
Im Kontrollzentrum zeigt Dokumentation die Seiten zum Lesen und Tests, wie die App getestet wird, samt den Dateien daneben; die Version wählen Sie wie bei ihren Dateien. Eine Seite lässt sich dort auch bearbeiten – das speichert die nächste Version. Die einfache Ansicht nennt die Dokumentation Über die App und zeigt nur, wofür die App da ist. Um das zu korrigieren, sagen Sie es dem Agenten.
Sie sind in der Sprache geschrieben, in der Sie mit dem Agenten sprechen – für den, der die App als Nächstes ändert, ob Mensch oder Agent. Keine Kopie des Codes, sondern wofür die App da ist und warum.
Gefahrlos ändern
Eine Version ändert sich nie mehr, sobald sie gespeichert ist – und genau deshalb lohnt es sich, jede aufzuheben: Jede lässt sich vergleichen und genau so wieder online stellen, wie sie war. Um ein Lambda zu ändern, das Leute nutzen, beginnen Sie stattdessen einen Entwurf.
- 1Beginnen Sie ihn aus einer beliebigen Version unter Versionen, oder lassen Sie den Agenten einen beginnen. Er ist eine Kopie von Code und Ressourcen dieser Version, darunter Dokumentation und Tests, und der Daten des Lambdas.
- 2Ändern Sie ihn so oft wie nötig – unter Code oder indem Sie den Agenten darum bitten. Seine Vorschau antwortet unter einer eigenen Adresse,
/features/…/, mit eigenen Testdaten. Besucher des Lambdas sehen nichts davon, und nichts, was er schreibt, erreicht die Daten des Lambdas. - 3Klicken Sie auf Online stellen, sobald alles passt: Der Entwurf wird zur nächsten Version, mit seinen Notizen, und geht online. Dabei verschwindet er – samt seiner Vorschau und seinen Testdaten.
POST /api/v1/lambdas/{editorKey}/features { "name": "Bestenliste" } PUT /api/v1/lambdas/{editorKey}/features/{feature}/files?deploy=true POST /api/v1/lambdas/{editorKey}/features/{feature}/merge { "deploy": true }
An mehreren Entwürfen kann gleichzeitig gearbeitet werden. Nur ein Entwurf, der auf dem neuesten Stand der Version ist, kann online gehen – damit er nie eine Version rückgängig macht, die nach seinem Beginn gespeichert wurde. Ging zuerst ein anderer online, holen Sie dessen Änderungen herein – oder bitten Sie den Agenten darum – und markieren Sie den Entwurf als aktuell. Nichts geht von selbst online; das ist Absicht. Die API nennt einen Entwurf „feature“ und das Online-Stellen „merge“.
Code und Ressourcen
Eine Version besteht aus beliebig vielen Dateien, in zwei Teilen. Ihr Code ist jede Datei außer ihren Ressourcen: Ihre .cs-Dateien werden kompiliert, in jedem Ordner, wie in jedem C#-Projekt, und jede andere Datei wird mit der Version gespeichert und nie kompiliert oder ausgeliefert: ihre Dokumentation, ihre Tests, das, woraus ein Frontend gebaut wird. Ihre Ressourcen in resources/ sind das, was sie zur Laufzeit liest und ausliefert – Seiten, Scripts, Stile, Bilder, die Migrationen der Datenbank – und die der Code als Resources erreicht.
lambda.cs the snippet: what it returns is served Shelf.cs more C#, compiled beside it models/Book.cs C# in a folder, compiled the same docs/ tests/ what is written about it frontend/ whatever else - kept, never compiled or served resources/ what it reads and serves while it runs
Typen müssen nicht unter dem Code stehen, der sie nutzt. Klicken Sie unter Code neben dem Code auf + und geben Sie einen Namen ein: Eine .cs-Datei wird zusammen mit dem Snippet im selben Namespace kompiliert, in welchem Ordner sie auch liegt, also müssen Sie nichts importieren. Ein Name ohne Endung und ohne Ordner gilt als C#.
var shelf = new Shelf(); return Inline.Create() .Get(() => shelf.All()) .Post((Book book) => shelf.Add(book));
public sealed class Shelf { private readonly List<Book> _books = []; public IEnumerable<Book> All() => _books; public Book Add(Book book) { _books.Add(book); return book; } } public record Book(string Title, string Author);
Wie der Code angeordnet ist, bleibt dem überlassen, der ihn schreibt – ein Ordner für Typen, einer für die Quellen eines Frontends, einer für Scripts. Jede .cs-Datei wird in die App kompiliert; C#, das nicht dazugehört – ein Test, ein eigenes Werkzeug –, gehört deshalb nicht als .cs-Datei in den Code. Der Code und die Ressourcen einer Version teilen sich ein Platzkontingent, das die Übersicht anzeigt.
Eine Seite ausliefern
Für eine Seite gibt es zwei Wege – und einen weiteren für das, was Leute daneben hochladen.
Eine Seite, direkt im Code
Gut für Kleines. Die Seite ist Teil des Snippets.
var page = Resource.FromString(""" <!doctype html> <title>Mine</title> <h1>It works</h1> """) .Type(new ContentType("text/html; charset=utf-8")); return Content.From(page);
Ein Ordner mit echten Dateien
Das Richtige für alles mit Stylesheet und Script. Die Dateien sind Ressourcen der Version und werden ausgeliefert, wie sie sind – nichts wird kompiliert.
return Layout.Create() .Add("api", api) .Add(Resources.App("site"));
Hochgeladene Dateien, aus den Daten
Für das, was Leute hochladen oder das Lambda erzeugt – Bilder, Dokumente –, ausgeliefert neben der App. Nicht für die Seiten der App selbst: Die gehören in die Ressourcen, damit sie in derselben Version stecken wie der Code, der sie braucht.
return Layout.Create() .Add("api", api) .Add("uploads", Workspace.Files("uploads")) .Add(Resources.App("site"));
Ein Frontend, Schritt für Schritt
Der zweite Weg im Detail. Jede Demo liefert ihre Seite so aus, aus resources/web – öffnen Sie zum Beispiel demo-crud. Demos sind schreibgeschützt; ihr Editor-Schlüssel ist ihr Name.
- 1Klicken Sie unter Code neben den Ressourcen auf + und geben Sie
site/index.htmlein: Daraus wirdresources/site/index.html. Ein Schrägstrich im Namen legt die Datei in einen Ordner. Eine Endung sagt, was für eine Datei es ist. - 2Legen Sie
site/app.cssundsite/app.jsgenauso an. Ihre Seite verweist über den Namen auf sie, etwa mithref="app.css". Denn der Ordner ist die Wurzel dessen, was ausgeliefert wird – kein Teil der Adresse. - 3Für alles, was kein Text ist, etwa Bilder oder Schriften, öffnen Sie eine Datei in
siteund klicken neben den Ressourcen auf den Upload-Button: Die Datei landet im selben Ordner. Ein PNG kann man nicht in einen Texteditor tippen – das hier ist der Weg. - 4Liefern Sie den Ordner in
lambda.csaus:return Layout.Create().Add(Resources.App("site"));
- 5Klicken Sie auf Deployen.
site/index.htmlantwortet unter/,site/app.cssunter/app.css. Jede Adresse ohne passende Datei bekommt die Seite. So funktioniert ein Frontend mit eigenem Routing auch, wenn jemand einen Deep Link neu lädt. - 6Mit einer API daneben hat die Seite auch einen Gesprächspartner:
var api = Inline.Create().Get("notes", () => notes); return Layout.Create() .Add("api", api) .Add(Resources.App("site"));
Woraus es gebaut wird
Manches an einem Lambda kann von einem Build-Werkzeug erzeugt werden, statt so geschrieben zu sein, wie es ausgeliefert oder kompiliert wird: kompiliert, gebündelt oder generiert. Die Version enthält, was das Werkzeug erzeugt – als ihre Ressourcen oder als ihren Code –, und die Dateien, aus denen es entsteht, gehören zu ihrem Code, in einem eigenen Ordner: etwa frontend/, mit einer README, die sagt, wie gebaut wird. Ihr Agent ändert diese Dateien, führt den Build dort aus, wo er arbeitet, und speichert beides in derselben Version. Diese Plattform baut nichts.
frontend/ what it is built from, in whatever shape the tool wants frontend/README.md how it is built, and where the build goes frontend/.gitignore what the build installs or keeps for itself, left out resources/web/ what the build wrote, if it makes resources *.cs what it wrote, if it makes code # run the build where you work, then git add -A && git commit -m "…" && git push -o deploy
Wie die Dokumentation gehören sie zur Version: im Verlauf verglichen, zurückgerollt, in einen Entwurf kopiert, geklont, heruntergeladen und mit dem übrigen Code veröffentlicht – und nie kompiliert oder ausgeliefert. Im Kontrollzentrum stehen sie unter Code, mit jeder anderen Datei der Version.
Was so geschrieben ist, wie es ausgeliefert oder kompiliert wird, braucht keinen. Was ein Build installiert oder für sich behält – etwa node_modules – ist nie Teil einer Version: Eine .gitignore in dessen Ordner hält es heraus.
Eine Version und ihre Daten
Ein Lambda hat Dateien an zwei Orten, und der Editor zeigt sie getrennt: Code enthält die Dateien einer Version – das Programm –, Daten den Workspace – was das Programm aufbewahrt. Der Unterschied ist, wem sie gehören. Die Dateien einer Version gehören zu dieser Version; die Daten gehören dem Lambda, und alle Versionen teilen sie. Jedes von beiden hat einen eigenen Speicherplatz: Code und Ressourcen einer Version teilen sich den einen, die Datenbank und der Workspace des Lambdas den anderen.
| In einer Version | In den Daten | |
|---|---|---|
| Inhalt | Code und Ressourcen: das Programm, samt Frontend – und seine Dokumentation, seine Tests und alles, woraus es gebaut wird | alles, was das Lambda schreibt oder jemand hochlädt |
| Ändert sich | nie – eine Änderung ist eine neue Version | sobald etwas hineingeschrieben wird |
| Ein Deployment | stellt genau diese Dateien online | lässt sie unberührt |
| Zurückrollen | bringt die alten Dateien zurück | keine Wirkung: Alle Versionen teilen sie |
| Ein Entwurf | beginnt als Kopie davon | arbeitet mit einer Kopie davon |
| Wird gelöscht | mit alten Versionen, sobald das Limit überschritten ist | mit dem Lambda oder wenn Sie sie ausschalten |
| im Code erreichbar als | Resources | Workspace |
Ein gemeinsamer Ort geht nicht. Sonst würde ein Deployment entweder alles löschen, was Ihr Lambda seitdem geschrieben hat – oder aus dem, was es ausliefert, ließe sich nie etwas entfernen. Ein Spiel mit Bestenliste braucht das Zweite, die Seite dazu das Erste. Also gehört die Seite in die Version und die Bestenliste in die Daten.
Datensätze speichern
Datensätze – Einträge, Konten, Bestellungen, Stimmen – gehören in die Datenbank: eine eigene SQLite-Datenbank des Lambdas, die Sie unter Daten einschalten. Der Code öffnet mit Database.GetConnection() eine Verbindung und liest und schreibt über Entity Framework Core, mit einem eigenen Kontext, der die Tabellen abbildet:
// resources/migrations/V1__Create_notes.sql: // CREATE TABLE notes (id INTEGER PRIMARY KEY, text TEXT NOT NULL); using (var connection = Database.GetConnection()) { new Evolve(connection) { Locations = [Resources.Root + "migrations"] }.Migrate(); } return Inline.Create() .Get("notes", () => { using var db = new Notes(Database.GetConnection()); return db.Entries.OrderBy(n => n.Id).Select(n => n.Text).ToList(); }) .Post("notes", (NoteInput input) => { using var db = new Notes(Database.GetConnection()); db.Entries.Add(new Note { Text = input.Text }); return db.SaveChanges(); }); record NoteInput(string Text); class Note { public long Id { get; set; } public string Text { get; set; } } // maps the table the migration made, on the connection it is handed class Notes(SqliteConnection connection) : DbContext { public DbSet<Note> Entries => Set<Note>(); protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseSqlite(connection, contextOwnsConnection: true); protected override void OnModelCreating(ModelBuilder model) => model.Entity<Note>().ToTable("notes"); }
Ihre Tabellen legen Migrationen an: SQL-Dateien in resources/migrations/, die zur Version gehören und beim Start des Lambdas von Evolve der Reihe nach angewendet werden – jede genau einmal, eine neue Version führt also nur aus, was neu ist. Ändern Sie nie eine Migration, die schon angewendet wurde; eine Änderung an einer Tabelle ist die nächste Datei.
Wie alle Daten teilen sich alle Versionen die Datenbank, Deployments und Zurückrollen lassen sie unberührt, und ein Entwurf arbeitet mit einer Kopie. Unter Daten sehen Sie ihre Tabellen und was darin steht – die einfache Ansicht nennt sie Einträge. Als .NET-Projekt herunterladen nimmt sie als gewöhnliche SQLite-Datei mit.
Legen Sie einen Kontext dort an, wo Sie ihn brauchen, geben Sie ihn danach wieder frei, und verwenden Sie ihn synchron – ToList und SaveChanges, nicht ToListAsync und SaveChangesAsync. Die Tabellen legen die Migrationen an, nie Entity Framework. Die Demo demo-crud zeigt all das.
Dateien speichern
Workspace ist ein privates Verzeichnis, in dem Ihr Lambda lesen und schreiben darf: der Ort für Dateien – Bilder, die jemand hochlädt, ein Dokument, das es erzeugt, ein Modell, das es lädt. Datensätze gehören in die Datenbank, und auch was man über eine Datei weiß – wer sie hochgeladen hat und wann –, ist ein Datensatz.
// uploads go into a folder of their own, served as they are Workspace.CreateFolder("photos"); return Layout.Create() .Add("photos", Workspace.Files("photos")) .Add("upload", Inline.Create().Post(async (Stream body) => { using var content = new MemoryStream(); await body.CopyToAsync(content); Workspace.WriteBytes($"photos/{Guid.NewGuid():N}.jpg", content.ToArray()); }));
Dazu gibt es ReadBytes, WriteBytes, Delete, List, CreateFolder und zum Ausliefern Tree/Files/App. Sonst ist nichts im Dateisystem erreichbar.
Schlüssel und Passwörter
Ein API-Schlüssel, ein Passwort oder ein Token gehört in die Secrets, nicht in den Code – dort hätte ihn jede Version, jeder Download und jeder, der die Historie liest. Der Code liest ein Secret über seinen Namen:
var weather = new System.Net.Http.HttpClient(); weather.DefaultRequestHeaders.Add("X-Api-Key", Secret.Read("WEATHER_API_KEY")); return Inline.Create() .Get("today", async () => await weather.GetStringAsync("https://weather.example/today"));
Schalten Sie Secrets unter Daten ein und setzen Sie den Wert dort. Einmal gespeichert, wird er nie wieder angezeigt – weder Ihnen noch einem Agenten; Sie können ihn nur ersetzen. Die Liste zeigt, welche Namen der Code liest, für die noch kein Wert gesetzt ist, und die Übersicht fragt danach. Secret.Exists sagt, ob eines gesetzt ist – für Code, der auch ohne auskommt. Wie alle Daten teilen sich alle Versionen die Secrets, und ein Entwurf arbeitet mit einer Kopie.
Sie werden verschlüsselt gespeichert, mit einem Schlüssel, der nicht in der Datenbank liegt. In einem heruntergeladenen Projekt liest Secret.Read("NAME") die Umgebungsvariable NAME – die Werte selbst bleiben hier.
Websockets
Unterstützt – und von Anfang an mitgedacht. Die Demo demo-game bringt Spieler zusammen und führt jede Partie auf dem Server aus. Die einfachste Form sind drei Callbacks:
var room = new ConcurrentDictionary<IReactiveConnection, string>(); var socket = Websocket.Functional() .OnOpen(c => { room[c] = "someone"; return ValueTask.CompletedTask; }) .OnMessage(async (c, text) => { foreach (var other in room.Keys) { await other.WritePayloadAsync(text); } }) .OnClose((c, _) => { room.TryRemove(c, out _); return ValueTask.CompletedTask; }); return Layout.Create().Add("chat", socket);
Wenn die Seite nur zuhört – ein Zähler, ein Feed, eine Rangliste –, sind Server-Sent Events einfacher: eine lange Antwort, in die der Server fortlaufend schreibt und die der Browser selbstständig wieder aufbaut. Die Demo demo-live schickt auf diese Weise jede Stimme an alle, die gerade zusehen. In beiden Fällen schickt der Server, was sich geändert hat. Eine Seite, die alle paar Sekunden erneut nachfragt, sendet jedes Mal eine Anfrage, ob sich etwas geändert hat oder nicht, und kommt trotzdem zu spät.
In diese Falle tappt jeder: Browser können beim Websocket-Handshake keine Header setzen. Übergeben Sie, was der Handler braucht, in der Query – er liest sie aus connection.Request.Header.Query. Secrets schicken Sie als erste Nachricht.
Was nicht erlaubt ist
Ihr Code läuft auf einem gemeinsam genutzten Server. Deshalb wird manches in C# schon vor dem Kompilieren abgelehnt: Prozesse starten, eigene Sockets öffnen, Assemblies laden, auf das Dateisystem außerhalb Ihres Workspace zugreifen – und Reflection, die all das umgehen soll. Ebenso das Warten auf einen Task mit .Result oder .Wait() statt await: Anfragen laufen auf einem Thread pro Kern, und der Task müsste genau auf dem Thread fertig werden, der auf ihn wartet.
Alles andere ist da, auch die komplette API der GenHTTP-Module. Wird etwas abgelehnt, sehen Sie, in welcher Zeile und warum – nicht nur, dass es fehlschlug.
Alles mitnehmen
Mit Als .NET-Projekt herunterladen im Editor bekommen Sie alles als Solution, die Sie öffnen, mit dotnet run starten und behalten können. Sie braucht nur das GenHTTP-Paket und bringt ein Dockerfile mit, um sie als Container zu bauen und zu betreiben.
Ihr Snippet wird zu Project.cs, und Program.cs liefert aus, was es zurückgibt. Ihre anderen Dateien kommen genau so mit, wie Sie sie geschrieben haben, und dort, wo sie waren – die Ressourcen in resources, die Dokumentation in docs, die Tests in tests. Workspace und Resources werden zu zwei Ordnern neben dem Programm, mit denselben Methoden, getrennt in einem Ordner Platform – an Ihrem Code ändert sich nichts. Secret liest dort gleichnamige Umgebungsvariablen; die Werte bleiben hier. Database öffnet database/database.db, die der Download samt den Einträgen enthält, die Ihre App aufbewahrt hat.
Gut zu wissen, bevor Sie hier etwas bauen: Was Sie schreiben, gehört Ihnen, und Sie können es komplett mitnehmen. Dass es auf unserem Server läuft, bindet es nicht an unseren Server.
Mit git arbeiten
Jedes Lambda ist zugleich ein git-Repository. Klonen im Kontrollzentrum, in der Übersicht und neben dem Code, zeigt seine Adresse – die Adresse Ihres Editors mit dem Namen der App dahinter –, und git clone liefert Ihnen das Projekt, das auch Herunterladen liefert, jede Version als Commit auf main, getaggt als v1, v2 und so weiter, und jeden Entwurf als Branch. Öffnen Sie es in Ihrem eigenen Editor, geben Sie es Ihrem Coding-Agent, starten Sie es mit dotnet run.
git clone https://genhttp.dev/editor/<editor key>/my-app.git cd my-app # change, commit git push -o deploy
Pushen, und es ist hier. Jeder Commit, den Sie auf main pushen, wird die nächste Version, seine erste Zeile die Änderung, die er vornimmt – zuerst kompiliert und abgelehnt, wenn er sich nicht kompilieren lässt –, und git push -o deploy stellt sie online. Ein gepushter Branch wird ein Entwurf, dessen Vorschau unter einer eigenen Adresse online ist; pushen Sie ihn auf main oder fügen Sie seinem letzten Push -o merge hinzu, dann ist er die nächste Version. Was die Plattform um Ihren Code legt, damit daraus ein Projekt wird – Program.cs, die Projektdatei, Platform –, gehört nicht zu Ihrer App; ein Push, der es ändert, wird deshalb abgelehnt, mit Begründung. AGENTS.md im Repository sagt einem Coding-Agent den Rest.
Die Adresse enthält Ihren Editor-Schlüssel, wie die Adresse des Editors: Wer sie hat, kann pushen. Was Ihre App speichert – ihre Einträge, ihre Dateien, ihre Schlüssel und Passwörter – liegt nie im Repository.
Den Code veröffentlichen
Wenn das, was Sie gebaut haben, anderen helfen könnte, veröffentlichen Sie den Code: Öffnen Sie im Kontrollzentrum Open Source, wählen Sie eine Lizenz – MIT, sofern Sie keine andere möchten – und schalten Sie die Veröffentlichung ein. Der Code bekommt eine eigene Seite unter den Open-Source-Apps. Dort kann ihn jeder lesen, mit einem Stern versehen, jede Version als dasselbe Projekt herunterladen, das Ihnen Herunterladen liefert, mit der Lizenz daneben – oder jede Version davon mit git klonen.
Veröffentlicht wird jede Version, auch die früheren, mit ihrem gesamten Code – Dokumentation und Tests eingeschlossen – und der Änderung, die sie gemacht hat. Was die App aufbewahrt, wird nie veröffentlicht – ihre Einträge, die Dateien, die sie gespeichert hat, die Werte ihrer Schlüssel und Passwörter –, ebenso wenig wie das, worum Sie in Ihren eigenen Worten gebeten haben, oder wer die App nutzt. Schalten Sie die Veröffentlichung aus, ist die Seite weg; ihre Sterne bleiben erhalten, falls Sie den Code wieder veröffentlichen.
Alles im Code wird öffentlich, auch die früheren Versionen. Ein Schlüssel oder Passwort gehört zu den Schlüsseln und Passwörtern unter Daten, nie in den Code – ob veröffentlicht oder nicht.
Mit einem Agenten arbeiten
Unter /mcp gibt es einen MCP-Endpunkt. Verbinden Sie einen Agenten damit, und er kann alles, was der Editor kann: die Anleitung lesen, eine Demo komplett lesen, Dateien schreiben, kompilieren und deployen. Darunter liegt dieselbe API.
Dabei sagt er, warum er etwas tut – write_code nimmt Spezifikation und Änderung entgegen. Und er kann prüfen, was er deployt hat: read_logs liefert die letzten Requests des Lambdas, seine Ausgaben und die Stacktraces aller Exceptions. So weiß ein Agent, dass sein Code funktioniert, statt es nur anzunehmen. Dasselbe sehen Sie im Kontrollzentrum. Er schreibt dabei auch die Dokumentation und die Tests, liest sie, bevor er etwas ändert, und führt die Tests gegen die Adresse eines Entwurfs aus, bevor er den Entwurf online stellt. Eine Seite, die gefunden werden soll, bekommt einen Titel, eine Beschreibung, ein Icon und eine Vorschau für den Fall, dass jemand ihren Link teilt. Am Ende der Seiten, die er baut, fügt er eine kleine Zeile hinzu, dass sie mit GenHTTP Lambda erstellt wurden – sagen Sie ihm, wenn Sie das nicht möchten, dann entfernt er sie.