
보안에 중점을 둔 AI 개인 비서

Stavrobot은 "AI 어시스턴트가 필요한 모든 접근 권한, 그 이상은 없다"는 원칙으로 구축된 개인 AI 어시스턴트입니다.
AI 어시스턴트의 모든 멋진 기능을 갖추고 있지만, 샌드박싱, 격리, 최소 권한에 중점을 둡니다. 가벼우며 docker compose up만으로 배포할 수 있습니다.
uv를 통해 pip 의존성을 가진 임의의 Python 코드를 호스트 환경과 격리하여 실행합니다.AI 지원 설치: 코딩 AI(Claude Code, Cursor, Windsurf 등)에게 https://stavrobot.stavros.io/INSTALL.md를 가져와서 따르도록 지시하면, 설정 전체를 대화형으로 안내합니다.
수동 설치:
Telegram에서 @BotFather에게 메시지를 보내 봇을 만들고 토큰을 복사합니다. @userinfobot에게 메시지를 보내 사용자 ID를 얻습니다(채팅 ID로 사용됨).
env.example을 .env로 복사하고 **POSTGRES_PASSWORD**를 안전한 값으로 변경하고 TZ를 사용자의 시간대로 설정합니다.
config.example.toml을 data/main/config.toml로 복사하고 필수 필드를 채웁니다: apiKey, password, publicHostname, [owner].name, [owner].telegram(사용자의 채팅 ID), [telegram].botToken. 그 외 파일의 모든 항목은 선택 사항입니다.
docker compose up --build
끝입니다. Telegram에서 봇에게 메시지를 보내면 응답할 것입니다. Signal, WhatsApp, 이메일 및 기타 옵션에 대한 자세한 설정 섹션은 아래를 참조하세요.
config.example.toml을 data/main/config.toml로 복사합니다.authFile(또는 apiKey)과 publicHostname을 설정합니다. 나머지는 모두 선택 사항입니다.env.example을 .env로 복사하고 시간대(TZ)를 설정합니다. Postgres 자격 증명 및 기타 환경 설정도 여기서 재정의할 수 있습니다. POSTGRES_PASSWORD는 항상 안전한 값으로 설정하세요 — 기본값은 약한 자리 표시자이므로 프로덕션에서 사용해서는 안 됩니다.Stavrobot은 config.toml에서 baseUrl을 설정하여 모든 OpenAI 호환 엔드포인트(Ollama, LiteLLM, vLLM 등) 또는 사용자 정의 Anthropic 호환 프록시를 가리킬 수 있습니다. 필요한 필드와 예시 구성은 config.example.toml을 참조하세요.
앱은 두 가지 인증 모드를 지원합니다: API 키 또는 OAuth.
config.toml에 apiKey를 설정합니다. 로그인이나 로그아웃이 필요하지 않습니다.config.toml에 authFile(자격 증명이 저장될 경로)을 설정합니다. 로그인 페이지는 Pi에서 지원하는 모든 OAuth 제공자와 함께 작동합니다.
<your-hostname>/login에 접속합니다. 페이지의 안내를 따르면 자격 증명이 인증 파일에 저장됩니다. 봇 실행 중에 인증이 만료되면 메시징 플랫폼을 통해 로그인 URL이 포함된 메시지를 보냅니다.authFile 경로의 파일을 삭제합니다. 봇은 다음 메시지에서 누락된 자격 증명을 감지하고 다시 로그인하라는 메시지를 표시합니다.coder 컨테이너는 선택 사항입니다(자체 프로그래밍 기능에만 필요). 구독 인증(OAuth)이 있는 Claude Code를 사용하며, 기본 앱의 API 키와는 별개입니다.
Docker Compose 프로필은 쉼표로 구분되므로 결합할 수 있습니다(예: COMPOSE_PROFILES=signal,coder).
.env 파일에 COMPOSE_PROFILES를 설정하여 coder를 포함시킵니다(예: COMPOSE_PROFILES=coder 또는 Signal도 사용하는 경우 COMPOSE_PROFILES=signal,coder).docker compose --profile coder up --builddocker compose exec -u coder coder claude (아직 로그인하지 않은 경우 로그인하라는 메시지가 표시됨).[coder].model을 Claude Code 모델 별칭(sonnet, opus, 또는 haiku)으로 설정합니다.Signal에는 별도의 전화번호가 필요합니다. 개인 번호가 아닙니다. 선불 SIM 또는 VoIP 번호가 작동합니다.
.env 파일에서 COMPOSE_PROFILES=signal의 주석을 해제하여 signal-bridge 컨테이너를 활성화합니다.docker compose --profile signal builddocker compose --profile signal run --rm --entrypoint bash signal-bridge -c 'signal-cli link -n "Stavrobot" | tee >(xargs -L 1 qrencode -t utf8)' — 휴대폰으로 QR 코드를 스캔합니다(Signal > 설정 > 연결된 기기).docker compose --profile signal run --rm --entrypoint bash signal-bridge -c 'signal-cli -u +YOUR_NUMBER register'를 실행한 다음, docker compose --profile signal run --rm --entrypoint bash signal-bridge -c 'signal-cli -u +YOUR_NUMBER verify CODE'로 확인합니다.[signal].account를 설정합니다.docker compose up --build/settings 웹 UI를 통해 허용된 번호를 추가합니다.[telegram].botToken을 설정합니다.[owner].telegram에 채팅 ID(휴대폰 번호가 아님)를 설정합니다./settings 웹 UI를 통해 허용된 채팅 ID를 추가합니다.WhatsApp에는 별도의 전화번호가 필요하지 않습니다. 그렇지 않으면 자기 자신에게 메시지를 보내는 셈이 되어 제대로 작동하지 않습니다. WhatsApp은 Baileys를 사용합니다. 이는 공식 WhatsApp Web 라이브러리가 아닌 것으로, 컴패니언 기기(WhatsApp Web처럼)로 연결됩니다.
위험: Baileys는 비공식 API를 사용합니다. WhatsApp은 이를 사용하는 계정을 차단할 수 있습니다. 사용에 따른 책임은 본인에게 있습니다.
config.toml에 [whatsapp] 섹션을 추가합니다(형식은 config.example.toml 참조).docker compose up --builddocker compose logs -f app)../data/whatsapp에 저장되어 재시작 후에도 유지됩니다./settings 웹 UI를 통해 허용된 전화번호를 추가합니다.이메일은 수신 배달에 Cloudflare Email Worker를, 발신에 SMTP를 사용합니다. 전체 Worker 코드와 자세한 설정 지침은 config.example.toml을 참조하세요.
config.toml에 [email] 섹션을 추가하고 SMTP 자격 증명과 임의의 webhookSecret을 설정합니다.config.example.toml의 코드) Worker에 WEBHOOK_URL 및 WEBHOOK_SECRET 환경 변수를 설정합니다./settings 웹 UI를 통해 허용된 발신자 주소를 추가합니다.docker compose up --build
API는 http://localhost:10567/chat에서 사용할 수 있습니다.
참고: Docker Compose는 앱을 localhost:10567에서만 노출합니다. 외부에서 접근 가능하게 하려면(Telegram/Signal 웹훅 및 publicHostname 설정에 필요) localhost:10567을 가리키는 리버스 프록시(예: Nginx, Caddy)를 설정하세요. 포트를 직접 노출할 수도 있지만, 트래픽이 암호화되지 않으므로 권장되지 않습니다.
Node.js >= 20과 실행 중인 PostgreSQL 인스턴스가 필요합니다.
npm install && npm run build && npm start
참고: Python 실행 및 Signal 통합은 Docker 컨테이너 내에서만 작동합니다.
Stavrobot에는 3계층 지식 시스템이 있습니다: 기억, 스크래치패드, 데이터베이스. 봇이 이를 꽤 잘 관리하지만, 봇이 제대로 사용할 수 있도록 사용자가 돕는 것이 중요하므로 알아두어야 합니다.
기억은 항상 시스템 프롬프트에 전체가 삽입됩니다. 이는 매번 컨텍스트에 포함되므로, 너무 많이 갖고 있으면 컨텍스트가 늘어날 수 있으므로 절약해서 사용해야 합니다. 좋은 기억의 예는 "사용자는 비공식적인 스타일로 채팅하는 것을 선호합니다."와 같이 봇이 매번 알아야 할 내용입니다. 추가 컨텍스트 길이에 비용이 들더라도 말이죠.
스크래치패드는 덜 자주 접근하는 지식을 보관하는 곳이지만, 특정 주제와 관련된 지식입니다. 스크래치패드 항목에는 제목과 본문이 있으며, 제목은 자동으로 컨텍스트에 삽입됩니다. 중요하지만 덜 자주 필요하고 일반적으로 특정 주제에 해당하는 것들에 사용하세요.
예를 들어, 좋은 스크래치패드 항목은 "식이 선호도"이며, 무엇을 언제 먹는지에 대한 세부 사항이 포함됩니다. 봇은 "식이 선호도"라는 주제가 있다는 것을 알지만, 자동으로 실제 텍스트를 컨텍스트에 로드하지는 않고 필요할 때만 접근합니다.
음식에 대해 봇과 대화할 때, 봇은 확인할 수 있는 "식이 선호도" 스크래치패드 항목이 있다는 것을 알고 있으며, 보통 스스로 그렇게 합니다.
데이터베이스는 세 번째 계층으로, 기억이나 스크래치패드에 속하지 않는 구조화된 데이터나 대량 데이터를 위한 곳입니다. 봇은 제한 없는 SQL을 통해 PostgreSQL에 대한 전체 읽기/쓰기 액세스 권한을 가지므로, 테이블을 만들고, 쿼리를 실행하고, 무엇이든 저장할 수 있습니다. 목록, 로그, 구조화된 레코드, 또는 산문으로 읽는 것보다 쿼리하는 것이 더 나은 데이터에 사용하세요.
봇은 일반적으로 무엇을 언제 사용해야 하는지 잘 알지만, 정보를 어디에 둘지 명시적으로 알려주고 싶을 때가 있습니다.
Stavrobot은 Signal, Telegram, WhatsApp 또는 이메일을 통해 사용자를 대신하여 사람들에게 메시지를 보낼 수 있습니다. 친구와 저녁 식사를 약속해야 하나요? 봇에게 두 사람 모두에게 맞는 시간을 찾으라고 하면, 봇이 그들에게 메시지를 보내고 날짜를 협상한 후 달력에 추가합니다. 약속을 잡거나, 그룹 외출을 조정하거나, 바쁠 때 누군가에게 질문하고 싶나요? 봇에게 필요한 것과 누구와 대화해야 하는지만 알려주세요.
봇은 각 대화에 대해 전용 하위 에이전트를 생성하며, 고유한 지침과 컨텍스트를 제공하여 다른 사람과의 주고받음을 처리하면서 기본 채팅을 복잡하게 만들지 않습니다. 작업이 완료되면 연락처를 비활성화하고 사용자에게 보고합니다.
안전을 위해 봇이 누군가와 대화하려면 두 가지가 필요합니다:
/settings로 이동하여 전화번호(Signal 또는 WhatsApp) 또는 채팅 ID(Telegram)를 추가합니다. 이는 사람당 한 번만 하면 됩니다. 봇은 이 목록을 수정할 수 없으며, 목록에 없는 사람에게는 어떤 경우에도 메시지를 보낼 수 없습니다.일반적인 흐름: /settings를 통해 친구의 전화번호를 허용 목록에 한 번 추가한 다음, 봇에게 "다음 주에 Alex와 저녁 식사 시간을 찾아줘"라고 말합니다. 봇이 Alex의 연락처 레코드를 생성하고, 하위 에이전트를 시작하고, Signal로 Alex에게 메시지를 보내고, 날짜를 찾기 위해 주고받은 다음 결과를 사용자에게 보고합니다.
스킬은 봇에게 새로운 기능(예: 테이블 생성, 지식 저장, 페이지 만들기, 특정 워크플로우 따르기 등)을 가르치는 일반 텍스트 지침 파일입니다. 코드가 아니라 봇이 읽고 따르는 자연어 지침입니다.
스킬 시스템을 설치하려면 봇에게 https://stavrobot.stavros.io/skills/bootstrap.md를 가져와서 지침을 따르라고 지시하세요.
사용 가능한 스킬의 전체 목록은 https://stavrobot.stavros.io/skills/index.md에 있습니다. 스킬을 설치하려면 봇에게 해당 URL에서 가져와서 설치하라고 지시하기만 하면 됩니다. 봇은 스킬이 무엇을 하는지 보여주고 진행하기 전에 확인을 요청합니다.
스킬 파일은 이 저장소의 pages 브랜치에 있습니다(Cloudflare Pages를 통해 제공됨). 스킬을 기여하려면 해당 브랜치의 skills/에 마크다운 파일을 추가하세요. 각 스킬 파일에는 title, description, version 및 선택적 author가 포함된 YAML front matter가 있으며, 본문에는 평이한 언어로 된 지침이 있습니다. 전체 작성 가이드는 SKILL-AUTHORING.md를 참조하세요. pages 브랜치에 PR을 제출하세요.
Stavrobot 플러그인을 만드는 데 필요한 모든 정보는 PLUGIN.md를 참조하세요. 이 문서는 사람과 LLM 모두를 위한 참고 자료로 사용됩니다.
플러그인은 봇의 핵심 기능(음성 메모 "듣기", 음성 메모 보내기, 주변 장소 인식, 웹 검색 등)을 활성화하는 데 상당히 필요합니다.
이러한 기능은 기본 제공되지 않으므로 사용자가 원하는 대로 봇을 사용자 정의할 수 있습니다. 하지만 플러그인을 설치해야 합니다. 그렇지 않으면 중요한 기능이 누락될 수 있습니다.
일부 자사 플러그인은 여기에서 찾을 수 있습니다:
https://github.com/orgs/stavrobot/repositories
세 개의 핵심 Docker 컨테이너: app(TypeScript 서버, POST /chat 노출, POST /telegram/webhook에서 Telegram 웹훅 처리, POST /email/webhook에서 수신 이메일 웹훅 처리, Baileys를 통해 인프로세스 방식으로 WhatsApp 실행), postgres(PostgreSQL 17, 영구 상태 저장), plugin-runner(Node.js 서버 — 로컬 생성 및 git 설치된 플러그인 목록, 검사, 실행). 선택적 coder 컨테이너(편집 가능한 플러그인 생성 및 수정을 위한 Claude Code 헤드리스 에이전트)는 coder Docker Compose 프로필을 통해 활성화됩니다. 주 에이전트는 각각 고유한 대화 기록, 시스템 프롬프트 및 도구 허용 목록을 가진 하위 에이전트를 생성할 수 있습니다. 대화 상대는 인바운드 메시지 라우팅을 위해 에이전트에 할당된 연락처 레코드입니다.
docker compose exec app node -e "fetch('http://localhost:3001/chat',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:'Send the message \"Hello from Stavrobot\" to my Signal number.'})}).then(r=>r.text()).then(console.log)"