Como funciona
Escreves um snippet de C#. Aquilo que ele devolve fica alojado num endereço público, com HTTPS, em poucos segundos. Aqui está tudo, pela ordem em que o vais encontrar.
O que é uma lambda
Uma lambda é um snippet que devolve um handler do GenHTTP. A plataforma compila-o, carrega-o e monta o que ele devolveu no teu próprio endereço. Não há projeto, nem ficheiro de build, nem instruções using. Todos os módulos do GenHTTP já vêm importados.
return Content.From(Resource.FromString("hello"));
Isto é uma lambda completa. Publicada em /lambda/your-key/, responde a todos os pedidos com a palavra hello.
O snippet é feito de instruções, não de uma classe. A última coisa que faz é devolver algo que consiga servir pedidos: um handler, ou um builder de um handler.
A tua primeira lambda
- 1Clica em Criar a minha lambda. Recebes um endereço público e uma chave de edição. A chave é a única forma de voltares a entrar, por isso guarda-a. Ninguém a consegue recuperar por ti.
- 2Vais parar ao painel de controlo, com um pequeno serviço REST já escrito como primeira versão. É só um ponto de partida.
- 3Dá a chave de edição a um agente e diz-lhe o que deve criar: ele escreve novas versões via MCP. Ou abre Código e escreve-o tu: Verificar compila sem guardar nada e diz-te o que o compilador acha, com ficheiro e linha.
- 4Clica em Fazer deploy. Agora está online. Antes disso não há nada acessível, e cada novo deploy prolonga o tempo que fica online.
O painel de controlo
O link de edição abre um painel de controlo em vez de uma caixa de texto: aqui, a maior parte do código é escrita por agentes, por isso a primeira coisa no ecrã é como está a tua lambda. A barra lateral tem a lambda (se está online, o endereço e um botão quando há uma versão mais recente à espera de ficar online) e as secções. O que se faz raramente, como mudar o endereço ou eliminá-la, está no menu ⋯ que lá encontras.
- Visão geral
- Se está online, quantos pedidos teve hoje e quantos falharam, a última alteração e quanto espaço ainda sobra.
- Alterar
- Diz o que deve ficar diferente e o agente deste servidor trata disso enquanto acompanhas. Trabalha num rascunho, experimenta-o lá e integra-o na próxima versão quando funcionar. Desliga Pôr online quando terminar para experimentares tu o rascunho primeiro.
- Rascunhos
- Alterações feitas ao lado da lambda: cada uma é experimentada num endereço próprio e integrada na próxima versão quando estiver bem. Aberto, um rascunho tem o seu próprio código, dados e logs.
- Ficheiros
- Os ficheiros de uma versão: o código e os assets, o próprio programa. Um cadeado ou um globo indica se o público lhes consegue aceder.
- Dados
- O que a lambda guarda enquanto corre, partilhado por todas as versões: o workspace. Vê o que lá está, carrega e elimina ficheiros, ou desliga-o.
- Versões
- O que cada versão mudou, o que foi pedido e a diferença para a anterior. Faz deploy ou reverte a partir daqui, ou começa um rascunho a partir de qualquer uma delas.
- Deploys
- O que esteve online e quando, e o que o pôs offline.
- Estatísticas
- Pedidos, falhas, tempos de resposta e os caminhos mais pedidos, na última hora ou nas últimas 24 horas.
- Logs
- Os pedidos, o que a lambda escreveu na consola e o stack trace de tudo o que correu mal, em tempo real.
- Código
- Para o escrever à mão. Verificar compila, Guardar cria uma versão, Fazer deploy põe-na online. Num rascunho, Guardar mantém-no no rascunho e Fazer deploy da pré-visualização põe-no online no endereço do rascunho.
Ctrl-Sguarda;F12vai para a declaração.
Todas as secções funcionam da mesma forma: o título, um ⓘ que a explica, as ações à direita e, quando há mais do que uma vista, uma fila de separadores por baixo. No código, os separadores são os ficheiros.
O tráfego e os logs ficam em memória, para acompanhar e não para guardar: um reinício do servidor põe-nos a zero. As versões e o histórico de deploys ficam guardados.
Explicar o porquê
Uma versão é o código e, se quiseres, duas notas sobre ele: a especificação, o que o utilizador quer e porquê, com as palavras dele sempre que possível, e a alteração, uma linha sobre o que a versão faz. Aparecem ao lado do diff no histórico de versões, por isso o porquê fica junto do quê: para ti e para o próximo agente que ler o histórico antes de mudar alguma coisa.
POST /api/v1/lambdas/{editorKey}/versions { "files": [ { "name": "lambda.cs", "code": "..." } ], "specification": "Um livro de visitas que as pessoas podem assinar; as entradas têm de sobreviver a um reinício", "change": "Guarda as entradas no workspace para sobreviverem a um reinício" }
Os agentes passam os mesmos dois campos a write_code. Em Código, guardar pede-te a alteração. Ambos são opcionais: em vez de ser recusada, uma especificação longa é cortada aos 4000 caracteres, e uma alteração aos 500. Um rascunho tem as suas próprias duas notas, e a versão em que é integrado fica com elas.
Alterar com segurança
Uma versão nunca muda depois de guardada, e é isso que faz com que valha a pena guardar cada uma: qualquer uma pode ser comparada e voltar a ficar online exatamente como era. Para alterar uma lambda que as pessoas usam, começa antes um rascunho.
- 1Começa-o em Rascunhos, ou a partir de qualquer versão. É uma cópia do código e dos assets dessa versão, e dos dados da lambda.
- 2Altera-o quantas vezes for preciso: em Código, ou pedindo ao agente. Fazer deploy da pré-visualização põe-no online num endereço próprio,
/features/…/, com a sua própria cópia dos dados. Os visitantes da lambda não veem nada disto, e nada do que ele escreve chega aos dados da lambda. - 3Quando estiver bem, Integrar faz dele a próxima versão, com as suas notas, e põe-no logo online se quiseres. O rascunho desaparece com isso: a pré-visualização e a cópia dos dados.
POST /api/v1/lambdas/{editorKey}/features { "name": "Ranking" } PUT /api/v1/lambdas/{editorKey}/features/{feature}/files?deploy=true POST /api/v1/lambdas/{editorKey}/features/{feature}/merge { "deploy": true }
Podes trabalhar em vários rascunhos ao mesmo tempo. Só um que se baseie na versão mais recente pode ser integrado, para que uma integração nunca desfaça uma versão guardada depois de o rascunho ter começado. Se outro foi integrado primeiro, traz as alterações dele (ou pede ao agente que o faça) e depois baseia o rascunho na versão mais recente. Nada se integra sozinho; é de propósito.
Mais do que um ficheiro
Os tipos não têm de ficar por baixo do código que os usa. Em Código, clica em + ao lado dos ficheiros: o novo ficheiro é compilado ao lado do snippet, no mesmo namespace, por isso não é preciso importar nada. Um nome sem extensão é tratado como 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);
Servir uma página
Há duas formas de servir uma página, e mais uma para o que as pessoas carregam junto dela.
Uma página, escrita no código
Serve para algo pequeno. A página faz parte do 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);
Uma pasta de ficheiros a sério
O que queres para qualquer coisa com uma folha de estilos e um script. Os ficheiros são adicionados da mesma forma que um ficheiro C#, e servidos exatamente como foram escritos. Nada os compila.
return Layout.Create() .Add("api", api) .Add(Assets.App("site"));
Ficheiros carregados, a partir dos dados
Para o que as pessoas carregam ou a lambda cria (fotografias, documentos), servido ao lado da app. Não para as páginas da própria app: essas pertencem a uma pasta de ficheiros, onde entram nas versões juntamente com o código que precisa delas.
return Layout.Create() .Add("api", api) .Add("uploads", Workspace.Files("uploads")) .Add(Assets.App("site"));
Um front-end, passo a passo
A segunda, em pormenor. Todas as demos servem a página assim, a partir de uma pasta chamada web: abre demo-crud para ver uma. As demos são só de leitura; a chave de edição de cada uma é o próprio nome.
- 1Em Código, clica em + ao lado dos ficheiros e escreve
site/index.html. Um nome com uma barra põe o ficheiro numa pasta; um nome com extensão é tratado como o tipo de ficheiro que indica. - 2Adiciona
site/app.cssesite/app.jsda mesma forma. A tua página refere-se a eles pelo nome, como emhref="app.css", porque a pasta é a raiz do que é servido e não faz parte do endereço. - 3Para o que não é texto, como uma imagem ou um tipo de letra, abre um ficheiro em
sitee clica no botão de carregar ao lado dos ficheiros: vai parar à mesma pasta. Um PNG não se escreve num editor de texto, por isso é por aí que entra. - 4Em
lambda.cs, serve a pasta:return Layout.Create().Add(Assets.App("site"));
- 5Clica em Fazer deploy.
site/index.htmlresponde em/,site/app.cssem/app.css, e qualquer endereço que não corresponda a nenhum ficheiro recebe a página. Assim, um front-end com routing próprio continua a funcionar quando alguém recarrega num deep link. - 6Junta-lhe uma API e a página já tem com quem falar:
var api = Inline.Create().Get("notes", () => notes); return Layout.Create() .Add("api", api) .Add(Assets.App("site"));
Os dois sítios onde vivem os ficheiros
Uma lambda guarda ficheiros em dois sítios, e o editor mostra-os em separado: Ficheiros tem os ficheiros de uma versão (o programa) e Dados tem o workspace (o que o programa guarda). A diferença está em a quem pertencem. Os ficheiros de uma versão pertencem a essa versão; os dados pertencem à lambda, e todas as versões os partilham.
| Numa versão | Nos dados | |
|---|---|---|
| o que guarda | o código e os assets: o programa, incluindo o front-end | tudo o que a lambda escreve, ou que alguém carrega |
| quando muda | nunca: uma alteração é uma nova versão | no momento em que algo é escrito |
| um deploy | põe online exatamente estes ficheiros | nunca lhes toca |
| reverter | traz de volta os ficheiros antigos | não tem efeito: são os mesmos para todas as versões |
| um rascunho | começa como uma cópia deles | trabalha numa cópia deles |
| quando desaparecem | com as versões antigas, passado o limite | com a lambda, ou quando os desligas |
| acedido no código como | Assets | Workspace |
Não podem ser um só sítio. Se fossem, um deploy ou apagava tudo o que a lambda escreveu entretanto, ou nunca se poderia remover nada do que ela traz. Um jogo com um ranking quer a segunda opção; a página que ele serve quer a primeira. Por isso, a página vai na versão, e o ranking nos dados.
Guardar dados
Workspace é um diretório privado onde a tua lambda pode ler e escrever. É o sítio para tudo o que tenha de durar mais do que um pedido, ou do que um 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; });
Há também ReadBytes, WriteBytes, Delete, List, CreateFolder e Tree/Files/App para o servir. Mais nada no sistema de ficheiros é acessível.
WebSockets
Suportados, e pensados de raiz. A demo demo-game emparelha jogadores e corre todos os jogos no servidor. A forma mais simples são três 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);
Há uma coisa que apanha toda a gente: um browser não consegue definir headers no handshake de um WebSocket. Passa o que o handler precisa na query, onde ele o lê a partir de connection.Request.Header.Query, ou envia os segredos na primeira mensagem.
O que não podes fazer
O teu código corre num servidor partilhado, por isso parte do C# é recusada antes de compilar: iniciar processos, abrir sockets próprios, carregar assemblies, aceder ao sistema de ficheiros fora do teu workspace, e usar reflection para contornar qualquer uma destas regras.
Todo o resto está lá, incluindo toda a API de módulos do GenHTTP. Se algo for recusado, ficas a saber em que linha e porquê, e não apenas que falhou.
Levar o código contigo
Transferir como projeto .NET, no editor, dá-te tudo de uma vez: uma solução que podes abrir, correr com dotnet run e guardar. Tem uma única referência de pacote e nenhum vestígio desta plataforma.
O teu snippet passa a ser o corpo de Program.cs, dentro de um host que serve o que ele devolve. Os teus outros ficheiros vêm exatamente como os escreveste. Workspace e Assets passam a ser duas pastas ao lado do código, com os mesmos métodos, por isso não tens de mudar nada no teu código.
Convém saber antes de começares: o que escreves é teu e sai daqui inteiro. Correr nesta máquina não o prende a ela.
Deixar um agente fazer o trabalho
Há um endpoint MCP em /mcp. Liga-lhe um agente e ele pode fazer tudo o que o editor faz: ler o guia, ler uma demo inteira, escrever ficheiros, compilá-los e fazer deploy. Por baixo, é a mesma API.
O agente explica o porquê à medida que avança (write_code recebe a especificação e a alteração) e pode ver o que publicou: read_logs responde com os pedidos recentes da lambda, o que ela escreveu na consola e o stack trace de tudo o que lançou. É assim que um agente descobre que o código funciona, em vez de o assumir. Tu vês o mesmo no painel de controlo.