배운 것을 모아두고, 자신의 말로 다시 설명하며 이해를 확인하는 local-first 학습 도구입니다.
AI 에이전트와 스킬은 lingo CLI로 노트와 질문을 만들고, 사용자는 localhost 브라우저에서 답합니다. 답변과 피드백은 내 컴퓨터의 SQLite에 쌓이며 Lingo 자체는 특정 AI provider를 호출하지 않습니다.
AI agent / skill ── lingo CLI ── local SQLite
│
User ─────────── browser UI ──────────┘
macOS와 Linux에서 최신 GitHub Release를 설치합니다. Bun이나 Node.js는 필요하지 않습니다.
curl -fsSL https://raw.githubusercontent.com/builder-mafia/lingo/main/install.sh | sh기본 설치 경로는 ~/.local/bin/lingo입니다. 이 디렉터리가 PATH에 없다면 사용하는 셸 설정에 다음 내용을 추가합니다.
export PATH="$HOME/.local/bin:$PATH"특정 버전이나 다른 설치 경로도 선택할 수 있습니다.
curl -fsSL https://raw.githubusercontent.com/builder-mafia/lingo/main/install.sh | \
sh -s -- --version v0.1.0 --install-dir "$HOME/bin"설치 스크립트는 운영체제와 CPU에 맞는 실행 파일을 선택하고 SHA256SUMS로 검증한 뒤 기존 lingo를 교체합니다. 최신 버전으로 업데이트할 때는 설치 명령을 다시 실행하면 됩니다.
지원 환경:
- macOS Apple Silicon, macOS Intel
- Linux arm64, Linux x64
Codex, Claude Code, Cursor 등에서 Lingo CLI를 올바른 학습 흐름으로 사용할 수 있도록 agent skill을 함께 제공합니다.
npx skills add builder-mafia/lingo --skill lingo이 명령은 agent용 지침을 설치합니다. 실제 lingo 실행 파일은 위 설치 스크립트로 별도 설치해야 합니다. 모든 프로젝트에서 사용하려면 -g를 추가할 수 있습니다.
lingo startLingo는 localhost 서버를 열고 접속 주소를 JSON으로 반환합니다.
{
"ok": true,
"data": {
"serverUrl": "http://127.0.0.1:4312"
}
}명령을 실행한 터미널은 서버를 유지하기 위해 계속 열어둡니다. 브라우저에서 serverUrl을 열고, 아래 CLI 명령은 다른 터미널에서 실행합니다.
lingo note create --data '{
"title": "캐시 무효화 이해하기",
"labels": ["Backend", "Architecture"]
}'성공 응답의 data.noteId를 이후 명령의 <note-id>에 사용합니다. data.noteUrl을 열면 해당 노트로 바로 이동합니다.
{
"ok": true,
"data": {
"noteId": "<note-id>",
"title": "캐시 무효화 이해하기",
"labels": ["Backend", "Architecture"],
"createdAt": "2026-07-18T12:00:00.000Z",
"noteUrl": "http://127.0.0.1:4312/notes/<note-id>"
}
}lingo note summary set <note-id> --data '{
"content": "캐시된 값과 원본 데이터의 일관성을 언제, 어떻게 맞출지 결정하는 문제"
}'lingo question add <note-id> --data '{
"question": "캐시 무효화가 어려운 이유를 자신의 말로 설명해보세요.",
"referenceAnswer": "원본 변경 시점과 캐시 갱신 시점이 어긋나면 오래된 값이 노출되며, 동시 요청과 실패 상황까지 고려해야 하기 때문이다."
}'이제 브라우저의 노트 작업공간에서 질문을 열고 답할 수 있습니다.
Lingo는 AI와 사용자가 서로 다른 인터페이스를 사용하도록 역할을 나눕니다.
- AI 에이전트나 스킬이 대화에서 배운 내용을
lingoCLI로 정리합니다. - 노트, 요약, 질문이 로컬 SQLite에 저장됩니다.
- 사용자는
lingo start로 연 브라우저에서 질문에 자신의 말로 답합니다. - 외부 AI 에이전트가 평가할 답변을 CLI로 읽고 피드백을 다시 저장합니다.
- 사용자는 브라우저에서 피드백을 확인하고 다시 답하거나 질문을 정리합니다.
Lingo는 답변을 대신 만들거나 AI provider를 선택하지 않습니다. Codex, Claude Code, Cursor 또는 다른 도구가 Lingo를 호출할 수 있지만, 로컬 앱은 어느 provider를 사용했는지 알 필요가 없습니다.
모든 CLI 응답은 JSON입니다. 실패하면 JSON 오류를 stderr에 출력하고 0이 아닌 종료 코드를 반환합니다.
| 목적 | 명령 |
|---|---|
| 버전 확인 | lingo --version |
| 브라우저 작업공간 열기 | lingo start |
| 노트 만들기 | lingo note create (--data <json> | --data-file <path>) |
| 노트 요약 저장 | lingo note summary set <note-id> (--data <json> | --data-file <path>) |
| 질문 추가 | lingo question add <note-id> (--data <json> | --data-file <path>) |
| 주관식 답변 저장 | lingo answer set <question-id> (--data <json> | --data-file <path>) |
| 평가가 필요한 답변 조회 | lingo answer list <note-id> |
| AI 피드백 저장 | lingo evaluation set <question-id> (--data <json> | --data-file <path>) |
노트에는 필수 제목과 선택 라벨을 저장합니다. 라벨의 앞뒤 공백과 중복은 자동으로 제거됩니다.
lingo note create --data '{
"title": "좋은 API 경계 설계하기",
"labels": ["API", "Design"]
}'요약은 현재 이해에 맞게 언제든 갱신할 수 있습니다.
lingo note summary set <note-id> --data '{
"content": "변경 이유가 다른 책임을 분리하고 안정적인 계약으로 연결한다."
}'referenceAnswer가 있으면 주관식 질문으로 저장됩니다.
lingo question add <note-id> --data '{
"question": "이 API에서 인증과 권한 검사를 분리해야 하는 이유는 무엇인가요?",
"referenceAnswer": "인증은 사용자의 신원을 확인하고 권한 검사는 해당 사용자의 행동 가능 범위를 판단하므로 변경 이유가 다르다."
}'브라우저 UI가 답변을 저장하지만 CLI에서도 같은 답변을 저장하거나 갱신할 수 있습니다.
lingo answer set <question-id> --data '{
"content": "신원을 확인하는 일과 허용된 행동을 판단하는 일은 서로 다른 정책에 따라 바뀌기 때문이다."
}'choices와 correctId가 있으면 객관식 질문으로 저장됩니다. correctId는 정답 선택지의 order를 가리킵니다.
lingo question add <note-id> --data '{
"question": "HTTP 401과 403을 가장 잘 구분한 설명은 무엇인가요?",
"choices": [
{
"order": 1,
"option": "401은 인증이 필요하고 403은 권한이 부족하다",
"explanation": "신원 확인 여부와 접근 권한 여부를 구분한다."
},
{
"order": 2,
"option": "두 상태 코드는 항상 같은 의미다",
"explanation": "인증과 권한 실패는 서로 다른 상황이다."
}
],
"correctId": 1
}'외부 AI 에이전트는 아직 피드백이 없는 주관식 답변을 읽습니다.
lingo answer list <note-id>{
"ok": true,
"data": [
{
"questionId": "<question-id>",
"question": "...",
"referenceAnswer": "...",
"answer": "..."
}
]
}평가가 끝나면 피드백을 저장합니다.
lingo evaluation set <question-id> --data '{
"feedback": "인증과 권한의 변경 이유를 잘 구분했습니다. 여러 역할이 하나의 리소스에 접근할 때 정책이 어떻게 달라지는지도 설명해보세요."
}'피드백을 저장한 답변은 다음 answer list <note-id> 결과에서 제외됩니다.
JSON 입력이 필요한 명령은 다음 중 정확히 하나를 사용합니다.
--data '<JSON string>'--data-file <JSON file path>
긴 입력은 JSON 파일로 관리할 수 있습니다.
{
"question": "낙관적 잠금은 어떤 충돌을 방지하나요?",
"referenceAnswer": "읽은 이후 다른 요청이 값을 변경했는지 버전으로 확인해 덮어쓰기를 방지한다."
}lingo question add <note-id> --data-file ./question.json--data와 --data-file을 함께 사용하거나 같은 플래그를 두 번 전달하면 명령이 실패합니다.
입력 규칙:
- 모든 ID는 UUID입니다.
- 제목, 요약, 질문, 답변, 피드백은 빈 문자열일 수 없습니다.
- 객관식 질문은 선택지가 2개 이상이어야 합니다.
choices[].order는 중복되지 않는 양의 정수입니다.correctId는 실제choices[].order중 하나여야 합니다.- 객관식은
choices와correctId, 주관식은referenceAnswer를 전달합니다.
- 모든 노트, 질문, 답변, 피드백은 기본적으로
~/.lingo/lingo.sqlite에 저장됩니다. lingo start는 외부 네트워크가 아닌127.0.0.1:4312에만 서버를 엽니다.- 실행 파일을 업데이트해도 로컬 데이터베이스는 유지됩니다.
- Lingo 앱은 AI provider의 API 키나 계정을 요구하지 않습니다.
- 답변 평가에 어떤 AI를 사용할지와 어떤 데이터를 전달할지는 Lingo를 호출하는 사용자 또는 스킬이 결정합니다.
포트를 변경하려면 LINGO_PORT를 지정합니다.
LINGO_PORT=4400 lingo start소스에서 개발할 때만 Bun이 필요합니다.
git clone https://github.com/builder-mafia/lingo.git
cd lingo
bun install --frozen-lockfile
bun test
bun run typecheck로컬 API 서버와 Vite UI를 함께 실행합니다.
bun run dev:ui기본 주소는 UI http://127.0.0.1:5173, API http://127.0.0.1:4312입니다. LINGO_UI_PORT와 LINGO_PORT로 각각 변경할 수 있습니다.
독립 실행 파일을 현재 플랫폼용으로 빌드합니다.
bun run build:binary지원하는 다른 플랫폼을 지정할 수도 있습니다.
bun run build:binary --target bun-darwin-arm64 --outfile dist/bin/lingo-darwin-arm64
bun run build:binary --target bun-darwin-x64 --outfile dist/bin/lingo-darwin-x64
bun run build:binary --target bun-linux-arm64 --outfile dist/bin/lingo-linux-arm64
bun run build:binary --target bun-linux-x64-baseline --outfile dist/bin/lingo-linux-x64릴리스할 버전으로 package.json을 갱신하고 main에 머지한 뒤 release 명령을 실행합니다. 명령은 현재 버전으로 annotated tag를 만들고 원격에 push합니다.
git switch main
git pull --ff-only
bun run release --dry-run
bun run releaserelease 명령은 작업 트리가 깨끗한지, 로컬 main이 origin/main과 같은지, 같은 버전 태그가 이미 존재하는지 검사합니다. 마지막 확인을 생략해야 하는 자동화 환경에서는 bun run release --yes를 사용합니다.
Release 워크플로는 전체 테스트와 타입 검사를 통과한 뒤 macOS·Linux의 arm64·x64 실행 파일, SHA256SUMS, artifact attestation을 게시합니다.
src/
├── cli/commands/ # CLI use cases
├── layers/ # Effect services and Live Layers
├── schemas/ # Zod domain contracts
├── server/ # Hono localhost API and UI server
├── ui/ # Vite + React browser app
├── cli.ts # CLI entry point
└── runtime.ts # Effect Layer composition