Como funciona
Você escreve um trecho de C#. O que ele retorna fica hospedado em um endereço público, com HTTPS, em poucos segundos. Aqui está tudo, na ordem em que você vai precisar.
O que é uma lambda
Uma lambda é um trecho de código que retorna um handler do GenHTTP. A plataforma compila, carrega e monta o que ele retornou no seu próprio endereço. Não tem projeto, nem arquivo de build, nem using. Todos os módulos do GenHTTP já vêm importados.
return Content.From(Resource.FromString("hello"));
Essa é uma lambda completa. No ar em /lambda/your-key/, ela responde a toda requisição com a palavra hello.
O trecho é feito de instruções, não de uma classe. A última coisa que ele faz é retornar algo que atenda requisições: um handler ou um builder de handler.
Sua primeira lambda
- 1Clique em Criar minha lambda. Você recebe um endereço público e uma chave de edição. A chave é o único jeito de voltar, então guarde bem. Ninguém consegue recuperar para você.
- 2Você cai no painel de controle, com um pequeno serviço REST já escrito como primeira versão. É só um ponto de partida.
- 3Passe a chave de edição para um agente e diga o que criar: ele escreve novas versões via MCP. Ou abra Código e escreva você mesmo: Verificar compila sem salvar nada e mostra o que o compilador achou, com arquivo e linha.
- 4Clique em Fazer deploy. Pronto, está no ar. Antes disso, nada fica acessível, e cada novo deploy estende o tempo que ela fica no ar.
O painel de controle
O link de edição abre um painel de controle, não uma caixa de texto: a maior parte do código aqui é escrita por agentes, então a primeira coisa na tela é como anda a sua lambda. A barra lateral mostra a lambda (se está no ar, o endereço e um botão quando uma versão mais nova está esperando para ir ao ar) e as seções dela. O que se faz raramente, como mudar o endereço ou excluir a lambda, fica no menu ⋯ ali.
- Visão geral
- Se está no ar, quantas requisições teve hoje e quantas falharam, a última mudança e quanto espaço ainda sobra.
- Mudar
- Diga o que deve ficar diferente e o agente deste servidor faz isso enquanto você acompanha. Ele trabalha num rascunho, testa lá e mescla na próxima versão quando funciona. Desligue Colocar no ar quando terminar para testar o rascunho você mesmo antes.
- Rascunhos
- Mudanças feitas ao lado da lambda: cada uma é testada num endereço próprio e mesclada na próxima versão quando estiver tudo certo. Aberto, um rascunho tem código, dados e log próprios.
- Arquivos
- Os arquivos de uma versão: o código e os assets, o próprio programa. Um cadeado ou um globo mostra se o público consegue acessar.
- Dados
- O que a lambda guarda enquanto roda, compartilhado por todas as versões: o workspace. Veja o que tem nele, envie e exclua arquivos, ou desligue.
- Versões
- O que cada versão mudou, o que foi pedido e a diferença para a anterior. Faça deploy ou volte uma versão por aqui, ou comece um rascunho a partir de qualquer uma delas.
- Deploys
- O que esteve no ar e quando, e o que tirou do ar.
- Métricas
- Requisições, falhas, tempos de resposta e os caminhos mais acessados, na última hora ou nas últimas 24 horas.
- Logs
- As requisições, o que ela imprimiu e o stack trace de qualquer erro, em tempo real.
- Código
- Para escrever à mão. Verificar compila, Salvar cria uma versão, Fazer deploy coloca no ar. Num rascunho, Salvar mantém a mudança no rascunho e Fazer deploy da prévia coloca no ar no endereço do rascunho.
Ctrl-Ssalva;F12vai para uma declaração.
Toda seção funciona do mesmo jeito: o título, um ⓘ que explica, as ações à direita e, quando há mais de uma visualização, uma fileira de abas embaixo. No código, as abas são os arquivos.
O tráfego e o log ficam em memória, para acompanhar, não para guardar: reiniciar o servidor zera tudo. As versões e o histórico de deploys ficam salvos.
Explicando o porquê
Uma versão é o código e, se você quiser, duas notas sobre ele: a especificação, o que o usuário quer e por quê, com as palavras dele quando possível, e a mudança, uma linha sobre o que a versão faz. As duas aparecem ao lado do diff no histórico de versões. Assim, o porquê fica junto do quê: para você 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 para as pessoas assinarem; as mensagens não podem sumir num reinício", "change": "Guarda as mensagens no workspace para não sumirem num reinício" }
Os agentes passam os mesmos dois campos para write_code. Em Código, salvar pede a mudança. Os dois são opcionais. Uma especificação longa é cortada em 4.000 caracteres, e uma mudança em 500, em vez de ser recusada. Um rascunho tem os próprios dois campos, e a versão em que ele é mesclado fica com eles.
Mudando com segurança
Uma versão nunca muda depois de salva, e é isso que faz cada uma valer a pena: qualquer uma delas pode ser comparada e colocada de volta no ar exatamente como era. Para mudar uma lambda que as pessoas usam, comece um rascunho.
- 1Comece em Rascunhos, ou a partir de qualquer versão. Ele é uma cópia do código e dos assets dessa versão, e dos dados da lambda.
- 2Mude quantas vezes precisar, em Código ou pedindo ao agente. Fazer deploy da prévia coloca no ar num endereço próprio,
/features/…/, com a própria cópia dos dados. Os visitantes da lambda não veem nada disso, e nada do que ele grava chega aos dados da lambda. - 3Quando estiver tudo certo, Mesclar faz dele a próxima versão, com as notas dele, e coloca no ar na hora, se você quiser. O rascunho some junto, com a prévia 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 }
Dá para trabalhar em vários rascunhos ao mesmo tempo. Só um baseado na versão mais recente pode ser mesclado, para que uma mesclagem nunca desfaça uma versão salva depois que o rascunho começou. Se outro foi mesclado antes, traga as mudanças dele (ou peça ao agente) e depois baseie o rascunho na versão mais recente. Nada é mesclado sozinho; isso é de propósito.
Mais de um arquivo
Os tipos não precisam ficar embaixo do código que os usa. Em Código, clique em + ao lado dos arquivos: o novo arquivo é compilado junto com o trecho, no mesmo namespace, então não precisa 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);
Servindo uma página
Existem dois jeitos de servir uma página, e mais um para o que as pessoas enviam junto com ela.
Uma página, escrita no código
Bom para algo pequeno. A página faz parte do trecho.
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 arquivos de verdade
O ideal para qualquer coisa com CSS e script. Os arquivos são adicionados do mesmo jeito que um arquivo C# e servidos exatamente como foram escritos. Nada compila esses arquivos.
return Layout.Create() .Add("api", api) .Add(Assets.App("site"));
Arquivos enviados, dos dados
Para o que as pessoas enviam ou a lambda cria (fotos, documentos), servido junto com o app. Não para as páginas do próprio app: essas ficam numa pasta de arquivos, onde entram nas versões junto com o código que depende delas.
return Layout.Create() .Add("api", api) .Add("uploads", Workspace.Files("uploads")) .Add(Assets.App("site"));
Um front-end, passo a passo
O segundo jeito, completo. Toda demo serve a página assim, de uma pasta chamada web. Abra demo-crud para ver uma. As demos são somente leitura; a chave de edição delas é o próprio nome.
- 1Em Código, clique em + ao lado dos arquivos e digite
site/index.html. Um nome com barra coloca o arquivo em uma pasta; um nome com extensão é tratado como o tipo de arquivo que ele indica. - 2Adicione
site/app.cssesite/app.jsdo mesmo jeito. Sua página se refere a eles pelo nome, como emhref="app.css", porque a pasta é a raiz do que é servido, e não parte do endereço. - 3Para o que não é texto, como uma imagem ou uma fonte, abra um arquivo em
sitee use o botão de enviar ao lado dos arquivos: ele vai para a mesma pasta. Não dá para digitar um PNG num editor de texto, então o caminho é esse. - 4Em
lambda.cs, sirva a pasta:return Layout.Create().Add(Assets.App("site"));
- 5Clique em Fazer deploy.
site/index.htmlresponde em/,site/app.cssem/app.css, e qualquer endereço que não bate com nenhum arquivo recebe a página. Assim, um front-end com roteamento próprio continua funcionando quando alguém recarrega a página num deep link. - 6Adicione uma API ao lado, e a página ganha com quem conversar:
var api = Inline.Create().Get("notes", () => notes); return Layout.Create() .Add("api", api) .Add(Assets.App("site"));
Os dois lugares onde ficam os arquivos
Uma lambda guarda arquivos em dois lugares, e o editor mostra cada um separado: Arquivos tem os arquivos de uma versão (o programa), e Dados tem o workspace (o que o programa guarda). A diferença é de quem eles são. Os arquivos de uma versão pertencem a essa versão; os dados pertencem à lambda, e todas as versões usam os mesmos.
| Numa versão | Nos dados | |
|---|---|---|
| o que guarda | o código e os assets: o programa, inclusive o front-end | tudo o que a lambda grava ou alguém envia |
| quando muda | nunca: uma mudança é uma nova versão | no momento em que algo é gravado |
| um deploy | coloca exatamente esses arquivos no ar | nunca mexe neles |
| voltar uma versão | traz os arquivos antigos de volta | nenhum 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 somem | com as versões antigas, depois do limite | com a lambda, ou quando você desliga |
| acessado no código como | Assets | Workspace |
Os dois não podem ser um lugar só. Se fossem, um deploy ou apagaria tudo o que a lambda gravou desde então, ou nada nunca poderia sair dos arquivos que vão com ela. Um jogo com ranking quer a segunda opção; a página que ele serve quer a primeira. Então a página fica na versão, e o ranking nos dados.
Guardando dados
Workspace é um diretório privado que sua lambda pode ler e gravar. É o lugar para tudo o que precisa durar mais que uma requisição, ou 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; });
Também tem ReadBytes, WriteBytes, Delete, List, CreateFolder e Tree/Files/App para servir o conteúdo. Nada mais no sistema de arquivos é acessível.
WebSockets
Suporte completo, pensado desde o início. A demo demo-game forma pares de jogadores e roda cada partida 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);
Uma coisa pega todo mundo: o navegador não consegue definir headers no handshake de um WebSocket. Passe o que o handler precisa na query, que ele lê de connection.Request.Header.Query, ou mande segredos na primeira mensagem.
O que não é permitido
Seu código roda em um servidor compartilhado, então parte do C# é recusada antes de compilar: iniciar processos, abrir seus próprios sockets, carregar assemblies, acessar o sistema de arquivos fora do seu workspace e usar reflection para contornar qualquer uma dessas regras.
Todo o resto está disponível, incluindo a API de módulos do GenHTTP inteira. Se algo for recusado, você fica sabendo a linha e o motivo, e não só que falhou.
Levando seu código embora
Baixar como projeto .NET, no editor, entrega tudo pronto: uma solução que você pode abrir, rodar com dotnet run e guardar. Ela tem uma única referência de pacote e nenhum rastro desta plataforma.
Seu trecho vira o corpo do Program.cs, dentro de um host que serve o que ele retorna. Seus outros arquivos vão exatamente como você escreveu. Workspace e Assets viram duas pastas ao lado do código, com os mesmos métodos, então nada no seu código precisa mudar.
Bom saber antes de criar qualquer coisa aqui: o que você escreve é seu e sai inteiro. Rodar nesta máquina não prende seu código a ela.
Deixando um agente fazer
Existe um endpoint MCP em /mcp. Conecte um agente a ele, e o agente pode fazer tudo o que o editor faz: ler o guia, ler uma demo inteira, escrever arquivos, compilar e fazer deploy. Por baixo, é a mesma API.
O agente explica o porquê enquanto trabalha (write_code recebe a especificação e a mudança) e pode ver o que colocou no ar: read_logs responde com as requisições recentes da lambda, o que ela imprimiu e o stack trace de qualquer exceção. É assim que ele descobre que o código funciona, em vez de supor. Você acompanha tudo isso no painel de controle.