작동 방식
C# 스니펫 하나를 작성하세요. 스니펫이 반환하는 것은 몇 초 만에 HTTPS 공개 주소에 호스팅돼요. 필요한 내용을 모두, 실제로 만나게 될 순서대로 정리했어요.
람다란?
람다는 GenHTTP 핸들러를 반환하는 스니펫이에요. 플랫폼이 스니펫을 컴파일하고 불러와서, 반환된 것을 내 주소 아래에 마운트해요. 프로젝트도, 빌드 파일도, using 문도 필요 없어요. GenHTTP 모듈은 이미 모두 임포트되어 있어요.
return Content.From(Resource.FromString("hello"));
이게 완전한 람다예요. /lambda/your-key/에 배포하면 모든 요청에 hello라고 답해요.
스니펫은 클래스가 아니라 문(statement)의 나열이에요. 마지막에는 요청을 처리할 수 있는 것, 즉 핸들러나 핸들러 빌더를 반환해요.
첫 람다 만들기
- 1람다 만들기를 누르세요. 공개 주소와 에디터 키가 나와요. 키는 다시 들어올 수 있는 유일한 방법이니 꼭 보관하세요. 누구도 대신 찾아 줄 수 없어요.
- 2곧바로 람다의 관리 화면으로 들어가요. 첫 버전으로 작은 REST 서비스가 이미 작성되어 있어요. 시작점일 뿐이에요.
- 3에디터 키를 에이전트에게 주고 무엇을 만들지 말하세요. 에이전트는 MCP로 새 버전을 써요. 아니면 코드를 열고 직접 작성하세요. 검사를 누르면 아무것도 저장하지 않고 컴파일해서, 컴파일러가 뭐라고 하는지 파일과 줄 단위로 알려 줘요.
- 4배포를 누르세요. 이제 온라인이에요. 배포하기 전에는 아무도 접속할 수 없어요. 다시 배포하면 온라인으로 유지되는 기간이 늘어나요.
관리 화면
에디터 링크를 열면 텍스트 상자가 아니라 관리 화면이 나와요. 여기 코드는 대부분 에이전트가 쓰기 때문에, 화면에서 가장 먼저 보이는 건 람다의 상태예요. 사이드바에는 람다 정보(온라인 여부, 주소, 온라인에 올라가길 기다리는 새 버전이 있을 때 나타나는 버튼)와 섹션들이 있어요. 주소 변경이나 삭제처럼 가끔 하는 일은 사이드바의 ⋯ 메뉴 안에 있어요.
- 개요
- 앱이 무엇인지, 온라인 여부, 오늘 받은 요청 수와 그중 실패한 수, 최근 변경, 남은 공간.
- 문서
- 앱이 무엇이고, 누구를 위한 것이며, 왜 있는지, 그리고 왜 이렇게 만들어졌는지. 에이전트가 작성하고, 버전마다 함께 보관돼요.
- 수정 요청
- 무엇을 바꿀지 말하면 이 서버의 에이전트가 눈앞에서 해 줘요. 초안에서 변경을 먼저 시도하고, 잘 되면 온라인으로 전환해요. 먼저 직접 초안을 써 보고 싶다면 끝나면 온라인으로 전환 스위치를 끄세요. 에이전트는 내 앱만 다뤄요. 앱과 관계없는 요청이나 해를 끼치려는 요청은 이유를 알려 주고 거절해요.
- 초안
- 온라인으로 전환하기 전에 시험해 보는 변경이에요. 초안마다 전용 주소와 전용 테스트 데이터가 있어요. 초안을 열면 초안만의 코드, 테스트 데이터, 로그가 있어요. 이 메뉴는 초안이 있을 때만 나타나요.
- 파일
- 버전의 파일, 즉 코드와 에셋으로 된 프로그램 그 자체. 자물쇠나 지구본 아이콘으로 공개 여부를 알려 줘요.
- 데이터
- 람다가 실행 중에 보관하는 것으로, 모든 버전이 함께 쓰는 데이터베이스, 워크스페이스, 시크릿이에요. 각각 탭이 따로 있어요. 테이블과 파일을 살펴보고, 파일을 업로드하고, 시크릿을 설정하거나 종류별로 켜고 끌 수 있어요. 간단히 보기에서는 앱이 무언가를 보관하면 나타나요.
- 버전
- 버전마다 무엇이 바뀌었고 무엇을 요청했는지, 그리고 이전 버전과의 차이. 여기서 배포하거나 롤백하고, 어느 버전에서든 초안을 만들 수 있어요.
- 배포 기록
- 언제 무엇이 온라인이었는지, 무엇 때문에 내려갔는지.
- 통계
- 최근 1시간 또는 하루 동안의 요청, 실패, 응답 시간, 가장 많이 요청된 경로.
- 로그
- 요청, 람다가 출력한 내용, 문제가 생긴 곳의 스택 트레이스를 실시간으로.
- 코드
- 직접 작성하기. 검사는 컴파일, 저장은 버전 만들기, 배포는 온라인으로 전환이에요. 초안에서는 저장을 누르면 초안에 저장되고 초안 주소에 바로 반영돼요.
Ctrl-S로 저장하고,F12로 선언으로 이동해요. - 테스트
- 앱을 자동으로 테스트하는 방법과, 그에 필요한 스크립트와 테스트 데이터. 전체 보기에만 있어요.
모든 섹션은 똑같이 생겼어요. 제목, 설명을 보여 주는 ⓘ, 오른쪽의 작업 버튼, 그리고 보기가 여러 개인 섹션이라면 그 아래에 탭이 한 줄 있어요. 코드 섹션에서는 파일이 탭이에요. 전체 보기에서는 섹션을 그룹으로 묶어 보여 줘요. 사람들이 앱을 찾아오는 방법, 수정하는 곳, 프로그램과 데이터, 실행 상태예요.
트래픽과 로그는 보관용이 아니라 지켜보기용이라 메모리에만 있어요. 서버가 재시작되면 처음부터 다시 쌓여요. 버전과 배포 기록은 저장돼요.
이유 남기기
버전은 코드와, 선택적으로 붙는 메모 두 개로 이뤄져요. 요구 사항은 사용자가 원하는 것과 그 이유를 가능하면 사용자의 말로 적은 것이고, 변경 사항은 이 버전이 하는 일을 한 줄로 적은 거예요. 둘 다 버전 기록에서 diff 옆에 표시돼서, 무엇 옆에 왜가 함께 남아요. 나를 위해서도, 무언가를 바꾸기 전에 기록을 읽을 다음 에이전트를 위해서도요.
POST /api/v1/lambdas/{editorKey}/versions { "files": [ { "name": "lambda.cs", "code": "..." } ], "specification": "사람들이 글을 남길 수 있는 방명록. 재시작해도 글이 남아 있어야 함", "change": "재시작해도 남도록 방명록 글을 데이터베이스에 저장" }
에이전트도 같은 두 필드를 write_code에 넘겨요. 코드에서는 저장할 때 변경 사항을 물어봐요. 둘 다 선택 사항이에요. 너무 길어도 거부하지 않고, 요구 사항은 4,000자, 변경 사항은 500자에서 잘라요. 초안도 자기 메모 두 개를 갖고 있고, 초안을 확정해서 생긴 버전이 그 메모를 이어받아요.
문서와 테스트
모든 버전은 프로그램 옆에 그 버전에 대해 적어 둔 것을 함께 보관해요. 앱이 무엇이고, 누구를 위한 것이며, 왜 있는지, 그리고 왜 이렇게 만들어졌는지를 적은 문서와, 앱이 동작하는지 자동으로 확인하는 방법을 스크립트와 테스트 데이터와 함께 적은 테스트예요. 에이전트는 새 람다를 만들 때 이것들을 작성하고, 수정할 때마다 최신 상태로 유지해요. 다음에 람다를 고치는 에이전트는 이것부터 읽기 때문에, 앱이 무엇을 위한 것이고 무엇이 계속 동작해야 하는지 알 수 있어요. 코드만 봐서는 알 수 없는 것들이에요.
- .lambda/docs/product.md
- 앱이 무엇이고, 누구를 위한 것이며, 사람들이 앱으로 무엇을 하고 왜 그런지
- .lambda/docs/decisions.md
- 기술적 결정과 그 이유
- .lambda/tests/README.md
- 앱을 자동으로 테스트하는 방법과 테스트 실행 방법
- .lambda/tests/…
- 테스트에 쓰는 스크립트와 테스트 데이터
이것들도 다른 파일처럼 버전의 파일이고, .lambda 폴더에 있어요. 기록에서는 버전마다 여기서 무엇이 바뀌었는지 보여 주고, 롤백하면 그 버전에 맞던 문서도 돌아와요. 초안은 자기만의 복사본을 갖고 있다가, 초안을 확정할 때 함께 반영돼요. 컴파일되지도 제공되지도 않고, 버전의 에셋 용량에 포함돼요.
관리 화면에서 문서는 읽을 페이지를, 테스트는 앱을 테스트하는 방법과 그 옆의 파일을 보여 줘요. 버전은 파일과 같은 방식으로 골라요. 페이지는 거기서 편집할 수도 있고, 저장하면 다음 버전이 돼요. 간단히 보기에서는 문서를 앱 소개라고 부르고, 앱이 무엇을 위한 것인지만 보여 줘요. 고치고 싶다면 에이전트에게 말하세요.
에이전트와 대화할 때 쓰는 언어로, 다음에 앱을 고칠 사람이나 에이전트를 위해 작성돼요. 코드를 옮겨 적은 게 아니라, 무엇을 위한 것이고 왜 그런지를 적어요.
안전하게 바꾸기
버전은 한 번 저장하면 바뀌지 않아요. 그래서 모든 버전을 남겨 둘 가치가 있어요. 어느 버전이든 비교할 수 있고, 저장했던 그대로 다시 온라인으로 전환할 수 있으니까요. 사람들이 쓰는 람다를 바꾸려면, 먼저 초안에서 변경을 시도해 보세요.
- 1버전에서 어느 버전으로든 만들거나, 에이전트에게 만들게 하세요. 그 버전의 코드, 에셋, 문서, 테스트와 람다 데이터의 복사본이에요.
- 2코드에서 직접, 또는 에이전트에게 요청해서 필요한 만큼 몇 번이고 고치세요. 초안의 미리 보기는 전용 주소
/features/…/에서 초안만의 테스트 데이터로 열려요. 람다의 방문자에게는 아무것도 보이지 않고, 초안이 쓴 것은 람다의 데이터에 닿지 않아요. - 3제대로 되면 온라인으로 전환하세요. 메모와 함께 다음 버전이 되어 온라인으로 전환돼요. 초안(미리 보기와 테스트 데이터)은 함께 사라져요.
POST /api/v1/lambdas/{editorKey}/features { "name": "순위표" } PUT /api/v1/lambdas/{editorKey}/features/{feature}/files?deploy=true POST /api/v1/lambdas/{editorKey}/features/{feature}/merge { "deploy": true }
초안은 여러 개를 동시에 작업할 수 있어요. 하지만 최신 버전을 반영한 초안만 온라인으로 전환할 수 있어요. 그래야 초안을 시작한 뒤에 저장된 버전이 되돌려지지 않아요. 다른 초안이 먼저 온라인으로 전환됐다면, 그 변경 사항을 가져온 다음(에이전트에게 맡겨도 돼요) 초안을 최신으로 표시하세요. 저절로 온라인으로 전환되는 건 없어요. 일부러 그렇게 만들었어요. API에서는 초안을 feature, 온라인으로 전환하는 것을 merge라고 불러요.
여러 파일 쓰기
타입을 꼭 그 타입을 쓰는 코드 아래에 둘 필요는 없어요. 코드에서 파일 옆의 +를 누르면, 새 파일이 스니펫과 같은 네임스페이스에서 함께 컴파일돼요. 그래서 아무것도 임포트하지 않아도 쓸 수 있어요. 확장자가 없는 이름은 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);
페이지 제공하기
페이지를 제공하는 방법은 두 가지이고, 사람들이 옆에 올리는 파일을 위한 방법이 하나 더 있어요.
인라인으로 쓴 페이지 하나
작은 거라면 이걸로 충분해요. 페이지가 스니펫의 일부가 돼요.
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);
실제 파일이 담긴 폴더
스타일시트와 스크립트가 있다면 이 방법이 맞아요. 파일은 C# 파일과 같은 방식으로 추가하고, 작성한 그대로 제공돼요. 컴파일은 하지 않아요.
return Layout.Create() .Add("api", api) .Add(Assets.App("site"));
업로드된 파일, 데이터에서
사람들이 업로드하거나 람다가 만든 것(사진, 문서)을 앱 옆에서 제공할 때. 앱 자체의 페이지용은 아니에요. 페이지는 파일 폴더에 두어야, 그 페이지가 필요한 코드와 함께 버전으로 관리돼요.
return Layout.Create() .Add("api", api) .Add("uploads", Workspace.Files("uploads")) .Add(Assets.App("site"));
프론트엔드 따라 만들기
두 번째 방법을 처음부터 끝까지 볼게요. 모든 데모가 web 폴더에서 이 방식으로 페이지를 제공해요. demo-crud 데모를 열어 직접 읽어 보세요. 데모는 읽기 전용이고, 에디터 키는 데모 이름과 같아요.
- 1코드에서 파일 옆의 +를 누르고
site/index.html파일을 만드세요. 이름에 슬래시가 있으면 파일이 폴더 안에 들어가고, 확장자가 있으면 그 확장자에 맞는 파일로 취급돼요. - 2
site/app.css파일과site/app.js파일도 같은 방법으로 추가하세요. 페이지에서는href="app.css"처럼 이름만으로 참조해요. 폴더는 주소의 일부가 아니라, 제공되는 파일의 루트이기 때문이에요. - 3이미지나 폰트처럼 텍스트가 아닌 파일은,
site안의 파일을 하나 연 다음 파일 옆의 업로드 버튼을 누르세요. 같은 폴더에 올라가요. PNG는 텍스트 에디터로 입력할 수 없으니, 이렇게 넣어야 해요. - 4
lambda.cs에서 폴더를 제공하세요.return Layout.Create().Add(Assets.App("site"));
- 5배포를 누르세요.
site/index.html파일은/주소에서,site/app.css파일은/app.css주소에서 응답해요. 어느 파일과도 맞지 않는 주소에는 페이지로 응답하기 때문에, 자체 라우팅을 하는 프론트엔드도 누군가 딥 링크에서 새로고침해도 잘 작동해요. - 6옆에 API를 추가하면 페이지가 통신할 상대가 생겨요.
var api = Inline.Create().Get("notes", () => notes); return Layout.Create() .Add("api", api) .Add(Assets.App("site"));
파일을 두는 두 곳
람다는 파일을 두 곳에 두고, 에디터도 둘을 따로 보여 줘요. 파일에는 버전의 파일, 즉 프로그램이 있고, 데이터에는 워크스페이스, 즉 프로그램이 보관하는 것이 있어요. 차이는 누구의 것이냐예요. 버전의 파일은 그 버전의 것이고, 데이터는 람다의 것이라 모든 버전이 함께 써요.
| 버전에 담긴 것 | 데이터에 담긴 것 | |
|---|---|---|
| 담는 것 | 코드와 에셋: 프론트엔드를 포함한 프로그램, 그리고 그 문서와 테스트 | 람다가 쓰거나 누군가 업로드한 모든 것 |
| 바뀌는 때 | 바뀌지 않음: 수정하면 새 버전이 생김 | 무언가 쓰이는 즉시 |
| 배포하면 | 정확히 이 파일들이 온라인에 올라감 | 그대로 |
| 롤백하면 | 예전 파일로 돌아감 | 영향 없음: 모든 버전이 함께 씀 |
| 초안을 만들면 | 이 파일들의 복사본으로 시작 | 복사본으로 작업 |
| 사라지는 때 | 한도를 넘으면 오래된 버전과 함께 | 람다와 함께, 또는 끌 때 |
| 코드에서 부르는 이름 | Assets | Workspace |
둘을 한 곳으로 합칠 수는 없어요. 합치면 배포할 때마다 람다가 그동안 쓴 걸 모두 지우거나, 반대로 배포한 파일을 절대 지울 수 없게 돼요. 순위표를 저장하는 게임에는 뒤쪽이, 그 게임이 제공하는 페이지에는 앞쪽이 필요해요. 그래서 페이지는 버전에, 순위표는 데이터에 둬요.
기록 저장하기
기록(글, 계정, 주문, 투표 등)은 데이터베이스에 두세요. 람다 전용 SQLite 데이터베이스로, 데이터에서 켜요. 코드는 Database.GetConnection()으로 연결을 열고, 테이블을 매핑하는 자체 컨텍스트를 두어 Entity Framework Core로 읽고 써요.
// 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 = [Assets.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"); }
테이블은 마이그레이션이 만들어요. 마이그레이션은 버전과 함께 migrations/에 담기는 SQL 파일로, 람다가 시작할 때 Evolve가 순서대로 적용해요. 각 파일은 한 번만 적용되니, 새 버전에서는 새로 추가된 것만 실행돼요. 이미 적용된 마이그레이션은 절대 바꾸지 마세요. 테이블을 바꾸려면 다음 파일을 추가하세요.
다른 데이터처럼 데이터베이스도 모든 버전이 함께 쓰고, 배포와 롤백은 데이터베이스를 건드리지 않으며, 초안은 복사본으로 작업해요. 데이터에서 테이블과 그 안의 내용을 볼 수 있어요. 간단히 보기에서는 이를 기록이라고 불러요. .NET 프로젝트로 다운로드하면 평범한 SQLite 파일로 함께 받을 수 있어요.
컨텍스트는 필요한 곳에서 만들고 다 쓰면 바로 해제하세요. 또 동기 방식으로 쓰세요. ToListAsync와 SaveChangesAsync 대신 ToList와 SaveChanges를 쓰면 돼요. 테이블은 Entity Framework가 아니라 마이그레이션이 만들어요. demo-crud 데모가 이 모든 걸 보여 줘요.
파일 저장하기
Workspace는 람다가 읽고 쓸 수 있는 비공개 디렉터리로, 파일을 두는 곳이에요. 누군가 업로드한 사진, 람다가 만드는 문서, 불러오는 모델 같은 것이요. 기록은 데이터베이스에 두세요. 파일에 대해 알려진 정보(누가, 언제 업로드했는지)도 기록이에요.
// 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()); }));
그 밖에 ReadBytes, WriteBytes, Delete, List, CreateFolder도 있고, 파일 제공용으로 Tree/Files/App도 있어요. 파일 시스템의 다른 곳에는 접근할 수 없어요.
키와 비밀번호
API 키, 비밀번호, 토큰은 코드가 아니라 시크릿에 두세요. 코드에 넣으면 모든 버전, 모든 다운로드, 기록을 읽는 모든 사람이 갖게 돼요. 코드는 시크릿을 이름으로 읽어요.
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"));
데이터에서 시크릿을 켜고 값을 설정하세요. 한 번 저장한 값은 다시 표시되지 않아요. 나에게도, 에이전트에게도요. 바꿀 수만 있어요. 목록에는 코드가 읽는데 아직 값이 없는 이름이 표시되고, 개요에서도 입력을 요청해요. Secret.Exists는 설정 여부를 알려 주므로, 없어도 동작하는 코드에 쓸 수 있어요. 다른 데이터처럼 시크릿도 모든 버전이 함께 쓰고, 초안은 복사본을 써요.
시크릿은 데이터베이스에 없는 키로 암호화해서 저장돼요. 다운로드한 프로젝트에서는 Secret.Read("NAME")가 환경 변수 NAME에서 읽어요. 값 자체는 여기에 남아요.
웹소켓
지원해요. 나중에 대충 붙인 기능도 아니에요. demo-game 데모는 플레이어를 짝지어 주고 모든 게임을 서버에서 실행해요. 가장 간단한 형태는 콜백 세 개예요.
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);
페이지가 내용을 듣기만 한다면(집계, 피드, 점수판 등) 서버 전송 이벤트(SSE)가 더 간단해요. 서버가 계속 써 내려가는 긴 응답 하나이고, 연결이 끊기면 브라우저가 알아서 다시 연결해요. demo-live 데모는 이 방식으로 모든 투표를 지켜보는 모두에게 보내요. 어느 쪽이든 바뀐 내용은 서버가 밀어 보내요. 몇 초마다 다시 묻는 페이지는 바뀌었는지 상관없이 매번 요청을 보내고, 그래도 늦어요.
누구나 한 번씩 걸리는 게 있어요. 브라우저는 웹소켓 핸드셰이크에 헤더를 설정할 수 없어요. 핸들러에 필요한 값은 쿼리로 넘겨서 connection.Request.Header.Query에서 읽게 하거나, 비밀 값은 첫 메시지로 보내세요.
할 수 없는 것
코드는 공유 서버에서 실행되기 때문에, C#의 일부 기능은 컴파일 전에 거부돼요. 프로세스 시작, 직접 소켓 열기, 어셈블리 로드, 워크스페이스 밖의 파일 시스템 접근, 그리고 이런 제한을 우회하려는 리플렉션이에요. 태스크를 await하지 않고 .Result나 .Wait()로 기다리는 것도 거부돼요. 요청은 코어당 하나의 스레드에서 실행되는데, 태스크는 바로 그것을 기다리는 스레드에서 끝나야 하기 때문이에요.
GenHTTP 모듈 API 전체를 포함해 나머지는 모두 쓸 수 있어요. 거부될 때는 그냥 실패했다고만 하지 않고, 어느 줄이 왜 거부됐는지 알려 줘요.
가지고 나가기
에디터에서 .NET 프로젝트로 다운로드를 누르면 전체를 통째로 받을 수 있어요. 바로 열어서 dotnet run으로 실행하고, 계속 가지고 있을 수 있는 솔루션이에요. GenHTTP 패키지만 있으면 되고, 컨테이너로 빌드하고 실행할 수 있는 Dockerfile도 함께 들어 있어요.
스니펫은 Project.cs가 되고, Program.cs가 그 반환값을 제공해요. 다른 파일은 작성한 그대로 옮겨져요. Workspace와 Assets는 프로그램 옆의 폴더 두 개가 되어 Platform 폴더에 따로 들어가고, 메서드도 같아서 코드를 하나도 바꿀 필요가 없어요. Secret은 같은 이름의 환경 변수를 읽고, 값은 여기에 남아요. 문서와 테스트는 docs와 tests에 담겨 함께 옮겨져요. Database는 database/database.db를 여는데, 다운로드에는 앱이 보관한 기록이 담긴 이 파일이 들어 있어요.
여기서 뭔가 만들기 전에 알아 두면 좋아요. 작성한 코드는 내 것이고, 통째로 가지고 나갈 수 있어요. 여기서 실행한다고 해서 여기에 묶이지 않아요.
코드 공개하기
만든 것이 다른 사람에게 도움이 될 것 같다면 코드를 공개하세요. 관리 화면에서 오픈 소스를 열고, 라이선스를 고른 다음(다른 걸 원하지 않으면 MIT) 켜세요. 그러면 오픈 소스 앱 목록에 코드의 전용 페이지가 생겨요. 누구나 코드를 읽고, 별표를 주고, 어느 버전이든 .NET 프로젝트로 다운로드로 받는 것과 같은 프로젝트로 라이선스와 함께 다운로드할 수 있어요.
이전 버전을 포함한 모든 버전이 문서, 테스트, 버전마다의 변경 사항과 함께 공개돼요. 앱이 보관하는 것(기록, 저장한 파일, 키와 비밀번호의 값)은 절대 공개되지 않고, 내가 직접 쓴 요청 내용이나 누가 앱을 쓰는지도 공개되지 않아요. 끄면 페이지가 사라지고, 별표는 다시 공개할 때를 위해 남아요.
코드에 있는 모든 것이 이전 버전까지 포함해 공개돼요. 키나 비밀번호는 공개 여부와 상관없이 코드에 넣지 말고, ‘데이터’의 키와 비밀번호에 두세요.
에이전트에게 맡기기
/mcp에 MCP 엔드포인트가 있어요. 에이전트를 여기에 연결하면 에디터로 할 수 있는 건 모두 할 수 있어요. 가이드 읽기, 데모 전체 읽기, 파일 작성, 컴파일, 배포까지요. 내부적으로는 같은 API예요.
에이전트는 작업하면서 이유도 남겨요. write_code가 요구 사항과 변경 사항을 함께 받거든요. 배포한 결과도 직접 확인할 수 있어요. read_logs는 람다의 최근 요청, 출력한 내용, 던진 예외의 스택 트레이스를 돌려줘요. 에이전트는 이걸로 코드가 작동한다고 짐작하지 않고 직접 확인해요. 같은 내용을 관리 화면에서도 볼 수 있어요. 에이전트는 작업하면서 문서와 테스트를 작성하고, 무언가를 바꾸기 전에 먼저 읽고, 초안을 확정하기 전에 초안 주소를 대상으로 테스트를 실행해요. 사람들이 찾아와야 하는 페이지에는 제목, 설명, 아이콘과 함께 링크를 공유할 때 보이는 미리보기도 달아요. 에이전트가 만드는 페이지 맨 아래에는 GenHTTP Lambda로 만들었다는 작은 한 줄을 넣어요. 원하지 않으면 말씀해 주세요. 그러면 빼 드려요.