Come funziona
Scrivi uno snippet di C#. Quello che restituisce va online a un indirizzo pubblico, in HTTPS, in pochi secondi. Qui trovi tutto, nell’ordine in cui lo incontrerai.
Cos’è una lambda
Una lambda è uno snippet che restituisce un handler GenHTTP. La piattaforma lo compila, lo carica e monta quello che ha restituito sotto il tuo indirizzo. Niente progetto, niente file di build, niente istruzioni using: tutti i moduli GenHTTP sono già importati.
return Content.From(Resource.FromString("hello"));
Questa è una lambda completa. Dopo il deploy su /lambda/your-key/, risponde a ogni richiesta con la parola «hello».
Lo snippet è fatto di istruzioni, non di una classe. L’ultima cosa che fa è restituire qualcosa in grado di servire le richieste: un handler, o un builder che ne crea uno.
La tua prima lambda
- 1Premi Crea la mia lambda. Ricevi un indirizzo pubblico e una chiave di modifica. La chiave è l’unico modo per rientrare, quindi conservala. Nessuno può recuperarla per te.
- 2Arrivi nel suo pannello di controllo, con un piccolo servizio REST già scritto come prima versione. È solo un punto di partenza.
- 3Passa la chiave di modifica a un agente e digli cosa creare: scrive nuove versioni tramite MCP. Oppure apri Codice e scrivi tu il codice: Verifica compila senza salvare niente e ti mostra cosa dice il compilatore, con file e riga.
- 4Premi Deploy. Ora è online. Prima non è raggiungibile, e ogni nuovo deploy allunga il tempo in cui resta online.
Il pannello di controllo
Il link di modifica apre un pannello di controllo, non un semplice editor di testo: qui gran parte del codice la scrivono gli agenti, quindi la prima cosa che vedi è come sta andando la tua lambda. La barra laterale mostra la lambda (se è online, il suo indirizzo e un pulsante quando una versione più recente aspetta di andare online) e le sue sezioni. Le azioni che servono di rado, come cambiare l’indirizzo o eliminarla, sono nel menu ⋯.
- Panoramica
- Se è online, quante richieste ha ricevuto oggi e quante sono fallite, l’ultima modifica e quanto spazio resta.
- Modifica
- Scrivi cosa deve cambiare e l’agente di questo server lo fa sotto i tuoi occhi. Lavora su una bozza, prova lì la modifica e la integra nella prossima versione quando funziona. Disattiva Metti online a lavoro finito per provare prima tu la bozza.
- Bozze
- Modifiche preparate accanto alla lambda: ognuna si prova a un indirizzo tutto suo e si integra nella prossima versione quando è a posto. Una volta aperta, una bozza ha il suo codice, i suoi dati e i suoi log.
- File
- I file di una versione: il codice e gli asset, cioè il programma vero e proprio. Un lucchetto o un globo indica se sono pubblici.
- Dati
- Quello che la lambda conserva mentre gira, condiviso da tutte le versioni: il workspace. Puoi guardarci dentro, caricare ed eliminare file, o disattivarlo.
- Versioni
- Cosa ha cambiato ogni versione, cosa era stato chiesto e le differenze rispetto alla precedente. Da qui fai il deploy o torni indietro, oppure avvii una bozza da una qualsiasi di esse.
- Deployment
- Cosa è stato online e quando, e cosa l’ha fermato.
- Statistiche
- Richieste, errori, tempi di risposta e i percorsi più richiesti, nell’ultima ora o nelle ultime 24 ore.
- Log
- Le richieste, cosa ha stampato e lo stack trace di ogni errore, in tempo reale.
- Codice
- Per scriverlo a mano. Verifica compila, Salva crea una versione, Deploy la mette online. In una bozza, Salva lo tiene nella bozza e Deploy dell’anteprima lo mette online all’indirizzo della bozza.
Ctrl-Ssalva;F12va alla dichiarazione.
Ogni sezione funziona allo stesso modo: il titolo, il pulsante ⓘ che la spiega, le azioni a destra e, dove ci sono più viste, una fila di schede sotto. Nel codice, le schede sono i file.
Traffico e log restano in memoria: servono per tenere d’occhio le cose, non per conservarle. Un riavvio del server li azzera. Le versioni e la cronologia dei deployment invece vengono salvate.
Spiegare il perché
Una versione è il codice più, se vuoi, due note: la specifica, cioè cosa vuole l’utente e perché, se possibile con parole sue, e la modifica, una riga su cosa fa la versione. Compaiono accanto al diff nella cronologia delle versioni, così il perché resta vicino al cosa: per te e per il prossimo agente che leggerà la cronologia prima di cambiare qualcosa.
POST /api/v1/lambdas/{editorKey}/versions { "files": [ { "name": "lambda.cs", "code": "..." } ], "specification": "Un guestbook che la gente può firmare; le voci devono sopravvivere a un riavvio", "change": "Salva le voci nel workspace così sopravvivono a un riavvio" }
Gli agenti passano gli stessi due campi a write_code. In Codice, quando salvi ti viene chiesta la modifica. Sono entrambi facoltativi: una specifica lunga viene tagliata a 4000 caratteri e una modifica a 500, invece di essere rifiutata. Una bozza ha le sue due note, e la versione in cui viene integrata le riprende.
Cambiarla senza rischi
Una versione, una volta salvata, non cambia più, ed è per questo che vale la pena conservarle tutte: ognuna si può confrontare e rimettere online esattamente com’era. Per cambiare una lambda che la gente usa, avvia invece una bozza.
- 1Avviala in Bozze, o da una versione qualsiasi. È una copia del codice e degli asset di quella versione, e dei dati della lambda.
- 2Modificala tutte le volte che serve, in Codice o chiedendolo all’agente. Deploy dell’anteprima la mette online a un indirizzo tutto suo,
/features/…/, con la sua copia dei dati. I visitatori della lambda non ne vedono niente, e niente di quello che scrive arriva ai dati della lambda. - 3Quando è a posto, premi Integra: diventa la prossima versione, con le sue note, e se vuoi va subito online. La bozza sparisce, insieme alla sua anteprima e alla sua copia dei dati.
POST /api/v1/lambdas/{editorKey}/features { "name": "Classifica" } PUT /api/v1/lambdas/{editorKey}/features/{feature}/files?deploy=true POST /api/v1/lambdas/{editorKey}/features/{feature}/merge { "deploy": true }
Si può lavorare a più bozze insieme. Si può integrare solo una bozza basata sulla versione più recente, così un’integrazione non annulla mai una versione salvata dopo l’avvio della bozza. Se prima ne è stata integrata un’altra, porta dentro le sue modifiche (o chiedilo all’agente), poi basa la bozza sulla versione più recente. Niente viene integrato da solo, ed è voluto.
Più di un file
I tipi non devono per forza stare sotto il codice che li usa. In Codice, premi + accanto ai file: il nuovo file viene compilato insieme allo snippet, nello stesso namespace, quindi non devi importare niente per usarlo. Un nome senza estensione viene considerato 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);
Servire una pagina
Ci sono due modi per servire una pagina, più uno per quello che la gente carica accanto.
Una pagina, scritta nel codice
Va bene per le cose piccole. La pagina fa parte dello snippet.
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);
Una cartella di file veri
Quello che ti serve per qualsiasi cosa con un foglio di stile e uno script. I file si aggiungono come un file C# e vengono serviti esattamente come li hai scritti. Niente li compila.
return Layout.Create() .Add("api", api) .Add(Assets.App("site"));
File caricati, dai dati
Per quello che la gente carica o che la lambda crea (foto, documenti), servito accanto all’app. Non per le pagine dell’app stessa: quelle vanno in una cartella di file, dove seguono le versioni insieme al codice che le usa.
return Layout.Create() .Add("api", api) .Add("uploads", Workspace.Files("uploads")) .Add(Assets.App("site"));
Un front-end, passo per passo
Il secondo modo, per intero. Ogni demo serve la sua pagina così, da una cartella chiamata web: apri demo-crud per vederne una. Le demo sono in sola lettura, e la loro chiave di modifica è il loro nome.
- 1In Codice, premi + accanto ai file e scrivi
site/index.html. Un nome con una barra mette il file in una cartella; un nome con un’estensione viene trattato come il tipo di file che indica. - 2Aggiungi
site/app.cssesite/app.jsallo stesso modo. La pagina li richiama per nome, come inhref="app.css", perché la cartella è la radice di ciò che viene servito, non una parte dell’indirizzo. - 3Per tutto ciò che non è testo, come un’immagine o un font, apri un file in
sitee premi il pulsante di caricamento accanto ai file: finisce nella stessa cartella. Un PNG non si può scrivere in un editor di testo, quindi si passa da lì. - 4In
lambda.cs, servi la cartella:return Layout.Create().Add(Assets.App("site"));
- 5Premi Deploy.
site/index.htmlrisponde su/,site/app.csssu/app.css, e qualsiasi indirizzo che non corrisponde a un file riceve la pagina: così un front-end con un suo routing funziona anche quando qualcuno ricarica la pagina su un deep link. - 6Aggiungi un’API accanto e la pagina avrà qualcosa con cui parlare:
var api = Inline.Create().Get("notes", () => notes); return Layout.Create() .Add("api", api) .Add(Assets.App("site"));
I due posti dove stanno i file
Una lambda tiene i file in due posti, e l’editor li mostra separati: File contiene i file di una versione (il programma) e Dati contiene il workspace (quello che il programma conserva). La differenza è di chi sono. I file di una versione appartengono a quella versione; i dati appartengono alla lambda, e tutte le versioni li condividono.
| In una versione | Nei dati | |
|---|---|---|
| cosa contiene | il codice e gli asset: il programma, front-end compreso | quello che scrive la lambda o che carica qualcuno |
| quando cambia | mai: una modifica è una nuova versione | appena ci viene scritto qualcosa |
| un deploy | mette online esattamente questi file | non li tocca mai |
| tornare indietro | riporta i vecchi file | nessun effetto: tutte le versioni li condividono |
| una bozza | parte da una copia di questi file | lavora su una copia dei dati |
| quando sparisce | con le versioni vecchie, oltre il limite | con la lambda, o quando disattivi il workspace |
| dal codice si raggiunge con | Assets | Workspace |
Non possono stare in un unico posto. Se ci stessero, un deploy cancellerebbe tutto ciò che la lambda ha scritto nel frattempo, oppure non si potrebbe mai togliere niente da ciò che pubblica. Un gioco con una classifica vuole la seconda cosa; la pagina che serve vuole la prima. Quindi la pagina va nella versione, e la classifica nei dati.
Salvare i dati
Workspace è una cartella privata che la tua lambda può leggere e scrivere. È il posto per tutto ciò che deve sopravvivere a una richiesta, o a un deploy.
var notes = new List<string>(); if (Workspace.Exists("notes.json")) { notes.AddRange(JsonSerializer.Deserialize<List<string>>(Workspace.ReadText("notes.json")) ?? []); } return Inline.Create() .Get("notes", () => notes) .Post("notes", (string text) => { notes.Add(text); Workspace.WriteText("notes.json", JsonSerializer.Serialize(notes)); return notes.Count; });
Ci sono anche ReadBytes, WriteBytes, Delete, List, CreateFolder, e Tree/Files/App per servirlo. Il resto del file system non è raggiungibile.
WebSocket
Supportati sul serio, non aggiunti all’ultimo momento. La demo demo-game abbina i giocatori e gestisce ogni partita sul server. La forma più semplice sono tre callback:
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);
C’è un tranello in cui cadono tutti: un browser non può impostare header nell’handshake di un websocket. Passa quello che serve all’handler nella query, dove lo legge da connection.Request.Header.Query, oppure manda i dati segreti come primo messaggio.
Cosa non puoi fare
Il tuo codice gira su un server condiviso, quindi una parte di C# viene rifiutata prima ancora della compilazione: avviare processi, aprire socket propri, caricare assembly, accedere al file system fuori dal workspace e usare la reflection per aggirare uno di questi limiti.
Tutto il resto c’è, compresa l’intera API dei moduli GenHTTP. Se qualcosa viene rifiutato, vedi quale riga e perché, non solo che non ha funzionato.
Portarla via
Con Scarica come progetto .NET, nell’editor, ti porti a casa tutto: una solution da aprire, avviare con dotnet run e tenere. Ha un solo riferimento a un pacchetto e nessuna traccia di questa piattaforma.
Il tuo snippet diventa il corpo di Program.cs, dentro un host che serve ciò che restituisce. Gli altri file arrivano esattamente come li hai scritti. Workspace e Assets diventano due cartelle accanto al codice, con gli stessi metodi, quindi nel tuo codice non devi cambiare niente.
Meglio saperlo prima di creare qualsiasi cosa qui: quello che scrivi è tuo e te lo porti via intero. Farlo girare su questo server non ti lega a questo server.
Lasciar fare a un agente
C’è un endpoint MCP su /mcp. Collegaci un agente e potrà fare tutto quello che fa l’editor: leggere la guida, leggere una demo per intero, scrivere file, compilarli e fare il deploy. Sotto c’è la stessa API.
Mentre lavora spiega il perché (write_code riceve la specifica e la modifica) e può controllare quello che ha pubblicato: read_logs restituisce le richieste recenti della lambda, cosa ha stampato e lo stack trace di ogni eccezione. È così che un agente scopre che il suo codice funziona, invece di darlo per scontato. Tu vedi le stesse cose nel pannello di controllo.